diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f9cf30c31..db0da6ad4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,298 +1,299 @@ stages: - configure - build - check-warnings - test - deploy .docker_build: image: 'docker:19.03.11' stage: .pre services: - docker:19.03.11-dind variables: # Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled DOCKER_HOST: tcp://docker:2376 DOCKER_TLS_CERTDIR: "/certs" before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: - cd test/ci/${IMAGE_NAME}/ - docker build -t registry.gitlab.com/akantu/akantu/${IMAGE_NAME} . - docker push registry.gitlab.com/akantu/akantu/${IMAGE_NAME} docker build:debian-testing: variables: IMAGE_NAME: debian:testing extends: .docker_build rules: - changes: - test/ci/debian:testing/Dockerfile docker build:ubuntu-lts: variables: IMAGE_NAME: ubuntu:lts extends: .docker_build rules: - changes: - test/ci/ubuntu:lts/Dockerfile .configure: stage: configure except: - tags variables: BLA_VENDOR: 'Generic' script: - cmake -E make_directory build - cd build - cmake -DAKANTU_COHESIVE_ELEMENT:BOOL=TRUE -DAKANTU_IMPLICIT:BOOL=TRUE -DAKANTU_PARALLEL:BOOL=TRUE -DAKANTU_STRUCTURAL_MECHANICS:BOOL=TRUE -DAKANTU_HEAT_TRANSFER:BOOL=TRUE -DAKANTU_DAMAGE_NON_LOCAL:BOOL=TRUE -DAKANTU_PYTHON_INTERFACE:BOOL=TRUE + -DAKANTU_CONTACT_MECHANICS:BOOL=TRUE -DAKANTU_EXAMPLES:BOOL=TRUE -DAKANTU_BUILD_ALL_EXAMPLES:BOOL=TRUE -DAKANTU_TEST_EXAMPLES:BOOL=FALSE -DAKANTU_TESTS:BOOL=TRUE -DAKANTU_RUN_IN_DOCKER:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Coverage .. artifacts: when: on_success paths: - build expire_in: 10h .build: stage: build script: - cmake --build build/src > >(tee -a ${output}-out.log) 2> >(tee -a ${output}-err.log >&2) - cmake --build build/python > >(tee -a ${output}-out.log) 2> >(tee -a ${output}-err.log >&2) - cmake --build build/test/ > >(tee -a ${output}-out.log) 2> >(tee -a ${output}-err.log >&2) - cmake --build build/examples > >(tee -a ${output}-out.log) 2> >(tee -a ${output}-err.log >&2) artifacts: when: on_success paths: - build/ #- ${output}-out.log - ${output}-err.log expire_in: 10h .tests: stage: test script: - cd build - ctest -T test --no-compress-output --timeout 1800 after_script: - cd build - tag=$(head -n 1 < Testing/TAG) - if [ -e Testing/${tag}/Test.xml ]; then - xsltproc -o ./juint.xml ${CI_PROJECT_DIR}/test/ci/ctest2junit.xsl Testing/${tag}/Test.xml; - fi - gcovr --xml --output coverage.xml --object-directory ${CI_PROJECT_DIR}/build --root ${CI_PROJECT_DIR} -s || true artifacts: when: always paths: - build/juint.xml - build/coverage.xml reports: junit: - build/juint.xml cobertura: - build/coverage.xml .analyse_build: stage: check-warnings script: - if [[ $(cat ${output}-err.log | grep warning -i) ]]; then - cat ${output}-err.log; - exit 1; - fi allow_failure: true artifacts: when: on_failure paths: - "$output-err.log" # ------------------------------------------------------------------------------ .cache_build: variables: CCACHE_BASEDIRE: ${CI_PROJECT_DIR}/build CCACHE_DIR: ${CI_PROJECT_DIR}/.ccache CCACHE_NOHASHDIR: 1 CCACHE_COMPILERCHECK: content cache: key: ${output} policy: pull-push paths: - .ccache/ - third-party/google-test - third-party/pybind11 before_script: - ccache --zero-stats || true after_script: - ccache --show-stats || true # ------------------------------------------------------------------------------ .image_debian_testing: image: registry.gitlab.com/akantu/akantu/debian:testing .image_ubuntu_lts: image: registry.gitlab.com/akantu/akantu/ubuntu:lts # ------------------------------------------------------------------------------ .compiler_gcc: variables: CC: /usr/lib/ccache/gcc CXX: /usr/lib/ccache/g++ FC: gfortran .compiler_clang: variables: CC: /usr/lib/ccache/clang CXX: /usr/lib/ccache/clang++ FC: gfortran # ------------------------------------------------------------------------------ .debian_testing_gcc: variables: output: debian_testing_gcc extends: - .compiler_gcc - .image_debian_testing - .cache_build .debian_testing_clang: variables: output: debian_testing_clang extends: - .compiler_clang - .image_debian_testing - .cache_build .ubuntu_lts_gcc: variables: output: ubuntu_lts_gcc extends: - .compiler_gcc - .image_ubuntu_lts - .cache_build # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ configure:debian_testing_gcc: extends: - .debian_testing_gcc - .configure cache: policy: pull-push build:debian_testing_gcc: extends: - .debian_testing_gcc - .build dependencies: - configure:debian_testing_gcc test:debian_testing_gcc: extends: - .debian_testing_gcc - .tests dependencies: - build:debian_testing_gcc analyse_build:debian_testing_gcc: extends: - .debian_testing_gcc - .analyse_build dependencies: - build:debian_testing_gcc # ------------------------------------------------------------------------------ configure:debian_testing_clang: extends: - .debian_testing_clang - .configure cache: policy: pull-push build:debian_testing_clang: extends: - .debian_testing_clang - .build dependencies: - configure:debian_testing_clang test:debian_testing_clang: extends: - .debian_testing_clang - .tests dependencies: - build:debian_testing_clang analyse_build:debian_testing_clang: extends: - .debian_testing_clang - .analyse_build dependencies: - build:debian_testing_clang # ------------------------------------------------------------------------------ configure:ubuntu_lts_gcc: extends: - .ubuntu_lts_gcc - .configure cache: policy: pull-push build:ubuntu_lts_gcc: extends: - .ubuntu_lts_gcc - .build dependencies: - configure:ubuntu_lts_gcc analyse_build:ubuntu_lts_gcc: extends: - .ubuntu_lts_gcc - .analyse_build dependencies: - build:ubuntu_lts_gcc test:ubuntu_lts_gcc: extends: - .ubuntu_lts_gcc - .tests dependencies: - build:ubuntu_lts_gcc # ------------------------------------------------------------------------------ include: - template: Code-Quality.gitlab-ci.yml code_quality: artifacts: paths: [gl-code-quality-report.json] # ------------------------------------------------------------------------------ pages: stage: deploy extends: - .debian_testing_gcc script: - cd build - cmake -DAKANTU_DOCUMENTATION_DEVELOPER_MANUAL=ON .. - cmake --build . -t sphinx-doc - mv doc/dev-doc/html ../public dependencies: - build:debian_testing_gcc artifacts: paths: - public only: - features/doc diff --git a/packages/contact_mechanics.cmake b/packages/contact_mechanics.cmake index c6ade2eed..6c39af946 100644 --- a/packages/contact_mechanics.cmake +++ b/packages/contact_mechanics.cmake @@ -1,64 +1,64 @@ #=============================================================================== # @file contact_mechanics.cmake # # @author Mohit Pundir # # @date creation: Sun Oct 21 2018 # @date last modification: Sun Oct 21 2018 # # @brief package description for contact mechanics # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== - package_declare(contact_mechanics + DEPENDS model_couplers DESCRIPTION "Use Contact Mechanics package of Akantu") package_declare_sources(contact_mechanics model/contact_mechanics/contact_mechanics_model.hh model/contact_mechanics/contact_mechanics_model.cc model/contact_mechanics/contact_detector.hh model/contact_mechanics/contact_detector.cc model/contact_mechanics/contact_detector_inline_impl.cc model/contact_mechanics/contact_element.hh model/contact_mechanics/geometry_utils.hh model/contact_mechanics/geometry_utils.cc model/contact_mechanics/geometry_utils_inline_impl.cc model/contact_mechanics/resolution.hh model/contact_mechanics/resolution.cc model/contact_mechanics/resolution_utils.hh model/contact_mechanics/resolution_utils.cc model/contact_mechanics/resolutions/resolution_penalty.hh model/contact_mechanics/resolutions/resolution_penalty.cc model/contact_mechanics/resolutions/resolution_penalty_quadratic.hh model/contact_mechanics/resolutions/resolution_penalty_quadratic.cc model/contact_mechanics/surface_selector.hh model/contact_mechanics/surface_selector.cc) package_declare_documentation_files(contact_mechanics manual-contactmechanicsmodel.tex manual-contact-detector.tex ) package_declare_documentation(contact_mechanics "This package activates the contact mechanics model") diff --git a/packages/damage_non_local.cmake b/packages/damage_non_local.cmake index bb3de2867..0635dc515 100644 --- a/packages/damage_non_local.cmake +++ b/packages/damage_non_local.cmake @@ -1,66 +1,65 @@ #=============================================================================== # @file damage_non_local.cmake # # @author Nicolas Richart # # @date creation: Fri Jun 15 2012 # @date last modification: Mon Jan 18 2016 # # @brief package description for non-local materials # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== - package_declare(damage_non_local DESCRIPTION "Package for Non-local damage constitutives laws Akantu" DEPENDS lapack) package_declare_sources(damage_non_local model/solid_mechanics/materials/material_damage/material_damage_non_local.hh model/solid_mechanics/materials/material_damage/material_marigo_non_local.cc model/solid_mechanics/materials/material_damage/material_marigo_non_local.hh model/solid_mechanics/materials/material_damage/material_mazars_non_local.cc model/solid_mechanics/materials/material_damage/material_mazars_non_local.hh model/solid_mechanics/materials/weight_functions/damaged_weight_function.hh model/solid_mechanics/materials/weight_functions/damaged_weight_function_inline_impl.hh model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function.hh model/solid_mechanics/materials/weight_functions/remove_damaged_weight_function_inline_impl.hh model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function.hh model/solid_mechanics/materials/weight_functions/remove_damaged_with_damage_rate_weight_function_inline_impl.hh model/solid_mechanics/materials/weight_functions/stress_based_weight_function.hh model/solid_mechanics/materials/weight_functions/stress_based_weight_function.cc model/solid_mechanics/materials/weight_functions/stress_based_weight_function_inline_impl.hh ) package_declare_material_infos(damage_non_local LIST AKANTU_DAMAGE_NON_LOCAL_MATERIAL_LIST INCLUDE material_non_local_includes.hh ) package_declare_documentation_files(damage_non_local manual-constitutive-laws-non_local.tex manual-appendix-materials-non-local.tex) package_declare_documentation(damage_non_local "This package activates the non local damage feature of AKANTU" "") diff --git a/packages/model_couplers.cmake b/packages/model_couplers.cmake index cf800957b..48e24dc72 100644 --- a/packages/model_couplers.cmake +++ b/packages/model_couplers.cmake @@ -1,50 +1,48 @@ #=============================================================================== # @file model_couplers.cmake # # @author Mohit Pundir # # @date creation: Sun Sep 30 2018 # @date last modification: Sun Sep 28 2018 # # @brief package description for model couplers # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== - -package_declare(model_couplers - DESCRIPTION "Use Model Couplers package of Akantu" - DEPENDS contact_mechanics) +package_declare(model_couplers ADVANCED + DESCRIPTION "Use Model Couplers package of Akantu") package_declare_sources(model_couplers model/model_couplers/coupler_solid_contact.hh model/model_couplers/coupler_solid_contact.cc model/model_couplers/coupler_solid_cohesive_contact.hh model/model_couplers/coupler_solid_cohesive_contact.cc ) package_declare_documentation_files(model_couplers # ) package_declare_documentation(model_couplers "This package activates the model couplers within Akantu. " "It has no additional dependencies." ) diff --git a/src/common/aka_grid_dynamic.hh b/src/common/aka_grid_dynamic.hh index 2872715de..2d1e9054e 100644 --- a/src/common/aka_grid_dynamic.hh +++ b/src/common/aka_grid_dynamic.hh @@ -1,533 +1,533 @@ /** * @file aka_grid_dynamic.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Thu Feb 21 2013 * @date last modification: Wed Nov 08 2017 * * @brief Grid that is auto balanced * * * Copyright (©) 2014-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_types.hh" #include "mesh_accessor.hh" #include /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef AKANTU_AKA_GRID_DYNAMIC_HH_ #define AKANTU_AKA_GRID_DYNAMIC_HH_ namespace akantu { class Mesh; template class SpatialGrid { public: explicit SpatialGrid(UInt dimension) : dimension(dimension), spacing(dimension), center(dimension), lower(dimension), upper(dimension), empty_cell() {} SpatialGrid(UInt dimension, const Vector & spacing, const Vector & center) : dimension(dimension), spacing(spacing), center(center), lower(dimension), upper(dimension), empty_cell() { for (UInt i = 0; i < dimension; ++i) { lower(i) = std::numeric_limits::max(); upper(i) = -std::numeric_limits::max(); } } virtual ~SpatialGrid() = default; class neighbor_cells_iterator; class cells_iterator; class CellID { public: CellID() = default; explicit CellID(UInt dimention) : ids(dimention) {} void setID(UInt dir, Int id) { ids(dir) = id; } Int getID(UInt dir) const { return ids(dir); } bool operator<(const CellID & id) const { return std::lexicographical_compare( ids.storage(), ids.storage() + ids.size(), id.ids.storage(), id.ids.storage() + id.ids.size()); } bool operator==(const CellID & id) const { return std::equal(ids.storage(), ids.storage() + ids.size(), id.ids.storage()); } bool operator!=(const CellID & id) const { return !(operator==(id)); } class neighbor_cells_iterator : private std::iterator { public: neighbor_cells_iterator(const CellID & cell_id, bool end) : cell_id(cell_id), position(cell_id.ids.size(), end ? 1 : -1) { this->updateIt(); if (end) { this->it++; } } neighbor_cells_iterator & operator++() { UInt i = 0; for (; i < position.size() && position(i) == 1; ++i) { ; } if (i == position.size()) { ++it; return *this; } for (UInt j = 0; j < i; ++j) { position(j) = -1; } position(i)++; updateIt(); return *this; } neighbor_cells_iterator operator++(int) { neighbor_cells_iterator tmp(*this); operator++(); return tmp; }; bool operator==(const neighbor_cells_iterator & rhs) const { return cell_id == rhs.cell_id && it == rhs.it; }; bool operator!=(const neighbor_cells_iterator & rhs) const { return !operator==(rhs); }; CellID operator*() const { CellID cur_cell_id(cell_id); cur_cell_id.ids += position; return cur_cell_id; }; private: void updateIt() { it = 0; for (UInt i = 0; i < position.size(); ++i) { it = it * 3 + (position(i) + 1); } } private: /// central cell id const CellID & cell_id; // number representing the current neighbor in base 3; UInt it; // current cell shift Vector position; }; class Neighbors { public: explicit Neighbors(const CellID & cell_id) : cell_id(cell_id) {} decltype(auto) begin() { return neighbor_cells_iterator(cell_id, false); } decltype(auto) end() { return neighbor_cells_iterator(cell_id, true); } private: const CellID & cell_id; }; decltype(auto) neighbors() { return Neighbors(*this); } private: friend class cells_iterator; Vector ids; }; /* ------------------------------------------------------------------------ */ class Cell { public: using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; Cell() : id(), data() {} explicit Cell(const CellID & cell_id) : id(cell_id), data() {} bool operator==(const Cell & cell) const { return id == cell.id; } bool operator!=(const Cell & cell) const { return id != cell.id; } Cell & add(const T & d) { data.push_back(d); return *this; } iterator begin() { return data.begin(); } const_iterator begin() const { return data.begin(); } iterator end() { return data.end(); } const_iterator end() const { return data.end(); } private: CellID id; std::vector data; }; private: using cells_container = std::map; public: const Cell & getCell(const CellID & cell_id) const { auto it = cells.find(cell_id); if (it != cells.end()) { return it->second; } return empty_cell; } decltype(auto) beginCell(const CellID & cell_id) { auto it = cells.find(cell_id); if (it != cells.end()) { return it->second.begin(); } return empty_cell.begin(); } decltype(auto) endCell(const CellID & cell_id) { auto it = cells.find(cell_id); if (it != cells.end()) { return it->second.end(); } return empty_cell.end(); } decltype(auto) beginCell(const CellID & cell_id) const { auto it = cells.find(cell_id); if (it != cells.end()) { return it->second.begin(); } return empty_cell.begin(); } decltype(auto) endCell(const CellID & cell_id) const { auto it = cells.find(cell_id); if (it != cells.end()) { return it->second.end(); } return empty_cell.end(); } /* ------------------------------------------------------------------------ */ class cells_iterator : private std::iterator { public: explicit cells_iterator(typename std::map::const_iterator it) : it(it) {} cells_iterator & operator++() { this->it++; return *this; } cells_iterator operator++(int) { cells_iterator tmp(*this); operator++(); return tmp; }; bool operator==(const cells_iterator & rhs) const { return it == rhs.it; }; bool operator!=(const cells_iterator & rhs) const { return !operator==(rhs); }; CellID operator*() const { CellID cur_cell_id(this->it->first); return cur_cell_id; }; private: /// map iterator typename std::map::const_iterator it; }; public: template Cell & insert(const T & d, const vector_type & position) { auto && cell_id = getCellID(position); auto && it = cells.find(cell_id); if (it == cells.end()) { Cell cell(cell_id); auto & tmp = (cells[cell_id] = cell).add(d); for (UInt i = 0; i < dimension; ++i) { Real posl = center(i) + cell_id.getID(i) * spacing(i); Real posu = posl + spacing(i); - if (posl <= lower(i)) + if (posl <= lower(i)) { lower(i) = posl; } if (posu > upper(i)) { upper(i) = posu; } } return tmp; } return it->second.add(d); } /* ------------------------------------------------------------------------ */ inline decltype(auto) begin() const { auto begin = this->cells.begin(); return cells_iterator(begin); } inline decltype(auto) end() const { auto end = this->cells.end(); return cells_iterator(end); } template CellID getCellID(const vector_type & position) const { CellID cell_id(dimension); for (UInt i = 0; i < dimension; ++i) { cell_id.setID(i, getCellID(position(i), i)); } return cell_id; } void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) { ; } std::streamsize prec = stream.precision(); std::ios_base::fmtflags ff = stream.flags(); stream.setf(std::ios_base::showbase); stream.precision(5); stream << space << "SpatialGrid<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; stream << space << " + dimension : " << this->dimension << std::endl; stream << space << " + lower bounds : {"; for (UInt i = 0; i < lower.size(); ++i) { if (i != 0) { stream << ", "; } stream << lower(i); }; stream << "}" << std::endl; stream << space << " + upper bounds : {"; for (UInt i = 0; i < upper.size(); ++i) { if (i != 0) { stream << ", "; } stream << upper(i); }; stream << "}" << std::endl; stream << space << " + spacing : {"; for (UInt i = 0; i < spacing.size(); ++i) { if (i != 0) { stream << ", "; } stream << spacing(i); }; stream << "}" << std::endl; stream << space << " + center : {"; for (UInt i = 0; i < center.size(); ++i) { if (i != 0) { stream << ", "; } stream << center(i); }; stream << "}" << std::endl; stream << space << " + nb_cells : " << this->cells.size() << "/"; Vector dist(this->dimension); dist = upper; dist -= lower; for (UInt i = 0; i < this->dimension; ++i) { dist(i) /= spacing(i); } UInt nb_cells = std::ceil(dist(0)); for (UInt i = 1; i < this->dimension; ++i) { nb_cells *= std::ceil(dist(i)); } stream << nb_cells << std::endl; stream << space << "]" << std::endl; stream.precision(prec); stream.flags(ff); } void saveAsMesh(Mesh & mesh) const; private: /* -------------------------------------------------------------------------- */ inline UInt getCellID(Real position, UInt direction) const { AKANTU_DEBUG_ASSERT(direction < center.size(), "The direction asked (" << direction << ") is out of range " << center.size()); Real dist_center = position - center(direction); Int id = std::floor(dist_center / spacing(direction)); // if(dist_center < 0) id--; return id; } friend class GridSynchronizer; public: AKANTU_GET_MACRO(LowerBounds, lower, const Vector &); AKANTU_GET_MACRO(UpperBounds, upper, const Vector &); AKANTU_GET_MACRO(Spacing, spacing, const Vector &); AKANTU_SET_MACRO(Spacing, spacing, Vector &); AKANTU_GET_MACRO(Center, center, const Vector &); AKANTU_SET_MACRO(Center, center, Vector &); protected: UInt dimension; cells_container cells; Vector spacing; Vector center; Vector lower; Vector upper; Cell empty_cell; }; /// standard output stream operator template inline std::ostream & operator<<(std::ostream & stream, const SpatialGrid & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "mesh.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template void SpatialGrid::saveAsMesh(Mesh & mesh) const { ElementType type = _not_defined; switch (dimension) { case 1: type = _segment_2; break; case 2: type = _quadrangle_4; break; case 3: type = _hexahedron_8; break; } MeshAccessor mesh_accessor(mesh); auto & connectivity = mesh_accessor.getConnectivity(type); auto & nodes = mesh_accessor.getNodes(); auto & uint_data = mesh.getDataPointer("tag_1", type); Vector pos(dimension); UInt global_id = 0; for (auto & cell_pair : cells) { UInt cur_node = nodes.size(); UInt cur_elem = connectivity.size(); const CellID & cell_id = cell_pair.first; for (UInt i = 0; i < dimension; ++i) { pos(i) = center(i) + cell_id.getID(i) * spacing(i); } nodes.push_back(pos); for (UInt i = 0; i < dimension; ++i) { pos(i) += spacing(i); } nodes.push_back(pos); connectivity.push_back(cur_node); switch (dimension) { case 1: connectivity(cur_elem, 1) = cur_node + 1; break; case 2: pos(0) -= spacing(0); nodes.push_back(pos); pos(0) += spacing(0); pos(1) -= spacing(1); nodes.push_back(pos); connectivity(cur_elem, 1) = cur_node + 3; connectivity(cur_elem, 2) = cur_node + 1; connectivity(cur_elem, 3) = cur_node + 2; break; case 3: pos(1) -= spacing(1); pos(2) -= spacing(2); nodes.push_back(pos); pos(1) += spacing(1); nodes.push_back(pos); pos(0) -= spacing(0); nodes.push_back(pos); pos(1) -= spacing(1); pos(2) += spacing(2); nodes.push_back(pos); pos(0) += spacing(0); nodes.push_back(pos); pos(0) -= spacing(0); pos(1) += spacing(1); nodes.push_back(pos); connectivity(cur_elem, 1) = cur_node + 2; connectivity(cur_elem, 2) = cur_node + 3; connectivity(cur_elem, 3) = cur_node + 4; connectivity(cur_elem, 4) = cur_node + 5; connectivity(cur_elem, 5) = cur_node + 6; connectivity(cur_elem, 6) = cur_node + 1; connectivity(cur_elem, 7) = cur_node + 7; break; } uint_data.push_back(global_id); ++global_id; } } } // namespace akantu #endif /* AKANTU_AKA_GRID_DYNAMIC_HH_ */ diff --git a/src/common/aka_math_tmpl.hh b/src/common/aka_math_tmpl.hh index db4fc09a6..547254b0a 100644 --- a/src/common/aka_math_tmpl.hh +++ b/src/common/aka_math_tmpl.hh @@ -1,873 +1,860 @@ /** * @file aka_math_tmpl.hh * * @author Ramin Aghababaei * @author Guillaume Anciaux * @author Alejandro M. Aragón * @author David Simon Kammer * @author Daniel Pino Muñoz * @author Mathilde Radiguet * @author Nicolas Richart * @author Leonardo Snozzi * @author Peter Spijker * @author Marco Vocialta * * @date creation: Wed Aug 04 2010 * @date last modification: Tue Feb 20 2018 * * @brief Implementation of the inline functions of the math toolkit * * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_blas_lapack.hh" #include "aka_math.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ namespace akantu { namespace Math { /* ------------------------------------------------------------------------ */ inline void matrix_vector(UInt im, UInt in, Real * A, // NOLINT(readability-non-const-parameter) Real * x, // NOLINT(readability-non-const-parameter) Real * y, Real alpha) { #ifdef AKANTU_USE_BLAS /// y = alpha*op(A)*x + beta*y char tran_A = 'N'; int incx = 1; int incy = 1; double beta = 0.; int m = im; int n = in; aka_gemv(&tran_A, &m, &n, &alpha, A, &m, x, &incx, &beta, y, &incy); #else std::fill_n(y, im, 0.); for (UInt i = 0; i < im; ++i) { for (UInt j = 0; j < in; ++j) { y[i] += A[i + j * im] * x[j]; } y[i] *= alpha; } #endif } /* ------------------------------------------------------------------------ */ inline void matrixt_vector(UInt im, UInt in, Real * A, // NOLINT(readability-non-const-parameter) Real * x, // NOLINT(readability-non-const-parameter) Real * y, Real alpha) { #ifdef AKANTU_USE_BLAS /// y = alpha*op(A)*x + beta*y char tran_A = 'T'; int incx = 1; int incy = 1; double beta = 0.; int m = im; int n = in; aka_gemv(&tran_A, &m, &n, &alpha, A, &m, x, &incx, &beta, y, &incy); #else std::fill_n(y, in, 0.); for (UInt i = 0; i < im; ++i) { for (UInt j = 0; j < in; ++j) { y[j] += A[j * im + i] * x[i]; } y[i] *= alpha; } #endif } /* ------------------------------------------------------------------------ */ inline void matrix_matrix(UInt im, UInt in, UInt ik, Real * A, // NOLINT(readability-non-const-parameter) Real * B, // NOLINT(readability-non-const-parameter) Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'N'; char trans_b = 'N'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &m, B, &k, &beta, C, &m); #else std::fill_n(C, im * in, 0.); for (UInt j = 0; j < in; ++j) { UInt _jb = j * ik; UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { for (UInt l = 0; l < ik; ++l) { UInt _la = l * im; C[i + _jc] += A[i + _la] * B[l + _jb]; } C[i + _jc] *= alpha; } } #endif } /* ------------------------------------------------------------------------ */ inline void matrixt_matrix(UInt im, UInt in, UInt ik, Real * A, // NOLINT(readability-non-const-parameter) Real * B, // NOLINT(readability-non-const-parameter) Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'T'; char trans_b = 'N'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &k, B, &k, &beta, C, &m); #else std::fill_n(C, im * in, 0.); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; UInt _jb = j * ik; for (UInt i = 0; i < im; ++i) { UInt _ia = i * ik; for (UInt l = 0; l < ik; ++l) { C[i + _jc] += A[l + _ia] * B[l + _jb]; } C[i + _jc] *= alpha; } } #endif } /* ------------------------------------------------------------------------ */ inline void matrix_matrixt(UInt im, UInt in, UInt ik, Real * A, // NOLINT(readability-non-const-parameter) Real * B, // NOLINT(readability-non-const-parameter) Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'N'; char trans_b = 'T'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &m, B, &n, &beta, C, &m); #else std::fill_n(C, im * in, 0.); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { for (UInt l = 0; l < ik; ++l) { UInt _la = l * im; UInt _lb = l * in; C[i + _jc] += A[i + _la] * B[j + _lb]; } C[i + _jc] *= alpha; } } #endif } /* ------------------------------------------------------------------------ */ inline void matrixt_matrixt(UInt im, UInt in, UInt ik, Real * A, // NOLINT(readability-non-const-parameter) Real * B, // NOLINT(readability-non-const-parameter) Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'T'; char trans_b = 'T'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &k, B, &n, &beta, C, &m); #else std::fill_n(C, im * in, 0.); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { UInt _ia = i * ik; for (UInt l = 0; l < ik; ++l) { UInt _lb = l * in; C[i + _jc] += A[l + _ia] * B[j + _lb]; } C[i + _jc] *= alpha; } } #endif } /* ------------------------------------------------------------------------ */ inline void aXplusY(UInt n, Real alpha, Real * x, // NOLINT(readability-non-const-parameter) Real * y) { #ifdef AKANTU_USE_BLAS /// y := alpha x + y int incx = 1, incy = 1; aka_axpy(&n, &alpha, x, &incx, y, &incy); #else for (UInt i = 0; i < n; ++i) { *(y++) += alpha * *(x++); } #endif } /* ------------------------------------------------------------------------ */ inline Real vectorDot(Real * v1, // NOLINT(readability-non-const-parameter) Real * v2, // NOLINT(readability-non-const-parameter) UInt in) { #ifdef AKANTU_USE_BLAS /// d := v1 . v2 int incx = 1, incy = 1, n = in; Real d = aka_dot(&n, v1, &incx, v2, &incy); #else Real d = 0; for (UInt i = 0; i < in; ++i) { d += v1[i] * v2[i]; } #endif return d; } /* ------------------------------------------------------------------------ */ template inline void matMul(UInt m, UInt n, UInt k, Real alpha, Real * A, // NOLINT(readability-non-const-parameter) Real * B, // NOLINT(readability-non-const-parameter) Real /*beta*/, Real * C) { if (tr_A) { if (tr_B) { matrixt_matrixt(m, n, k, A, B, C, alpha); } else { matrixt_matrix(m, n, k, A, B, C, alpha); } } else { if (tr_B) { matrix_matrixt(m, n, k, A, B, C, alpha); } else { matrix_matrix(m, n, k, A, B, C, alpha); } } } /* ------------------------------------------------------------------------ */ template inline void matVectMul(UInt m, UInt n, Real alpha, Real * A, // NOLINT(readability-non-const-parameter) Real * x, // NOLINT(readability-non-const-parameter) Real /*beta*/, Real * y) { if (tr_A) { matrixt_vector(m, n, A, x, y, alpha); } else { matrix_vector(m, n, A, x, y, alpha); } } /* ------------------------------------------------------------------------ */ template inline void matrixEig(UInt n, T * A, // NOLINT(readability-non-const-parameter) T * d, T * V) { // Matrix A is row major, so the lapack function in fortran will // process A^t. Asking for the left eigenvectors of A^t will give the // transposed right eigenvectors of A so in the C++ code the right // eigenvectors. char jobvr{'N'}; if (V != nullptr) { jobvr = 'V'; // compute left eigenvectors } char jobvl{'N'}; // compute right eigenvectors auto * di = new T[n]; // imaginary part of the eigenvalues int info; int N = n; T wkopt; int lwork = -1; // query and allocate the optimal workspace aka_geev(&jobvl, &jobvr, &N, A, &N, d, di, nullptr, &N, V, &N, &wkopt, &lwork, &info); lwork = int(wkopt); auto * work = new T[lwork]; // solve the eigenproblem aka_geev(&jobvl, &jobvr, &N, A, &N, d, di, nullptr, &N, V, &N, work, &lwork, &info); AKANTU_DEBUG_ASSERT( info == 0, "Problem computing eigenvalues/vectors. DGEEV exited with the value " << info); delete[] work; delete[] di; // I hope for you that there was no complex eigenvalues !!! } /* ------------------------------------------------------------------------ */ inline void matrix22_eigenvalues(Real * A, // NOLINT(readability-non-const-parameter) Real * Adiag) { /// d = determinant of Matrix A Real d = det2(A); /// b = trace of Matrix A Real b = A[0] + A[3]; Real c = std::sqrt(b * b - 4 * d); Adiag[0] = .5 * (b + c); Adiag[1] = .5 * (b - c); } /* ------------------------------------------------------------------------ */ inline void matrix33_eigenvalues(Real * A, // NOLINT(readability-non-const-parameter) Real * Adiag) { matrixEig(3, A, Adiag); } /* ------------------------------------------------------------------------ */ template inline void eigenvalues(Real * A, // NOLINT(readability-non-const-parameter) Real * d) { if (dim == 1) { d[0] = A[0]; } else if (dim == 2) { matrix22_eigenvalues(A, d); } // else if(dim == 3) { matrix33_eigenvalues(A, d); } else { matrixEig(dim, A, d); } } /* ------------------------------------------------------------------------ */ inline Real det2(const Real * mat) { return mat[0] * mat[3] - mat[1] * mat[2]; } /* ------------------------------------------------------------------------ */ inline Real det3(const Real * mat) { return mat[0] * (mat[4] * mat[8] - mat[7] * mat[5]) - mat[3] * (mat[1] * mat[8] - mat[7] * mat[2]) + mat[6] * (mat[1] * mat[5] - mat[4] * mat[2]); } /* ------------------------------------------------------------------------ */ template inline Real det(const Real * mat) { if (n == 1) { return *mat; } if (n == 2) { return det2(mat); } if (n == 3) { return det3(mat); } return det(n, mat); } /* ------------------------------------------------------------------------ */ template inline T det(UInt n, const T * A) { int N = n; int info; auto * ipiv = new int[N + 1]; auto * LU = new T[N * N]; std::copy(A, A + N * N, LU); // LU factorization of A aka_getrf(&N, &N, LU, &N, ipiv, &info); if (info > 0) { AKANTU_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } // det(A) = det(L) * det(U) = 1 * det(U) = product_i U_{ii} T det = 1.; for (int i = 0; i < N; ++i) { det *= (2 * (ipiv[i] == i) - 1) * LU[i * n + i]; } delete[] ipiv; delete[] LU; return det; } /* ------------------------------------------------------------------------ */ inline void normal2(const Real * vec, Real * normal) { normal[0] = vec[1]; normal[1] = -vec[0]; normalize2(normal); } /* ------------------------------------------------------------------------ */ inline void normal3(const Real * vec1, const Real * vec2, Real * normal) { vectorProduct3(vec1, vec2, normal); normalize3(normal); } /* ------------------------------------------------------------------------ */ inline void normalize2(Real * vec) { Real norm = norm2(vec); vec[0] /= norm; vec[1] /= norm; } /* ------------------------------------------------------------------------ */ inline void normalize3(Real * vec) { Real norm = norm3(vec); vec[0] /= norm; vec[1] /= norm; vec[2] /= norm; } /* ------------------------------------------------------------------------ */ inline Real norm2(const Real * vec) { return sqrt(vec[0] * vec[0] + vec[1] * vec[1]); } /* ------------------------------------------------------------------------ */ inline Real norm3(const Real * vec) { return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]); } /* ------------------------------------------------------------------------ */ inline Real norm(UInt n, const Real * vec) { Real norm = 0.; for (UInt i = 0; i < n; ++i) { norm += vec[i] * vec[i]; } return sqrt(norm); } /* ------------------------------------------------------------------------ */ inline void inv2(const Real * mat, Real * inv) { Real det_mat = det2(mat); inv[0] = mat[3] / det_mat; inv[1] = -mat[1] / det_mat; inv[2] = -mat[2] / det_mat; inv[3] = mat[0] / det_mat; } /* ------------------------------------------------------------------------ */ inline void inv3(const Real * mat, Real * inv) { Real det_mat = det3(mat); inv[0] = (mat[4] * mat[8] - mat[7] * mat[5]) / det_mat; inv[1] = (mat[2] * mat[7] - mat[8] * mat[1]) / det_mat; inv[2] = (mat[1] * mat[5] - mat[4] * mat[2]) / det_mat; inv[3] = (mat[5] * mat[6] - mat[8] * mat[3]) / det_mat; inv[4] = (mat[0] * mat[8] - mat[6] * mat[2]) / det_mat; inv[5] = (mat[2] * mat[3] - mat[5] * mat[0]) / det_mat; inv[6] = (mat[3] * mat[7] - mat[6] * mat[4]) / det_mat; inv[7] = (mat[1] * mat[6] - mat[7] * mat[0]) / det_mat; inv[8] = (mat[0] * mat[4] - mat[3] * mat[1]) / det_mat; } /* ------------------------------------------------------------------------ */ template inline void inv(const Real * A, Real * Ainv) { if (n == 1) { *Ainv = 1. / *A; } else if (n == 2) { inv2(A, Ainv); } else if (n == 3) { inv3(A, Ainv); } else { inv(n, A, Ainv); } } /* ------------------------------------------------------------------------ */ template inline void inv(UInt n, const T * A, T * invA) { int N = n; int info; auto * ipiv = new int[N + 1]; int lwork = N * N; auto * work = new T[lwork]; std::copy(A, A + n * n, invA); aka_getrf(&N, &N, invA, &N, ipiv, &info); if (info > 0) { AKANTU_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } aka_getri(&N, invA, &N, ipiv, work, &lwork, &info); if (info != 0) { AKANTU_ERROR("Cannot invert the matrix (info: " << info << " )"); } delete[] ipiv; delete[] work; } /* ------------------------------------------------------------------------ */ template inline void solve(UInt n, const T * A, T * x, const T * b) { int N = n; int info; auto * ipiv = new int[N]; auto * lu_A = new T[N * N]; std::copy(A, A + N * N, lu_A); aka_getrf(&N, &N, lu_A, &N, ipiv, &info); if (info > 0) { AKANTU_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } char trans = 'N'; int nrhs = 1; std::copy(b, b + N, x); aka_getrs(&trans, &N, &nrhs, lu_A, &N, ipiv, x, &N, &info); if (info != 0) { AKANTU_ERROR("Cannot solve the system (info: " << info << " )"); } delete[] ipiv; delete[] lu_A; } /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ inline Real matrixDoubleDot22(Real * A, // NOLINT(readability-non-const-parameter) Real * B // NOLINT(readability-non-const-parameter) ) { Real d; d = A[0] * B[0] + A[1] * B[1] + A[2] * B[2] + A[3] * B[3]; return d; } /* ------------------------------------------------------------------------ */ inline Real matrixDoubleDot33(Real * A, // NOLINT(readability-non-const-parameter) Real * B // NOLINT(readability-non-const-parameter) ) { Real d; d = A[0] * B[0] + A[1] * B[1] + A[2] * B[2] + A[3] * B[3] + A[4] * B[4] + A[5] * B[5] + A[6] * B[6] + A[7] * B[7] + A[8] * B[8]; return d; } /* ------------------------------------------------------------------------ */ inline Real matrixDoubleDot(UInt n, Real * A, // NOLINT(readability-non-const-parameter) Real * B // NOLINT(readability-non-const-parameter) ) { Real d = 0.; for (UInt i = 0; i < n; ++i) { for (UInt j = 0; j < n; ++j) { d += A[i * n + j] * B[i * n + j]; } } return d; } /* ------------------------------------------------------------------------ */ inline void vectorProduct3(const Real * v1, const Real * v2, Real * res) { res[0] = v1[1] * v2[2] - v1[2] * v2[1]; res[1] = v1[2] * v2[0] - v1[0] * v2[2]; res[2] = v1[0] * v2[1] - v1[1] * v2[0]; } /* ------------------------------------------------------------------------ */ inline Real vectorDot2(const Real * v1, const Real * v2) { return (v1[0] * v2[0] + v1[1] * v2[1]); } /* ------------------------------------------------------------------------ */ inline Real vectorDot3(const Real * v1, const Real * v2) { return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]); } /* ------------------------------------------------------------------------ */ inline Real distance_2d(const Real * x, const Real * y) { return std::sqrt((y[0] - x[0]) * (y[0] - x[0]) + (y[1] - x[1]) * (y[1] - x[1])); } + /* ------------------------------------------------------------------------ */ + inline Real triangle_inradius_2d(const Real * coord1, const Real * coord2, + const Real * coord3) { + /** + * @f{eqnarray*}{ + * r &=& A / s \\ + * A &=& 1/4 * \sqrt{(a + b + c) * (a - b + c) * (a + b - c) (-a + b + c)} + * \\ s &=& \frac{a + b + c}{2} + * @f} + */ -/* -------------------------------------------------------------------------- */ -inline Real Math::triangle_inradius_2d(const Real * coord1, const Real * coord2, - const Real * coord3) { - /** - * @f{eqnarray*}{ - * r &=& A / s \\ - * A &=& 1/4 * \sqrt{(a + b + c) * (a - b + c) * (a + b - c) (-a + b + c)} \\ - * s &=& \frac{a + b + c}{2} - * @f} - */ - - Real a, b, c; - - a = distance_2d(coord1, coord2); - b = distance_2d(coord2, coord3); - c = distance_2d(coord1, coord3); - - Real s; - s = (a + b + c) * 0.5; - - return sqrt((s - a) * (s - b) * (s - c) / s); -} - - -/* -------------------------------------------------------------------------- */ -inline Real Math::triangle_inradius_3d(const Real * coord1, const Real * coord2, - const Real * coord3) { - /** - * @f{eqnarray*}{ - * r &=& A / s \\ - * A &=& 1/4 * \sqrt{(a + b + c) * (a - b + c) * (a + b - c) (-a + b + c)} \\ - * s &=& \frac{a + b + c}{2} - * @f} - */ - - Real a, b, c; - - a = distance_3d(coord1, coord2); - b = distance_3d(coord2, coord3); - c = distance_3d(coord1, coord3); - - Real s; - s = (a + b + c) * 0.5; - - return sqrt((s - a) * (s - b) * (s - c) / s); -} + Real a, b, c; -/* -------------------------------------------------------------------------- */ -inline Real Math::distance_3d(const Real * x, const Real * y) { - return sqrt((y[0] - x[0]) * (y[0] - x[0]) + (y[1] - x[1]) * (y[1] - x[1]) + - (y[2] - x[2]) * (y[2] - x[2])); -} + a = distance_2d(coord1, coord2); + b = distance_2d(coord2, coord3); + c = distance_2d(coord1, coord3); + + Real s; + s = (a + b + c) * 0.5; + + return sqrt((s - a) * (s - b) * (s - c) / s); + } + + /* ------------------------------------------------------------------------ */ + inline Real triangle_inradius_3d(const Real * coord1, const Real * coord2, + const Real * coord3) { + /** + * @f{eqnarray*}{ + * r &=& A / s \\ + * A &=& 1/4 * \sqrt{(a + b + c) * (a - b + c) * (a + b - c) (-a + b + c)} + * \\ s &=& \frac{a + b + c}{2} + * @f} + */ + + Real a, b, c; + + a = distance_3d(coord1, coord2); + b = distance_3d(coord2, coord3); + c = distance_3d(coord1, coord3); - auto s = (a + b + c) * 0.5; + Real s; + s = (a + b + c) * 0.5; - return std::sqrt((s - a) * (s - b) * (s - c) / s); + return sqrt((s - a) * (s - b) * (s - c) / s); } /* ------------------------------------------------------------------------ */ inline Real distance_3d(const Real * x, const Real * y) { return std::sqrt((y[0] - x[0]) * (y[0] - x[0]) + (y[1] - x[1]) * (y[1] - x[1]) + (y[2] - x[2]) * (y[2] - x[2])); } /* ------------------------------------------------------------------------ */ inline Real tetrahedron_volume(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4) { Real xx[9]; xx[0] = coord2[0]; xx[1] = coord2[1]; xx[2] = coord2[2]; xx[3] = coord3[0]; xx[4] = coord3[1]; xx[5] = coord3[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; auto vol = det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord3[0]; xx[4] = coord3[1]; xx[5] = coord3[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol -= det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord2[0]; xx[4] = coord2[1]; xx[5] = coord2[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol += det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord2[0]; xx[4] = coord2[1]; xx[5] = coord2[2]; xx[6] = coord3[0]; xx[7] = coord3[1]; xx[8] = coord3[2]; vol -= det3(xx); vol /= 6; return vol; } /* ------------------------------------------------------------------------ */ inline Real tetrahedron_inradius(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4) { auto l12 = distance_3d(coord1, coord2); auto l13 = distance_3d(coord1, coord3); auto l14 = distance_3d(coord1, coord4); auto l23 = distance_3d(coord2, coord3); auto l24 = distance_3d(coord2, coord4); auto l34 = distance_3d(coord3, coord4); auto s1 = (l12 + l23 + l13) * 0.5; s1 = std::sqrt(s1 * (s1 - l12) * (s1 - l23) * (s1 - l13)); auto s2 = (l12 + l24 + l14) * 0.5; s2 = std::sqrt(s2 * (s2 - l12) * (s2 - l24) * (s2 - l14)); auto s3 = (l23 + l34 + l24) * 0.5; s3 = std::sqrt(s3 * (s3 - l23) * (s3 - l34) * (s3 - l24)); auto s4 = (l13 + l34 + l14) * 0.5; s4 = std::sqrt(s4 * (s4 - l13) * (s4 - l34) * (s4 - l14)); auto volume = tetrahedron_volume(coord1, coord2, coord3, coord4); return 3 * volume / (s1 + s2 + s3 + s4); } /* ------------------------------------------------------------------------ */ inline void barycenter(const Real * coord, UInt nb_points, UInt spatial_dimension, Real * barycenter) { std::fill_n(barycenter, spatial_dimension, 0.); for (UInt n = 0; n < nb_points; ++n) { UInt offset = n * spatial_dimension; for (UInt i = 0; i < spatial_dimension; ++i) { barycenter[i] += coord[offset + i] / (Real)nb_points; } } } /* ------------------------------------------------------------------------ */ inline void vector_2d(const Real * x, const Real * y, Real * res) { res[0] = y[0] - x[0]; res[1] = y[1] - x[1]; } /* ------------------------------------------------------------------------ */ inline void vector_3d(const Real * x, const Real * y, Real * res) { res[0] = y[0] - x[0]; res[1] = y[1] - x[1]; res[2] = y[2] - x[2]; } /* ------------------------------------------------------------------------ */ /// Combined absolute and relative tolerance test proposed in /// Real-time collision detection by C. Ericson (2004) inline bool are_float_equal(const Real x, const Real y) { Real abs_max = std::max(std::abs(x), std::abs(y)); abs_max = std::max(abs_max, Real(1.)); return std::abs(x - y) <= (tolerance * abs_max); } /* ------------------------------------------------------------------------ */ inline bool isnan(Real x) { #if defined(__INTEL_COMPILER) #pragma warning(push) #pragma warning(disable : 1572) #endif // defined(__INTEL_COMPILER) // x = x return false means x = quiet_NaN return !(x == x); #if defined(__INTEL_COMPILER) #pragma warning(pop) #endif // defined(__INTEL_COMPILER) } /* ------------------------------------------------------------------------ */ inline bool are_vector_equal(UInt n, Real * x, Real * y) { bool test = true; for (UInt i = 0; i < n; ++i) { test &= are_float_equal(x[i], y[i]); } return test; } /* ------------------------------------------------------------------------ */ inline bool intersects(Real x_min, Real x_max, Real y_min, Real y_max) { return not((x_max < y_min) or (x_min > y_max)); } /* ------------------------------------------------------------------------ */ inline bool is_in_range(Real a, Real x_min, Real x_max) { return ((a >= x_min) and (a <= x_max)); } /* ------------------------------------------------------------------------ */ template inline T pow(T x) { return (pow

(x) * x); } template <> inline UInt pow<0, UInt>(__attribute__((unused)) UInt x) { return (1); } template <> inline Real pow<0, Real>(__attribute__((unused)) Real x) { return (1.); } /* ------------------------------------------------------------------------ */ template Real NewtonRaphson::solve(const Functor & funct, Real x_0) { Real x = x_0; Real f_x = funct.f(x); UInt iter = 0; while (std::abs(f_x) > this->tolerance && iter < this->max_iteration) { x -= f_x / funct.f_prime(x); f_x = funct.f(x); iter++; } AKANTU_DEBUG_ASSERT(iter < this->max_iteration, "Newton Raphson (" << funct.name << ") solve did not converge in " << this->max_iteration << " iterations (tolerance: " << this->tolerance << ")"); return x; } } // namespace Math } // namespace akantu diff --git a/src/mesh/mesh_inline_impl.hh b/src/mesh/mesh_inline_impl.hh index 9360ca87d..627a3ee3e 100644 --- a/src/mesh/mesh_inline_impl.hh +++ b/src/mesh/mesh_inline_impl.hh @@ -1,776 +1,776 @@ /** * @file mesh_inline_impl.hh * * @author Guillaume Anciaux * @author Dana Christen * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Thu Jul 15 2010 * @date last modification: Mon Dec 18 2017 * * @brief Implementation of the inline functions of the mesh class * * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "element_class.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef AKANTU_MESH_INLINE_IMPL_HH_ #define AKANTU_MESH_INLINE_IMPL_HH_ namespace akantu { /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ inline ElementKind Element::kind() const { return Mesh::getKind(type); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template Mesh::ElementTypesIteratorHelper Mesh::elementTypes(pack &&... _pack) const { return connectivities.elementTypes(_pack...); } /* -------------------------------------------------------------------------- */ inline RemovedNodesEvent::RemovedNodesEvent(const Mesh & mesh, const std::string & origin) : MeshEvent(origin), new_numbering(mesh.getNbNodes(), 1, "new_numbering") {} /* -------------------------------------------------------------------------- */ inline RemovedElementsEvent::RemovedElementsEvent(const Mesh & mesh, const ID & new_numbering_id, const std::string & origin) : MeshEvent(origin), new_numbering(new_numbering_id, mesh.getID(), mesh.getMemoryID()) {} /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(NewElementsEvent & event) { this->fillNodesToElements(); /*this->nodes_to_elements.resize(nodes->size()); for (const auto & elem : event.getList()) { const Array & conn = connectivities(elem.type, elem.ghost_type); UInt nb_nodes_per_elem = Mesh::getNbNodesPerElement(elem.type); for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = conn(elem.element, n); if (not nodes_to_elements[node]) { nodes_to_elements[node] = std::make_unique>(); } nodes_to_elements[node]->insert(elem); } }*/ EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(NewNodesEvent & event) { this->computeBoundingBox(); this->nodes_flags->resize(this->nodes->size(), NodeFlag::_normal); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(RemovedElementsEvent & event) { this->connectivities.onElementsRemoved(event.getNewNumbering()); this->fillNodesToElements(); this->computeBoundingBox(); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(RemovedNodesEvent & event) { const auto & new_numbering = event.getNewNumbering(); this->removeNodesFromArray(*nodes, new_numbering); if (nodes_global_ids and not is_mesh_facets) { this->removeNodesFromArray(*nodes_global_ids, new_numbering); } if (not is_mesh_facets) { this->removeNodesFromArray(*nodes_flags, new_numbering); } if (not nodes_to_elements.empty()) { std::vector>> tmp( nodes_to_elements.size()); auto it = nodes_to_elements.begin(); UInt new_nb_nodes = 0; for (auto new_i : new_numbering) { if (new_i != UInt(-1)) { tmp[new_i] = std::move(*it); ++new_nb_nodes; } ++it; } tmp.resize(new_nb_nodes); std::move(tmp.begin(), tmp.end(), nodes_to_elements.begin()); } computeBoundingBox(); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template inline void Mesh::removeNodesFromArray(Array & vect, const Array & new_numbering) { Array tmp(vect.size(), vect.getNbComponent()); UInt nb_component = vect.getNbComponent(); UInt new_nb_nodes = 0; for (UInt i = 0; i < new_numbering.size(); ++i) { UInt new_i = new_numbering(i); if (new_i != UInt(-1)) { T * to_copy = vect.storage() + i * nb_component; std::uninitialized_copy(to_copy, to_copy + nb_component, tmp.storage() + new_i * nb_component); ++new_nb_nodes; } } tmp.resize(new_nb_nodes); vect.copy(tmp); } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getNodesGlobalIdsPointer() { AKANTU_DEBUG_IN(); if (not nodes_global_ids) { nodes_global_ids = std::make_shared>( nodes->size(), 1, getID() + ":nodes_global_ids"); for (auto && global_ids : enumerate(*nodes_global_ids)) { std::get<1>(global_ids) = std::get<0>(global_ids); } } AKANTU_DEBUG_OUT(); return *nodes_global_ids; } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getConnectivityPointer(ElementType type, GhostType ghost_type) { if (connectivities.exists(type, ghost_type)) { return connectivities(type, ghost_type); } if (ghost_type != _not_ghost) { ghosts_counters.alloc(0, 1, type, ghost_type, 1); } AKANTU_DEBUG_INFO("The connectivity vector for the type " << type << " created"); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); return connectivities.alloc(0, nb_nodes_per_element, type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array> & Mesh::getElementToSubelementPointer(ElementType type, GhostType ghost_type) { return getDataPointer>("element_to_subelement", type, ghost_type, 1, true); } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getSubelementToElementPointer(ElementType type, GhostType ghost_type) { auto & array = getDataPointer( "subelement_to_element", type, ghost_type, getNbFacetsPerElement(type), false, is_mesh_facets, ElementNull); return array; } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getElementToSubelement() const { return getData>("element_to_subelement"); } /* -------------------------------------------------------------------------- */ inline auto & Mesh::getElementToSubelementNC() { return getData>("element_to_subelement"); } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getElementToSubelement(ElementType type, GhostType ghost_type) const { return getData>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline auto & Mesh::getElementToSubelementNC(ElementType type, GhostType ghost_type) { return getData>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getElementToSubelement(const Element & element) const { return getData>("element_to_subelement")(element, 0); } /* -------------------------------------------------------------------------- */ inline auto & Mesh::getElementToSubelementNC(const Element & element) { return getData>("element_to_subelement")(element, 0); } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getSubelementToElement() const { return getData("subelement_to_element"); } /* -------------------------------------------------------------------------- */ inline auto & Mesh::getSubelementToElementNC() { return getData("subelement_to_element"); } /* -------------------------------------------------------------------------- */ inline const auto & Mesh::getSubelementToElement(ElementType type, GhostType ghost_type) const { return getData("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline auto & Mesh::getSubelementToElementNC(ElementType type, GhostType ghost_type) { return getData("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline VectorProxy Mesh::getSubelementToElement(const Element & element) const { return this->getSubelementToElement().get(element); } /* -------------------------------------------------------------------------- */ inline VectorProxy Mesh::getSubelementToElementNC(const Element & element) { return this->getSubelementToElement().get(element); } /* -------------------------------------------------------------------------- */ template inline Array & Mesh::getDataPointer(const ID & data_name, ElementType el_type, GhostType ghost_type, UInt nb_component, bool size_to_nb_element, bool resize_with_parent) { Array & tmp = this->getElementalDataArrayAlloc( data_name, el_type, ghost_type, nb_component); if (size_to_nb_element) { if (resize_with_parent) { tmp.resize(mesh_parent->getNbElement(el_type, ghost_type)); } else { tmp.resize(this->getNbElement(el_type, ghost_type)); } } return tmp; } /* -------------------------------------------------------------------------- */ template inline Array & Mesh::getDataPointer(const ID & data_name, ElementType el_type, GhostType ghost_type, UInt nb_component, bool size_to_nb_element, bool resize_with_parent, const T & defaul_) { Array & tmp = this->getElementalDataArrayAlloc( data_name, el_type, ghost_type, nb_component); if (size_to_nb_element) { if (resize_with_parent) { tmp.resize(mesh_parent->getNbElement(el_type, ghost_type), defaul_); } else { tmp.resize(this->getNbElement(el_type, ghost_type), defaul_); } } return tmp; } /* -------------------------------------------------------------------------- */ template inline const Array & Mesh::getData(const ID & data_name, ElementType el_type, GhostType ghost_type) const { return this->getElementalDataArray(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template inline Array & Mesh::getData(const ID & data_name, ElementType el_type, GhostType ghost_type) { return this->getElementalDataArray(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template inline const ElementTypeMapArray & Mesh::getData(const ID & data_name) const { return this->getElementalData(data_name); } /* -------------------------------------------------------------------------- */ template inline ElementTypeMapArray & Mesh::getData(const ID & data_name) { return this->getElementalData(data_name); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(ElementType type, GhostType ghost_type) const { try { const Array & conn = connectivities(type, ghost_type); return conn.size(); } catch (...) { return 0; } } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const UInt spatial_dimension, GhostType ghost_type, ElementKind kind) const { AKANTU_DEBUG_ASSERT(spatial_dimension <= 3 || spatial_dimension == UInt(-1), "spatial_dimension is " << spatial_dimension << " and is greater than 3 !"); UInt nb_element = 0; for (auto type : elementTypes(spatial_dimension, ghost_type, kind)) { nb_element += getNbElement(type, ghost_type); } return nb_element; } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(const Element & element, Vector & barycenter) const { Vector conn = getConnectivity(element); Matrix local_coord(spatial_dimension, conn.size()); auto node_begin = make_view(*nodes, spatial_dimension).begin(); for (auto && node : enumerate(conn)) { local_coord(std::get<0>(node)) = Vector(node_begin[std::get<1>(node)]); } Math::barycenter(local_coord.storage(), conn.size(), spatial_dimension, barycenter.storage()); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElement(ElementType type) { UInt nb_nodes_per_element = 0; #define GET_NB_NODES_PER_ELEMENT(type) \ nb_nodes_per_element = ElementClass::getNbNodesPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_NODES_PER_ELEMENT); #undef GET_NB_NODES_PER_ELEMENT return nb_nodes_per_element; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getP1ElementType(ElementType type) { ElementType p1_type = _not_defined; #define GET_P1_TYPE(type) p1_type = ElementClass::getP1ElementType() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_P1_TYPE); #undef GET_P1_TYPE return p1_type; } /* -------------------------------------------------------------------------- */ inline ElementKind Mesh::getKind(ElementType type) { ElementKind kind = _ek_not_defined; #define GET_KIND(type) kind = ElementClass::getKind() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_KIND); #undef GET_KIND return kind; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getSpatialDimension(ElementType type) { UInt spatial_dimension = 0; #define GET_SPATIAL_DIMENSION(type) \ spatial_dimension = ElementClass::getSpatialDimension() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SPATIAL_DIMENSION); #undef GET_SPATIAL_DIMENSION return spatial_dimension; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNaturalSpaceDimension(const ElementType & type) { UInt natural_dimension = 0; #define GET_NATURAL_DIMENSION(type) \ natural_dimension = ElementClass::getNaturalSpaceDimension() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NATURAL_DIMENSION); #undef GET_NATURAL_DIMENSION return natural_dimension; } /* -------------------------------------------------------------------------- */ -inline UInt Mesh::getNbFacetTypes(ElementType & type, UInt /*t*/) { +inline UInt Mesh::getNbFacetTypes(ElementType type, UInt /*t*/) { UInt nb = 0; #define GET_NB_FACET_TYPE(type) nb = ElementClass::getNbFacetTypes() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET_TYPE); #undef GET_NB_FACET_TYPE return nb; } /* -------------------------------------------------------------------------- */ inline constexpr auto Mesh::getFacetType(ElementType type, UInt t) { #define GET_FACET_TYPE(type) return ElementClass::getFacetType(t); AKANTU_BOOST_ALL_ELEMENT_SWITCH_NO_DEFAULT(GET_FACET_TYPE); #undef GET_FACET_TYPE return _not_defined; } /* -------------------------------------------------------------------------- */ inline constexpr auto Mesh::getAllFacetTypes(ElementType type) { #define GET_FACET_TYPE(type) return ElementClass::getFacetTypes(); AKANTU_BOOST_ALL_ELEMENT_SWITCH_NO_DEFAULT(GET_FACET_TYPE); #undef GET_FACET_TYPE return ElementClass<_not_defined>::getFacetTypes(); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(ElementType type) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) n_facet = ElementClass::getNbFacetsPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(ElementType type, UInt t) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) \ n_facet = ElementClass::getNbFacetsPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline auto Mesh::getFacetLocalConnectivity(ElementType type, UInt t) { AKANTU_DEBUG_IN(); #define GET_FACET_CON(type) \ AKANTU_DEBUG_OUT(); \ return ElementClass::getFacetLocalConnectivityPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_CON); #undef GET_FACET_CON AKANTU_DEBUG_OUT(); return ElementClass<_not_defined>::getFacetLocalConnectivityPerElement(0); // This avoid a compilation warning but will certainly // also cause a segfault if reached } /* -------------------------------------------------------------------------- */ inline auto Mesh::getFacetConnectivity(const Element & element, UInt t) const { AKANTU_DEBUG_IN(); Matrix local_facets(getFacetLocalConnectivity(element.type, t)); Matrix facets(local_facets.rows(), local_facets.cols()); const Array & conn = connectivities(element.type, element.ghost_type); for (UInt f = 0; f < facets.rows(); ++f) { for (UInt n = 0; n < facets.cols(); ++n) { facets(f, n) = conn(element.element, local_facets(f, n)); } } AKANTU_DEBUG_OUT(); return facets; } /* -------------------------------------------------------------------------- */ inline VectorProxy Mesh::getConnectivity(const Element & element) const { return connectivities.get(element); } /* -------------------------------------------------------------------------- */ inline VectorProxy Mesh::getConnectivityNC(const Element & element) { return connectivities.get(element); } /* -------------------------------------------------------------------------- */ template inline void Mesh::extractNodalValuesFromElement( const Array & nodal_values, T * local_coord, const UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const { for (UInt n = 0; n < n_nodes; ++n) { memcpy(local_coord + n * nb_degree_of_freedom, nodal_values.storage() + connectivity[n] * nb_degree_of_freedom, nb_degree_of_freedom * sizeof(T)); } } /* -------------------------------------------------------------------------- */ inline void Mesh::addConnectivityType(ElementType type, GhostType ghost_type) { getConnectivityPointer(type, ghost_type); } /* -------------------------------------------------------------------------- */ inline bool Mesh::isPureGhostNode(UInt n) const { return ((*nodes_flags)(n)&NodeFlag::_shared_mask) == NodeFlag::_pure_ghost; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalOrMasterNode(UInt n) const { return ((*nodes_flags)(n)&NodeFlag::_local_master_mask) == NodeFlag::_normal; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalNode(UInt n) const { return ((*nodes_flags)(n)&NodeFlag::_shared_mask) == NodeFlag::_normal; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isMasterNode(UInt n) const { return ((*nodes_flags)(n)&NodeFlag::_shared_mask) == NodeFlag::_master; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isSlaveNode(UInt n) const { return ((*nodes_flags)(n)&NodeFlag::_shared_mask) == NodeFlag::_slave; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isPeriodicSlave(UInt n) const { return ((*nodes_flags)(n)&NodeFlag::_periodic_mask) == NodeFlag::_periodic_slave; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isPeriodicMaster(UInt n) const { return ((*nodes_flags)(n)&NodeFlag::_periodic_mask) == NodeFlag::_periodic_master; } /* -------------------------------------------------------------------------- */ inline NodeFlag Mesh::getNodeFlag(UInt local_id) const { return (*nodes_flags)(local_id); } /* -------------------------------------------------------------------------- */ inline Int Mesh::getNodePrank(UInt local_id) const { auto it = nodes_prank.find(local_id); return it == nodes_prank.end() ? -1 : it->second; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeGlobalId(UInt local_id) const { return nodes_global_ids ? (*nodes_global_ids)(local_id) : local_id; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeLocalId(UInt global_id) const { if (nodes_global_ids == nullptr) { return global_id; } return nodes_global_ids->find(global_id); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbGlobalNodes() const { return nodes_global_ids ? nb_global_nodes : nodes->size(); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElementList(const Array & elements) { UInt nb_nodes_per_element = 0; UInt nb_nodes = 0; ElementType current_element_type = _not_defined; for (const auto & el : elements) { if (el.type != current_element_type) { current_element_type = el.type; nb_nodes_per_element = Mesh::getNbNodesPerElement(current_element_type); } nb_nodes += nb_nodes_per_element; } return nb_nodes; } /* -------------------------------------------------------------------------- */ inline Mesh & Mesh::getMeshFacets() { if (this->mesh_facets == nullptr) { AKANTU_SILENT_EXCEPTION( "No facet mesh is defined yet! check the buildFacets functions"); } return *this->mesh_facets; } /* -------------------------------------------------------------------------- */ inline const Mesh & Mesh::getMeshFacets() const { if (this->mesh_facets == nullptr) { AKANTU_SILENT_EXCEPTION( "No facet mesh is defined yet! check the buildFacets functions"); } return *this->mesh_facets; } /* -------------------------------------------------------------------------- */ inline const Mesh & Mesh::getMeshParent() const { if (this->mesh_parent == nullptr) { AKANTU_SILENT_EXCEPTION( "No parent mesh is defined! This is only valid in a mesh_facets"); } return *this->mesh_parent; } /* -------------------------------------------------------------------------- */ void Mesh::addPeriodicSlave(UInt slave, UInt master) { if (master == slave) { return; } // if pair already registered auto master_slaves = periodic_master_slave.equal_range(master); auto slave_it = std::find_if(master_slaves.first, master_slaves.second, [&](auto & pair) { return pair.second == slave; }); if (slave_it == master_slaves.second) { // no duplicates periodic_master_slave.insert(std::make_pair(master, slave)); AKANTU_DEBUG_INFO("adding periodic slave, slave gid:" << getNodeGlobalId(slave) << " [lid: " << slave << "]" << ", master gid:" << getNodeGlobalId(master) << " [lid: " << master << "]"); // std::cout << "adding periodic slave, slave gid:" << // getNodeGlobalId(slave) // << " [lid: " << slave << "]" // << ", master gid:" << getNodeGlobalId(master) // << " [lid: " << master << "]" << std::endl; } periodic_slave_master[slave] = master; auto set_flag = [&](auto node, auto flag) { (*nodes_flags)[node] &= ~NodeFlag::_periodic_mask; // clean periodic flags (*nodes_flags)[node] |= flag; }; set_flag(slave, NodeFlag::_periodic_slave); set_flag(master, NodeFlag::_periodic_master); } /* -------------------------------------------------------------------------- */ UInt Mesh::getPeriodicMaster(UInt slave) const { return periodic_slave_master.at(slave); } /* -------------------------------------------------------------------------- */ class Mesh::PeriodicSlaves { using internal_iterator = std::unordered_multimap::const_iterator; std::pair pair; public: PeriodicSlaves(const Mesh & mesh, UInt master) : pair(mesh.getPeriodicMasterSlaves().equal_range(master)) {} PeriodicSlaves(const PeriodicSlaves & other) = default; PeriodicSlaves(PeriodicSlaves && other) = default; PeriodicSlaves & operator=(const PeriodicSlaves & other) = default; class const_iterator { internal_iterator it; public: const_iterator(internal_iterator it) : it(it) {} const_iterator operator++() { ++it; return *this; } bool operator!=(const const_iterator & other) { return other.it != it; } auto operator*() { return it->second; } }; auto begin() const { return const_iterator(pair.first); } auto end() const { return const_iterator(pair.second); } }; /* -------------------------------------------------------------------------- */ inline decltype(auto) Mesh::getPeriodicSlaves(UInt master) const { return PeriodicSlaves(*this, master); } /* -------------------------------------------------------------------------- */ inline Vector Mesh::getConnectivityWithPeriodicity(const Element & element) const { Vector conn = getConnectivity(element); if (not isPeriodic()) { return conn; } for (auto && node : conn) { if (isPeriodicSlave(node)) { node = getPeriodicMaster(node); } } return conn; } } // namespace akantu #endif /* AKANTU_MESH_INLINE_IMPL_HH_ */ diff --git a/src/mesh_utils/cohesive_element_inserter_helper.cc b/src/mesh_utils/cohesive_element_inserter_helper.cc index dd304a2a2..b50fea3d3 100644 --- a/src/mesh_utils/cohesive_element_inserter_helper.cc +++ b/src/mesh_utils/cohesive_element_inserter_helper.cc @@ -1,936 +1,947 @@ /** * @file cohesive_element_inserter_helper.cc * * @author Nicolas Richart * * @date creation jeu sep 03 2020 * * @brief A Documented file. * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter_helper.hh" /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "element_synchronizer.hh" #include "fe_engine.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ CohesiveElementInserterHelper::CohesiveElementInserterHelper( Mesh & mesh, const ElementTypeMapArray & facet_insertion) : doubled_nodes(0, 2, "doubled_nodes"), mesh(mesh), mesh_facets(mesh.getMeshFacets()) { auto spatial_dimension = mesh_facets.getSpatialDimension(); for (auto gt : ghost_types) { for (auto type : mesh_facets.elementTypes(_ghost_type = gt)) { nb_new_facets(type, gt) = mesh_facets.getNbElement(type, gt); } } std::array nb_facet_to_insert{0, 0}; // creates a vector of the facets to insert std::vector potential_facets_to_double; for (auto gt_facet : ghost_types) { for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { const auto & f_insertion = facet_insertion(type_facet, gt_facet); auto & counter = nb_facet_to_insert[gt_facet == _not_ghost ? 0 : 1]; for (auto && data : enumerate(f_insertion)) { if (std::get<1>(data)) { UInt el = std::get<0>(data); potential_facets_to_double.push_back({type_facet, el, gt_facet}); ++counter; } } } } // Defines a global order of insertion oof cohesive element to ensure node // doubling appens in the smae order, this is necessary for the global node // numbering if (mesh_facets.isDistributed()) { const auto & comm = mesh_facets.getCommunicator(); ElementTypeMapArray global_orderings; global_orderings.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = -1); auto starting_index = nb_facet_to_insert[0]; comm.exclusiveScan(starting_index); // define the local numbers for facet to insert for (auto gt_facet : ghost_types) { for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { for (auto data : zip(facet_insertion(type_facet, gt_facet), global_orderings(type_facet, gt_facet))) { if (std::get<0>(data)) { std::get<1>(data) = starting_index; ++starting_index; } } } } // retreives the oorder number from neighoring processors auto && synchronizer = mesh_facets.getElementSynchronizer(); SimpleElementDataAccessor data_accessor( global_orderings, SynchronizationTag::_ce_insertion_order); synchronizer.synchronizeOnce(data_accessor, SynchronizationTag::_ce_insertion_order); // sort the facets to double based on this global ordering std::sort(potential_facets_to_double.begin(), potential_facets_to_double.end(), [&global_orderings](auto && el1, auto && el2) { return global_orderings(el1) < global_orderings(el2); }); } for (auto d : arange(spatial_dimension)) { facets_to_double_by_dim[d] = std::make_unique>( 0, 2, "facets_to_double_" + std::to_string(d)); } auto & facets_to_double = *facets_to_double_by_dim[spatial_dimension - 1]; MeshAccessor mesh_accessor(mesh_facets); auto & elements_to_subelements = mesh_accessor.getElementToSubelement(); for (auto && facet_to_double : potential_facets_to_double) { auto gt_facet = facet_to_double.ghost_type; auto type_facet = facet_to_double.type; auto & elements_to_facets = elements_to_subelements(type_facet, gt_facet); auto & elements_to_facet = elements_to_facets(facet_to_double.element); if (elements_to_facet[1].type == _not_defined #if defined(AKANTU_COHESIVE_ELEMENT) || elements_to_facet[1].kind() == _ek_cohesive #endif ) { AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary"); continue; } auto new_facet = nb_new_facets(type_facet, gt_facet)++; facets_to_double.push_back(Vector{ facet_to_double, Element{type_facet, new_facet, gt_facet}}); /// update facet_to_element vector auto & element_to_update = elements_to_facet[1]; auto el = element_to_update.element; auto & facets_to_elements = mesh_facets.getSubelementToElement( element_to_update.type, element_to_update.ghost_type); auto facets_to_element = Vector( make_view(facets_to_elements, facets_to_elements.getNbComponent()) .begin()[el]); auto facet_to_update = std::find(facets_to_element.begin(), facets_to_element.end(), facet_to_double); AKANTU_DEBUG_ASSERT(facet_to_update != facets_to_element.end(), "Facet not found"); facet_to_update->element = new_facet; /// update elements connected to facet const auto & first_facet_list = elements_to_facet; elements_to_facets.push_back(first_facet_list); /// set new and original facets as boundary facets elements_to_facets(new_facet)[0] = elements_to_facets(new_facet)[1]; elements_to_facets(new_facet)[1] = ElementNull; elements_to_facets(facet_to_double.element)[1] = ElementNull; } } /* -------------------------------------------------------------------------- */ inline auto CohesiveElementInserterHelper::hasElement(const Vector & nodes_element, const Vector & nodes) -> bool { // if one of the nodes of "nodes" is not in "nodes_element" it stops auto it = std::mismatch(nodes.begin(), nodes.end(), nodes_element.begin(), [&](auto && node, auto && /*node2*/) -> bool { auto it = std::find(nodes_element.begin(), nodes_element.end(), node); return (it != nodes_element.end()); }); // true if all "nodes" where found in "nodes_element" return (it.first == nodes.end()); } /* -------------------------------------------------------------------------- */ inline auto CohesiveElementInserterHelper::removeElementsInVector( const std::vector & elem_to_remove, std::vector & elem_list) -> bool { if (elem_list.size() <= elem_to_remove.size()) { return true; } auto el_it = elem_to_remove.begin(); auto el_last = elem_to_remove.end(); std::vector::iterator el_del; UInt deletions = 0; for (; el_it != el_last; ++el_it) { el_del = std::find(elem_list.begin(), elem_list.end(), *el_it); if (el_del != elem_list.end()) { elem_list.erase(el_del); ++deletions; } } AKANTU_DEBUG_ASSERT(deletions == 0 || deletions == elem_to_remove.size(), "Not all elements have been erased"); return deletions == 0; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserterHelper::updateElementalConnectivity( Mesh & mesh, UInt old_node, UInt new_node, const std::vector & element_list, const std::vector * facet_list) { AKANTU_DEBUG_IN(); for (auto & element : element_list) { if (element.type == _not_defined) { continue; } Vector connectivity = mesh.getConnectivity(element); if (element.kind() == _ek_cohesive) { AKANTU_DEBUG_ASSERT( facet_list != nullptr, "Provide a facet list in order to update cohesive elements"); const Vector facets = mesh_facets.getSubelementToElement(element); auto facet_nb_nodes = connectivity.size() / 2; /// loop over cohesive element's facets for (const auto & facet : enumerate(facets)) { /// skip facets if not present in the list if (std::find(facet_list->begin(), facet_list->end(), std::get<1>(facet)) == facet_list->end()) { continue; } auto n = std::get<0>(facet); auto begin = connectivity.begin() + static_cast(n * facet_nb_nodes); auto end = begin + facet_nb_nodes; auto it = std::find(begin, end, old_node); AKANTU_DEBUG_ASSERT(it != end, "Node not found in current element"); *it = new_node; } } else { auto it = std::find(connectivity.begin(), connectivity.end(), old_node); AKANTU_DEBUG_ASSERT(it != connectivity.end(), "Node not found in current element"); /// update connectivity *it = new_node; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserterHelper::updateSubelementToElement(UInt dim, bool facet_mode) { auto & facets_to_double = *facets_to_double_by_dim[dim]; auto & facets_to_subfacets = elementsOfDimToElementsOfDim(dim + static_cast(facet_mode), dim); for (auto && data : zip(make_view(facets_to_double, 2), facets_to_subfacets)) { const auto & old_subfacet = std::get<0>(data)[0]; const auto & new_subfacet = std::get<0>(data)[1]; auto & facet_to_subfacets = std::get<1>(data); MeshAccessor mesh_accessor(mesh_facets); for (auto & facet : facet_to_subfacets) { Vector subfacets = mesh_accessor.getSubelementToElement(facet); auto && subfacet_to_update_it = std::find(subfacets.begin(), subfacets.end(), old_subfacet); AKANTU_DEBUG_ASSERT(subfacet_to_update_it != subfacets.end(), "Subfacet not found"); *subfacet_to_update_it = new_subfacet; } } } /* -------------------------------------------------------------------------- */ void CohesiveElementInserterHelper::updateElementToSubelement(UInt dim, bool facet_mode) { auto & facets_to_double = *facets_to_double_by_dim[dim]; auto & facets_to_subfacets = elementsOfDimToElementsOfDim( dim + static_cast(facet_mode), dim); MeshAccessor mesh_accessor(mesh_facets); // resize the arrays mesh_accessor.getElementToSubelement().initialize( mesh_facets, _spatial_dimension = dim, _with_nb_element = true); for (auto && data : zip(make_view(facets_to_double, 2), facets_to_subfacets)) { const auto & new_facet = std::get<0>(data)[1]; mesh_accessor.getElementToSubelement(new_facet) = std::get<1>(data); } } /* -------------------------------------------------------------------------- */ void CohesiveElementInserterHelper::updateQuadraticSegments(UInt dim) { AKANTU_DEBUG_IN(); auto spatial_dimension = mesh.getSpatialDimension(); auto & facets_to_double = *facets_to_double_by_dim[dim]; MeshAccessor mesh_accessor(mesh_facets); auto & connectivities = mesh_accessor.getConnectivities(); /// this ones matter only for segments in 3D Array> * element_to_subfacet_double = nullptr; Array> * facet_to_subfacet_double = nullptr; if (dim == spatial_dimension - 2) { element_to_subfacet_double = &elementsOfDimToElementsOfDim(dim + 2, dim); facet_to_subfacet_double = &elementsOfDimToElementsOfDim(dim + 1, dim); } auto & element_to_subelement = mesh_facets.getElementToSubelement(); std::vector middle_nodes; for (auto && facet_to_double : make_view(facets_to_double, 2)) { auto & old_facet = facet_to_double[0]; if (old_facet.type != _segment_3) { continue; } auto node = connectivities(old_facet, 2); if (not mesh.isPureGhostNode(node)) { middle_nodes.push_back(node); } } auto n = doubled_nodes.size(); doubleNodes(middle_nodes); for (auto && data : enumerate(make_view(facets_to_double, 2))) { auto facet = std::get<0>(data); auto & old_facet = std::get<1>(data)[0]; if (old_facet.type != _segment_3) { continue; } auto old_node = connectivities(old_facet, 2); if (mesh.isPureGhostNode(old_node)) { continue; } auto new_node = doubled_nodes(n, 1); auto & new_facet = std::get<1>(data)[1]; connectivities(new_facet, 2) = new_node; if (dim == spatial_dimension - 2) { updateElementalConnectivity(mesh_facets, old_node, new_node, element_to_subelement(new_facet, 0)); updateElementalConnectivity(mesh, old_node, new_node, (*element_to_subfacet_double)(facet), &(*facet_to_subfacet_double)(facet)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_subelement(new_facet, 0)); } ++n; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserterHelper::insertCohesiveElement() { auto nb_new_facets = insertFacetsOnly(); if (nb_new_facets == 0) { return 0; } updateCohesiveData(); return nb_new_facets; } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserterHelper::insertFacetsOnly() { UInt spatial_dimension = mesh.getSpatialDimension(); if (facets_to_double_by_dim[spatial_dimension - 1]->empty()) { return 0; } if (spatial_dimension == 1) { doublePointFacet(); } else if (spatial_dimension == 2) { doubleFacets<1>(); findSubfacetToDouble<1>(); doubleSubfacet<2>(); } else if (spatial_dimension == 3) { doubleFacets<2>(); findSubfacetToDouble<2>(); doubleFacets<1>(); findSubfacetToDouble<1>(); doubleSubfacet<3>(); } return facets_to_double_by_dim[spatial_dimension - 1]->size(); } /* -------------------------------------------------------------------------- */ template void CohesiveElementInserterHelper::doubleFacets() { AKANTU_DEBUG_IN(); NewElementsEvent new_facets; auto spatial_dimension = mesh_facets.getSpatialDimension(); auto & facets_to_double = *facets_to_double_by_dim[dim]; MeshAccessor mesh_accessor(mesh_facets); for (auto && facet_to_double : make_view(facets_to_double, 2)) { auto && old_facet = facet_to_double[0]; auto && new_facet = facet_to_double[1]; auto & facets_connectivities = mesh_accessor.getConnectivity(old_facet.type, old_facet.ghost_type); facets_connectivities.resize( nb_new_facets(old_facet.type, old_facet.ghost_type)); auto facets_connectivities_begin = make_view(facets_connectivities, facets_connectivities.getNbComponent()) .begin(); // copy the connectivities Vector new_conn(facets_connectivities_begin[new_facet.element]); Vector old_conn(facets_connectivities_begin[old_facet.element]); new_conn = old_conn; // this will fail if multiple facet types exists for a given element type // \TODO handle multiple sub-facet types auto nb_subfacet_per_facet = Mesh::getNbFacetsPerElement(old_facet.type); auto & subfacets_to_facets = mesh_accessor.getSubelementToElementNC( old_facet.type, old_facet.ghost_type); subfacets_to_facets.resize( nb_new_facets(old_facet.type, old_facet.ghost_type), ElementNull); auto subfacets_to_facets_begin = make_view(subfacets_to_facets, nb_subfacet_per_facet).begin(); // copy the subfacet to facets information Vector old_subfacets_to_facet( subfacets_to_facets_begin[old_facet.element]); Vector new_subfacet_to_facet( subfacets_to_facets_begin[new_facet.element]); new_subfacet_to_facet = old_subfacets_to_facet; for (auto & subfacet : old_subfacets_to_facet) { if (subfacet == ElementNull) { continue; } /// update facet_to_subfacet array mesh_accessor.getElementToSubelement(subfacet).push_back(new_facet); } new_facets.getList().push_back(new_facet); } /// update facet_to_subfacet and _segment_3 facets if any if (dim != spatial_dimension - 1) { updateSubelementToElement(dim, true); updateElementToSubelement(dim, true); updateQuadraticSegments(dim); } else { updateQuadraticSegments(dim); } mesh_facets.sendEvent(new_facets); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void CohesiveElementInserterHelper::findSubfacetToDouble() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); MeshAccessor mesh_accessor(mesh_facets); auto & facets_to_double = *facets_to_double_by_dim[spatial_dimension - 1]; auto & subfacets_to_facets = mesh_facets.getSubelementToElement(); auto & elements_to_facets = mesh_accessor.getElementToSubelement(); /// loop on every facet for (auto f : arange(2)) { for (auto && facet_to_double : make_view(facets_to_double, 2)) { auto old_facet = facet_to_double[f]; auto new_facet = facet_to_double[1 - f]; const auto & starting_element = elements_to_facets(new_facet, 0)[0]; auto current_facet = old_facet; Vector subfacets_to_facet = subfacets_to_facets.get(old_facet); /// loop on every subfacet for (auto & subfacet : subfacets_to_facet) { if (subfacet == ElementNull) { continue; } if (dim == spatial_dimension - 2) { Vector subsubfacets_to_subfacet = subfacets_to_facets.get(subfacet); /// loop on every subsubfacet for (auto & subsubfacet : subsubfacets_to_subfacet) { if (subsubfacet == ElementNull) { continue; } Vector subsubfacet_connectivity = mesh_facets.getConnectivity(subsubfacet); std::vector element_list; std::vector facet_list; std::vector subfacet_list; /// check if subsubfacet is to be doubled if (findElementsAroundSubfacet( starting_element, current_facet, subsubfacet_connectivity, element_list, facet_list, &subfacet_list) == false and removeElementsInVector( subfacet_list, elements_to_facets(subsubfacet)) == false) { Element new_subsubfacet{ subsubfacet.type, nb_new_facets(subsubfacet.type, subsubfacet.ghost_type)++, subsubfacet.ghost_type}; facets_to_double_by_dim[dim - 1]->push_back( Vector{subsubfacet, new_subsubfacet}); elementsOfDimToElementsOfDim(dim - 1, dim - 1) .push_back(subfacet_list); elementsOfDimToElementsOfDim(dim, dim - 1) .push_back(facet_list); elementsOfDimToElementsOfDim(dim + 1, dim - 1) .push_back(element_list); } } } else { std::vector element_list; std::vector facet_list; Vector subfacet_connectivity = mesh_facets.getConnectivity(subfacet); /// check if subfacet is to be doubled if (findElementsAroundSubfacet(starting_element, current_facet, subfacet_connectivity, element_list, facet_list) == false and removeElementsInVector(facet_list, elements_to_facets(subfacet)) == false) { Element new_subfacet{ subfacet.type, nb_new_facets(subfacet.type, subfacet.ghost_type)++, subfacet.ghost_type}; facets_to_double_by_dim[dim - 1]->push_back( Vector{subfacet, new_subfacet}); elementsOfDimToElementsOfDim(dim, dim - 1).push_back(facet_list); elementsOfDimToElementsOfDim(dim + 1, dim - 1) .push_back(element_list); } } } } } } /* -------------------------------------------------------------------------- */ void CohesiveElementInserterHelper::doubleNodes( const std::vector & old_nodes) { auto & position = mesh.getNodes(); auto spatial_dimension = mesh.getSpatialDimension(); auto old_nb_nodes = position.size(); position.reserve(old_nb_nodes + old_nodes.size()); doubled_nodes.reserve(doubled_nodes.size() + old_nodes.size()); auto position_begin = position.begin(spatial_dimension); for (auto && data : enumerate(old_nodes)) { auto n = std::get<0>(data); auto old_node = std::get<1>(data); decltype(old_node) new_node = old_nb_nodes + n; /// store doubled nodes doubled_nodes.push_back(Vector{old_node, new_node}); /// update position Vector coords = Vector(position_begin[old_node]); position.push_back(coords); } } /* -------------------------------------------------------------------------- */ bool CohesiveElementInserterHelper::findElementsAroundSubfacet( const Element & starting_element, const Element & end_facet, const Vector & subfacet_connectivity, std::vector & element_list, std::vector & facet_list, std::vector * subfacet_list) { bool facet_matched = false; element_list.push_back(starting_element); std::queue elements_to_check; elements_to_check.push(starting_element); /// keep going as long as there are elements to check while (not elements_to_check.empty()) { /// check current element Element & current_element = elements_to_check.front(); const Vector facets_to_element = mesh_facets.getSubelementToElement(current_element); // for every facet of the element for (auto & current_facet : facets_to_element) { if (current_facet == ElementNull) { continue; } if (current_facet == end_facet) { facet_matched = true; } auto find_facet = std::find(facet_list.begin(), facet_list.end(), current_facet); // facet already listed or subfacet_connectivity is not in the // connectivity of current_facet; if ((find_facet != facet_list.end()) or not hasElement(mesh_facets.getConnectivity(current_facet), subfacet_connectivity)) { continue; } facet_list.push_back(current_facet); if (subfacet_list != nullptr) { const Vector subfacets_of_facet = mesh_facets.getSubelementToElement(current_facet); /// check subfacets for (const auto & current_subfacet : subfacets_of_facet) { if (current_subfacet == ElementNull) { continue; } auto find_subfacet = std::find( subfacet_list->begin(), subfacet_list->end(), current_subfacet); if ((find_subfacet != subfacet_list->end()) or not hasElement(mesh_facets.getConnectivity(current_subfacet), subfacet_connectivity)) { continue; } subfacet_list->push_back(current_subfacet); } } /// consider opposing element const auto & elements_to_facet = mesh_facets.getElementToSubelement(current_facet); UInt opposing = 0; if (elements_to_facet[0] == current_element) { opposing = 1; } auto & opposing_element = elements_to_facet[opposing]; /// skip null elements since they are on a boundary if (opposing_element == ElementNull) { continue; } /// skip this element if already added if (std::find(element_list.begin(), element_list.end(), opposing_element) != element_list.end()) { continue; } /// only regular elements have to be checked if (opposing_element.kind() == _ek_regular) { elements_to_check.push(opposing_element); } element_list.push_back(opposing_element); AKANTU_DEBUG_ASSERT(hasElement(mesh.getConnectivity(opposing_element), subfacet_connectivity), "Subfacet doesn't belong to this element"); } /// erased checked element from the list elements_to_check.pop(); } return facet_matched; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserterHelper::updateCohesiveData() { UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; MeshAccessor mesh_accessor(mesh); MeshAccessor mesh_facets_accessor(mesh_facets); for (auto ghost_type : ghost_types) { for (auto cohesive_type : mesh.elementTypes(_element_kind = _ek_cohesive)) { auto nb_cohesive_elements = mesh.getNbElement(cohesive_type, ghost_type); nb_new_facets(cohesive_type, ghost_type) = nb_cohesive_elements; mesh_facets_accessor.getSubelementToElement(cohesive_type, ghost_type); } } auto & facets_to_double = *facets_to_double_by_dim[spatial_dimension - 1]; new_elements.reserve(new_elements.size() + facets_to_double.size()); std::array facets; auto & element_to_facet = mesh_facets_accessor.getElementToSubelement(); auto & facets_to_cohesive_elements = mesh_facets_accessor.getSubelementToElement(); for (auto && facet_to_double : make_view(facets_to_double, 2)) { auto & old_facet = facet_to_double[0]; /// (in 3D cohesive elements connectivity is inverted) facets[third_dimension ? 1 : 0] = old_facet; facets[third_dimension ? 0 : 1] = facet_to_double[1]; auto type_cohesive = FEEngine::getCohesiveElementType(old_facet.type); auto & facet_connectivities = mesh_facets.getConnectivity(old_facet.type, old_facet.ghost_type); auto facet_connectivity_it = facet_connectivities.begin(facet_connectivities.getNbComponent()); auto cohesive_element = Element{ type_cohesive, nb_new_facets(type_cohesive, old_facet.ghost_type)++, old_facet.ghost_type}; auto & cohesives_connectivities = mesh_accessor.getConnectivity(type_cohesive, old_facet.ghost_type); Matrix connectivity(facet_connectivities.getNbComponent(), 2); Vector facets_to_cohesive_element(2); for (auto s : arange(2)) { /// store doubled facets facets_to_cohesive_element[s] = facets[s]; // update connectivities connectivity(s) = Vector(facet_connectivity_it[facets[s].element]); /// update element_to_facet vectors element_to_facet(facets[s], 0)[1] = cohesive_element; } cohesives_connectivities.push_back(connectivity); facets_to_cohesive_elements(type_cohesive, old_facet.ghost_type) .push_back(facets_to_cohesive_element); /// add cohesive element to the element event list new_elements.push_back(cohesive_element); } } /* -------------------------------------------------------------------------- */ void CohesiveElementInserterHelper::doublePointFacet() { UInt spatial_dimension = mesh.getSpatialDimension(); if (spatial_dimension != 1) { return; } + NewElementsEvent new_facets_event; + auto & facets_to_double = *facets_to_double_by_dim[spatial_dimension - 1]; auto & element_to_facet = mesh_facets.getElementToSubelement(); auto & position = mesh.getNodes(); MeshAccessor mesh_accessor(mesh_facets); for (auto ghost_type : ghost_types) { for (auto facet_type : nb_new_facets.elementTypes( spatial_dimension - 1, ghost_type, _ek_regular)) { auto nb_new_element = nb_new_facets(facet_type, ghost_type); auto & connectivities = mesh_accessor.getConnectivity(facet_type, ghost_type); connectivities.resize(connectivities.size() + nb_new_element); } } for (auto facet_to_double : make_view(facets_to_double, 2)) { auto & old_facet = facet_to_double[0]; auto & new_facet = facet_to_double[1]; auto element = element_to_facet(new_facet)[0]; auto & facet_connectivities = mesh_accessor.getConnectivity(old_facet.type, old_facet.ghost_type); auto old_node = facet_connectivities(old_facet.element); auto new_node = position.size(); /// update position position.push_back(position(old_node)); facet_connectivities(new_facet.element) = new_node; Vector segment_conectivity = mesh.getConnectivity(element); /// update facet connectivity auto it = std::find(segment_conectivity.begin(), segment_conectivity.end(), old_node); *it = new_node; doubled_nodes.push_back(Vector{old_node, new_node}); + new_facets_event.getList().push_back(new_facet); } + + mesh_facets.sendEvent(new_facets_event); } /* -------------------------------------------------------------------------- */ template void CohesiveElementInserterHelper::doubleSubfacet() { if (spatial_dimension == 1) { return; } + NewElementsEvent new_facets_event; + std::vector nodes_to_double; MeshAccessor mesh_accessor(mesh_facets); auto & connectivities = mesh_accessor.getConnectivities(); auto & facets_to_double = *facets_to_double_by_dim[0]; ElementTypeMap nb_new_elements; for (auto && facet_to_double : make_view(facets_to_double, 2)) { auto && old_element = facet_to_double[0]; nb_new_elements(old_element.type, old_element.ghost_type) = 0; } for (auto && facet_to_double : make_view(facets_to_double, 2)) { auto && old_element = facet_to_double[0]; ++nb_new_elements(old_element.type, old_element.ghost_type); } for (auto ghost_type : ghost_types) { for (auto facet_type : nb_new_elements.elementTypes(0, ghost_type, _ek_regular)) { auto & connectivities = mesh_accessor.getConnectivity(facet_type, ghost_type); connectivities.resize(connectivities.size() + nb_new_elements(facet_type, ghost_type)); } } for (auto && facet_to_double : make_view(facets_to_double, 2)) { auto & old_facet = facet_to_double(0); // auto & new_facet = facet_to_double(1); AKANTU_DEBUG_ASSERT( old_facet.type == _point_1, "Only _point_1 subfacet doubling is supported at the moment"); /// list nodes double nodes_to_double.push_back(connectivities(old_facet)); } auto old_nb_doubled_nodes = doubled_nodes.size(); doubleNodes(nodes_to_double); auto double_nodes_view = make_view(doubled_nodes, 2); for (auto && data : zip(make_view(facets_to_double, 2), range(double_nodes_view.begin() + old_nb_doubled_nodes, double_nodes_view.end()), arange(facets_to_double.size()))) { // auto & old_facet = std::get<0>(data)[0]; auto & new_facet = std::get<0>(data)[1]; + new_facets_event.getList().push_back(new_facet); + auto & nodes = std::get<1>(data); auto old_node = nodes(0); auto new_node = nodes(1); auto f = std::get<2>(data); /// add new nodes in connectivity connectivities(new_facet) = new_node; updateElementalConnectivity(mesh, old_node, new_node, elementsOfDimToElementsOfDim(2, 0)(f), &elementsOfDimToElementsOfDim(1, 0)(f)); updateElementalConnectivity(mesh_facets, old_node, new_node, elementsOfDimToElementsOfDim(1, 0)(f)); if (spatial_dimension == 3) { updateElementalConnectivity(mesh_facets, old_node, new_node, elementsOfDimToElementsOfDim(0, 0)(f)); } } updateSubelementToElement(0, spatial_dimension == 2); updateElementToSubelement(0, spatial_dimension == 2); + + mesh_facets.sendEvent(new_facets_event); } } // namespace akantu diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 161085d33..0491e90d8 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,812 +1,810 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Leonardo Snozzi * @author Marco Vocialta * * @date creation: Fri Aug 20 2010 * @date last modification: Wed Feb 21 2018 * * @brief All mesh utils necessary for various tasks * * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "fe_engine.hh" #include "mesh_accessor.hh" #include "mesh_iterators.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) { spatial_dimension = mesh.getSpatialDimension(); } /// count number of occurrence of each node UInt nb_nodes = mesh.getNbNodes(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); for_each_element( mesh, [&](auto && element) { Vector conn = mesh.getConnectivity(element); for (auto && node : conn) { ++node_to_elem.rowOffset(node); } }, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined); node_to_elem.countToCSR(); node_to_elem.resizeCols(); /// rearrange element to get the node-element list // Element e; node_to_elem.beginInsertions(); for_each_element( mesh, [&](auto && element) { Vector conn = mesh.getConnectivity(element); for (auto && node : conn) { node_to_elem.insertInRow(node, element); } }, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined); node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR & node_to_elem, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, ghost_type).size(); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { ++node_to_elem.rowOffset(conn_val[el_offset + n]); } } /// convert the occurrence array in a csr one node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { node_to_elem.insertInRow(conn_val[el_offset + n], el); } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (auto ghost_type : ghost_types) { for (const auto & type : mesh.elementTypes(spatial_dimension - 1, ghost_type)) { mesh.getConnectivity(type, ghost_type).resize(0); // \todo inform the mesh event handler } } buildFacetsDimension(mesh, mesh, true, spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension) { AKANTU_DEBUG_IN(); to_dimension = std::max(to_dimension, UInt(0)); AKANTU_DEBUG_ASSERT( mesh_facets.isMeshFacets(), "The mesh_facets should be initialized with initMeshFacets"); /// generate facets buildFacetsDimension(mesh, mesh_facets, false, from_dimension); /// sort facets and generate sub-facets for (UInt i = from_dimension - 1; i > to_dimension; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension) { AKANTU_DEBUG_IN(); // save the current parent of mesh_facets and set it temporarly to mesh since // mesh is the one containing the elements for which mesh_facets has the // sub-elements // example: if the function is called with mesh = mesh_facets const Mesh * mesh_facets_parent = nullptr; try { mesh_facets_parent = &mesh_facets.getMeshParent(); } catch (...) { } mesh_facets.defineMeshParent(mesh); MeshAccessor mesh_accessor(mesh_facets); UInt spatial_dimension = mesh.getSpatialDimension(); const Array & mesh_facets_nodes = mesh_facets.getNodes(); const auto mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); CSR node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array counter; std::vector connected_elements; NewElementsEvent event(AKANTU_CURRENT_FUNCTION); // init the SubelementToElement data to improve performance for (auto && ghost_type : ghost_types) { for (auto && type : mesh.elementTypes(dimension, ghost_type)) { auto & subelement_to_element = mesh_accessor.getSubelementToElement(type, ghost_type); subelement_to_element.resize(mesh.getNbElement(type, ghost_type), ElementNull); auto facet_types = mesh.getAllFacetTypes(type); for (auto && ft : arange(facet_types.size())) { auto facet_type = facet_types(ft); mesh_accessor.getElementToSubelement(facet_type, ghost_type); mesh_accessor.getConnectivity(facet_type, ghost_type); } } } const ElementSynchronizer * synchronizer = nullptr; if (mesh.isDistributed()) { synchronizer = &(mesh.getElementSynchronizer()); } Element current_element; for (auto && ghost_type : ghost_types) { GhostType facet_ghost_type = ghost_type; current_element.ghost_type = ghost_type; for (auto && type : mesh.elementTypes(dimension, ghost_type)) { auto facet_types = mesh.getAllFacetTypes(type); current_element.type = type; for (auto && ft : arange(facet_types.size())) { auto facet_type = facet_types(ft); auto nb_element = mesh.getNbElement(type, ghost_type); auto && element_to_subelement = &mesh_accessor.getElementToSubelementNC(facet_type, ghost_type); auto && connectivity_facets = &mesh_accessor.getConnectivity(facet_type, ghost_type); auto nb_nodes_per_facet = connectivity_facets->getNbComponent(); // Vector facet(nb_nodes_per_facet); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; auto && facets = mesh.getFacetConnectivity(current_element, ft).transpose(); for (auto facet : facets) { // facet = facets(f); UInt first_node_nb_elements = node_to_elem.getNbCols(facet(0)); counter.resize(first_node_nb_elements); counter.zero(); // loop over the other nodes to search intersecting elements, // which are the elements that share another node with the // starting element after first_node for (auto && data : enumerate(node_to_elem.getRow(facet(0)))) { auto && local_el = std::get<0>(data); auto && first_node = std::get<1>(data); for (auto n : arange(1, nb_nodes_per_facet)) { auto && node_elements = node_to_elem.getRow(facet(n)); counter(local_el) += std::count( node_elements.begin(), node_elements.end(), first_node); } } // counting the number of elements connected to the facets and // taking the minimum element number, because the facet should // be inserted just once UInt nb_element_connected_to_facet = 0; Element minimum_el = ElementNull; connected_elements.clear(); for (auto && data : enumerate(node_to_elem.getRow(facet(0)))) { if (not(counter(std::get<0>(data)) == nb_nodes_per_facet - 1)) { continue; } auto && real_el = std::get<1>(data); ++nb_element_connected_to_facet; minimum_el = std::min(minimum_el, real_el); connected_elements.push_back(real_el); } if (minimum_el != current_element) { continue; } bool full_ghost_facet = false; UInt n = 0; while (n < nb_nodes_per_facet and mesh.isPureGhostNode(facet(n))) { ++n; } if (n == nb_nodes_per_facet) { full_ghost_facet = true; } if (full_ghost_facet) { continue; } if (boundary_only and nb_element_connected_to_facet != 1) { continue; } std::vector elements; // build elements_on_facets: linearized_el must come first // in order to store the facet in the correct direction // and avoid to invert the sign in the normal computation elements.reserve(elements.size() + connected_elements.size()); for (auto && connected_element : connected_elements) { elements.push_back(connected_element); } if (nb_element_connected_to_facet == 1) { /// boundary facet elements.push_back(ElementNull); } else if (nb_element_connected_to_facet == 2) { /// internal facet /// check if facet is in between ghost and normal /// elements: if it's the case, the facet is either /// ghost or not ghost. The criterion to decide this /// is arbitrary. It was chosen to check the processor /// id (prank) of the two neighboring elements. If /// prank of the ghost element is lower than prank of /// the normal one, the facet is not ghost, otherwise /// it's ghost GhostType gt[2] = {_not_ghost, _not_ghost}; for (UInt el = 0; el < connected_elements.size(); ++el) { gt[el] = connected_elements[el].ghost_type; } if ((gt[0] == _not_ghost) xor (gt[1] == _not_ghost)) { UInt prank[2]; for (UInt el = 0; el < 2; ++el) { prank[el] = synchronizer->getRank(connected_elements[el]); } // ugly trick from Marco detected :P bool ghost_one = (gt[0] != _ghost); if (prank[ghost_one] > prank[!ghost_one]) { facet_ghost_type = _not_ghost; } else { facet_ghost_type = _ghost; } connectivity_facets = &mesh_accessor.getConnectivity( facet_type, facet_ghost_type); element_to_subelement = &mesh_accessor.getElementToSubelementNC( facet_type, facet_ghost_type); } } element_to_subelement->push_back(elements); connectivity_facets->push_back(facet); /// current facet index UInt current_facet = connectivity_facets->size() - 1; Element facet_element{facet_type, current_facet, facet_ghost_type}; event.getList().push_back(facet_element); /// loop on every element connected to current facet and /// insert current facet in the first free spot of the /// subelement_to_element vector for (auto & loc_el : elements) { if (loc_el == ElementNull) { continue; } auto && subelements = mesh_accessor.getSubelementToElement(loc_el); for (auto & el : subelements) { if (el != ElementNull) { continue; } el = facet_element; break; } } /// reset connectivity in case a facet was found in /// between ghost and normal elements if (facet_ghost_type != ghost_type) { facet_ghost_type = ghost_type; connectivity_facets = &mesh_accessor.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_accessor.getElementToSubelement( facet_type, facet_ghost_type); } } } } } } mesh_facets.sendEvent(event); // restore the parent of mesh_facet if (mesh_facets_parent != nullptr) { mesh_facets.defineMeshParent(*mesh_facets_parent); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, Array & local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array & old_nodes_numbers) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map renumbering_map; for (UInt i = 0; i < old_nodes_numbers.size(); ++i) { renumbering_map[old_nodes_numbers(i)] = i; } /// renumber the nodes renumberNodesInConnectivity(local_connectivities, (nb_local_element + nb_ghost_element) * nb_nodes_per_element, renumbering_map); old_nodes_numbers.resize(renumbering_map.size()); for (auto & renumber_pair : renumbering_map) { old_nodes_numbers(renumber_pair.second) = renumber_pair.first; } renumbering_map.clear(); MeshAccessor mesh_accessor(mesh); /// copy the renumbered connectivity to the right place auto & local_conn = mesh_accessor.getConnectivity(type); local_conn.resize(nb_local_element); if (nb_local_element > 0) { memcpy(local_conn.storage(), local_connectivities.storage(), nb_local_element * nb_nodes_per_element * sizeof(UInt)); } auto & ghost_conn = mesh_accessor.getConnectivity(type, _ghost); ghost_conn.resize(nb_ghost_element); if (nb_ghost_element > 0) { std::memcpy(ghost_conn.storage(), local_connectivities.storage() + nb_local_element * nb_nodes_per_element, nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); } auto & ghost_counter = mesh_accessor.getGhostsCounters(type, _ghost); ghost_counter.resize(nb_ghost_element, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity( Array & list_nodes, UInt nb_nodes, std::map & renumbering_map) { AKANTU_DEBUG_IN(); UInt * connectivity = list_nodes.storage(); UInt new_node_num = renumbering_map.size(); for (UInt n = 0; n < nb_nodes; ++n, ++connectivity) { UInt & node = *connectivity; auto it = renumbering_map.find(node); if (it == renumbering_map.end()) { UInt old_node = node; renumbering_map[old_node] = new_node_num; node = new_node_num; ++new_node_num; } else { node = it->second; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::purifyMesh(Mesh & mesh) { AKANTU_DEBUG_IN(); std::map renumbering_map; RemovedNodesEvent remove_nodes(mesh, AKANTU_CURRENT_FUNCTION); Array & nodes_removed = remove_nodes.getList(); for (auto ghost_type : ghost_types) { for (auto type : mesh.elementTypes(_all_dimensions, ghost_type, _ek_not_defined)) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); Array & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity.size()); renumberNodesInConnectivity( connectivity, nb_element * nb_nodes_per_element, renumbering_map); } } Array & new_numbering = remove_nodes.getNewNumbering(); std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); for (auto && pair : renumbering_map) { new_numbering(std::get<0>(pair)) = std::get<1>(pair); } for (UInt i = 0; i < new_numbering.size(); ++i) { if (new_numbering(i) == UInt(-1)) { nodes_removed.push_back(i); } } mesh.sendEvent(remove_nodes); - mesh_facets.sendEvent(event); - AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::flipFacets( Mesh & mesh_facets, const ElementTypeMapArray & remote_global_connectivities, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); /// get global connectivity for local mesh ElementTypeMapArray local_global_connectivities( "local_global_connectivity", mesh_facets.getID(), mesh_facets.getMemoryID()); local_global_connectivities.initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _ghost_type = gt_facet, _with_nb_nodes_per_element = true, _with_nb_element = true); mesh_facets.getGlobalConnectivity(local_global_connectivities); MeshAccessor mesh_accessor(mesh_facets); /// loop on every facet for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { auto & connectivity = mesh_accessor.getConnectivity(type_facet, gt_facet); auto & local_global_connectivity = local_global_connectivities(type_facet, gt_facet); const auto & remote_global_connectivity = remote_global_connectivities(type_facet, gt_facet); auto & element_per_facet = mesh_accessor.getElementToSubelementNC(type_facet, gt_facet); auto & subfacet_to_facet = mesh_accessor.getSubelementToElementNC(type_facet, gt_facet); auto nb_nodes_per_facet = connectivity.getNbComponent(); auto nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); for (auto && data : zip(make_view(connectivity, nb_nodes_per_facet), make_view(local_global_connectivity, nb_nodes_per_facet), make_view(remote_global_connectivity, nb_nodes_per_facet), make_view(subfacet_to_facet, subfacet_to_facet.getNbComponent()), make_view(element_per_facet))) { auto & conn = std::get<0>(data); auto & local_gconn = std::get<1>(data); const auto & remote_gconn = std::get<2>(data); /// skip facet if connectivities are the same if (local_gconn == remote_gconn) { continue; } /// re-arrange connectivity auto conn_tmp = conn; auto begin = local_gconn.begin(); auto end = local_gconn.end(); AKANTU_DEBUG_ASSERT(std::is_permutation(begin, end, remote_gconn.begin()), "This facets are not just permutation of each other, " << local_gconn << " and " << remote_gconn); for (auto && data : enumerate(remote_gconn)) { auto it = std::find(begin, end, std::get<1>(data)); AKANTU_DEBUG_ASSERT(it != end, "Node not found"); UInt new_position = it - begin; conn(new_position) = conn_tmp(std::get<0>(data)); ; } // std::transform(remote_gconn.begin(), remote_gconn.end(), conn.begin(), // [&](auto && gnode) { // auto it = std::find(begin, end, gnode); // AKANTU_DEBUG_ASSERT(it != end, "Node not found"); // return conn_tmp(it - begin); // }); /// if 3D, check if facets are just rotated if (spatial_dimension == 3) { auto begin = remote_gconn.begin(); /// find first node auto it = std::find(begin, remote_gconn.end(), local_gconn(0)); UInt n; UInt start = it - begin; /// count how many nodes in the received connectivity follow /// the same order of those in the local connectivity for (n = 1; n < nb_nodes_per_P1_facet && local_gconn(n) == remote_gconn((start + n) % nb_nodes_per_P1_facet); ++n) { ; } /// skip the facet inversion if facet is just rotated if (n == nb_nodes_per_P1_facet) { continue; } } /// update data to invert facet auto & element_per_facet = std::get<4>(data); if (element_per_facet[1] != ElementNull) { // by convention the first facet // cannot be a ElementNull std::swap(element_per_facet[0], element_per_facet[1]); } auto & subfacets_of_facet = std::get<3>(data); std::swap(subfacets_of_facet(0), subfacets_of_facet(1)); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::fillElementToSubElementsData(Mesh & mesh) { AKANTU_DEBUG_IN(); if (mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) { AKANTU_DEBUG_INFO("There are not facets, add them in the mesh file or call " "the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray barycenters("barycenter_tmp", mesh.getID(), mesh.getMemoryID()); barycenters.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = _all_dimensions); Element element; for (auto ghost_type : ghost_types) { element.ghost_type = ghost_type; for (const auto & type : mesh.elementTypes(_all_dimensions, ghost_type)) { element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array & barycenters_arr = barycenters(type, ghost_type); barycenters_arr.resize(nb_element); auto bary = barycenters_arr.begin(spatial_dimension); auto bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { element.element = el; mesh.getBarycenter(element, *bary); } } } MeshAccessor mesh_accessor(mesh); for (Int sp(spatial_dimension); sp >= 1; --sp) { if (mesh.getNbElement(sp) == 0) { continue; } for (auto ghost_type : ghost_types) { for (auto & type : mesh.elementTypes(sp, ghost_type)) { auto & subelement_to_element = mesh_accessor.getSubelementToElement(type, ghost_type); subelement_to_element.resize(mesh.getNbElement(type, ghost_type)); subelement_to_element.set(ElementNull); } for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { auto & element_to_subelement = mesh_accessor.getElementToSubelement(type, ghost_type); element_to_subelement.resize(mesh.getNbElement(type, ghost_type)); element_to_subelement.clear(); } } CSR nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (auto ghost_type : ghost_types) { facet_element.ghost_type = ghost_type; for (const auto & type : mesh.elementTypes(sp - 1, ghost_type)) { facet_element.type = type; auto & element_to_subelement = mesh_accessor.getElementToSubelement(type, ghost_type); const auto & connectivity = mesh.getConnectivity(type, ghost_type); //element_to_subelement.resize(connectivity.size()); for (auto && data : enumerate( make_view(connectivity, mesh.getNbNodesPerElement(type)))) { const auto & facet = std::get<1>(data); facet_element.element = std::get<0>(data); std::map element_seen_counter; auto nb_nodes_per_facet = mesh.getNbNodesPerElement(Mesh::getP1ElementType(type)); // count the number of node in common between the facet and the // other element connected to the nodes of the facet for (auto node : arange(nb_nodes_per_facet)) { for (auto & elem : nodes_to_elements.getRow(facet(node))) { auto cit = element_seen_counter.find(elem); if (cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } // check which are the connected elements std::vector connected_elements; for (auto && cit : element_seen_counter) { if (cit.second == nb_nodes_per_facet) { connected_elements.push_back(cit.first); } } // add the connected elements as sub-elements for (auto & connected_element : connected_elements) { element_to_subelement(facet_element.element) .push_back(connected_element); } // add the element as sub-element to the connected elements for (auto & connected_element : connected_elements) { Vector subelements_to_element = mesh.getSubelementToElement(connected_element); // find the position where to insert the element auto it = std::find(subelements_to_element.begin(), subelements_to_element.end(), ElementNull); AKANTU_DEBUG_ASSERT( it != subelements_to_element.end(), "The element " << connected_element << " seems to have too many facets!! (" << (it - subelements_to_element.begin()) << " < " << mesh.getNbFacetsPerElement(connected_element.type) << ")"); *it = facet_element; } } } } } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/common/non_linear_solver/non_linear_solver_newton_raphson.cc b/src/model/common/non_linear_solver/non_linear_solver_newton_raphson.cc index 537e19ad0..77ef110ab 100644 --- a/src/model/common/non_linear_solver/non_linear_solver_newton_raphson.cc +++ b/src/model/common/non_linear_solver/non_linear_solver_newton_raphson.cc @@ -1,212 +1,210 @@ /** * @file non_linear_solver_newton_raphson.cc * * @author Nicolas Richart * * @date creation: Tue Sep 15 2015 * @date last modification: Wed Feb 21 2018 * * @brief Implementation of the default NonLinearSolver * * * Copyright (©) 2015-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ +#include "non_linear_solver_newton_raphson.hh" #include "communicator.hh" #include "dof_manager_default.hh" -#include "non_linear_solver_newton_raphson.hh" #include "solver_callback.hh" #include "solver_vector.hh" #include "sparse_solver_mumps.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolverNewtonRaphson::NonLinearSolverNewtonRaphson( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id), dof_manager(dof_manager), solver(std::make_unique( dof_manager, "J", id + ":sparse_solver", memory_id)) { this->supported_type.insert(NonLinearSolverType::_newton_raphson_modified); this->supported_type.insert(NonLinearSolverType::_newton_raphson_contact); this->supported_type.insert(NonLinearSolverType::_newton_raphson); this->supported_type.insert(NonLinearSolverType::_linear); this->checkIfTypeIsSupported(); this->registerParam("threshold", convergence_criteria, 1e-10, _pat_parsmod, "Threshold to consider results as converged"); this->registerParam("convergence_type", convergence_criteria_type, SolveConvergenceCriteria::_solution, _pat_parsmod, "Type of convergence criteria"); this->registerParam("max_iterations", max_iterations, 10, _pat_parsmod, "Max number of iterations"); this->registerParam("error", error, _pat_readable, "Last reached error"); this->registerParam("nb_iterations", n_iter, _pat_readable, "Last reached number of iterations"); this->registerParam("converged", converged, _pat_readable, "Did last solve converged"); this->registerParam("force_linear_recompute", force_linear_recompute, true, _pat_modifiable, "Force reassembly of the jacobian matrix"); } /* -------------------------------------------------------------------------- */ NonLinearSolverNewtonRaphson::~NonLinearSolverNewtonRaphson() = default; /* ------------------------------------------------------------------------ */ void NonLinearSolverNewtonRaphson::solve(SolverCallback & solver_callback) { solver_callback.beforeSolveStep(); this->dof_manager.updateGlobalBlockedDofs(); solver_callback.predictor(); if (non_linear_solver_type == NonLinearSolverType::_linear and solver_callback.canSplitResidual()) { solver_callback.assembleMatrix("K"); } this->assembleResidual(solver_callback); if (this->non_linear_solver_type == NonLinearSolverType::_newton_raphson_modified || (this->non_linear_solver_type == NonLinearSolverType::_linear && this->force_linear_recompute)) { solver_callback.assembleMatrix("J"); this->force_linear_recompute = false; } this->n_iter = 0; this->converged = false; this->convergence_criteria_normalized = this->convergence_criteria; if (this->convergence_criteria_type == SolveConvergenceCriteria::_residual) { this->converged = this->testConvergence(this->dof_manager.getResidual()); if (this->converged) { return; } this->convergence_criteria_normalized = this->error * this->convergence_criteria; } do { if (this->non_linear_solver_type == NonLinearSolverType::_newton_raphson or this->non_linear_solver_type == - NonLinearSolverType::_newton_raphson_contact) + NonLinearSolverType::_newton_raphson_contact) { solver_callback.assembleMatrix("J"); - } + } - this->solver->solve(); + this->solver->solve(); - solver_callback.corrector(); + solver_callback.corrector(); - // EventManager::sendEvent(NonLinearSolver::AfterSparseSolve(method)); + // EventManager::sendEvent(NonLinearSolver::AfterSparseSolve(method)); - if (this->convergence_criteria_type == SolveConvergenceCriteria::_residual) { - this->assembleResidual(solver_callback); - this->converged = this->testConvergence(this->dof_manager.getResidual()); - } else { - this->converged = this->testConvergence(this->dof_manager.getSolution()); - } + if (this->convergence_criteria_type == + SolveConvergenceCriteria::_residual) { + this->assembleResidual(solver_callback); + this->converged = this->testConvergence(this->dof_manager.getResidual()); + } else { + this->converged = this->testConvergence(this->dof_manager.getSolution()); + } - if (this->convergence_criteria_type == SolveConvergenceCriteria::_solution and - not this->converged) { + if (this->convergence_criteria_type == + SolveConvergenceCriteria::_solution and + not this->converged) { + this->assembleResidual(solver_callback); + } + + this->n_iter++; + AKANTU_DEBUG_INFO( + "[" << this->convergence_criteria_type << "] Convergence iteration " + << std::setw(std::log10(this->max_iterations)) << this->n_iter + << ": error " << this->error << (this->converged ? " < " : " > ") + << this->convergence_criteria); + } while (not this->converged and this->n_iter <= this->max_iterations); + + // this makes sure that you have correct strains and stresses after the + // solveStep function (e.g., for dumping) + if (this->convergence_criteria_type == SolveConvergenceCriteria::_solution) { this->assembleResidual(solver_callback); } - this->n_iter++; - AKANTU_DEBUG_INFO( - "[" << this->convergence_criteria_type << "] Convergence iteration " - << std::setw(std::log10(this->max_iterations)) << this->n_iter - << ": error " << this->error << (this->converged ? " < " : " > ") - << this->convergence_criteria); -} -while (not this->converged and this->n_iter <= this->max_iterations) - ; - -// this makes sure that you have correct strains and stresses after the -// solveStep function (e.g., for dumping) -if (this->convergence_criteria_type == SolveConvergenceCriteria::_solution) { - this->assembleResidual(solver_callback); -} + this->converged = + this->converged and not(this->n_iter > this->max_iterations); -this->converged = this->converged and not(this->n_iter > this->max_iterations); + solver_callback.afterSolveStep(this->converged); -solver_callback.afterSolveStep(this->converged); - -if (not this->converged) { - AKANTU_CUSTOM_EXCEPTION(debug::NLSNotConvergedException( - this->convergence_criteria, this->n_iter, this->error)); - - AKANTU_DEBUG_WARNING("[" << this->convergence_criteria_type - << "] Convergence not reached after " - << std::setw(std::log10(this->max_iterations)) - << this->n_iter << " iteration" - << (this->n_iter == 1 ? "" : "s") << "!"); -} + if (not this->converged) { + AKANTU_CUSTOM_EXCEPTION(debug::NLSNotConvergedException( + this->convergence_criteria, this->n_iter, this->error)); + AKANTU_DEBUG_WARNING("[" << this->convergence_criteria_type + << "] Convergence not reached after " + << std::setw(std::log10(this->max_iterations)) + << this->n_iter << " iteration" + << (this->n_iter == 1 ? "" : "s") << "!"); + } } /* -------------------------------------------------------------------------- */ bool NonLinearSolverNewtonRaphson::testConvergence( const SolverVector & solver_vector) { AKANTU_DEBUG_IN(); const auto & blocked_dofs = this->dof_manager.getBlockedDOFs(); const Array & array(solver_vector); UInt nb_degree_of_freedoms = array.size(); auto arr_it = array.begin(); auto bld_it = blocked_dofs.begin(); Real norm = 0.; for (UInt n = 0; n < nb_degree_of_freedoms; ++n, ++arr_it, ++bld_it) { bool is_local_node = this->dof_manager.isLocalOrMasterDOF(n); if ((!*bld_it) && is_local_node) { norm += *arr_it * *arr_it; } } dof_manager.getCommunicator().allReduce(norm, SynchronizerOperation::_sum); norm = std::sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something went wrong in the solve phase"); this->error = norm; - std::cout << error << "-----" << this->convergence_criteria_normalized - << std::endl; return (error < this->convergence_criteria_normalized); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/contact_mechanics/geometry_utils.cc b/src/model/contact_mechanics/geometry_utils.cc index 25ed03479..7a66183bc 100644 --- a/src/model/contact_mechanics/geometry_utils.cc +++ b/src/model/contact_mechanics/geometry_utils.cc @@ -1,804 +1,790 @@ /** * @file geometry_utils.cc * * @author Mohit Pundir * * @date creation: Mon Mmay 20 2019 * @date last modification: Mon May 20 2019 * - * @brief Implementation of various utilities needed for contact geometry + * @brief Implementation of various utilities needed for contact geometry * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "geometry_utils.hh" /* -------------------------------------------------------------------------- */ - namespace akantu { - + /* -------------------------------------------------------------------------- */ void GeometryUtils::normal(const Mesh & mesh, const Array & positions, - const Element & element, Vector & normal, bool outward) { + const Element & element, Vector & normal, + bool outward) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt surface_dimension = spatial_dimension - 1; - + UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); Matrix coords(spatial_dimension, nb_nodes_per_element); UInt * elem_val = mesh.getConnectivity(element.type, _not_ghost).storage(); mesh.extractNodalValuesFromElement(positions, coords.storage(), - elem_val + element.element * nb_nodes_per_element, + elem_val + + element.element * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); Matrix vectors(spatial_dimension, surface_dimension); switch (spatial_dimension) { case 1: { normal[0] = 1; break; } case 2: { vectors(0) = Vector(coords(1)) - Vector(coords(0)); Math::normal2(vectors.storage(), normal.storage()); break; } case 3: { vectors(0) = Vector(coords(1)) - Vector(coords(0)); vectors(1) = Vector(coords(2)) - Vector(coords(0)); Math::normal3(vectors(0).storage(), vectors(1).storage(), normal.storage()); break; } - default: { AKANTU_ERROR("Unknown dimension : " << spatial_dimension); } + default: { + AKANTU_ERROR("Unknown dimension : " << spatial_dimension); + } } // to ensure that normal is always outwards from master surface if (outward) { - - const auto & element_to_subelement = - mesh.getElementToSubelement(element.type)(element.element); - - Vector outside(spatial_dimension); - mesh.getBarycenter(element, outside); - - // check if mesh facets exists for cohesive elements contact - Vector inside(spatial_dimension); - if (mesh.isMeshFacets()) { - mesh.getMeshParent().getBarycenter(element_to_subelement[0], inside); - } else { - mesh.getBarycenter(element_to_subelement[0], inside); - } - - Vector inside_to_outside = outside - inside; - auto projection = inside_to_outside.dot(normal); - - if (projection < 0) { - normal *= -1.0; - } + + const auto & element_to_subelement = + mesh.getElementToSubelement(element.type)(element.element); + + Vector outside(spatial_dimension); + mesh.getBarycenter(element, outside); + + // check if mesh facets exists for cohesive elements contact + Vector inside(spatial_dimension); + if (mesh.isMeshFacets()) { + mesh.getMeshParent().getBarycenter(element_to_subelement[0], inside); + } else { + mesh.getBarycenter(element_to_subelement[0], inside); + } + + Vector inside_to_outside = outside - inside; + auto projection = inside_to_outside.dot(normal); + + if (projection < 0) { + normal *= -1.0; + } } } /* -------------------------------------------------------------------------- */ -void GeometryUtils::normal(const Mesh & mesh, const Element & element, Matrix & tangents, - Vector & normal, bool outward) { +void GeometryUtils::normal(const Mesh & mesh, const Element & element, + Matrix & tangents, Vector & normal, + bool outward) { UInt spatial_dimension = mesh.getSpatialDimension(); - + // to ensure that normal is always outwards from master surface we // compute a direction vector form inside of element attached to the // suurface element - + Vector inside_to_outside(spatial_dimension); if (outward) { - - const auto & element_to_subelement = - mesh.getElementToSubelement(element.type)(element.element); - - Vector outside(spatial_dimension); - mesh.getBarycenter(element, outside); - - // check if mesh facets exists for cohesive elements contact - Vector inside(spatial_dimension); - if (mesh.isMeshFacets()) { - mesh.getMeshParent().getBarycenter(element_to_subelement[0], inside); - } else { - mesh.getBarycenter(element_to_subelement[0], inside); - } - - inside_to_outside = outside - inside; - //auto projection = inside_to_outside.dot(normal); - - //if (projection < 0) { - // normal *= -1.0; - //} + + const auto & element_to_subelement = + mesh.getElementToSubelement(element.type)(element.element); + + Vector outside(spatial_dimension); + mesh.getBarycenter(element, outside); + + // check if mesh facets exists for cohesive elements contact + Vector inside(spatial_dimension); + if (mesh.isMeshFacets()) { + mesh.getMeshParent().getBarycenter(element_to_subelement[0], inside); + } else { + mesh.getBarycenter(element_to_subelement[0], inside); + } + + inside_to_outside = outside - inside; + // auto projection = inside_to_outside.dot(normal); + + // if (projection < 0) { + // normal *= -1.0; + //} } - + // to ensure that direction of tangents are correct, cross product // of tangents should give be in the same direction as of inside to outside switch (spatial_dimension) { case 2: { normal[0] = -tangents(0, 1); - normal[1] = tangents(0, 0); + normal[1] = tangents(0, 0); auto ddot = inside_to_outside.dot(normal); if (ddot < 0) { tangents *= -1.0; normal *= -1.0; } - break; } case 3: { auto tang_trans = tangents.transpose(); auto tang1 = Vector(tang_trans(0)); auto tang2 = Vector(tang_trans(1)); auto tang1_cross_tang2 = tang1.crossProduct(tang2); normal = tang1_cross_tang2 / tang1_cross_tang2.norm(); auto ddot = inside_to_outside.dot(normal); if (ddot < 0) { tang_trans(1) *= -1.0; normal *= -1.0; } tangents = tang_trans.transpose(); break; } default: break; } - - } - - + /* -------------------------------------------------------------------------- */ -void GeometryUtils::covariantBasis(const Mesh & mesh, const Array & positions, - const Element & element, const Vector & normal, - Vector & natural_coord, - Matrix & tangents) { +void GeometryUtils::covariantBasis(const Mesh & mesh, + const Array & positions, + const Element & element, + const Vector & normal, + Vector & natural_coord, + Matrix & tangents) { UInt spatial_dimension = mesh.getSpatialDimension(); - + const ElementType & type = element.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage(); Matrix nodes_coord(spatial_dimension, nb_nodes_per_element); mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(), - elem_val + element.element * nb_nodes_per_element, + elem_val + + element.element * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); UInt surface_dimension = spatial_dimension - 1; Matrix dnds(surface_dimension, nb_nodes_per_element); - -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ + +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(natural_coord, dnds) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL tangents.mul(dnds, nodes_coord); auto temp_tangents = tangents.transpose(); for (UInt i = 0; i < spatial_dimension - 1; ++i) { auto temp = Vector(temp_tangents(i)); temp_tangents(i) = temp.normalize(); } tangents = temp_tangents.transpose(); // to ensure that direction of tangents are correct, cross product // of tangents should give the normal vector computed earlier switch (spatial_dimension) { case 2: { Vector e_z(3); e_z[0] = 0.; e_z[1] = 0.; e_z[2] = 1.; Vector tangent(3); tangent[0] = tangents(0, 0); tangent[1] = tangents(0, 1); tangent[2] = 0.; auto exp_normal = e_z.crossProduct(tangent); auto ddot = normal.dot(exp_normal); if (ddot < 0) { tangents *= -1.0; } break; } case 3: { auto tang_trans = tangents.transpose(); auto tang1 = Vector(tang_trans(0)); auto tang2 = Vector(tang_trans(1)); auto tang1_cross_tang2 = tang1.crossProduct(tang2); auto exp_normal = tang1_cross_tang2 / tang1_cross_tang2.norm(); auto ddot = normal.dot(exp_normal); if (ddot < 0) { tang_trans(1) *= -1.0; } tangents = tang_trans.transpose(); break; } default: break; } } /* -------------------------------------------------------------------------- */ -void GeometryUtils::covariantBasis(const Mesh & mesh, const Array & positions, - const Element & element, Vector & natural_coord, - Matrix & tangents) { +void GeometryUtils::covariantBasis(const Mesh & mesh, + const Array & positions, + const Element & element, + Vector & natural_coord, + Matrix & tangents) { UInt spatial_dimension = mesh.getSpatialDimension(); - + const ElementType & type = element.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage(); Matrix nodes_coord(spatial_dimension, nb_nodes_per_element); mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(), - elem_val + element.element * nb_nodes_per_element, + elem_val + + element.element * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); UInt surface_dimension = spatial_dimension - 1; Matrix dnds(surface_dimension, nb_nodes_per_element); - -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ + +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(natural_coord, dnds) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL tangents.mul(dnds, nodes_coord); auto temp_tangents = tangents.transpose(); for (UInt i = 0; i < spatial_dimension - 1; ++i) { auto temp = Vector(temp_tangents(i)); temp_tangents(i) = temp.normalize(); } tangents = temp_tangents.transpose(); } - /* -------------------------------------------------------------------------- */ void GeometryUtils::curvature(const Mesh & mesh, const Array & positions, - const Element & element, const Vector & natural_coord, - Matrix & curvature) { + const Element & element, + const Vector & natural_coord, + Matrix & curvature) { UInt spatial_dimension = mesh.getSpatialDimension(); auto surface_dimension = spatial_dimension - 1; const ElementType & type = element.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage(); - + Matrix dn2ds2(surface_dimension * surface_dimension, - Mesh::getNbNodesPerElement(type)); - -#define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type) \ - ElementClass::computeDN2DS2(natural_coord, dn2ds2) - AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_SECOND_DERIVATIVES_NATURAL); + Mesh::getNbNodesPerElement(type)); + +#define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type) \ + ElementClass::computeDN2DS2(natural_coord, dn2ds2) + AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_SECOND_DERIVATIVES_NATURAL); #undef GET_SHAPE_SECOND_DERIVATIVES_NATURAL - Matrix coords(spatial_dimension, nb_nodes_per_element); - mesh.extractNodalValuesFromElement(positions, coords.storage(), - elem_val + element.element * nb_nodes_per_element, - nb_nodes_per_element, spatial_dimension); + Matrix coords(spatial_dimension, nb_nodes_per_element); + mesh.extractNodalValuesFromElement(positions, coords.storage(), + elem_val + + element.element * nb_nodes_per_element, + nb_nodes_per_element, spatial_dimension); - curvature.mul(coords, dn2ds2); + curvature.mul(coords, dn2ds2); } - /* -------------------------------------------------------------------------- */ -UInt GeometryUtils::orthogonalProjection(const Mesh & mesh, const Array & positions, - const Vector & slave, - const Array & elements, - Real & gap, Vector & natural_projection, - Vector & normal, Real alpha, - UInt max_iterations, - Real projection_tolerance, - Real extension_tolerance) { +UInt GeometryUtils::orthogonalProjection( + const Mesh & mesh, const Array & positions, + const Vector & slave, const Array & elements, Real & gap, + Vector & natural_projection, Vector & normal, Real alpha, + UInt max_iterations, Real projection_tolerance, Real extension_tolerance) { UInt index = UInt(-1); Real min_gap = std::numeric_limits::max(); UInt spatial_dimension = mesh.getSpatialDimension(); - UInt surface_dimension = spatial_dimension - 1; - + UInt surface_dimension = spatial_dimension - 1; + UInt nb_same_sides{0}; UInt nb_boundary_elements{0}; UInt counter{0}; auto & contact_group = mesh.getElementGroup("contact_surface"); - + for (auto & element : elements) { // filter out elements which are not there in the element group // contact surface created by the surface selector and is stored // in the mesh or mesh_facet, if a element is not there it // returnas UInt(-1) - + auto & elements_of_type = contact_group.getElements(element.type); - if(elements_of_type.find(element.element) == UInt(-1)) + if (elements_of_type.find(element.element) == UInt(-1)) continue; - - //if (!GeometryUtils::isBoundaryElement(mesh, element)) + // if (!GeometryUtils::isBoundaryElement(mesh, element)) // continue; nb_boundary_elements++; // find the natural coordinate corresponding to the minimum gap // between slave node and master element - - + /* Vector normal_ele(spatial_dimension); GeometryUtils::normal(mesh, positions, element, normal_ele); - + Vector master(spatial_dimension); - GeometryUtils::realProjection(mesh, positions, slave, element, normal_ele, master); + GeometryUtils::realProjection(mesh, positions, slave, element, normal_ele, + master); Vector xi(natural_projection.size()); GeometryUtils::naturalProjection(mesh, positions, element, master, xi, - max_iterations, + max_iterations, projection_tolerance);*/ Vector master(spatial_dimension); - + Vector xi(natural_projection.size()); - GeometryUtils::naturalProjection(mesh, positions, element, - slave, master, xi, - max_iterations, projection_tolerance); + GeometryUtils::naturalProjection(mesh, positions, element, slave, master, + xi, max_iterations, projection_tolerance); Matrix tangent_ele(surface_dimension, spatial_dimension); - GeometryUtils::covariantBasis(mesh, positions, element, xi, - tangent_ele); + GeometryUtils::covariantBasis(mesh, positions, element, xi, tangent_ele); Vector normal_ele(spatial_dimension); GeometryUtils::normal(mesh, element, tangent_ele, normal_ele); - - // if gap between master projection and slave point is zero, then // it means that slave point lies on the master element, hence the // normal from master to slave cannot be computed in that case - + auto master_to_slave = slave - master; Real temp_gap = master_to_slave.norm(); - - if (temp_gap != 0) + + if (temp_gap != 0) master_to_slave /= temp_gap; - + // also the slave point should lie inside the master surface in // case of explicit or outside in case of implicit, one way to // check that is by checking the dot product of normal at each // master element, if the values of all dot product is same then // the slave point lies on the same side of each master element - - + // A alpha parameter is introduced which is 1 in case of explicit // and -1 in case of implicit, therefor the variation (dot product // + alpha) should be close to zero (within tolerance) for both // cases Real direction_tolerance = 1e-8; auto product = master_to_slave.dot(normal_ele); auto variation = std::abs(product + alpha); - - if (variation <= direction_tolerance and - temp_gap <= min_gap and - GeometryUtils::isValidProjection(xi, extension_tolerance)) { - gap = -temp_gap; + if (variation <= direction_tolerance and temp_gap <= min_gap and + GeometryUtils::isValidProjection(xi, extension_tolerance)) { + + gap = -temp_gap; min_gap = temp_gap; - index = counter; + index = counter; natural_projection = xi; normal = normal_ele; - } - if(temp_gap == 0 or variation <= direction_tolerance) + if (temp_gap == 0 or variation <= direction_tolerance) nb_same_sides++; - + counter++; } // if point is not on the same side of all the boundary elements // than it is not consider even if the closet master element is // found - if(nb_same_sides != nb_boundary_elements) + if (nb_same_sides != nb_boundary_elements) index = UInt(-1); - + return index; } - /* -------------------------------------------------------------------------- */ -UInt GeometryUtils::orthogonalProjection(const Mesh & mesh, const Array & positions, - const Vector & slave, - const Array & elements, - Real & gap, Vector & natural_projection, - Vector & normal, - Matrix & tangent, - Real alpha, - UInt max_iterations, - Real projection_tolerance, - Real extension_tolerance) { +UInt GeometryUtils::orthogonalProjection( + const Mesh & mesh, const Array & positions, + const Vector & slave, const Array & elements, Real & gap, + Vector & natural_projection, Vector & normal, + Matrix & tangent, Real /*alpha*/, UInt max_iterations, + Real projection_tolerance, Real extension_tolerance) { UInt index = UInt(-1); Real min_gap = std::numeric_limits::max(); UInt spatial_dimension = mesh.getSpatialDimension(); - UInt surface_dimension = spatial_dimension - 1; - + UInt surface_dimension = spatial_dimension - 1; + auto & contact_group = mesh.getElementGroup("contact_surface"); for (auto && tuple : enumerate(elements)) { auto & counter = std::get<0>(tuple); auto & element = std::get<1>(tuple); // filter out elements which are not there in the element group // contact surface created by the surface selector and is stored // in the mesh or mesh_facet, if a element is not there it // returnas UInt(-1) - + auto & elements_of_type = contact_group.getElements(element.type); - if(elements_of_type.find(element.element) == UInt(-1)) + if (elements_of_type.find(element.element) == UInt(-1)) continue; Vector master(spatial_dimension); - + Vector xi_ele(natural_projection.size()); - GeometryUtils::naturalProjection(mesh, positions, element, - slave, master, xi_ele, - max_iterations, projection_tolerance); + GeometryUtils::naturalProjection(mesh, positions, element, slave, master, + xi_ele, max_iterations, + projection_tolerance); Matrix tangent_ele(surface_dimension, spatial_dimension); - GeometryUtils::covariantBasis(mesh, positions, element, xi_ele, - tangent_ele); + GeometryUtils::covariantBasis(mesh, positions, element, xi_ele, + tangent_ele); Vector normal_ele(spatial_dimension); GeometryUtils::normal(mesh, element, tangent_ele, normal_ele); - + // if gap between master projection and slave point is zero, then // it means that slave point lies on the master element, hence the // normal from master to slave cannot be computed in that case - + auto master_to_slave = slave - master; Real temp_gap = master_to_slave.norm(); - - if (temp_gap != 0) + + if (temp_gap != 0) master_to_slave /= temp_gap; - + // A alpha parameter is introduced which is 1 in case of explicit // and -1 in case of implicit, therefor the variation (dot product // + alpha) should be close to zero (within tolerance) for both // cases auto product = master_to_slave.dot(normal_ele); - - if (product < 0 and - temp_gap <= min_gap and - GeometryUtils::isValidProjection(xi_ele, extension_tolerance)) { - gap = -temp_gap; + if (product < 0 and temp_gap <= min_gap and + GeometryUtils::isValidProjection(xi_ele, extension_tolerance)) { + + gap = -temp_gap; min_gap = temp_gap; - index = counter; + index = counter; natural_projection = xi_ele; normal = normal_ele; tangent = tangent_ele; } } - + return index; } - - /* -------------------------------------------------------------------------- */ -void GeometryUtils::realProjection(const Mesh & mesh, const Array & positions, - const Vector & slave, const Element & element, - const Vector & normal, - Vector & projection) { +void GeometryUtils::realProjection(const Mesh & mesh, + const Array & positions, + const Vector & slave, + const Element & element, + const Vector & normal, + Vector & projection) { UInt spatial_dimension = mesh.getSpatialDimension(); const ElementType & type = element.type; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type); UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage(); Matrix nodes_coord(spatial_dimension, nb_nodes_per_element); mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(), - elem_val + element.element * nb_nodes_per_element, + elem_val + + element.element * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); - + Vector point(nodes_coord(0)); Real alpha = (slave - point).dot(normal); projection = slave - alpha * normal; } /* -------------------------------------------------------------------------- */ -void GeometryUtils::realProjection(const Mesh & mesh, const Array & positions, - const Element & element, const Vector & natural_coord, - Vector & projection) { +void GeometryUtils::realProjection(const Mesh & mesh, + const Array & positions, + const Element & element, + const Vector & natural_coord, + Vector & projection) { UInt spatial_dimension = mesh.getSpatialDimension(); const ElementType & type = element.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element.type); - - Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ + + Vector shapes(nb_nodes_per_element); +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(natural_coord, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL Matrix nodes_coord(spatial_dimension, nb_nodes_per_element); UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage(); mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(), - elem_val + element.element * nb_nodes_per_element, + elem_val + + element.element * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); projection.mul(nodes_coord, shapes); } /* -------------------------------------------------------------------------- */ -void GeometryUtils::naturalProjection(const Mesh & mesh, const Array & positions, - const Element & element, - const Vector & slave_coords, - Vector & master_coords, - Vector & natural_projection, - UInt max_iterations, - Real projection_tolerance) { +void GeometryUtils::naturalProjection( + const Mesh & mesh, const Array & positions, const Element & element, + const Vector & slave_coords, Vector & master_coords, + Vector & natural_projection, UInt max_iterations, + Real projection_tolerance) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt surface_dimension = spatial_dimension - 1; - + const ElementType & type = element.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage(); Matrix nodes_coord(spatial_dimension, nb_nodes_per_element); mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(), - elem_val + element.element * nb_nodes_per_element, + elem_val + + element.element * nb_nodes_per_element, nb_nodes_per_element, spatial_dimension); // initial guess - natural_projection.clear(); - + natural_projection.zero(); + // obhjective function computed on the natural_guess Matrix f(surface_dimension, 1); // jacobian matrix computed on the natural_guess Matrix J(surface_dimension, surface_dimension); - + // Jinv = J^{-1} Matrix Jinv(surface_dimension, surface_dimension); - + // dxi = \xi_{k+1} - \xi_{k} in the iterative process Matrix dxi(surface_dimension, 1); // gradient at natural projection Matrix gradient(surface_dimension, spatial_dimension); - + // second derivative at natural peojection Matrix double_gradient(surface_dimension, surface_dimension); - // second derivative of shape function at natural projection Matrix dn2ds2(surface_dimension * surface_dimension, - nb_nodes_per_element); + nb_nodes_per_element); - auto compute_double_gradient = [&double_gradient, &dn2ds2, - &nodes_coord, surface_dimension, - spatial_dimension](UInt & alpha, UInt & beta) { + auto compute_double_gradient = + [&double_gradient, &dn2ds2, &nodes_coord, surface_dimension, + spatial_dimension](UInt & alpha, UInt & beta) { + auto index = alpha * surface_dimension + beta; + Vector d_alpha_beta(spatial_dimension); - auto index = alpha * surface_dimension + beta; - Vector d_alpha_beta(spatial_dimension); + auto dn2ds2_transpose = dn2ds2.transpose(); + Vector dn2ds2_alpha_beta(dn2ds2_transpose(index)); - auto dn2ds2_transpose = dn2ds2.transpose(); - Vector dn2ds2_alpha_beta(dn2ds2_transpose(index)); + d_alpha_beta.mul(nodes_coord, dn2ds2_alpha_beta); - d_alpha_beta.mul(nodes_coord, dn2ds2_alpha_beta); + return d_alpha_beta; + }; - return d_alpha_beta; - }; - /* --------------------------- */ /* init before iteration loop */ /* --------------------------- */ // do interpolation auto update_f = [&f, &master_coords, &natural_projection, &nodes_coord, - &slave_coords, &gradient, surface_dimension, spatial_dimension, - nb_nodes_per_element, type]() { - + &slave_coords, &gradient, surface_dimension, + spatial_dimension, nb_nodes_per_element, type]() { // compute real coords on natural projection - Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ - ElementClass::computeShapes(natural_projection, shapes) + Vector shapes(nb_nodes_per_element); +#define GET_SHAPE_NATURAL(type) \ + ElementClass::computeShapes(natural_projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL master_coords.mul(nodes_coord, shapes); auto distance = slave_coords - master_coords; // first derivative of shape function at natural projection - Matrix dnds(surface_dimension, nb_nodes_per_element); - - // computing gradient at projection point -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ - ElementClass::computeDNDS(natural_projection, dnds) + Matrix dnds(surface_dimension, nb_nodes_per_element); + + // computing gradient at projection point +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ + ElementClass::computeDNDS(natural_projection, dnds) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL gradient.mul(dnds, nodes_coord); // gradient transpose at natural projection Matrix gradient_transpose(surface_dimension, spatial_dimension); gradient_transpose = gradient.transpose(); - + // loop over surface dimensions - for(auto alpha : arange(surface_dimension)) { + for (auto alpha : arange(surface_dimension)) { Vector gradient_alpha(gradient_transpose(alpha)); - f(alpha, 0) = -2.*gradient_alpha.dot(distance); + f(alpha, 0) = -2. * gradient_alpha.dot(distance); } - + // compute initial error auto error = f.norm(); return error; - }; - auto projection_error = update_f(); - + /* --------------------------- */ /* iteration loop */ /* --------------------------- */ UInt iterations{0}; - while(projection_tolerance < projection_error and iterations < max_iterations) { + while (projection_tolerance < projection_error and + iterations < max_iterations) { // compute covariant components of metric tensor auto a = GeometryUtils::covariantMetricTensor(gradient); // computing second derivative at natural projection -#define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type) \ - ElementClass::computeDN2DS2(natural_projection, dn2ds2) +#define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type) \ + ElementClass::computeDN2DS2(natural_projection, dn2ds2) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_SECOND_DERIVATIVES_NATURAL); #undef GET_SHAPE_SECOND_DERIVATIVES_NATURAL // real coord - physical guess auto distance = slave_coords - master_coords; - + // computing Jacobian J - for(auto alpha : arange(surface_dimension)) { - for(auto beta : arange(surface_dimension)) { - auto dgrad_alpha_beta = compute_double_gradient(alpha, beta); - J(alpha, beta) = 2.*(a(alpha, beta) - dgrad_alpha_beta.dot(distance)); + for (auto alpha : arange(surface_dimension)) { + for (auto beta : arange(surface_dimension)) { + auto dgrad_alpha_beta = compute_double_gradient(alpha, beta); + J(alpha, beta) = 2. * (a(alpha, beta) - dgrad_alpha_beta.dot(distance)); } } Jinv.inverse(J); - + // compute increment dxi.mul(Jinv, f, -1.0); // update our guess natural_projection += Vector(dxi(0)); projection_error = update_f(); iterations++; } - - - /* + + /* #define GET_NATURAL_COORDINATE(type) \ ElementClass::inverseMap(slave_coords, nodes_coord, \ - natural_projection, max_iterations, projection_tolerance) - AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NATURAL_COORDINATE); + natural_projection, max_iterations, +projection_tolerance) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NATURAL_COORDINATE); #undef GET_NATURAL_COORDINATE*/ } - /* -------------------------------------------------------------------------- */ void GeometryUtils::contravariantBasis(const Matrix & covariant, - Matrix & contravariant) { - + Matrix & contravariant) { + auto inv_A = GeometryUtils::contravariantMetricTensor(covariant); - contravariant.mul(inv_A, covariant); + contravariant.mul(inv_A, covariant); } - /* -------------------------------------------------------------------------- */ -Matrix GeometryUtils::covariantMetricTensor(const Matrix & covariant_bases) { - +Matrix +GeometryUtils::covariantMetricTensor(const Matrix & covariant_bases) { + Matrix A(covariant_bases.rows(), covariant_bases.rows()); A.mul(covariant_bases, covariant_bases); return A; } - /* -------------------------------------------------------------------------- */ -Matrix GeometryUtils::contravariantMetricTensor(const Matrix & covariant_bases) { +Matrix +GeometryUtils::contravariantMetricTensor(const Matrix & covariant_bases) { auto A = GeometryUtils::covariantMetricTensor(covariant_bases); auto inv_A = A.inverse(); return inv_A; } /* -------------------------------------------------------------------------- */ -Matrix GeometryUtils::covariantCurvatureTensor(const Mesh & mesh, - const Array & positions, - const Element & element, - const Vector & natural_coord, - const Vector & normal) { +Matrix GeometryUtils::covariantCurvatureTensor( + const Mesh & mesh, const Array & positions, const Element & element, + const Vector & natural_coord, const Vector & normal) { UInt spatial_dimension = mesh.getSpatialDimension(); auto surface_dimension = spatial_dimension - 1; const ElementType & type = element.type; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage(); - + Matrix dn2ds2(surface_dimension * surface_dimension, - nb_nodes_per_element); - -#define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type) \ + nb_nodes_per_element); + +#define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type) \ ElementClass::computeDN2DS2(natural_coord, dn2ds2) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_SECOND_DERIVATIVES_NATURAL); #undef GET_SHAPE_SECOND_DERIVATIVES_NATURAL Matrix coords(spatial_dimension, nb_nodes_per_element); mesh.extractNodalValuesFromElement(positions, coords.storage(), - elem_val + element.element * nb_nodes_per_element, - nb_nodes_per_element, spatial_dimension); + elem_val + + element.element * nb_nodes_per_element, + nb_nodes_per_element, spatial_dimension); - Matrix curvature(spatial_dimension, surface_dimension*surface_dimension); + Matrix curvature(spatial_dimension, + surface_dimension * surface_dimension); curvature.mul(coords, dn2ds2); Matrix H(surface_dimension, surface_dimension); UInt i = 0; for (auto alpha : arange(surface_dimension)) { for (auto beta : arange(surface_dimension)) { Vector temp(curvature(i)); H(alpha, beta) = temp.dot(normal); i++; } } return H; } -} +} // namespace akantu diff --git a/src/model/contact_mechanics/resolution_utils.cc b/src/model/contact_mechanics/resolution_utils.cc index 20c4cbc95..9c8670571 100644 --- a/src/model/contact_mechanics/resolution_utils.cc +++ b/src/model/contact_mechanics/resolution_utils.cc @@ -1,336 +1,330 @@ /** * @file resolution_utils.cc * * @author Mohit Pundir * * @date creation: Mon Mmay 20 2019 * @date last modification: Mon May 20 2019 * - * @brief Implementation of various utilities neede for resolution class + * @brief Implementation of various utilities neede for resolution class * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "resolution_utils.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ -void ResolutionUtils::computeShapeFunctionMatric(const ContactElement & element, - const Vector & projection, - Matrix & shape_matric) { - - shape_matric.clear(); +void ResolutionUtils::computeShapeFunctionMatric( + const ContactElement & element, const Vector & projection, + Matrix & shape_matric) { + + shape_matric.zero(); const ElementType & type = element.master.type; - + auto surface_dimension = Mesh::getSpatialDimension(type); auto spatial_dimension = surface_dimension + 1; UInt nb_nodes_per_contact = element.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); - AKANTU_DEBUG_ASSERT( - spatial_dimension == shape_matric.rows() - && spatial_dimension* nb_nodes_per_contact == shape_matric.cols(), - "Shape Matric dimensions are not correct"); + AKANTU_DEBUG_ASSERT(spatial_dimension == shape_matric.rows() && + spatial_dimension * nb_nodes_per_contact == + shape_matric.cols(), + "Shape Matric dimensions are not correct"); - Vector shapes(nb_nodes_per_element); + Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL for (auto i : arange(nb_nodes_per_contact)) { for (auto j : arange(spatial_dimension)) { if (i == 0) { - shape_matric(j, i*spatial_dimension + j) = 1; - continue; + shape_matric(j, i * spatial_dimension + j) = 1; + continue; } - shape_matric(j, i*spatial_dimension + j) = -shapes[i-1]; + shape_matric(j, i * spatial_dimension + j) = -shapes[i - 1]; } } - } /* -------------------------------------------------------------------------- */ /*void ResolutionUtils::firstVariationNormalGap(const ContactElement & element, - const Vector & projection, - const Vector & normal, - Vector & delta_g) { + const Vector & projection, + const Vector & normal, + Vector & delta_g) { delta_g.clear(); - + const auto & type = element.master.type; auto surface_dimension = Mesh::getSpatialDimension(type); auto spatial_dimension = surface_dimension + 1; - + Vector shapes(Mesh::getNbNodesPerElement(type)); - + #define GET_SHAPES_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPES_NATURAL); #undef GET_SHAPES_NATURAL for (UInt i : arange(spatial_dimension)) { delta_g[i] = normal[i]; for (UInt j : arange(shapes.size())) { delta_g[(1 + j) * spatial_dimension + i] = -shapes[j] * normal[i]; } } }*/ /* -------------------------------------------------------------------------- */ /*void ResolutionUtils::secondVariationNormalGap(const ContactElement & element, - const Matrix & covariant_basis, - const Matrix & curvature, - const Vector & projection, - const Vector & normal, Real & gap, - Matrix & ddelta_g) { + const Matrix & covariant_basis, + const Matrix & curvature, + const Vector & projection, + const Vector & normal, Real & gap, + Matrix & ddelta_g) { const auto & type = element.master.type; auto surface_dimension = Mesh::getSpatialDimension(type); auto spatial_dimension = surface_dimension + 1; UInt nb_nodes = element.getNbNodes(); - + Array dnds_n(nb_nodes * spatial_dimension, surface_dimension); ResolutionUtils::computeNalpha(element, projection, normal, dnds_n); - + Array delta_xi(nb_nodes * spatial_dimension, surface_dimension); ResolutionUtils::firstVariationNaturalCoordinate(element, covariant_basis, - projection, normal, gap, delta_xi); - + projection, normal, gap, delta_xi); + Matrix a_alpha_beta(surface_dimension, surface_dimension); ResolutionUtils::computeMetricTensor(a_alpha_beta, covariant_basis); a_alpha_beta = a_alpha_beta.inverse(); Matrix h_alpha_beta(surface_dimension, surface_dimension); ResolutionUtils::computeSecondMetricTensor(element, curvature, - normal, h_alpha_beta); + normal, h_alpha_beta); for (auto && values : zip(arange(surface_dimension), - make_view(dnds_n, dnds_n.size()), - make_view(delta_xi, delta_xi.size()))) { + make_view(dnds_n, dnds_n.size()), + make_view(delta_xi, delta_xi.size()))) { auto & alpha = std::get<0>(values); auto & dnds_n_alpha = std::get<1>(values); auto & delta_xi_alpha = std::get<2>(values); // term 1 from Numerical methods in contact mechanics : Vlad - // Yastrebov eq 2.48 + // Yastrebov eq 2.48 Matrix mat_n(dnds_n_alpha.storage(), dnds_n_alpha.size(), 1); Matrix mat_xi(delta_xi_alpha.storage(), delta_xi_alpha.size(), 1); Matrix tmp1(dnds_n_alpha.size(), dnds_n_alpha.size()); tmp1.mul(mat_n, mat_xi, -1); Matrix tmp2(dnds_n_alpha.size(), dnds_n_alpha.size()); tmp2.mul(mat_xi, mat_n, -1); Matrix term1(dnds_n_alpha.size(), dnds_n_alpha.size()); term1 = tmp1 + tmp2; // computing term 2 & term 3 from Numerical methods in contact // mechanics : Vlad Yastrebov eq 2.48 Matrix term2(delta_xi_alpha.size(), delta_xi_alpha.size()); Matrix term3(dnds_n_alpha.size(), dnds_n_alpha.size()); for (auto && values2 : zip(arange(surface_dimension), - make_view(dnds_n, dnds_n.size()), - make_view(delta_xi, delta_xi.size()))) { + make_view(dnds_n, dnds_n.size()), + make_view(delta_xi, delta_xi.size()))) { auto & beta = std::get<0>(values2); auto & dnds_n_beta = std::get<1>(values2); auto & delta_xi_beta = std::get<2>(values2); // term 2 Matrix mat_xi_beta(delta_xi_beta.storage(), delta_xi.size(), 1); Matrix tmp3(delta_xi_beta.size(), delta_xi_beta.size()); Real pre_factor = h_alpha_beta(alpha, beta); for (auto k : arange(surface_dimension)) { - for (auto m : arange(surface_dimension)) { - pre_factor -= gap * h_alpha_beta(alpha, k) * a_alpha_beta(k, m) * h_alpha_beta(m, beta); - } + for (auto m : arange(surface_dimension)) { + pre_factor -= gap * h_alpha_beta(alpha, k) * a_alpha_beta(k, m) * + h_alpha_beta(m, beta); + } } pre_factor *= -1.; tmp3.mul(mat_xi, mat_xi_beta, pre_factor); // term 3 Matrix mat_n_beta(dnds_n_beta.storage(), dnds_n_beta.size(), 1); Real factor = gap * a_alpha_beta(alpha, beta); Matrix tmp4(dnds_n_alpha.size(), dnds_n_alpha.size()); tmp4.mul(mat_n, mat_n_beta, factor); term3 += tmp4; } ddelta_g += term1 + term2 + term3; } }*/ - + /* -------------------------------------------------------------------------- */ /*void ResolutionUtils::computeTalpha(const ContactElement & element, - const Matrix & covariant_basis, - const Vector & projection, Array & t_alpha) { + const Matrix & covariant_basis, + const Vector & projection, Array & t_alpha) { t_alpha.clear(); const auto & type = element.master.type; auto surface_dimension = Mesh::getSpatialDimension(type); auto spatial_dimension = surface_dimension + 1; - + Vector shapes(Mesh::getNbNodesPerElement(type)); #define GET_SHAPES_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPES_NATURAL); #undef GET_SHAPES_NATURAL for (auto && values : - zip(covariant_basis.transpose(), - make_view(t_alpha, t_alpha.size()))) { + zip(covariant_basis.transpose(), + make_view(t_alpha, t_alpha.size()))) { auto & tangent_beta = std::get<0>(values); auto & t_beta = std::get<1>(values); - + for (UInt i : arange(spatial_dimension)) { t_beta[i] = tangent_beta(i); for (UInt j : arange(shapes.size())) { - t_beta[(1 + j) * spatial_dimension + i] = -shapes[j] * tangent_beta(i); + t_beta[(1 + j) * spatial_dimension + i] = -shapes[j] * tangent_beta(i); } } } }*/ /* -------------------------------------------------------------------------- */ -/*void ResolutionUtils::computeNalpha(const ContactElement & element, const Vector & projection, - const Vector & normal, Array & n_alpha) { +/*void ResolutionUtils::computeNalpha(const ContactElement & element, const +Vector & projection, const Vector & normal, Array & n_alpha) { n_alpha.clear(); const auto & type = element.master.type; auto surface_dimension = Mesh::getSpatialDimension(type); auto spatial_dimension = surface_dimension + 1; - + Matrix shape_derivatives(surface_dimension, - Mesh::getNbNodesPerElement(type)); + Mesh::getNbNodesPerElement(type)); #define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(projection, shape_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL - + for (auto && values : - zip(shape_derivatives.transpose(), - make_view(n_alpha, n_alpha.size()))) { + zip(shape_derivatives.transpose(), + make_view(n_alpha, n_alpha.size()))) { auto & dnds = std::get<0>(values); auto & n_s = std::get<1>(values); for (UInt i : arange(spatial_dimension)) { n_s[i] = 0; for (UInt j : arange(dnds.size())) { n_s[(1 + j) * spatial_dimension + i] = -dnds(j) * normal[i]; } } } }*/ /* -------------------------------------------------------------------------- */ -/*void ResolutionUtils::firstVariationNaturalCoordinate(const ContactElement & element, - const Matrix & covariant_basis, - const Vector & projection, - const Vector & normal, const Real & gap, - Array & delta_xi) { +/*void ResolutionUtils::firstVariationNaturalCoordinate(const ContactElement & +element, const Matrix & covariant_basis, const Vector & projection, + const Vector & normal, const Real & gap, + Array & delta_xi) { delta_xi.clear(); - + const auto & type = element.master.type; auto surface_dimension = Mesh::getSpatialDimension(type); auto spatial_dimension = surface_dimension + 1; - + auto inv_A = GeometryUtils::contravariantMetricTensor(covariant_basis); auto nb_nodes = element.getNbNodes(); - + Array t_alpha(nb_nodes * spatial_dimension, surface_dimension); Array n_alpha(nb_nodes * spatial_dimension, surface_dimension); ResolutionUtils::computeTalpha(element, covariant_basis, projection, t_alpha); ResolutionUtils::computeNalpha(element, projection, normal, n_alpha); - + for (auto && entry : - zip(arange(surface_dimension), - make_view(delta_xi, delta_xi.size()))) { + zip(arange(surface_dimension), + make_view(delta_xi, delta_xi.size()))) { auto & alpha = std::get<0>(entry); auto & d_alpha = std::get<1>(entry); for (auto && values : zip(arange(surface_dimension), - make_view(t_alpha, t_alpha.size()), + make_view(t_alpha, t_alpha.size()), make_view(n_alpha, n_alpha.size()))) { auto & beta = std::get<0>(values); auto & t_beta = std::get<1>(values); //auto & n_beta = std::get<2>(values); //d_alpha += (t_beta + gap * n_beta) * m_alpha_beta(alpha, //beta); d_alpha += t_beta * inv_A(alpha, beta); } } }*/ /* -------------------------------------------------------------------------- */ /*void ResolutionUtils::computeMetricTensor(Matrix & m_alpha_beta, - const Matrix & tangents) { + const Matrix & tangents) { m_alpha_beta.mul(tangents, tangents); }*/ - /* -------------------------------------------------------------------------- */ -/*void ResolutionUtils::computeSecondMetricTensor(const ContactElement & element, - const Matrix & curvature, - const Vector & normal, - Matrix & metric) { +/*void ResolutionUtils::computeSecondMetricTensor(const ContactElement & + element, const Matrix & curvature, const Vector & normal, + Matrix & metric) { const auto & type = element.master.type; auto surface_dimension = Mesh::getSpatialDimension(type); - + auto i = 0; for (auto alpha : arange(surface_dimension) ) { for (auto beta : arange(surface_dimension)) { Vector temp(curvature(i)); metric(alpha, beta) = normal.dot(temp); i++; } - } + } }*/ - - - -} //akantu +} // namespace akantu diff --git a/src/model/contact_mechanics/resolutions/resolution_penalty.cc b/src/model/contact_mechanics/resolutions/resolution_penalty.cc index 8da33879b..598aff62f 100644 --- a/src/model/contact_mechanics/resolutions/resolution_penalty.cc +++ b/src/model/contact_mechanics/resolutions/resolution_penalty.cc @@ -1,881 +1,903 @@ /** * @file resolution_penalty.cc * * @author Mohit Pundir * * @date creation: Mon Jan 7 2019 * @date last modification: Mon Jan 7 2019 * * @brief Specialization of the resolution class for the penalty method * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "resolution_penalty.hh" namespace akantu { /* -------------------------------------------------------------------------- */ ResolutionPenalty::ResolutionPenalty(ContactMechanicsModel & model, const ID & id) : Resolution(model, id) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::initialize() { this->registerParam("epsilon_n", epsilon_n, Real(0.), _pat_parsable | _pat_modifiable, "Normal penalty parameter"); this->registerParam("epsilon_t", epsilon_t, Real(0.), _pat_parsable | _pat_modifiable, "Tangential penalty parameter"); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ Real ResolutionPenalty::computeNormalTraction(Real & gap) { return epsilon_n * macaulay(gap); } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeNormalForce(const ContactElement & element, - Vector & force) { + Vector & force) { - force.clear(); + force.zero(); auto & gaps = model.getGaps(); auto & projections = model.getProjections(); auto & normals = model.getNormals(); auto surface_dimension = spatial_dimension - 1; - + Real gap(gaps.begin()[element.slave]); Vector normal(normals.begin(spatial_dimension)[element.slave]); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & nodal_area = const_cast &>(model.getNodalArea()); - + // compute normal traction Real p_n = computeNormalTraction(gap); p_n *= nodal_area[element.slave]; - + UInt nb_nodes_per_contact = element.getNbNodes(); Matrix shape_matric(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - ResolutionUtils::computeShapeFunctionMatric(element, projection, shape_matric); + spatial_dimension * nb_nodes_per_contact); + ResolutionUtils::computeShapeFunctionMatric(element, projection, + shape_matric); force.mul(shape_matric, normal, p_n); - } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeTangentialForce(const ContactElement & element, - Vector & force) { - + Vector & force) { + if (mu == 0) return; - force.clear(); - - UInt surface_dimension = spatial_dimension - 1; - + force.zero(); + + UInt surface_dimension = spatial_dimension - 1; + // compute covariant basis auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); - + auto & normals = model.getNormals(); Vector normal(normals.begin(spatial_dimension)[element.slave]); - + auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); - + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); + // check for no-contact to contact condition // need a better way to check if new node added is not presnt in the // previous master elemets auto & previous_master_elements = model.getPreviousMasterElements(); - if(element.slave >= previous_master_elements.size()) + if (element.slave >= previous_master_elements.size()) return; - + auto & previous_element = previous_master_elements[element.slave]; if (previous_element.type == _not_defined) return; - + // compute tangential traction using return map algorithm auto & tangential_tractions = model.getTangentialTractions(); - Vector tangential_traction(tangential_tractions.begin(surface_dimension)[element.slave]); + Vector tangential_traction( + tangential_tractions.begin(surface_dimension)[element.slave]); this->computeTangentialTraction(element, covariant_basis, - tangential_traction); + tangential_traction); UInt nb_nodes_per_contact = element.getNbNodes(); Matrix shape_matric(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + spatial_dimension * nb_nodes_per_contact); ResolutionUtils::computeShapeFunctionMatric(element, projection, - shape_matric); + shape_matric); auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); auto & nodal_area = const_cast &>(model.getNodalArea()); - - for (auto && values1 : enumerate(covariant_basis.transpose()) ) { + + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); auto & tangent_alpha = std::get<1>(values1); for (auto && values2 : enumerate(tangential_traction)) { auto & beta = std::get<0>(values2); auto & traction_beta = std::get<1>(values2); Vector tmp(force.size()); tmp.mul(shape_matric, tangent_alpha, traction_beta); - tmp *= contravariant_metric_tensor(alpha, beta) * nodal_area[element.slave]; + tmp *= + contravariant_metric_tensor(alpha, beta) * nodal_area[element.slave]; force += tmp; } } } /* -------------------------------------------------------------------------- */ -void ResolutionPenalty::computeTangentialTraction(const ContactElement & element, - const Matrix & covariant_basis, - Vector & traction_tangential) { +void ResolutionPenalty::computeTangentialTraction( + const ContactElement & element, const Matrix & covariant_basis, + Vector & traction_tangential) { UInt surface_dimension = spatial_dimension - 1; - + auto & gaps = model.getGaps(); auto & gap = gaps.begin()[element.slave]; // Return map algorithm is employed // compute trial traction Vector traction_trial(surface_dimension); - this->computeTrialTangentialTraction(element, covariant_basis, traction_trial); + this->computeTrialTangentialTraction(element, covariant_basis, + traction_trial); // compute norm of trial traction Real traction_trial_norm = 0; auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); for (auto i : arange(surface_dimension)) { for (auto j : arange(surface_dimension)) { - traction_trial_norm += traction_trial[i] * traction_trial[j] * contravariant_metric_tensor(i, j); + traction_trial_norm += traction_trial[i] * traction_trial[j] * + contravariant_metric_tensor(i, j); } } traction_trial_norm = sqrt(traction_trial_norm); // check stick or slip condition auto & contact_state = model.getContactState(); auto & state = contact_state.begin()[element.slave]; - + Real p_n = computeNormalTraction(gap); bool stick = (traction_trial_norm <= mu * p_n) ? true : false; if (stick) { state = ContactState::_stick; - computeStickTangentialTraction(element, traction_trial, traction_tangential); + computeStickTangentialTraction(element, traction_trial, + traction_tangential); } else { state = ContactState::_slip; computeSlipTangentialTraction(element, covariant_basis, traction_trial, - traction_tangential); + traction_tangential); } - } /* -------------------------------------------------------------------------- */ -void ResolutionPenalty::computeTrialTangentialTraction(const ContactElement & element, - const Matrix & covariant_basis, - Vector & traction) { - +void ResolutionPenalty::computeTrialTangentialTraction( + const ContactElement & element, const Matrix & covariant_basis, + Vector & traction) { + UInt surface_dimension = spatial_dimension - 1; - - auto & projections = model.getProjections(); - Vector current_projection(projections.begin(surface_dimension)[element.slave]); + + auto & projections = model.getProjections(); + Vector current_projection( + projections.begin(surface_dimension)[element.slave]); auto & previous_projections = model.getPreviousProjections(); - Vector previous_projection(previous_projections.begin(surface_dimension)[element.slave]); + Vector previous_projection( + previous_projections.begin(surface_dimension)[element.slave]); // method from Laursen et. al. - /*auto covariant_metric_tensor = GeometryUtils::covariantMetricTensor(covariant_basis); - auto increment_projection = current_projection - previous_projection; + /*auto covariant_metric_tensor = + GeometryUtils::covariantMetricTensor(covariant_basis); auto + increment_projection = current_projection - previous_projection; traction.mul(covariant_metric_tensor, increment_projection, epsilon_t); - + auto & previous_tangential_tractions = model.getPreviousTangentialTractions(); - Vector previous_traction(previous_tangential_tractions.begin(surface_dimension)[element.slave]); + Vector + previous_traction(previous_tangential_tractions.begin(surface_dimension)[element.slave]); traction = previous_traction + traction;*/ // method from Schweizerhof - auto covariant_metric_tensor = GeometryUtils::covariantMetricTensor(covariant_basis); + auto covariant_metric_tensor = + GeometryUtils::covariantMetricTensor(covariant_basis); auto & previous_tangential_tractions = model.getPreviousTangentialTractions(); - Vector previous_traction(previous_tangential_tractions.begin(surface_dimension)[element.slave]); + Vector previous_traction( + previous_tangential_tractions.begin(surface_dimension)[element.slave]); auto & previous_tangents = model.getPreviousTangents(); - Matrix previous_covariant_basis(previous_tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); + Matrix previous_covariant_basis(previous_tangents.begin( + surface_dimension, spatial_dimension)[element.slave]); auto previous_contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(previous_covariant_basis); + GeometryUtils::contravariantMetricTensor(previous_covariant_basis); auto current_tangent = covariant_basis.transpose(); auto previous_tangent = previous_covariant_basis.transpose(); - - for (auto alpha :arange(surface_dimension)) { + + for (auto alpha : arange(surface_dimension)) { Vector tangent_alpha(current_tangent(alpha)); for (auto gamma : arange(surface_dimension)) { for (auto beta : arange(surface_dimension)) { - Vector tangent_beta(previous_tangent(beta)); - auto t_alpha_t_beta = tangent_beta.dot(tangent_alpha); - traction[alpha] += previous_traction[gamma]*previous_contravariant_metric_tensor(gamma, beta)*t_alpha_t_beta; + Vector tangent_beta(previous_tangent(beta)); + auto t_alpha_t_beta = tangent_beta.dot(tangent_alpha); + traction[alpha] += previous_traction[gamma] * + previous_contravariant_metric_tensor(gamma, beta) * + t_alpha_t_beta; } } } - + auto & previous_master_elements = model.getPreviousMasterElements(); auto & previous_element = previous_master_elements[element.slave]; Vector previous_real_projection(spatial_dimension); - GeometryUtils::realProjection(model.getMesh(), model.getContactDetector().getPositions(), - previous_element, previous_projection, - previous_real_projection); - + GeometryUtils::realProjection( + model.getMesh(), model.getContactDetector().getPositions(), + previous_element, previous_projection, previous_real_projection); + Vector current_real_projection(spatial_dimension); - GeometryUtils::realProjection(model.getMesh(), model.getContactDetector().getPositions(), - element.master, current_projection, - current_real_projection); + GeometryUtils::realProjection( + model.getMesh(), model.getContactDetector().getPositions(), + element.master, current_projection, current_real_projection); auto increment_real = current_real_projection - previous_real_projection; Vector increment_xi(surface_dimension); auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); // increment in natural coordinate for (auto beta : arange(surface_dimension)) { - for (auto gamma: arange(surface_dimension)) { + for (auto gamma : arange(surface_dimension)) { auto temp = increment_real.dot(current_tangent(gamma)); temp *= contravariant_metric_tensor(beta, gamma); increment_xi[beta] += temp; } } Vector temp(surface_dimension); temp.mul(covariant_metric_tensor, increment_xi, epsilon_t); traction -= temp; } /* -------------------------------------------------------------------------- */ -void ResolutionPenalty::computeStickTangentialTraction(const ContactElement & /*element*/, - Vector & traction_trial, - Vector & traction_tangential) { +void ResolutionPenalty::computeStickTangentialTraction( + const ContactElement & /*element*/, Vector & traction_trial, + Vector & traction_tangential) { traction_tangential = traction_trial; } - + /* -------------------------------------------------------------------------- */ -void ResolutionPenalty::computeSlipTangentialTraction(const ContactElement & element, - const Matrix & covariant_basis, - Vector & traction_trial, - Vector & traction_tangential) { - UInt surface_dimension = spatial_dimension - 1; +void ResolutionPenalty::computeSlipTangentialTraction( + const ContactElement & element, const Matrix & covariant_basis, + Vector & traction_trial, Vector & traction_tangential) { + UInt surface_dimension = spatial_dimension - 1; auto & gaps = model.getGaps(); auto & gap = gaps.begin()[element.slave]; // compute norm of trial traction Real traction_trial_norm = 0; auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); for (auto alpha : arange(surface_dimension)) { for (auto beta : arange(surface_dimension)) { - traction_trial_norm += traction_trial[alpha] * traction_trial[beta] - * contravariant_metric_tensor(alpha, beta); + traction_trial_norm += traction_trial[alpha] * traction_trial[beta] * + contravariant_metric_tensor(alpha, beta); } } traction_trial_norm = sqrt(traction_trial_norm); - + auto slip_direction = traction_trial; slip_direction /= traction_trial_norm; Real p_n = computeNormalTraction(gap); traction_tangential = slip_direction; traction_tangential *= mu * p_n; } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeNormalModuli(const ContactElement & element, - Matrix & stiffness) { - + Matrix & stiffness) { + auto surface_dimension = spatial_dimension - 1; - auto & gaps = model.getGaps(); + auto & gaps = model.getGaps(); Real gap(gaps.begin()[element.slave]); auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & nodal_areas = model.getNodalArea(); auto & nodal_area = nodal_areas.begin()[element.slave]; - + auto & normals = model.getNormals(); Vector normal(normals.begin(spatial_dimension)[element.slave]); - + auto & mesh = model.getMesh(); // method from Schweizerhof and A. Konyukhov, K. Schweizerhof // DOI 10.1007/s00466-004-0616-7 and DOI 10.1007/s00466-003-0515-3 - + // construct A matrix const ElementType & type = element.master.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); - Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ + Vector shapes(nb_nodes_per_element); +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL UInt nb_nodes_per_contact = element.getNbNodes(); - Matrix A(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix A(spatial_dimension, spatial_dimension * nb_nodes_per_contact); for (auto i : arange(nb_nodes_per_contact)) { for (auto j : arange(spatial_dimension)) { if (i == 0) { - A(j, i*spatial_dimension + j) = 1; - continue; + A(j, i * spatial_dimension + j) = 1; + continue; } - A(j, i*spatial_dimension + j) = -shapes[i-1]; + A(j, i * spatial_dimension + j) = -shapes[i - 1]; } } // construct the main part of normal matrix - Matrix k_main(nb_nodes_per_contact*spatial_dimension, nb_nodes_per_contact*spatial_dimension); + Matrix k_main(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); Matrix n_outer_n(spatial_dimension, spatial_dimension); Matrix mat_n(normal.storage(), normal.size(), 1.); n_outer_n.mul(mat_n, mat_n); - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix tmp(spatial_dimension, spatial_dimension * nb_nodes_per_contact); tmp.mul(n_outer_n, A); k_main.mul(A, tmp); k_main *= epsilon_n * heaviside(gap) * nodal_area; - - // construct the rotational part of the normal matrix + + // construct the rotational part of the normal matrix auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); - //GeometryUtils::covariantBasis(model.getMesh(), model.getContactDetector().getPositions(), - // element.master, normal, projection, covariant_basis); + // GeometryUtils::covariantBasis(model.getMesh(), + // model.getContactDetector().getPositions(), element.master, + // normal, + // projection, covariant_basis); auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); - + GeometryUtils::contravariantMetricTensor(covariant_basis); + // computing shape derivatives Matrix shape_derivatives(surface_dimension, - Mesh::getNbNodesPerElement(type)); + Mesh::getNbNodesPerElement(type)); -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(projection, shape_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL - + // consists of 2 rotational parts - Matrix k_rot1(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_rot2(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix Aj(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + Matrix k_rot1(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_rot2(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix Aj(spatial_dimension, spatial_dimension * nb_nodes_per_contact); auto construct_Aj = [&](auto && dnds) { - - for (auto i : arange(nb_nodes_per_contact)) { - for (auto j : arange(spatial_dimension)) { - if (i == 0) { - Aj(j, i*spatial_dimension + j) = 0; - continue; + for (auto i : arange(nb_nodes_per_contact)) { + for (auto j : arange(spatial_dimension)) { + if (i == 0) { + Aj(j, i * spatial_dimension + j) = 0; + continue; + } + Aj(j, i * spatial_dimension + j) = dnds(i - 1); } - Aj(j, i*spatial_dimension + j) = dnds(i-1); } - } }; - + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); - auto & tangent = std::get<1>(values1); + auto & tangent = std::get<1>(values1); Matrix n_outer_t(spatial_dimension, spatial_dimension); Matrix mat_t(tangent.storage(), tangent.size(), 1.); n_outer_t.mul(mat_n, mat_t); - + Matrix t_outer_n(spatial_dimension, spatial_dimension); t_outer_n.mul(mat_t, mat_n); - + for (auto && values2 : enumerate(shape_derivatives.transpose())) { auto & beta = std::get<0>(values2); auto & dnds = std::get<1>(values2); // construct Aj from shape function wrt to jth natural // coordinate construct_Aj(dnds); - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); tmp.mul(n_outer_t, A); tmp1.mul(Aj, tmp); tmp1 *= contravariant_metric_tensor(alpha, beta); k_rot1 += tmp1; - + tmp.mul(t_outer_n, Aj); tmp1.mul(A, tmp); tmp1 *= contravariant_metric_tensor(alpha, beta); k_rot2 += tmp1; - } + } } k_rot1 *= -epsilon_n * heaviside(gap) * gap * nodal_area; k_rot2 *= -epsilon_n * heaviside(gap) * gap * nodal_area; stiffness += k_main + k_rot1 + k_rot2; -} - +} + /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeTangentialModuli(const ContactElement & element, - Matrix & stiffness){ + Matrix & stiffness) { if (mu == 0) return; - stiffness.clear(); - + stiffness.zero(); + auto & contact_state = model.getContactState(); UInt state = contact_state.begin()[element.slave]; switch (state) { case ContactState::_stick: { computeStickModuli(element, stiffness); break; } case ContactState::_slip: { computeSlipModuli(element, stiffness); break; } default: break; } } - /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeStickModuli(const ContactElement & element, - Matrix & stiffness) { + Matrix & stiffness) { auto surface_dimension = spatial_dimension - 1; auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & nodal_areas = model.getNodalArea(); auto & nodal_area = nodal_areas.begin()[element.slave]; - + auto & mesh = model.getMesh(); // method from Schweizerhof and A. Konyukhov, K. Schweizerhof // DOI 10.1007/s00466-004-0616-7 and DOI 10.1007/s00466-003-0515-3 - + // construct A matrix const ElementType & type = element.master.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); - Vector shapes(nb_nodes_per_element); + Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL UInt nb_nodes_per_contact = element.getNbNodes(); - Matrix A(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix A(spatial_dimension, spatial_dimension * nb_nodes_per_contact); for (auto i : arange(nb_nodes_per_contact)) { for (auto j : arange(spatial_dimension)) { if (i == 0) { - A(j, i*spatial_dimension + j) = 1; - continue; + A(j, i * spatial_dimension + j) = 1; + continue; } - A(j, i*spatial_dimension + j) = -shapes[i-1]; + A(j, i * spatial_dimension + j) = -shapes[i - 1]; } } // computing shape derivatives Matrix shape_derivatives(surface_dimension, - Mesh::getNbNodesPerElement(type)); + Mesh::getNbNodesPerElement(type)); -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(projection, shape_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL - - Matrix Aj(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix Aj(spatial_dimension, spatial_dimension * nb_nodes_per_contact); auto construct_Aj = [&](auto && dnds) { - - for (auto i : arange(nb_nodes_per_contact)) { - for (auto j : arange(spatial_dimension)) { - if (i == 0) { - Aj(j, i*spatial_dimension + j) = 0; - continue; + for (auto i : arange(nb_nodes_per_contact)) { + for (auto j : arange(spatial_dimension)) { + if (i == 0) { + Aj(j, i * spatial_dimension + j) = 0; + continue; + } + Aj(j, i * spatial_dimension + j) = dnds(i - 1); } - Aj(j, i*spatial_dimension + j) = dnds(i-1); } - } }; // tangents should have been calculated in normal modulii auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); - + GeometryUtils::contravariantMetricTensor(covariant_basis); + // construct 1st part of the stick modulii - Matrix k_main(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - + Matrix k_main(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); auto & tangent_alpha = std::get<1>(values1); Matrix t_outer_t(spatial_dimension, spatial_dimension); Matrix mat_t_alpha(tangent_alpha.storage(), tangent_alpha.size(), 1.); - + for (auto && values2 : enumerate(covariant_basis.transpose())) { auto & beta = std::get<0>(values2); auto & tangent_beta = std::get<1>(values2); Matrix mat_t_beta(tangent_beta.storage(), tangent_beta.size(), 1.); t_outer_t.mul(mat_t_alpha, mat_t_beta); - - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); tmp.mul(t_outer_t, A); tmp1.mul(A, tmp); tmp1 *= contravariant_metric_tensor(alpha, beta); k_main += tmp1; } } k_main *= -epsilon_t; - + // construct 2nd part of the stick modulii auto & tangential_tractions = model.getTangentialTractions(); - Vector tangential_traction(tangential_tractions.begin(surface_dimension)[element.slave]); - - Matrix k_second(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - + Vector tangential_traction( + tangential_tractions.begin(surface_dimension)[element.slave]); + + Matrix k_second(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto alpha : arange(surface_dimension)) { - - Matrix k_sum(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - + + Matrix k_sum(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto && values1 : enumerate(shape_derivatives.transpose())) { auto & beta = std::get<0>(values1); auto & dnds = std::get<1>(values1); // construct Aj from shape function wrt to jth natural // coordinate construct_Aj(dnds); for (auto && values2 : enumerate(covariant_basis.transpose())) { - auto & gamma = std::get<0>(values2); - auto & tangent_gamma = std::get<1>(values2); - - Matrix t_outer_t(spatial_dimension, spatial_dimension); - Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), 1.); - - for (auto && values3 : enumerate(covariant_basis.transpose())) { - auto & theta = std::get<0>(values3); - auto & tangent_theta = std::get<1>(values3); - - Matrix mat_t_theta(tangent_theta.storage(), tangent_theta.size(), 1.); - t_outer_t.mul(mat_t_gamma, mat_t_theta); - - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - tmp.mul(t_outer_t, Aj); - tmp1.mul(A, tmp); - tmp1 *= contravariant_metric_tensor(alpha, theta) * contravariant_metric_tensor(beta, gamma); - - Matrix tmp2(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp3(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - tmp2.mul(t_outer_t, A); - tmp3.mul(Aj, tmp2); - tmp3 *= contravariant_metric_tensor(alpha, gamma) * contravariant_metric_tensor(beta, theta); - - k_sum += tmp1 + tmp3; - } + auto & gamma = std::get<0>(values2); + auto & tangent_gamma = std::get<1>(values2); + + Matrix t_outer_t(spatial_dimension, spatial_dimension); + Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), + 1.); + + for (auto && values3 : enumerate(covariant_basis.transpose())) { + auto & theta = std::get<0>(values3); + auto & tangent_theta = std::get<1>(values3); + + Matrix mat_t_theta(tangent_theta.storage(), + tangent_theta.size(), 1.); + t_outer_t.mul(mat_t_gamma, mat_t_theta); + + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + tmp.mul(t_outer_t, Aj); + tmp1.mul(A, tmp); + tmp1 *= contravariant_metric_tensor(alpha, theta) * + contravariant_metric_tensor(beta, gamma); + + Matrix tmp2(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp3(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + tmp2.mul(t_outer_t, A); + tmp3.mul(Aj, tmp2); + tmp3 *= contravariant_metric_tensor(alpha, gamma) * + contravariant_metric_tensor(beta, theta); + + k_sum += tmp1 + tmp3; + } } } - k_second += tangential_traction[alpha] * k_sum; + k_second += tangential_traction[alpha] * k_sum; } - - stiffness += k_main*nodal_area - k_second*nodal_area; + stiffness += k_main * nodal_area - k_second * nodal_area; } /* -------------------------------------------------------------------------- */ void ResolutionPenalty::computeSlipModuli(const ContactElement & element, - Matrix & stiffness) { + Matrix & stiffness) { - auto surface_dimension = spatial_dimension - 1; - auto & gaps = model.getGaps(); + auto & gaps = model.getGaps(); Real gap(gaps.begin()[element.slave]); auto & nodal_areas = model.getNodalArea(); auto & nodal_area = nodal_areas.begin()[element.slave]; - + // compute normal traction Real p_n = computeNormalTraction(gap); auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & normals = model.getNormals(); Vector normal(normals.begin(spatial_dimension)[element.slave]); // restructure normal as a matrix for an outer product Matrix mat_n(normal.storage(), normal.size(), 1.); - + auto & mesh = model.getMesh(); // method from Schweizerhof and A. Konyukhov, K. Schweizerhof // DOI 10.1007/s00466-004-0616-7 and DOI 10.1007/s00466-003-0515-3 - + // construct A matrix const ElementType & type = element.master.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); - Vector shapes(nb_nodes_per_element); + Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL UInt nb_nodes_per_contact = element.getNbNodes(); - Matrix A(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix A(spatial_dimension, spatial_dimension * nb_nodes_per_contact); for (auto i : arange(nb_nodes_per_contact)) { for (auto j : arange(spatial_dimension)) { if (i == 0) { - A(j, i*spatial_dimension + j) = 1; - continue; + A(j, i * spatial_dimension + j) = 1; + continue; } - A(j, i*spatial_dimension + j) = -shapes[i-1]; + A(j, i * spatial_dimension + j) = -shapes[i - 1]; } } // computing shape derivatives Matrix shape_derivatives(surface_dimension, - Mesh::getNbNodesPerElement(type)); + Mesh::getNbNodesPerElement(type)); -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(projection, shape_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL - - Matrix Aj(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix Aj(spatial_dimension, spatial_dimension * nb_nodes_per_contact); auto construct_Aj = [&](auto && dnds) { - - for (auto i : arange(nb_nodes_per_contact)) { - for (auto j : arange(spatial_dimension)) { - if (i == 0) { - Aj(j, i*spatial_dimension + j) = 0; - continue; + for (auto i : arange(nb_nodes_per_contact)) { + for (auto j : arange(spatial_dimension)) { + if (i == 0) { + Aj(j, i * spatial_dimension + j) = 0; + continue; + } + Aj(j, i * spatial_dimension + j) = dnds(i - 1); } - Aj(j, i*spatial_dimension + j) = dnds(i-1); } - } }; // tangents should have been calculated in normal modulii auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); - + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); + auto & tangential_tractions = model.getTangentialTractions(); - Vector tangential_traction(tangential_tractions.begin(surface_dimension)[element.slave]); - + Vector tangential_traction( + tangential_tractions.begin(surface_dimension)[element.slave]); + // compute norm of trial traction Real traction_norm = 0; auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); for (auto i : arange(surface_dimension)) { for (auto j : arange(surface_dimension)) { - traction_norm += tangential_traction[i] * tangential_traction[j] * contravariant_metric_tensor(i, j); + traction_norm += tangential_traction[i] * tangential_traction[j] * + contravariant_metric_tensor(i, j); } } traction_norm = sqrt(traction_norm); // construct four parts of stick modulii (eq 107,107a-c) - Matrix k_first(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_second(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_third(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_fourth(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - - + Matrix k_first(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_second(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_third(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_fourth(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); auto & tangent_alpha = std::get<1>(values1); Matrix mat_t_alpha(tangent_alpha.storage(), tangent_alpha.size(), 1.); - + Matrix t_outer_n(spatial_dimension, spatial_dimension); Matrix t_outer_t(spatial_dimension, spatial_dimension); - - for (auto && values2 : zip(arange(surface_dimension), - covariant_basis.transpose(), - shape_derivatives.transpose())) { + + for (auto && values2 : + zip(arange(surface_dimension), covariant_basis.transpose(), + shape_derivatives.transpose())) { auto & beta = std::get<0>(values2); auto & tangent_beta = std::get<1>(values2); auto & dnds = std::get<2>(values2); - //construct Aj from shape function wrt to jth natural + // construct Aj from shape function wrt to jth natural // coordinate construct_Aj(dnds); // eq 107 Matrix mat_t_beta(tangent_beta.storage(), tangent_beta.size(), 1.); t_outer_n.mul(mat_t_beta, mat_n); - - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); tmp.mul(t_outer_n, A); tmp1.mul(A, tmp); - tmp1 *= epsilon_n * mu * tangential_traction[alpha] * contravariant_metric_tensor(alpha, beta); + tmp1 *= epsilon_n * mu * tangential_traction[alpha] * + contravariant_metric_tensor(alpha, beta); tmp1 /= traction_norm; k_first += tmp1 * nodal_area; // eq 107a t_outer_t.mul(mat_t_alpha, mat_t_beta); - + tmp.mul(t_outer_t, A); tmp1.mul(A, tmp); tmp1 *= epsilon_t * mu * p_n * contravariant_metric_tensor(alpha, beta); tmp1 /= traction_norm; k_second += tmp1 * nodal_area; - + for (auto && values3 : enumerate(covariant_basis.transpose())) { - auto & gamma = std::get<0>(values3); - auto & tangent_gamma = std::get<1>(values3); - - Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), 1.); - - for (auto && values4 : enumerate(covariant_basis.transpose())) { - auto & theta = std::get<0>(values4); - auto & tangent_theta = std::get<1>(values4); - - Matrix mat_t_theta(tangent_theta.storage(), tangent_theta.size(), 1.); - t_outer_t.mul(mat_t_gamma, mat_t_theta); - - // eq 107b - tmp.mul(t_outer_t, A); - tmp1.mul(A, tmp); - - tmp1 *= epsilon_t*mu*p_n*tangential_traction[alpha]*tangential_traction[beta]; - tmp1 *= contravariant_metric_tensor(alpha, gamma) * contravariant_metric_tensor(beta, theta); - tmp1 /= pow(traction_norm, 3); - - k_third += tmp1 * nodal_area; - - // eq 107c - tmp.mul(t_outer_t, Aj); - tmp1.mul(A, tmp); - tmp1 *= contravariant_metric_tensor(alpha, theta) * contravariant_metric_tensor(beta, gamma); - tmp1 *= mu * p_n * tangential_traction[alpha]; - tmp1 /= traction_norm; - - Matrix tmp2(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp3(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - tmp2.mul(t_outer_t, A); - tmp3.mul(Aj, tmp2); - tmp3 *= contravariant_metric_tensor(alpha, gamma) * contravariant_metric_tensor(beta, theta); - tmp3 *= mu * p_n * tangential_traction[alpha]; - tmp3 /= traction_norm; - - k_fourth += (tmp1 + tmp3) * nodal_area; - } - } + auto & gamma = std::get<0>(values3); + auto & tangent_gamma = std::get<1>(values3); + + Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), + 1.); + + for (auto && values4 : enumerate(covariant_basis.transpose())) { + auto & theta = std::get<0>(values4); + auto & tangent_theta = std::get<1>(values4); + + Matrix mat_t_theta(tangent_theta.storage(), + tangent_theta.size(), 1.); + t_outer_t.mul(mat_t_gamma, mat_t_theta); + + // eq 107b + tmp.mul(t_outer_t, A); + tmp1.mul(A, tmp); + + tmp1 *= epsilon_t * mu * p_n * tangential_traction[alpha] * + tangential_traction[beta]; + tmp1 *= contravariant_metric_tensor(alpha, gamma) * + contravariant_metric_tensor(beta, theta); + tmp1 /= pow(traction_norm, 3); + + k_third += tmp1 * nodal_area; + + // eq 107c + tmp.mul(t_outer_t, Aj); + tmp1.mul(A, tmp); + tmp1 *= contravariant_metric_tensor(alpha, theta) * + contravariant_metric_tensor(beta, gamma); + tmp1 *= mu * p_n * tangential_traction[alpha]; + tmp1 /= traction_norm; + + Matrix tmp2(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp3(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + tmp2.mul(t_outer_t, A); + tmp3.mul(Aj, tmp2); + tmp3 *= contravariant_metric_tensor(alpha, gamma) * + contravariant_metric_tensor(beta, theta); + tmp3 *= mu * p_n * tangential_traction[alpha]; + tmp3 /= traction_norm; + + k_fourth += (tmp1 + tmp3) * nodal_area; + } + } } } - + stiffness += k_third + k_fourth - k_first - k_second; } /* -------------------------------------------------------------------------- */ -void ResolutionPenalty::beforeSolveStep() { -} +void ResolutionPenalty::beforeSolveStep() {} /* -------------------------------------------------------------------------- */ void ResolutionPenalty::afterSolveStep(__attribute__((unused)) bool converged) { /*auto method = model.getAnalysisMethod(); if (method == _explicit_lumped_mass) { return ; } - + auto & K = const_cast(model.getDOFManager().getMatrix("K")); auto k_min = K.min(); auto roundoff_error = 1e-17; - const auto blocked_dofs = model.getDOFManager().getBlockedDOFs("displacement"); - Real nb_unknowns = 0; + const auto blocked_dofs = + model.getDOFManager().getBlockedDOFs("displacement"); Real nb_unknowns = 0; for (auto & bld : make_view(blocked_dofs)) { if (not bld) nb_unknowns++; } auto max_epsilon_n = k_min / sqrt(nb_unknowns * roundoff_error); if (epsilon_n > max_epsilon_n) epsilon_n = max_epsilon_n;*/ - } - + INSTANTIATE_RESOLUTION(penalty_linear, ResolutionPenalty); } // namespace akantu diff --git a/src/model/contact_mechanics/resolutions/resolution_penalty_quadratic.cc b/src/model/contact_mechanics/resolutions/resolution_penalty_quadratic.cc index 21cdb80e4..c914ff133 100644 --- a/src/model/contact_mechanics/resolutions/resolution_penalty_quadratic.cc +++ b/src/model/contact_mechanics/resolutions/resolution_penalty_quadratic.cc @@ -1,864 +1,886 @@ /** * @file resolution_penalty_quadratic.cc * * @author Mohit Pundir * * @date creation: Sun Aug 2 2020 * @date last modification: Sun Aug 2 2020 * - * @brief Specialization of the resolution class for the quadratic penalty method + * @brief Specialization of the resolution class for the quadratic penalty + * method * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "resolution_penalty_quadratic.hh" namespace akantu { /* -------------------------------------------------------------------------- */ -ResolutionPenaltyQuadratic::ResolutionPenaltyQuadratic(ContactMechanicsModel & model , - const ID & id) - : Parent(model, id) { +ResolutionPenaltyQuadratic::ResolutionPenaltyQuadratic( + ContactMechanicsModel & model, const ID & id) + : Parent(model, id) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ResolutionPenaltyQuadratic::initialize() {} /* -------------------------------------------------------------------------- */ Real ResolutionPenaltyQuadratic::computeNormalTraction(Real & gap) { - return epsilon_n *( macaulay(gap) * macaulay(gap) + macaulay(gap)); + return epsilon_n * (macaulay(gap) * macaulay(gap) + macaulay(gap)); } - + /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeNormalForce(const ContactElement & element, - Vector & force) { - force.clear(); - +void ResolutionPenaltyQuadratic::computeNormalForce( + const ContactElement & element, Vector & force) { + force.zero(); + auto & gaps = model.getGaps(); auto & projections = model.getProjections(); auto & normals = model.getNormals(); auto surface_dimension = spatial_dimension - 1; - + Real gap(gaps.begin()[element.slave]); Vector normal(normals.begin(spatial_dimension)[element.slave]); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & nodal_area = const_cast &>(model.getNodalArea()); - + // compute normal traction Real p_n = computeNormalTraction(gap); p_n *= nodal_area[element.slave]; - + UInt nb_nodes_per_contact = element.getNbNodes(); Matrix shape_matric(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - ResolutionUtils::computeShapeFunctionMatric(element, projection, shape_matric); + spatial_dimension * nb_nodes_per_contact); + ResolutionUtils::computeShapeFunctionMatric(element, projection, + shape_matric); force.mul(shape_matric, normal, p_n); - } - + /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeTangentialForce(const ContactElement & element, - Vector & force) { - +void ResolutionPenaltyQuadratic::computeTangentialForce( + const ContactElement & element, Vector & force) { + if (mu == 0) return; - force.clear(); - - UInt surface_dimension = spatial_dimension - 1; - + force.zero(); + + UInt surface_dimension = spatial_dimension - 1; + // compute tangents auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); - + auto & normals = model.getNormals(); Vector normal(normals.begin(spatial_dimension)[element.slave]); - + auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); // check for no-contact to contact condition // need a better way to check if new node added is not presnt in the // previous master elemets auto & previous_master_elements = model.getPreviousMasterElements(); - if(element.slave >= previous_master_elements.size()) + if (element.slave >= previous_master_elements.size()) return; - + auto & previous_element = previous_master_elements[element.slave]; if (previous_element.type == _not_defined) return; - + // compute tangential traction using return map algorithm auto & tangential_tractions = model.getTangentialTractions(); - Vector tangential_traction(tangential_tractions.begin(surface_dimension)[element.slave]); + Vector tangential_traction( + tangential_tractions.begin(surface_dimension)[element.slave]); this->computeTangentialTraction(element, covariant_basis, - tangential_traction); + tangential_traction); UInt nb_nodes_per_contact = element.getNbNodes(); Matrix shape_matric(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + spatial_dimension * nb_nodes_per_contact); ResolutionUtils::computeShapeFunctionMatric(element, projection, - shape_matric); + shape_matric); auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); auto & nodal_area = const_cast &>(model.getNodalArea()); - - for (auto && values1 : enumerate(covariant_basis.transpose()) ) { + + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); auto & tangent_alpha = std::get<1>(values1); for (auto && values2 : enumerate(tangential_traction)) { auto & beta = std::get<0>(values2); auto & traction_beta = std::get<1>(values2); Vector tmp(force.size()); tmp.mul(shape_matric, tangent_alpha, traction_beta); - tmp *= contravariant_metric_tensor(alpha, beta) * nodal_area[element.slave]; + tmp *= + contravariant_metric_tensor(alpha, beta) * nodal_area[element.slave]; force += tmp; } } - - // compute first variation of natural coordinate + // compute first variation of natural coordinate /*auto & gaps = model.getGaps(); auto & gap = gaps.begin()[element.slave]; auto nb_nodes = element.getNbNodes(); Array delta_xi(nb_nodes * spatial_dimension, surface_dimension); ResolutionUtils::firstVariationNaturalCoordinate(element, covariant_basis, - projection, normal, gap, delta_xi); + projection, normal, gap, delta_xi); // compute tangential force auto & nodal_area = const_cast &>(model.getNodalArea()); for (auto && values : zip(tangential_traction, - make_view(delta_xi, delta_xi.size()))) { + make_view(delta_xi, delta_xi.size()))) { auto & traction_alpha = std::get<0>(values); auto & delta_xi_alpha = std::get<1>(values); force += delta_xi_alpha * traction_alpha * nodal_area[element.slave]; }*/ } - /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeTangentialTraction(const ContactElement & element, - const Matrix & covariant_basis, - Vector & traction_tangential) { +void ResolutionPenaltyQuadratic::computeTangentialTraction( + const ContactElement & element, const Matrix & covariant_basis, + Vector & traction_tangential) { UInt surface_dimension = spatial_dimension - 1; - + auto & gaps = model.getGaps(); auto & gap = gaps.begin()[element.slave]; // Return map algorithm is employed // compute trial traction Vector traction_trial(surface_dimension); - this->computeTrialTangentialTraction(element, covariant_basis, traction_trial); + this->computeTrialTangentialTraction(element, covariant_basis, + traction_trial); // compute norm of trial traction Real traction_trial_norm = 0; auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); for (auto i : arange(surface_dimension)) { for (auto j : arange(surface_dimension)) { - traction_trial_norm += traction_trial[i] * traction_trial[j] * contravariant_metric_tensor(i, j); + traction_trial_norm += traction_trial[i] * traction_trial[j] * + contravariant_metric_tensor(i, j); } } traction_trial_norm = sqrt(traction_trial_norm); // check stick or slip condition auto & contact_state = model.getContactState(); auto & state = contact_state.begin()[element.slave]; - + Real p_n = computeNormalTraction(gap); bool stick = (traction_trial_norm <= mu * p_n) ? true : false; if (stick) { state = ContactState::_stick; - computeStickTangentialTraction(element, traction_trial, traction_tangential); + computeStickTangentialTraction(element, traction_trial, + traction_tangential); } else { state = ContactState::_slip; computeSlipTangentialTraction(element, covariant_basis, traction_trial, - traction_tangential); + traction_tangential); } - } /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeTrialTangentialTraction(const ContactElement & element, - const Matrix & covariant_basis, - Vector & traction) { - +void ResolutionPenaltyQuadratic::computeTrialTangentialTraction( + const ContactElement & element, const Matrix & covariant_basis, + Vector & traction) { + UInt surface_dimension = spatial_dimension - 1; - - auto & projections = model.getProjections(); - Vector current_projection(projections.begin(surface_dimension)[element.slave]); + + auto & projections = model.getProjections(); + Vector current_projection( + projections.begin(surface_dimension)[element.slave]); auto & previous_projections = model.getPreviousProjections(); - Vector previous_projection(previous_projections.begin(surface_dimension)[element.slave]); + Vector previous_projection( + previous_projections.begin(surface_dimension)[element.slave]); // method from Laursen et. al. - /*auto covariant_metric_tensor = GeometryUtils::covariantMetricTensor(covariant_basis); - auto increment_projection = current_projection - previous_projection; + /*auto covariant_metric_tensor = + GeometryUtils::covariantMetricTensor(covariant_basis); auto + increment_projection = current_projection - previous_projection; traction.mul(covariant_metric_tensor, increment_projection, epsilon_t); - + auto & previous_tangential_tractions = model.getPreviousTangentialTractions(); - Vector previous_traction(previous_tangential_tractions.begin(surface_dimension)[element.slave]); + Vector + previous_traction(previous_tangential_tractions.begin(surface_dimension)[element.slave]); traction = previous_traction + traction;*/ // method from Schweizerhof - auto covariant_metric_tensor = GeometryUtils::covariantMetricTensor(covariant_basis); + auto covariant_metric_tensor = + GeometryUtils::covariantMetricTensor(covariant_basis); auto & previous_tangential_tractions = model.getPreviousTangentialTractions(); - Vector previous_traction(previous_tangential_tractions.begin(surface_dimension)[element.slave]); + Vector previous_traction( + previous_tangential_tractions.begin(surface_dimension)[element.slave]); auto & previous_tangents = model.getPreviousTangents(); - Matrix previous_covariant_basis(previous_tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); + Matrix previous_covariant_basis(previous_tangents.begin( + surface_dimension, spatial_dimension)[element.slave]); auto previous_contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(previous_covariant_basis); + GeometryUtils::contravariantMetricTensor(previous_covariant_basis); auto current_tangent = covariant_basis.transpose(); auto previous_tangent = previous_covariant_basis.transpose(); - - for (auto alpha :arange(surface_dimension)) { + + for (auto alpha : arange(surface_dimension)) { Vector tangent_alpha(current_tangent(alpha)); for (auto gamma : arange(surface_dimension)) { for (auto beta : arange(surface_dimension)) { - Vector tangent_beta(previous_tangent(beta)); - auto t_alpha_t_beta = tangent_beta.dot(tangent_alpha); - traction[alpha] += previous_traction[gamma]*previous_contravariant_metric_tensor(gamma, beta)*t_alpha_t_beta; + Vector tangent_beta(previous_tangent(beta)); + auto t_alpha_t_beta = tangent_beta.dot(tangent_alpha); + traction[alpha] += previous_traction[gamma] * + previous_contravariant_metric_tensor(gamma, beta) * + t_alpha_t_beta; } } } - + auto & previous_master_elements = model.getPreviousMasterElements(); auto & previous_element = previous_master_elements[element.slave]; Vector previous_real_projection(spatial_dimension); - GeometryUtils::realProjection(model.getMesh(), model.getContactDetector().getPositions(), - previous_element, previous_projection, - previous_real_projection); - + GeometryUtils::realProjection( + model.getMesh(), model.getContactDetector().getPositions(), + previous_element, previous_projection, previous_real_projection); + Vector current_real_projection(spatial_dimension); - GeometryUtils::realProjection(model.getMesh(), model.getContactDetector().getPositions(), - element.master, current_projection, - current_real_projection); + GeometryUtils::realProjection( + model.getMesh(), model.getContactDetector().getPositions(), + element.master, current_projection, current_real_projection); auto increment_real = current_real_projection - previous_real_projection; Vector increment_xi(surface_dimension); - auto contravariant_metric_tensor = GeometryUtils::contravariantMetricTensor(covariant_basis); + auto contravariant_metric_tensor = + GeometryUtils::contravariantMetricTensor(covariant_basis); // increment in natural coordinate for (auto beta : arange(surface_dimension)) { - for (auto gamma: arange(surface_dimension)) { + for (auto gamma : arange(surface_dimension)) { auto temp = increment_real.dot(current_tangent(gamma)); temp *= contravariant_metric_tensor(beta, gamma); increment_xi[beta] += temp; } } Vector temp(surface_dimension); temp.mul(covariant_metric_tensor, increment_xi, epsilon_t); traction -= temp; } /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeStickTangentialTraction(const ContactElement & /*element*/, - Vector & traction_trial, - Vector & traction_tangential) { +void ResolutionPenaltyQuadratic::computeStickTangentialTraction( + const ContactElement & /*element*/, Vector & traction_trial, + Vector & traction_tangential) { traction_tangential = traction_trial; } - + /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeSlipTangentialTraction(const ContactElement & element, - const Matrix & covariant_basis, - Vector & traction_trial, - Vector & traction_tangential) { - UInt surface_dimension = spatial_dimension - 1; +void ResolutionPenaltyQuadratic::computeSlipTangentialTraction( + const ContactElement & element, const Matrix & covariant_basis, + Vector & traction_trial, Vector & traction_tangential) { + UInt surface_dimension = spatial_dimension - 1; auto & gaps = model.getGaps(); auto & gap = gaps.begin()[element.slave]; // compute norm of trial traction Real traction_trial_norm = 0; - auto contravariant_metric_tensor = GeometryUtils::contravariantMetricTensor(covariant_basis); + auto contravariant_metric_tensor = + GeometryUtils::contravariantMetricTensor(covariant_basis); for (auto i : arange(surface_dimension)) { for (auto j : arange(surface_dimension)) { - traction_trial_norm += traction_trial[i] * traction_trial[j] * contravariant_metric_tensor(i, j); + traction_trial_norm += traction_trial[i] * traction_trial[j] * + contravariant_metric_tensor(i, j); } } traction_trial_norm = sqrt(traction_trial_norm); - + auto slip_direction = traction_trial; slip_direction /= traction_trial_norm; Real p_n = computeNormalTraction(gap); traction_tangential = slip_direction; traction_tangential *= mu * p_n; } /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeNormalModuli(const ContactElement & element, - Matrix & stiffness) { - +void ResolutionPenaltyQuadratic::computeNormalModuli( + const ContactElement & element, Matrix & stiffness) { + auto surface_dimension = spatial_dimension - 1; - auto & gaps = model.getGaps(); + auto & gaps = model.getGaps(); Real gap(gaps.begin()[element.slave]); auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & nodal_areas = model.getNodalArea(); auto & nodal_area = nodal_areas.begin()[element.slave]; - + auto & normals = model.getNormals(); Vector normal(normals.begin(spatial_dimension)[element.slave]); - + auto & mesh = model.getMesh(); // method from Schweizerhof and A. Konyukhov, K. Schweizerhof // DOI 10.1007/s00466-004-0616-7 and DOI 10.1007/s00466-003-0515-3 - + // construct A matrix const ElementType & type = element.master.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); - Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ + Vector shapes(nb_nodes_per_element); +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL UInt nb_nodes_per_contact = element.getNbNodes(); - Matrix A(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix A(spatial_dimension, spatial_dimension * nb_nodes_per_contact); for (auto i : arange(nb_nodes_per_contact)) { for (auto j : arange(spatial_dimension)) { if (i == 0) { - A(j, i*spatial_dimension + j) = 1; - continue; + A(j, i * spatial_dimension + j) = 1; + continue; } - A(j, i*spatial_dimension + j) = -shapes[i-1]; + A(j, i * spatial_dimension + j) = -shapes[i - 1]; } } // construct the main part of normal matrix - Matrix k_main(nb_nodes_per_contact*spatial_dimension, nb_nodes_per_contact*spatial_dimension); + Matrix k_main(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); Matrix n_outer_n(spatial_dimension, spatial_dimension); Matrix mat_n(normal.storage(), normal.size(), 1.); n_outer_n.mul(mat_n, mat_n); - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix tmp(spatial_dimension, spatial_dimension * nb_nodes_per_contact); tmp.mul(n_outer_n, A); k_main.mul(A, tmp); - k_main *= epsilon_n * heaviside(gap) * (2*gap + 1) * nodal_area; - - // construct the rotational part of the normal matrix + k_main *= epsilon_n * heaviside(gap) * (2 * gap + 1) * nodal_area; + + // construct the rotational part of the normal matrix auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); - + GeometryUtils::contravariantMetricTensor(covariant_basis); + // computing shape derivatives Matrix shape_derivatives(surface_dimension, - Mesh::getNbNodesPerElement(type)); + Mesh::getNbNodesPerElement(type)); -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(projection, shape_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL - + // consists of 2 rotational parts - Matrix k_rot1(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_rot2(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix Aj(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + Matrix k_rot1(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_rot2(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix Aj(spatial_dimension, spatial_dimension * nb_nodes_per_contact); auto construct_Aj = [&](auto && dnds) { - - for (auto i : arange(nb_nodes_per_contact)) { - for (auto j : arange(spatial_dimension)) { - if (i == 0) { - Aj(j, i*spatial_dimension + j) = 0; - continue; + for (auto i : arange(nb_nodes_per_contact)) { + for (auto j : arange(spatial_dimension)) { + if (i == 0) { + Aj(j, i * spatial_dimension + j) = 0; + continue; + } + Aj(j, i * spatial_dimension + j) = dnds(i - 1); } - Aj(j, i*spatial_dimension + j) = dnds(i-1); } - } }; - + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); - auto & tangent = std::get<1>(values1); + auto & tangent = std::get<1>(values1); Matrix n_outer_t(spatial_dimension, spatial_dimension); Matrix mat_t(tangent.storage(), tangent.size(), 1.); n_outer_t.mul(mat_n, mat_t); - + Matrix t_outer_n(spatial_dimension, spatial_dimension); t_outer_n.mul(mat_t, mat_n); - + for (auto && values2 : enumerate(shape_derivatives.transpose())) { auto & beta = std::get<0>(values2); auto & dnds = std::get<1>(values2); // construct Aj from shape function wrt to jth natural // coordinate construct_Aj(dnds); - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); tmp.mul(n_outer_t, A); tmp1.mul(Aj, tmp); tmp1 *= contravariant_metric_tensor(alpha, beta); k_rot1 += tmp1; - + tmp.mul(t_outer_n, Aj); tmp1.mul(A, tmp); tmp1 *= contravariant_metric_tensor(alpha, beta); k_rot2 += tmp1; - } + } } - k_rot1 *= -epsilon_n * heaviside(gap) * ( gap*gap + gap) * nodal_area; - k_rot2 *= -epsilon_n * heaviside(gap) * ( gap*gap + gap) * nodal_area; + k_rot1 *= -epsilon_n * heaviside(gap) * (gap * gap + gap) * nodal_area; + k_rot2 *= -epsilon_n * heaviside(gap) * (gap * gap + gap) * nodal_area; stiffness += k_main + k_rot1 + k_rot2; -} - +} + /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeTangentialModuli(const ContactElement & element, - Matrix & stiffness){ +void ResolutionPenaltyQuadratic::computeTangentialModuli( + const ContactElement & element, Matrix & stiffness) { if (mu == 0) return; - stiffness.clear(); - + stiffness.zero(); + auto & contact_state = model.getContactState(); UInt state = contact_state.begin()[element.slave]; switch (state) { case ContactState::_stick: { computeStickModuli(element, stiffness); break; } case ContactState::_slip: { computeSlipModuli(element, stiffness); break; } default: break; } } - /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeStickModuli(const ContactElement & element, - Matrix & stiffness) { +void ResolutionPenaltyQuadratic::computeStickModuli( + const ContactElement & element, Matrix & stiffness) { auto surface_dimension = spatial_dimension - 1; auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & nodal_areas = model.getNodalArea(); auto & nodal_area = nodal_areas.begin()[element.slave]; - + auto & mesh = model.getMesh(); // method from Schweizerhof and A. Konyukhov, K. Schweizerhof // DOI 10.1007/s00466-004-0616-7 and DOI 10.1007/s00466-003-0515-3 - + // construct A matrix const ElementType & type = element.master.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); - Vector shapes(nb_nodes_per_element); + Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL UInt nb_nodes_per_contact = element.getNbNodes(); - Matrix A(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix A(spatial_dimension, spatial_dimension * nb_nodes_per_contact); for (auto i : arange(nb_nodes_per_contact)) { for (auto j : arange(spatial_dimension)) { if (i == 0) { - A(j, i*spatial_dimension + j) = 1; - continue; + A(j, i * spatial_dimension + j) = 1; + continue; } - A(j, i*spatial_dimension + j) = -shapes[i-1]; + A(j, i * spatial_dimension + j) = -shapes[i - 1]; } } // computing shape derivatives Matrix shape_derivatives(surface_dimension, - Mesh::getNbNodesPerElement(type)); + Mesh::getNbNodesPerElement(type)); -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(projection, shape_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL - - Matrix Aj(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix Aj(spatial_dimension, spatial_dimension * nb_nodes_per_contact); auto construct_Aj = [&](auto && dnds) { - - for (auto i : arange(nb_nodes_per_contact)) { - for (auto j : arange(spatial_dimension)) { - if (i == 0) { - Aj(j, i*spatial_dimension + j) = 0; - continue; + for (auto i : arange(nb_nodes_per_contact)) { + for (auto j : arange(spatial_dimension)) { + if (i == 0) { + Aj(j, i * spatial_dimension + j) = 0; + continue; + } + Aj(j, i * spatial_dimension + j) = dnds(i - 1); } - Aj(j, i*spatial_dimension + j) = dnds(i-1); } - } }; // tangents should have been calculated in normal modulii auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); - + GeometryUtils::contravariantMetricTensor(covariant_basis); + // construct 1st part of the stick modulii - Matrix k_main(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - + Matrix k_main(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); auto & tangent_alpha = std::get<1>(values1); Matrix t_outer_t(spatial_dimension, spatial_dimension); Matrix mat_t_alpha(tangent_alpha.storage(), tangent_alpha.size(), 1.); - + for (auto && values2 : enumerate(covariant_basis.transpose())) { auto & beta = std::get<0>(values2); auto & tangent_beta = std::get<1>(values2); Matrix mat_t_beta(tangent_beta.storage(), tangent_beta.size(), 1.); t_outer_t.mul(mat_t_alpha, mat_t_beta); - - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); tmp.mul(t_outer_t, A); tmp1.mul(A, tmp); tmp1 *= contravariant_metric_tensor(alpha, beta); k_main += tmp1; } } k_main *= -epsilon_t; - + // construct 2nd part of the stick modulii auto & tangential_tractions = model.getTangentialTractions(); - Vector tangential_traction(tangential_tractions.begin(surface_dimension)[element.slave]); - - Matrix k_second(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - + Vector tangential_traction( + tangential_tractions.begin(surface_dimension)[element.slave]); + + Matrix k_second(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto alpha : arange(surface_dimension)) { - - Matrix k_sum(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - + + Matrix k_sum(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto && values1 : enumerate(shape_derivatives.transpose())) { auto & beta = std::get<0>(values1); auto & dnds = std::get<1>(values1); // construct Aj from shape function wrt to jth natural // coordinate construct_Aj(dnds); for (auto && values2 : enumerate(covariant_basis.transpose())) { - auto & gamma = std::get<0>(values2); - auto & tangent_gamma = std::get<1>(values2); - - Matrix t_outer_t(spatial_dimension, spatial_dimension); - Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), 1.); - - for (auto && values3 : enumerate(covariant_basis.transpose())) { - auto & theta = std::get<0>(values3); - auto & tangent_theta = std::get<1>(values3); - - Matrix mat_t_theta(tangent_theta.storage(), tangent_theta.size(), 1.); - t_outer_t.mul(mat_t_gamma, mat_t_theta); - - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - tmp.mul(t_outer_t, Aj); - tmp1.mul(A, tmp); - tmp1 *= contravariant_metric_tensor(alpha, theta) * contravariant_metric_tensor(beta, gamma); - - Matrix tmp2(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp3(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - tmp2.mul(t_outer_t, A); - tmp3.mul(Aj, tmp2); - tmp3 *= contravariant_metric_tensor(alpha, gamma) * contravariant_metric_tensor(beta, theta); - - k_sum += tmp1 + tmp3; - } + auto & gamma = std::get<0>(values2); + auto & tangent_gamma = std::get<1>(values2); + + Matrix t_outer_t(spatial_dimension, spatial_dimension); + Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), + 1.); + + for (auto && values3 : enumerate(covariant_basis.transpose())) { + auto & theta = std::get<0>(values3); + auto & tangent_theta = std::get<1>(values3); + + Matrix mat_t_theta(tangent_theta.storage(), + tangent_theta.size(), 1.); + t_outer_t.mul(mat_t_gamma, mat_t_theta); + + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + tmp.mul(t_outer_t, Aj); + tmp1.mul(A, tmp); + tmp1 *= contravariant_metric_tensor(alpha, theta) * + contravariant_metric_tensor(beta, gamma); + + Matrix tmp2(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp3(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + tmp2.mul(t_outer_t, A); + tmp3.mul(Aj, tmp2); + tmp3 *= contravariant_metric_tensor(alpha, gamma) * + contravariant_metric_tensor(beta, theta); + + k_sum += tmp1 + tmp3; + } } } - k_second += tangential_traction[alpha] * k_sum; + k_second += tangential_traction[alpha] * k_sum; } - - stiffness += k_main*nodal_area - k_second*nodal_area; + stiffness += k_main * nodal_area - k_second * nodal_area; } /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::computeSlipModuli(const ContactElement & element, - Matrix & stiffness) { +void ResolutionPenaltyQuadratic::computeSlipModuli( + const ContactElement & element, Matrix & stiffness) { - auto surface_dimension = spatial_dimension - 1; - auto & gaps = model.getGaps(); + auto & gaps = model.getGaps(); Real gap(gaps.begin()[element.slave]); auto & nodal_areas = model.getNodalArea(); auto & nodal_area = nodal_areas.begin()[element.slave]; - + // compute normal traction Real p_n = computeNormalTraction(gap); auto & projections = model.getProjections(); Vector projection(projections.begin(surface_dimension)[element.slave]); auto & normals = model.getNormals(); Vector normal(normals.begin(spatial_dimension)[element.slave]); // restructure normal as a matrix for an outer product Matrix mat_n(normal.storage(), normal.size(), 1.); - + auto & mesh = model.getMesh(); // method from Schweizerhof and A. Konyukhov, K. Schweizerhof // DOI 10.1007/s00466-004-0616-7 and DOI 10.1007/s00466-003-0515-3 - + // construct A matrix const ElementType & type = element.master.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); - Vector shapes(nb_nodes_per_element); + Vector shapes(nb_nodes_per_element); -#define GET_SHAPE_NATURAL(type) \ +#define GET_SHAPE_NATURAL(type) \ ElementClass::computeShapes(projection, shapes) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL); #undef GET_SHAPE_NATURAL UInt nb_nodes_per_contact = element.getNbNodes(); - Matrix A(spatial_dimension, spatial_dimension*nb_nodes_per_contact); + Matrix A(spatial_dimension, spatial_dimension * nb_nodes_per_contact); for (auto i : arange(nb_nodes_per_contact)) { for (auto j : arange(spatial_dimension)) { if (i == 0) { - A(j, i*spatial_dimension + j) = 1; - continue; + A(j, i * spatial_dimension + j) = 1; + continue; } - A(j, i*spatial_dimension + j) = -shapes[i-1]; + A(j, i * spatial_dimension + j) = -shapes[i - 1]; } } // computing shape derivatives Matrix shape_derivatives(surface_dimension, - Mesh::getNbNodesPerElement(type)); + Mesh::getNbNodesPerElement(type)); -#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ +#define GET_SHAPE_DERIVATIVES_NATURAL(type) \ ElementClass::computeDNDS(projection, shape_derivatives) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL); #undef GET_SHAPE_DERIVATIVES_NATURAL - - Matrix Aj(spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix Aj(spatial_dimension, spatial_dimension * nb_nodes_per_contact); auto construct_Aj = [&](auto && dnds) { - - for (auto i : arange(nb_nodes_per_contact)) { - for (auto j : arange(spatial_dimension)) { - if (i == 0) { - Aj(j, i*spatial_dimension + j) = 0; - continue; + for (auto i : arange(nb_nodes_per_contact)) { + for (auto j : arange(spatial_dimension)) { + if (i == 0) { + Aj(j, i * spatial_dimension + j) = 0; + continue; + } + Aj(j, i * spatial_dimension + j) = dnds(i - 1); } - Aj(j, i*spatial_dimension + j) = dnds(i-1); } - } }; // tangents should have been calculated in normal modulii auto & tangents = model.getTangents(); - Matrix covariant_basis(tangents.begin(surface_dimension, - spatial_dimension)[element.slave]); - + Matrix covariant_basis( + tangents.begin(surface_dimension, spatial_dimension)[element.slave]); + auto & tangential_tractions = model.getTangentialTractions(); - Vector tangential_traction(tangential_tractions.begin(surface_dimension)[element.slave]); - + Vector tangential_traction( + tangential_tractions.begin(surface_dimension)[element.slave]); + // compute norm of trial traction Real traction_norm = 0; auto contravariant_metric_tensor = - GeometryUtils::contravariantMetricTensor(covariant_basis); + GeometryUtils::contravariantMetricTensor(covariant_basis); for (auto i : arange(surface_dimension)) { for (auto j : arange(surface_dimension)) { - traction_norm += tangential_traction[i] * tangential_traction[j] * contravariant_metric_tensor(i, j); + traction_norm += tangential_traction[i] * tangential_traction[j] * + contravariant_metric_tensor(i, j); } } traction_norm = sqrt(traction_norm); // construct four parts of stick modulii (eq 107,107a-c) - Matrix k_first(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_second(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_third(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - Matrix k_fourth(nb_nodes_per_contact*spatial_dimension, - nb_nodes_per_contact*spatial_dimension); - - + Matrix k_first(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_second(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_third(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + Matrix k_fourth(nb_nodes_per_contact * spatial_dimension, + nb_nodes_per_contact * spatial_dimension); + for (auto && values1 : enumerate(covariant_basis.transpose())) { auto & alpha = std::get<0>(values1); auto & tangent_alpha = std::get<1>(values1); Matrix mat_t_alpha(tangent_alpha.storage(), tangent_alpha.size(), 1.); - + Matrix t_outer_n(spatial_dimension, spatial_dimension); Matrix t_outer_t(spatial_dimension, spatial_dimension); - - for (auto && values2 : zip(arange(surface_dimension), - covariant_basis.transpose(), - shape_derivatives.transpose())) { + + for (auto && values2 : + zip(arange(surface_dimension), covariant_basis.transpose(), + shape_derivatives.transpose())) { auto & beta = std::get<0>(values2); auto & tangent_beta = std::get<1>(values2); auto & dnds = std::get<2>(values2); - //construct Aj from shape function wrt to jth natural + // construct Aj from shape function wrt to jth natural // coordinate construct_Aj(dnds); // eq 107 Matrix mat_t_beta(tangent_beta.storage(), tangent_beta.size(), 1.); t_outer_n.mul(mat_t_beta, mat_n); - - Matrix tmp(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp1(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); + + Matrix tmp(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp1(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); tmp.mul(t_outer_n, A); tmp1.mul(A, tmp); - tmp1 *= epsilon_n * mu * tangential_traction[alpha] * contravariant_metric_tensor(alpha, beta); + tmp1 *= epsilon_n * mu * tangential_traction[alpha] * + contravariant_metric_tensor(alpha, beta); tmp1 /= traction_norm; k_first += tmp1 * nodal_area; // eq 107a t_outer_t.mul(mat_t_alpha, mat_t_beta); - + tmp.mul(t_outer_t, A); tmp1.mul(A, tmp); tmp1 *= epsilon_t * mu * p_n * contravariant_metric_tensor(alpha, beta); tmp1 /= traction_norm; k_second += tmp1 * nodal_area; - + for (auto && values3 : enumerate(covariant_basis.transpose())) { - auto & gamma = std::get<0>(values3); - auto & tangent_gamma = std::get<1>(values3); - - Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), 1.); - - for (auto && values4 : enumerate(covariant_basis.transpose())) { - auto & theta = std::get<0>(values4); - auto & tangent_theta = std::get<1>(values4); - - Matrix mat_t_theta(tangent_theta.storage(), tangent_theta.size(), 1.); - t_outer_t.mul(mat_t_gamma, mat_t_theta); - - // eq 107b - tmp.mul(t_outer_t, A); - tmp1.mul(A, tmp); - - tmp1 *= epsilon_t*mu*p_n*tangential_traction[alpha]*tangential_traction[beta]; - tmp1 *= contravariant_metric_tensor(alpha, gamma) * contravariant_metric_tensor(beta, theta); - tmp1 /= pow(traction_norm, 3); - - k_third += tmp1 * nodal_area; - - // eq 107c - tmp.mul(t_outer_t, Aj); - tmp1.mul(A, tmp); - tmp1 *= contravariant_metric_tensor(alpha, theta) * contravariant_metric_tensor(beta, gamma); - tmp1 *= mu * p_n * tangential_traction[alpha]; - tmp1 /= traction_norm; - - Matrix tmp2(spatial_dimension, spatial_dimension*nb_nodes_per_contact); - Matrix tmp3(nb_nodes_per_contact*spatial_dimension, - spatial_dimension*nb_nodes_per_contact); - tmp2.mul(t_outer_t, A); - tmp3.mul(Aj, tmp2); - tmp3 *= contravariant_metric_tensor(alpha, gamma) * contravariant_metric_tensor(beta, theta); - tmp3 *= mu * p_n * tangential_traction[alpha]; - tmp3 /= traction_norm; - - k_fourth += (tmp1 + tmp3) * nodal_area; - } - } + auto & gamma = std::get<0>(values3); + auto & tangent_gamma = std::get<1>(values3); + + Matrix mat_t_gamma(tangent_gamma.storage(), tangent_gamma.size(), + 1.); + + for (auto && values4 : enumerate(covariant_basis.transpose())) { + auto & theta = std::get<0>(values4); + auto & tangent_theta = std::get<1>(values4); + + Matrix mat_t_theta(tangent_theta.storage(), + tangent_theta.size(), 1.); + t_outer_t.mul(mat_t_gamma, mat_t_theta); + + // eq 107b + tmp.mul(t_outer_t, A); + tmp1.mul(A, tmp); + + tmp1 *= epsilon_t * mu * p_n * tangential_traction[alpha] * + tangential_traction[beta]; + tmp1 *= contravariant_metric_tensor(alpha, gamma) * + contravariant_metric_tensor(beta, theta); + tmp1 /= pow(traction_norm, 3); + + k_third += tmp1 * nodal_area; + + // eq 107c + tmp.mul(t_outer_t, Aj); + tmp1.mul(A, tmp); + tmp1 *= contravariant_metric_tensor(alpha, theta) * + contravariant_metric_tensor(beta, gamma); + tmp1 *= mu * p_n * tangential_traction[alpha]; + tmp1 /= traction_norm; + + Matrix tmp2(spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + Matrix tmp3(nb_nodes_per_contact * spatial_dimension, + spatial_dimension * nb_nodes_per_contact); + tmp2.mul(t_outer_t, A); + tmp3.mul(Aj, tmp2); + tmp3 *= contravariant_metric_tensor(alpha, gamma) * + contravariant_metric_tensor(beta, theta); + tmp3 *= mu * p_n * tangential_traction[alpha]; + tmp3 /= traction_norm; + + k_fourth += (tmp1 + tmp3) * nodal_area; + } + } } } - + stiffness += k_third + k_fourth - k_first - k_second; } /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::beforeSolveStep() { -} +void ResolutionPenaltyQuadratic::beforeSolveStep() {} /* -------------------------------------------------------------------------- */ -void ResolutionPenaltyQuadratic::afterSolveStep(__attribute__((unused)) bool converged) { -} - +void ResolutionPenaltyQuadratic::afterSolveStep( + __attribute__((unused)) bool converged) {} + +INSTANTIATE_RESOLUTION(penalty_quadratic, ResolutionPenaltyQuadratic); -INSTANTIATE_RESOLUTION(penalty_quadratic, ResolutionPenaltyQuadratic); - } // namespace akantu diff --git a/src/model/model_couplers/coupler_solid_cohesive_contact.cc b/src/model/model_couplers/coupler_solid_cohesive_contact.cc index 0bb3a90a4..deed306eb 100644 --- a/src/model/model_couplers/coupler_solid_cohesive_contact.cc +++ b/src/model/model_couplers/coupler_solid_cohesive_contact.cc @@ -1,667 +1,655 @@ /** * @file coupler_solid_cohesive_contact.cc * * @author Mohit Pundir * * @date creation: Thu Jan 17 2019 * @date last modification: Thu May 22 2019 * * @brief class for coupling of solid mechanics cohesive and conatct mechanics * model * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "coupler_solid_cohesive_contact.hh" #include "dumpable_inline_impl.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { CouplerSolidCohesiveContact::CouplerSolidCohesiveContact( Mesh & mesh, UInt dim, const ID & id, std::shared_ptr dof_manager, const ModelType model_type) : Model(mesh, model_type, dof_manager, dim, id) { AKANTU_DEBUG_IN(); - this->registerFEEngineObject("CohesiveFEEngine", - mesh, Model::spatial_dimension); + this->registerFEEngineObject( + "CohesiveFEEngine", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper("coupler_solid_cohesive_contact", id, true); this->mesh.addDumpMeshToDumper("coupler_solid_cohesive_contact", mesh, Model::spatial_dimension, _not_ghost, _ek_cohesive); #endif this->registerDataAccessor(*this); solid = new SolidMechanicsModelCohesive(mesh, Model::spatial_dimension, "solid_mechanics_model_cohesive", 0, this->dof_manager); - contact = new ContactMechanicsModel(mesh.getMeshFacets(), Model::spatial_dimension, - "contact_mechanics_model", 0, - this->dof_manager); + contact = new ContactMechanicsModel( + mesh.getMeshFacets(), Model::spatial_dimension, "contact_mechanics_model", + 0, this->dof_manager); registerFEEngineObject( "FacetsFEEngine", mesh.getMeshFacets(), Model::spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ CouplerSolidCohesiveContact::~CouplerSolidCohesiveContact() {} /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::initFullImpl(const ModelOptions & options) { Model::initFullImpl(options); this->initBC(*this, *displacement, *displacement_increment, *external_force); - + const auto & cscc_options = aka::as_type(options); - - solid->initFull( _analysis_method = cscc_options.analysis_method, - _is_extrinsic = cscc_options.is_extrinsic); + + solid->initFull(_analysis_method = cscc_options.analysis_method, + _is_extrinsic = cscc_options.is_extrinsic); contact->initFull(_analysis_method = cscc_options.analysis_method); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::initModel() { getFEEngine("CohesiveFEEngine").initShapeFunctions(_not_ghost); getFEEngine("CohesiveFEEngine").initShapeFunctions(_ghost); getFEEngine("FacetsFEEngine").initShapeFunctions(_not_ghost); getFEEngine("FacetsFEEngine").initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ FEEngine & CouplerSolidCohesiveContact::getFEEngineBoundary(const ID & name) { return dynamic_cast( getFEEngineClassBoundary(name)); } /* -------------------------------------------------------------------------- */ -void CouplerSolidCohesiveContact::initSolver(TimeStepSolverType time_step_solver_type, - NonLinearSolverType non_linear_solver_type) { - auto & solid_model_solver = - aka::as_type(*solid); - solid_model_solver.initSolver(time_step_solver_type, non_linear_solver_type); - - auto & contact_model_solver = - aka::as_type(*contact); - contact_model_solver.initSolver(time_step_solver_type, non_linear_solver_type); +void CouplerSolidCohesiveContact::initSolver( + TimeStepSolverType time_step_solver_type, + NonLinearSolverType non_linear_solver_type) { + auto & solid_model_solver = aka::as_type(*solid); + solid_model_solver.initSolver(time_step_solver_type, non_linear_solver_type); + auto & contact_model_solver = aka::as_type(*contact); + contact_model_solver.initSolver(time_step_solver_type, + non_linear_solver_type); } /* -------------------------------------------------------------------------- */ std::tuple CouplerSolidCohesiveContact::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_lumped_mass: { return std::make_tuple("explicit_lumped", TimeStepSolverType::_dynamic_lumped); } case _explicit_consistent_mass: { return std::make_tuple("explicit", TimeStepSolverType::_dynamic); } case _static: { return std::make_tuple("static", TimeStepSolverType::_static); } case _implicit_dynamic: { return std::make_tuple("implicit", TimeStepSolverType::_dynamic); } default: return std::make_tuple("unknown", TimeStepSolverType::_not_defined); - } - + } + /*switch (method) { case _explicit_contact: { return std::make_tuple("explicit_contact", TimeStepSolverType::_static); } case _implicit_contact: { return std::make_tuple("implicit_contact", TimeStepSolverType::_static); } case _explicit_dynamic_contact: { return std::make_tuple("explicit_dynamic_contact", TimeStepSolverType::_dynamic_lumped); break; } default: return std::make_tuple("unkown", TimeStepSolverType::_not_defined); }*/ } /* -------------------------------------------------------------------------- */ TimeStepSolverType CouplerSolidCohesiveContact::getDefaultSolverType() const { return TimeStepSolverType::_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions CouplerSolidCohesiveContact::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case TimeStepSolverType::_dynamic_lumped: { options.non_linear_solver_type = NonLinearSolverType::_lumped; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case TimeStepSolverType::_dynamic: { options.non_linear_solver_type = NonLinearSolverType::_lumped; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case TimeStepSolverType::_static: { options.non_linear_solver_type = NonLinearSolverType::_newton_raphson_contact; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); break; } return options; } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleResidual() { // computes the internal forces this->assembleInternalForces(); auto & internal_force = solid->getInternalForce(); auto & external_force = solid->getExternalForce(); auto & contact_force = contact->getInternalForce(); - /* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- + */ this->getDOFManager().assembleToResidual("displacement", external_force, 1); this->getDOFManager().assembleToResidual("displacement", internal_force, 1); this->getDOFManager().assembleToResidual("displacement", contact_force, 1); - + /*auto get_connectivity = [&](auto & slave, auto & master) { - Vector master_conn(const_cast(mesh).getConnectivity(master)); - Vector elem_conn(master_conn.size() + 1); + Vector master_conn(const_cast(mesh).getConnectivity(master)); Vector elem_conn(master_conn.size() + + 1); elem_conn[0] = slave; for (UInt i = 1; i < elem_conn.size(); ++i) { elem_conn[i] = master_conn[i - 1]; } return elem_conn; }; - + switch (method) { case _explicit_dynamic_contact: case _explicit_contact: { for (auto & element : contact->getContactElements()) { for (auto & conn : get_connectivity(element.slave, element.master)) { - for (auto dim : arange(spatial_dimension)) { - external_force(conn, dim) = contact_force(conn, dim); - } + for (auto dim : arange(spatial_dimension)) { + external_force(conn, dim) = contact_force(conn, dim); + } } } } default: break; }*/ /* ------------------------------------------------------------------------ */ /*this->getDOFManager().assembleToResidual("displacement", external_force, 1); this->getDOFManager().assembleToResidual("displacement", internal_force, 1); switch (method) { case _implicit_contact: { this->getDOFManager().assembleToResidual("displacement", contact_force, 1); break; } default: break; }*/ - - } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleResidual(const ID & residual_part) { AKANTU_DEBUG_IN(); auto & internal_force = solid->getInternalForce(); auto & external_force = solid->getExternalForce(); auto & contact_force = contact->getInternalForce(); /*auto get_connectivity = [&](auto & slave, auto & master) { - Vector master_conn(const_cast(mesh).getConnectivity(master)); - Vector elem_conn(master_conn.size() + 1); + Vector master_conn(const_cast(mesh).getConnectivity(master)); Vector elem_conn(master_conn.size() + + 1); elem_conn[0] = slave; for (UInt i = 1; i < elem_conn.size(); ++i) { elem_conn[i] = master_conn[i - 1]; } return elem_conn; }; - + switch (method) { case _explicit_dynamic_contact: case _explicit_contact: { for (auto & element : contact->getContactElements()) { for (auto & conn : get_connectivity(element.slave, element.master)) { - for (auto dim : arange(spatial_dimension)) { - external_force(conn, dim) = contact_force(conn, dim); - } + for (auto dim : arange(spatial_dimension)) { + external_force(conn, dim) = contact_force(conn, dim); + } } } } default: break; } - + if ("external" == residual_part) { this->getDOFManager().assembleToResidual("displacement", external_force, 1); AKANTU_DEBUG_OUT(); return; } if ("internal" == residual_part) { this->getDOFManager().assembleToResidual("displacement", internal_force, 1); switch (method) { case _implicit_contact: { this->getDOFManager().assembleToResidual("displacement", contact_force, 1); break; } default: break; } AKANTU_DEBUG_OUT(); return; }*/ if ("external" == residual_part) { this->getDOFManager().assembleToResidual("displacement", external_force, 1); this->getDOFManager().assembleToResidual("displacement", contact_force, 1); AKANTU_DEBUG_OUT(); return; } if ("internal" == residual_part) { this->getDOFManager().assembleToResidual("displacement", internal_force, 1); AKANTU_DEBUG_OUT(); return; } AKANTU_CUSTOM_EXCEPTION( debug::SolverCallbackResidualPartUnknown(residual_part)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::predictor() { - - auto & solid_model_solver = - aka::as_type(*solid); + auto & solid_model_solver = aka::as_type(*solid); solid_model_solver.predictor(); - + switch (method) { case _static: - case _explicit_lumped_mass: { + case _explicit_lumped_mass: { auto & current_positions = contact->getContactDetector().getPositions(); current_positions.copy(solid->getCurrentPosition()); contact->search(); break; } default: break; } - + /*switch (method) { case _explicit_dynamic_contact: { Array displacement(0, Model::spatial_dimension); auto & current_positions = contact->getContactDetector().getPositions(); current_positions.copy(mesh.getNodes()); auto us = this->getDOFManager().getDOFs("displacement"); const auto blocked_dofs = this->getDOFManager().getBlockedDOFs("displacement"); for (auto && tuple : zip(make_view(us), make_view(blocked_dofs), make_view(current_positions))) { auto & u = std::get<0>(tuple); const auto & bld = std::get<1>(tuple); auto & cp = std::get<2>(tuple); if (not bld) cp += u; } contact->search(); break; } default: break; }*/ - - } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::corrector() { - - auto & solid_model_solver = - aka::as_type(*solid); + auto & solid_model_solver = aka::as_type(*solid); solid_model_solver.corrector(); - + switch (method) { case _static: - case _implicit_dynamic: { + case _implicit_dynamic: { auto & current_positions = contact->getContactDetector().getPositions(); current_positions.copy(solid->getCurrentPosition()); contact->search(); break; } default: break; } - + /*switch (method) { case _implicit_contact: case _explicit_contact: { Array displacement(0, Model::spatial_dimension); auto & current_positions = contact->getContactDetector().getPositions(); current_positions.copy(mesh.getNodes()); auto us = this->getDOFManager().getDOFs("displacement"); const auto blocked_dofs = this->getDOFManager().getBlockedDOFs("displacement"); for (auto && tuple : zip(make_view(us), make_view(blocked_dofs), make_view(current_positions))) { auto & u = std::get<0>(tuple); const auto & bld = std::get<1>(tuple); auto & cp = std::get<2>(tuple); if (not bld) cp += u; } contact->search(); break; } default: break; }*/ } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::beforeSolveStep() { - auto & solid_solver_callback = - aka::as_type(*solid); + auto & solid_solver_callback = aka::as_type(*solid); solid_solver_callback.beforeSolveStep(); - - auto & contact_solver_callback = - aka::as_type(*contact); + + auto & contact_solver_callback = aka::as_type(*contact); contact_solver_callback.beforeSolveStep(); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::afterSolveStep(bool converged) { - auto & solid_solver_callback = - aka::as_type(*solid); + auto & solid_solver_callback = aka::as_type(*solid); solid_solver_callback.afterSolveStep(converged); - - auto & contact_solver_callback = - aka::as_type(*contact); + + auto & contact_solver_callback = aka::as_type(*contact); contact_solver_callback.afterSolveStep(converged); } - /* -------------------------------------------------------------------------- */ MatrixType CouplerSolidCohesiveContact::getMatrixType(const ID & matrix_id) { if (matrix_id == "K") return _symmetric; if (matrix_id == "M") { return _symmetric; } return _mt_not_defined; } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } else if (matrix_id == "M") { solid->assembleMass(); } } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { solid->assembleMassLumped(); } } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleInternalForces() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); solid->assembleInternalForces(); contact->assembleInternalForces(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix"); solid->assembleStiffnessMatrix(); switch (method) { case _static: case _implicit_dynamic: { contact->assembleStiffnessMatrix(); break; } default: break; } - + /*switch (method) { case _implicit_contact: { contact->assembleStiffnessMatrix(); break; } default: break; }*/ AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleMassLumped() { solid->assembleMassLumped(); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleMass() { solid->assembleMass(); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleMassLumped(GhostType ghost_type) { solid->assembleMassLumped(ghost_type); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::assembleMass(GhostType ghost_type) { solid->assembleMass(ghost_type); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidCohesiveContact::createElementalField( const std::string & field_name, const std::string & group_name, - bool padding_flag, const UInt & spatial_dimension, - const ElementKind & kind) { + bool padding_flag, UInt spatial_dimension, ElementKind kind) { std::shared_ptr field; field = solid->createElementalField(field_name, group_name, padding_flag, - spatial_dimension, kind); + spatial_dimension, kind); return field; } /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidCohesiveContact::createNodalFieldReal( const std::string & field_name, const std::string & group_name, bool padding_flag) { std::shared_ptr field; if (field_name == "contact_force" or field_name == "normals" or field_name == "normal_force" or field_name == "tangential_force" or - field_name == "contact_state" or - field_name == "gaps" or field_name == "previous_gaps" or - field_name == "areas" or field_name == "tangents") { - field = contact->createNodalFieldReal(field_name, group_name, padding_flag); + field_name == "contact_state" or field_name == "gaps" or + field_name == "previous_gaps" or field_name == "areas" or + field_name == "tangents") { + field = contact->createNodalFieldReal(field_name, group_name, padding_flag); } else { field = solid->createNodalFieldReal(field_name, group_name, padding_flag); } - + return field; } /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidCohesiveContact::createNodalFieldBool( const std::string & field_name, const std::string & group_name, bool padding_flag) { std::shared_ptr field; field = solid->createNodalFieldBool(field_name, group_name, padding_flag); return field; } #else /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidCohesiveContact::createElementalField(const std::string &, const std::string &, bool, const UInt &, const ElementKind &) { return nullptr; } /* ----------------------------------------------------------------------- */ std::shared_ptr CouplerSolidCohesiveContact::createNodalFieldReal(const std::string &, const std::string &, bool) { return nullptr; } /*-------------------------------------------------------------------*/ std::shared_ptr CouplerSolidCohesiveContact::createNodalFieldBool(const std::string &, const std::string &, bool) { return nullptr; } #endif /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::dump(const std::string & dumper_name) { solid->onDump(); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::dump(const std::string & dumper_name, UInt step) { solid->onDump(); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::dump(const std::string & dumper_name, Real time, UInt step) { solid->onDump(); mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::dump() { solid->onDump(); mesh.dump(); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::dump(UInt step) { solid->onDump(); mesh.dump(step); } /* -------------------------------------------------------------------------- */ void CouplerSolidCohesiveContact::dump(Real time, UInt step) { solid->onDump(); mesh.dump(time, step); } } // namespace akantu diff --git a/src/model/model_couplers/coupler_solid_cohesive_contact.hh b/src/model/model_couplers/coupler_solid_cohesive_contact.hh index 5d09d4c2c..689d171d2 100644 --- a/src/model/model_couplers/coupler_solid_cohesive_contact.hh +++ b/src/model/model_couplers/coupler_solid_cohesive_contact.hh @@ -1,287 +1,286 @@ /** * @file coupler_solid_cohesive_contact.hh * * @author Mohit Pundir * * @date creation: Thu Jan 17 2019 * @date last modification: Thu Jan 17 2019 * * @brief class for coupling of solid mechanics and conatct mechanics * model in explicit * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "contact_mechanics_model.hh" #include "data_accessor.hh" #include "model.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COUPLER_SOLID_COHESIVE_CONTACT_HH__ #define __AKANTU_COUPLER_SOLID_COHESIVE_CONTACT_HH__ /* ------------------------------------------------------------------------ */ /* Coupling : Solid Mechanics / Contact Mechanics */ /* ------------------------------------------------------------------------ */ namespace akantu { template class IntegratorGauss; template class ShapeLagrange; class DOFManager; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ class CouplerSolidCohesiveContact : public Model, public DataAccessor, public DataAccessor, public BoundaryCondition { /* ------------------------------------------------------------------------ */ /* Constructor/Destructor */ /* ------------------------------------------------------------------------ */ using MyFEEngineCohesiveType = FEEngineTemplate; using MyFEEngineFacetType = FEEngineTemplate; public: CouplerSolidCohesiveContact( Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "coupler_solid_cohesive_contact", std::shared_ptr dof_manager = nullptr, const ModelType model_type = ModelType::_coupler_solid_cohesive_contact); ~CouplerSolidCohesiveContact() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize completely the model void initFullImpl(const ModelOptions & options) override; /// initialize the modelType void initModel() override; /// get some default values for derived classes std::tuple getDefaultSolverID(const AnalysisMethod & method) override; /* ------------------------------------------------------------------------ */ /* Solver Interface */ /* ------------------------------------------------------------------------ */ public: /// assembles the contact stiffness matrix virtual void assembleStiffnessMatrix(); /// assembles the contant internal forces virtual void assembleInternalForces(); protected: /// callback for the solver, this adds f_{ext} - f_{int} to the residual void assembleResidual() override; /// callback for the solver, this adds f_{ext} or f_{int} to the residual void assembleResidual(const ID & residual_part) override; bool canSplitResidual() override { return true; } /// get the type of matrix needed MatrixType getMatrixType(const ID & matrix_id) override; /// callback for the solver, this assembles different matrices void assembleMatrix(const ID & matrix_id) override; /// callback for the solver, this assembles the stiffness matrix void assembleLumpedMatrix(const ID & matrix_id) override; /// callback for the solver, this is called at beginning of solve void predictor() override; /// callback for the solver, this is called at end of solve void corrector() override; /// callback for the solver, this is called at beginning of solve void beforeSolveStep() override; /// callback for the solver, this is called at end of solve void afterSolveStep(bool converged = true) override; /// callback for the model to instantiate the matricess when needed void initSolver(TimeStepSolverType, NonLinearSolverType) override; /* ------------------------------------------------------------------------ */ /* Mass matrix for solid mechanics model */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); protected: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); protected: /* -------------------------------------------------------------------------- */ TimeStepSolverType getDefaultSolverType() const override; /* -------------------------------------------------------------------------- */ ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const; public: bool isDefaultSolverExplicit() { return method == _explicit_dynamic_contact; } /* ------------------------------------------------------------------------ */ public: // DataAccessor UInt getNbData(const Array &, const SynchronizationTag &) const override { return 0; } void packData(CommunicationBuffer &, const Array &, const SynchronizationTag &) const override {} void unpackData(CommunicationBuffer &, const Array &, const SynchronizationTag &) override {} // DataAccessor nodes UInt getNbData(const Array &, const SynchronizationTag &) const override { return 0; } void packData(CommunicationBuffer &, const Array &, const SynchronizationTag &) const override {} void unpackData(CommunicationBuffer &, const Array &, const SynchronizationTag &) override {} /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: FEEngine & getFEEngineBoundary(const ID & name = "") override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt); /// get the ContactMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array &); /// get the ContactMechanicsModel::increment vector \warn only consistent /// if ContactMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *displacement_increment, Array &); /// get the ContactMechanicsModel::external_force vector (external forces) AKANTU_GET_MACRO(ExternalForce, *external_force, Array &); /// get the ContactMechanicsModel::force vector (external forces) Array & getForce() { AKANTU_DEBUG_WARNING("getForce was maintained for backward compatibility, " "use getExternalForce instead"); return *external_force; } /// get the solid mechanics model AKANTU_GET_MACRO(SolidMechanicsModelCohesive, *solid, SolidMechanicsModelCohesive &); /// get the contact mechanics model AKANTU_GET_MACRO(ContactMechanicsModel, *contact, ContactMechanicsModel &); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: std::shared_ptr createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) override; std::shared_ptr createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) override; std::shared_ptr createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, - const UInt & spatial_dimension, - const ElementKind & kind) override; + UInt spatial_dimension, ElementKind kind) override; virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); void dump() override; virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Members */ /* ------------------------------------------------------------------------ */ private: /// solid mechanics model SolidMechanicsModelCohesive * solid{nullptr}; /// contact mechanics model ContactMechanicsModel * contact{nullptr}; /// Array * displacement{nullptr}; /// Array * displacement_increment{nullptr}; /// external forces array Array * external_force{nullptr}; bool search_for_contact; UInt step; }; } // namespace akantu #endif /* __COUPLER_SOLID_CONTACT_HH__ */ diff --git a/src/model/model_couplers/coupler_solid_contact.cc b/src/model/model_couplers/coupler_solid_contact.cc index a17ef1ff5..2649346c5 100644 --- a/src/model/model_couplers/coupler_solid_contact.cc +++ b/src/model/model_couplers/coupler_solid_contact.cc @@ -1,482 +1,468 @@ /** * @file coupler_solid_contact.cc * * @author Mohit Pundir * * @date creation: Thu Jan 17 2019 * @date last modification: Thu May 22 2019 * * @brief class for coupling of solid mechanics and conatct mechanics * model * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "coupler_solid_contact.hh" #include "dumpable_inline_impl.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { CouplerSolidContact::CouplerSolidContact( Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id, std::shared_ptr dof_manager, const ModelType model_type) : Model(mesh, model_type, dof_manager, dim, id, memory_id) { AKANTU_DEBUG_IN(); this->registerFEEngineObject("CouplerSolidContact", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper("coupler_solid_contact", id, true); this->mesh.addDumpMeshToDumper("coupler_solid_contact", mesh, Model::spatial_dimension, _not_ghost, _ek_regular); #endif this->registerDataAccessor(*this); solid = new SolidMechanicsModel(mesh, Model::spatial_dimension, "solid_mechanics_model", 0, this->dof_manager); contact = new ContactMechanicsModel(mesh, Model::spatial_dimension, "contact_mechanics_model", 0, this->dof_manager); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ CouplerSolidContact::~CouplerSolidContact() {} /* -------------------------------------------------------------------------- */ void CouplerSolidContact::initFullImpl(const ModelOptions & options) { Model::initFullImpl(options); this->initBC(*this, *displacement, *displacement_increment, *external_force); - solid->initFull( _analysis_method = this->method); - contact->initFull(_analysis_method = this->method); + solid->initFull(_analysis_method = this->method); + contact->initFull(_analysis_method = this->method); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::initModel() { getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ FEEngine & CouplerSolidContact::getFEEngineBoundary(const ID & name) { return dynamic_cast( getFEEngineClassBoundary(name)); } /* -------------------------------------------------------------------------- */ -void CouplerSolidContact::initSolver(TimeStepSolverType time_step_solver_type, - NonLinearSolverType non_linear_solver_type) { - auto & solid_model_solver = - aka::as_type(*solid); - solid_model_solver.initSolver(time_step_solver_type, non_linear_solver_type); +void CouplerSolidContact::initSolver( + TimeStepSolverType time_step_solver_type, + NonLinearSolverType non_linear_solver_type) { + auto & solid_model_solver = aka::as_type(*solid); + solid_model_solver.initSolver(time_step_solver_type, non_linear_solver_type); - auto & contact_model_solver = - aka::as_type(*contact); - contact_model_solver.initSolver(time_step_solver_type, non_linear_solver_type); + auto & contact_model_solver = aka::as_type(*contact); + contact_model_solver.initSolver(time_step_solver_type, + non_linear_solver_type); } /* -------------------------------------------------------------------------- */ std::tuple CouplerSolidContact::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_lumped_mass: { return std::make_tuple("explicit_lumped", TimeStepSolverType::_dynamic_lumped); } case _explicit_consistent_mass: { return std::make_tuple("explicit", TimeStepSolverType::_dynamic); } case _static: { return std::make_tuple("static", TimeStepSolverType::_static); } case _implicit_dynamic: { return std::make_tuple("implicit", TimeStepSolverType::_dynamic); } default: return std::make_tuple("unknown", TimeStepSolverType::_not_defined); - } + } } /* -------------------------------------------------------------------------- */ TimeStepSolverType CouplerSolidContact::getDefaultSolverType() const { return TimeStepSolverType::_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions CouplerSolidContact::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case TimeStepSolverType::_dynamic_lumped: { options.non_linear_solver_type = NonLinearSolverType::_lumped; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case TimeStepSolverType::_dynamic: { options.non_linear_solver_type = NonLinearSolverType::_lumped; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case TimeStepSolverType::_static: { options.non_linear_solver_type = NonLinearSolverType::_newton_raphson_contact; options.integration_scheme_type["displacement"] = IntegrationSchemeType::_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); break; } return options; } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleResidual() { // computes the internal forces - + switch (method) { - case _explicit_lumped_mass: { + case _explicit_lumped_mass: { auto & current_positions = contact->getContactDetector().getPositions(); current_positions.copy(solid->getCurrentPosition()); contact->search(); break; } default: break; } this->assembleInternalForces(); auto & internal_force = solid->getInternalForce(); auto & external_force = solid->getExternalForce(); auto & contact_force = contact->getInternalForce(); - - /* ------------------------------------------------------------------------ */ this->getDOFManager().assembleToResidual("displacement", external_force, 1); this->getDOFManager().assembleToResidual("displacement", internal_force, 1); this->getDOFManager().assembleToResidual("displacement", contact_force, 1); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleResidual(const ID & residual_part) { AKANTU_DEBUG_IN(); - //contact->assembleInternalForces(); - + // contact->assembleInternalForces(); + auto & internal_force = solid->getInternalForce(); auto & external_force = solid->getExternalForce(); auto & contact_force = contact->getInternalForce(); - + if ("external" == residual_part) { this->getDOFManager().assembleToResidual("displacement", external_force, 1); this->getDOFManager().assembleToResidual("displacement", contact_force, 1); AKANTU_DEBUG_OUT(); return; } if ("internal" == residual_part) { this->getDOFManager().assembleToResidual("displacement", internal_force, 1); AKANTU_DEBUG_OUT(); return; } AKANTU_CUSTOM_EXCEPTION( debug::SolverCallbackResidualPartUnknown(residual_part)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::predictor() { - - auto & solid_model_solver = - aka::as_type(*solid); - solid_model_solver.predictor(); - + + auto & solid_model_solver = aka::as_type(*solid); + solid_model_solver.predictor(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::corrector() { - auto & solid_model_solver = - aka::as_type(*solid); + auto & solid_model_solver = aka::as_type(*solid); solid_model_solver.corrector(); - + switch (method) { case _static: - case _implicit_dynamic: { + case _implicit_dynamic: { auto & current_positions = contact->getContactDetector().getPositions(); current_positions.copy(solid->getCurrentPosition()); contact->search(); break; } default: break; } - } /* -------------------------------------------------------------------------- */ MatrixType CouplerSolidContact::getMatrixType(const ID & matrix_id) { if (matrix_id == "K") return _symmetric; if (matrix_id == "M") { return _symmetric; } return _mt_not_defined; } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } else if (matrix_id == "M") { solid->assembleMass(); } } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { solid->assembleMassLumped(); } } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::beforeSolveStep() { - auto & solid_solver_callback = - aka::as_type(*solid); + auto & solid_solver_callback = aka::as_type(*solid); solid_solver_callback.beforeSolveStep(); - - auto & contact_solver_callback = - aka::as_type(*contact); + + auto & contact_solver_callback = aka::as_type(*contact); contact_solver_callback.beforeSolveStep(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::afterSolveStep(bool converged) { - auto & solid_solver_callback = - aka::as_type(*solid); + auto & solid_solver_callback = aka::as_type(*solid); solid_solver_callback.afterSolveStep(converged); - - auto & contact_solver_callback = - aka::as_type(*contact); + + auto & contact_solver_callback = aka::as_type(*contact); contact_solver_callback.afterSolveStep(converged); } - - /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleInternalForces() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); solid->assembleInternalForces(); contact->assembleInternalForces(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix"); solid->assembleStiffnessMatrix(true); - + switch (method) { case _static: case _implicit_dynamic: { - contact->assembleStiffnessMatrix(); + contact->assembleStiffnessMatrix(); break; } default: break; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleMassLumped() { solid->assembleMassLumped(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleMass() { solid->assembleMass(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleMassLumped(GhostType ghost_type) { solid->assembleMassLumped(ghost_type); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::assembleMass(GhostType ghost_type) { solid->assembleMass(ghost_type); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidContact::createElementalField( const std::string & field_name, const std::string & group_name, - bool padding_flag, const UInt & spatial_dimension, - const ElementKind & kind) { + bool padding_flag, UInt spatial_dimension, ElementKind kind) { std::shared_ptr field; field = solid->createElementalField(field_name, group_name, padding_flag, - spatial_dimension, kind); - + spatial_dimension, kind); + return field; } /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidContact::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::shared_ptr field; if (field_name == "contact_force" or field_name == "normals" or field_name == "normal_force" or field_name == "tangential_force" or - field_name == "contact_state" or - field_name == "gaps" or field_name == "previous_gaps" or - field_name == "areas" or field_name == "tangents") { - field = contact->createNodalFieldReal(field_name, group_name, padding_flag); + field_name == "contact_state" or field_name == "gaps" or + field_name == "previous_gaps" or field_name == "areas" or + field_name == "tangents") { + field = contact->createNodalFieldReal(field_name, group_name, padding_flag); } else { field = solid->createNodalFieldReal(field_name, group_name, padding_flag); } return field; } /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidContact::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { - std::shared_ptr field; field = solid->createNodalFieldBool(field_name, group_name, padding_flag); return field; } #else /* -------------------------------------------------------------------------- */ std::shared_ptr CouplerSolidContact::createElementalField(const std::string &, const std::string &, bool, const UInt &, const ElementKind &) { return nullptr; } /* ----------------------------------------------------------------------- */ std::shared_ptr CouplerSolidContact::createNodalFieldReal(const std::string &, const std::string &, bool) { return nullptr; } /*-------------------------------------------------------------------*/ std::shared_ptr CouplerSolidContact::createNodalFieldBool(const std::string &, const std::string &, bool) { return nullptr; } #endif /* -------------------------------------------------------------------------- */ void CouplerSolidContact::dump(const std::string & dumper_name) { solid->onDump(); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::dump(const std::string & dumper_name, UInt step) { solid->onDump(); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void CouplerSolidContact::dump(const std::string & dumper_name, Real time, UInt step) { solid->onDump(); mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::dump() { solid->onDump(); mesh.dump(); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::dump(UInt step) { solid->onDump(); mesh.dump(step); } /* -------------------------------------------------------------------------- */ void CouplerSolidContact::dump(Real time, UInt step) { solid->onDump(); mesh.dump(time, step); } } // namespace akantu diff --git a/src/model/model_couplers/coupler_solid_contact.hh b/src/model/model_couplers/coupler_solid_contact.hh index 083409526..3e2c7832b 100644 --- a/src/model/model_couplers/coupler_solid_contact.hh +++ b/src/model/model_couplers/coupler_solid_contact.hh @@ -1,282 +1,281 @@ /** * @file coupler_solid_contact_explicit.hh * * @author Mohit Pundir * * @date creation: Thu Jan 17 2019 * @date last modification: Thu Jan 17 2019 * * @brief class for coupling of solid mechanics and conatct mechanics * model in explicit * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "contact_mechanics_model.hh" #include "data_accessor.hh" #include "fe_engine.hh" #include "model.hh" #include "solid_mechanics_model.hh" #include "sparse_matrix.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COUPLER_SOLID_CONTACT_HH__ #define __AKANTU_COUPLER_SOLID_CONTACT_HH__ /* ------------------------------------------------------------------------ */ /* Coupling : Solid Mechanics / Contact Mechanics */ /* ------------------------------------------------------------------------ */ namespace akantu { template class IntegratorGauss; template class ShapeLagrange; class DOFManager; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ class CouplerSolidContact : public Model, public DataAccessor, public DataAccessor, public BoundaryCondition { /* ------------------------------------------------------------------------ */ /* Constructor/Destructor */ /* ------------------------------------------------------------------------ */ using MyFEEngineType = FEEngineTemplate; public: CouplerSolidContact( Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "coupler_solid_contact", const MemoryID & memory_id = 0, std::shared_ptr dof_manager = nullptr, const ModelType model_type = ModelType::_coupler_solid_contact); ~CouplerSolidContact() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize completely the model void initFullImpl(const ModelOptions & options) override; /// initialize the modelType void initModel() override; /// get some default values for derived classes std::tuple getDefaultSolverID(const AnalysisMethod & method) override; /* ------------------------------------------------------------------------ */ /* Solver Interface */ /* ------------------------------------------------------------------------ */ public: /// assembles the contact stiffness matrix virtual void assembleStiffnessMatrix(); /// assembles the contant internal forces virtual void assembleInternalForces(); protected: /// callback for the solver, this adds f_{ext} - f_{int} to the residual void assembleResidual() override; /// callback for the solver, this adds f_{ext} or f_{int} to the residual void assembleResidual(const ID & residual_part) override; bool canSplitResidual() override { return true; } /// get the type of matrix needed MatrixType getMatrixType(const ID & matrix_id) override; /// callback for the solver, this assembles different matrices void assembleMatrix(const ID & matrix_id) override; /// callback for the solver, this assembles the stiffness matrix void assembleLumpedMatrix(const ID & matrix_id) override; /// callback for the solver, this is called at beginning of solve void predictor() override; /// callback for the solver, this is called at end of solve void corrector() override; /// callback for the solver, this is called at beginning of solve void beforeSolveStep() override; /// callback for the solver, this is called at end of solve void afterSolveStep(bool converged = true) override; /// callback for the model to instantiate the matricess when needed void initSolver(TimeStepSolverType, NonLinearSolverType) override; /* ------------------------------------------------------------------------ */ /* Mass matrix for solid mechanics model */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); protected: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); protected: /* -------------------------------------------------------------------------- */ TimeStepSolverType getDefaultSolverType() const override; /* -------------------------------------------------------------------------- */ ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const; public: bool isDefaultSolverExplicit() { return method == _explicit_dynamic_contact; } /* ------------------------------------------------------------------------ */ public: // DataAccessor UInt getNbData(const Array &, const SynchronizationTag &) const override { return 0; } void packData(CommunicationBuffer &, const Array &, const SynchronizationTag &) const override {} void unpackData(CommunicationBuffer &, const Array &, const SynchronizationTag &) override {} // DataAccessor nodes UInt getNbData(const Array &, const SynchronizationTag &) const override { return 0; } void packData(CommunicationBuffer &, const Array &, const SynchronizationTag &) const override {} void unpackData(CommunicationBuffer &, const Array &, const SynchronizationTag &) override {} /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: FEEngine & getFEEngineBoundary(const ID & name = "") override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt); /// get the ContactMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array &); /// get the ContactMechanicsModel::increment vector \warn only consistent /// if ContactMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *displacement_increment, Array &); /// get the ContactMechanicsModel::external_force vector (external forces) AKANTU_GET_MACRO(ExternalForce, *external_force, Array &); /// get the ContactMechanicsModel::force vector (external forces) Array & getForce() { AKANTU_DEBUG_WARNING("getForce was maintained for backward compatibility, " "use getExternalForce instead"); return *external_force; } /// get the solid mechanics model AKANTU_GET_MACRO(SolidMechanicsModel, *solid, SolidMechanicsModel &); /// get the contact mechanics model AKANTU_GET_MACRO(ContactMechanicsModel, *contact, ContactMechanicsModel &); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: std::shared_ptr createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) override; std::shared_ptr createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) override; std::shared_ptr createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, - const UInt & spatial_dimension, - const ElementKind & kind) override; + UInt spatial_dimension, ElementKind kind) override; virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); void dump() override; virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Members */ /* ------------------------------------------------------------------------ */ private: /// solid mechanics model SolidMechanicsModel * solid{nullptr}; /// contact mechanics model ContactMechanicsModel * contact{nullptr}; /// Array * displacement{nullptr}; /// Array * displacement_increment{nullptr}; /// external forces array Array * external_force{nullptr}; bool search_for_contact; UInt step; }; } // namespace akantu #endif /* __COUPLER_SOLID_CONTACT_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_damage/material_von_mises_mazars_inline_impl.hh b/src/model/solid_mechanics/materials/material_damage/material_von_mises_mazars_inline_impl.hh index f680e5144..e9bdee79e 100644 --- a/src/model/solid_mechanics/materials/material_damage/material_von_mises_mazars_inline_impl.hh +++ b/src/model/solid_mechanics/materials/material_damage/material_von_mises_mazars_inline_impl.hh @@ -1,118 +1,121 @@ /* -------------------------------------------------------------------------- */ #include "material_von_mises_mazars.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ - template class Parent> - inline void MaterialVonMisesMazars::computeStressOnQuad( +template class Parent> +inline void +MaterialVonMisesMazars::computeStressOnQuad( const Matrix & grad_u, Matrix & sigma, Real & dam, Real & Ehat) { Matrix epsilon(3, 3); - epsilon.clear(); + epsilon.zero(); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) epsilon(i, j) = .5 * (grad_u(i, j) + grad_u(j, i)); Vector Fdiag(3); Math::matrixEig(3, epsilon.storage(), Fdiag.storage()); Ehat = 0.; for (UInt i = 0; i < 3; ++i) { Real epsilon_p = std::max(Real(0.), Fdiag(i)); Ehat += epsilon_p * epsilon_p; } Ehat = sqrt(Ehat); - //MaterialElastic::computeStressOnQuad(grad_u, sigma); + // MaterialElastic::computeStressOnQuad(grad_u, sigma); if (damage_in_compute_stress) { computeDamageOnQuad(Ehat, sigma, Fdiag, dam); } if (not this->is_non_local) { computeDamageAndStressOnQuad(grad_u, sigma, dam, Ehat); } } /* -------------------------------------------------------------------------- */ - template class Parent> - inline void MaterialVonMisesMazars::computeDamageAndStressOnQuad( +template class Parent> +inline void +MaterialVonMisesMazars::computeDamageAndStressOnQuad( const Matrix & grad_u, Matrix & sigma, Real & dam, Real & Ehat) { if (!damage_in_compute_stress) { Vector Fdiag(3); - Fdiag.clear(); + Fdiag.zero(); Matrix epsilon(3, 3); - epsilon.clear(); + epsilon.zero(); for (UInt i = 0; i < spatial_dimension; ++i) for (UInt j = 0; j < spatial_dimension; ++j) epsilon(i, j) = .5 * (grad_u(i, j) + grad_u(j, i)); Math::matrixEig(3, epsilon.storage(), Fdiag.storage()); computeDamageOnQuad(Ehat, sigma, Fdiag, dam); } sigma *= 1 - dam; } /* -------------------------------------------------------------------------- */ - template class Parent> - inline void MaterialVonMisesMazars::computeDamageOnQuad( +template class Parent> +inline void +MaterialVonMisesMazars::computeDamageOnQuad( const Real & epsilon_equ, __attribute__((unused)) const Matrix & sigma, const Vector & epsilon_princ, Real & dam) { Real Fs = epsilon_equ - K0; if (Fs > 0.) { Real dam_t; Real dam_c; dam_t = 1 - K0 * (1 - At) / epsilon_equ - At * (exp(-Bt * (epsilon_equ - K0))); dam_c = 1 - K0 * (1 - Ac) / epsilon_equ - Ac * (exp(-Bc * (epsilon_equ - K0))); Real Cdiag; Cdiag = this->E * (1 - this->nu) / ((1 + this->nu) * (1 - 2 * this->nu)); Vector sigma_princ(3); sigma_princ(0) = Cdiag * epsilon_princ(0) + this->lambda * (epsilon_princ(1) + epsilon_princ(2)); sigma_princ(1) = Cdiag * epsilon_princ(1) + this->lambda * (epsilon_princ(0) + epsilon_princ(2)); sigma_princ(2) = Cdiag * epsilon_princ(2) + this->lambda * (epsilon_princ(1) + epsilon_princ(0)); Vector sigma_p(3); for (UInt i = 0; i < 3; i++) sigma_p(i) = std::max(Real(0.), sigma_princ(i)); // sigma_p *= 1. - dam; Real trace_p = this->nu / this->E * (sigma_p(0) + sigma_p(1) + sigma_p(2)); Real alpha_t = 0; for (UInt i = 0; i < 3; ++i) { Real epsilon_t = (1 + this->nu) / this->E * sigma_p(i) - trace_p; Real epsilon_p = std::max(Real(0.), epsilon_princ(i)); alpha_t += epsilon_t * epsilon_p; } alpha_t /= epsilon_equ * epsilon_equ; alpha_t = std::min(alpha_t, Real(1.)); Real alpha_c = 1. - alpha_t; alpha_t = std::pow(alpha_t, beta); alpha_c = std::pow(alpha_c, beta); Real damtemp; damtemp = alpha_t * dam_t + alpha_c * dam_c; dam = std::max(damtemp, dam); dam = std::min(dam, Real(1.)); } } } // namespace akantu diff --git a/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.cc b/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.cc index a468b177d..7d40076a9 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.cc @@ -1,205 +1,193 @@ /** * @file material_plastic.cc * * @author Mohit Pundir * * @date creation: Wed Sep 09 2020 * @date last modification: Wed Sep 09 2020 * * @brief Implementation of the akantu::MaterialDruckerPrager class * * * Copyright (©) 2014-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_drucker_prager.hh" /* -------------------------------------------------------------------------- */ namespace akantu { -template +template MaterialDruckerPrager::MaterialDruckerPrager( SolidMechanicsModel & model, const ID & id) - : MaterialPlastic(model, id) { + : MaterialPlastic(model, id) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template -MaterialDruckerPrager:: - MaterialDruckerPrager(SolidMechanicsModel & model, UInt dim, - const Mesh & mesh, FEEngine & fe_engine, - const ID & id) +MaterialDruckerPrager::MaterialDruckerPrager( + SolidMechanicsModel & model, UInt dim, const Mesh & mesh, + FEEngine & fe_engine, const ID & id) : MaterialPlastic(model, dim, mesh, fe_engine, id) { AKANTU_DEBUG_IN(); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -template +template void MaterialDruckerPrager::initialize() { this->registerParam("phi", phi, Real(0.), _pat_parsable | _pat_modifiable, - "Internal friction angle in degrees"); + "Internal friction angle in degrees"); this->registerParam("fc", fc, Real(1.), _pat_parsable | _pat_modifiable, - "Compressive strength"); + "Compressive strength"); this->registerParam("radial_return", radial_return_mapping, bool(true), - _pat_parsable | _pat_modifiable, - "Radial return mapping"); + _pat_parsable | _pat_modifiable, "Radial return mapping"); - this->updateInternalParameters(); } /* -------------------------------------------------------------------------- */ -template +template void MaterialDruckerPrager::updateInternalParameters() { MaterialElastic::updateInternalParameters(); - + // compute alpha and k parameters for Drucker-Prager Real phi_radian = this->phi * M_PI / 180.; - this->alpha = (6.*sin(phi_radian))/(3.-sin(phi_radian)); - Real cohesion = this->fc * (1. - sin(phi_radian))/(2.*cos(phi_radian)); - this->k = (6. * cohesion * cos(phi_radian))/(3. - sin(phi_radian)); + this->alpha = (6. * sin(phi_radian)) / (3. - sin(phi_radian)); + Real cohesion = this->fc * (1. - sin(phi_radian)) / (2. * cos(phi_radian)); + this->k = (6. * cohesion * cos(phi_radian)) / (3. - sin(phi_radian)); } /* -------------------------------------------------------------------------- */ -template +template void MaterialDruckerPrager::computeStress( ElementType el_type, GhostType ghost_type) { - + AKANTU_DEBUG_IN(); - MaterialThermal::computeStress(el_type, ghost_type); // infinitesimal and finite deformation auto sigma_th_it = this->sigma_th(el_type, ghost_type).begin(); auto previous_sigma_th_it = this->sigma_th.previous(el_type, ghost_type).begin(); auto previous_gradu_it = this->gradu.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto previous_stress_it = this->stress.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto inelastic_strain_it = this->inelastic_strain(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto previous_inelastic_strain_it = this->inelastic_strain.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); // // Finite Deformations // if (this->finite_deformation) { auto previous_piola_kirchhoff_2_it = this->piola_kirchhoff_2.previous(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto green_strain_it = this->green_strain(el_type, ghost_type) .begin(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); auto & inelastic_strain_tensor = *inelastic_strain_it; auto & previous_inelastic_strain_tensor = *previous_inelastic_strain_it; auto & previous_grad_u = *previous_gradu_it; auto & previous_sigma = *previous_piola_kirchhoff_2_it; auto & green_strain = *green_strain_it; this->template gradUToE(grad_u, green_strain); Matrix previous_green_strain(spatial_dimension, spatial_dimension); this->template gradUToE(previous_grad_u, - previous_green_strain); + previous_green_strain); Matrix F_tensor(spatial_dimension, spatial_dimension); this->template gradUToF(grad_u, F_tensor); computeStressOnQuad(green_strain, previous_green_strain, sigma, previous_sigma, inelastic_strain_tensor, previous_inelastic_strain_tensor, *sigma_th_it, *previous_sigma_th_it, F_tensor); ++sigma_th_it; ++inelastic_strain_it; ++previous_sigma_th_it; //++previous_stress_it; ++previous_gradu_it; ++green_strain_it; ++previous_inelastic_strain_it; ++previous_piola_kirchhoff_2_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } // Infinitesimal deformations else { MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); auto & inelastic_strain_tensor = *inelastic_strain_it; auto & previous_inelastic_strain_tensor = *previous_inelastic_strain_it; auto & previous_grad_u = *previous_gradu_it; auto & previous_sigma = *previous_stress_it; computeStressOnQuad( grad_u, previous_grad_u, sigma, previous_sigma, inelastic_strain_tensor, previous_inelastic_strain_tensor, *sigma_th_it, *previous_sigma_th_it); ++sigma_th_it; ++inelastic_strain_it; ++previous_sigma_th_it; ++previous_stress_it; ++previous_gradu_it; ++previous_inelastic_strain_it; - + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; } AKANTU_DEBUG_OUT(); - AKANTU_DEBUG_OUT(); } - /* -------------------------------------------------------------------------- */ -template +template void MaterialDruckerPrager::computeTangentModuli( - __attribute__((unused)) const ElementType & el_type, - __attribute__((unused)) Array & tangent_matrix, - __attribute__((unused)) GhostType ghost_type) { - + ElementType /*el_type*/, Array & /*tangent_matrix*/, + GhostType /*ghost_type*/) { AKANTU_DEBUG_IN(); - AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ -INSTANTIATE_MATERIAL(plastic_drucker_prager, - MaterialDruckerPrager); +INSTANTIATE_MATERIAL(plastic_drucker_prager, MaterialDruckerPrager); - } // namespace akantu - diff --git a/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.hh b/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.hh index b03908395..b44efa9b6 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.hh +++ b/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager.hh @@ -1,145 +1,145 @@ /** * @file material_drucker_pruger.hh * * @author Mohit Pundir * * @date creation: Wed Sep 09 2020 * @date last modification: Wed Sep 09 2020 * * @brief Specialization of the material class for isotropic * plasticity with Drucker-Pruger yield criterion * * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_voigthelper.hh" #include "material_plastic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_DRUCKER_PRAGER_HH__ #define __AKANTU_MATERIAL_DRUCKER_PRAGER_HH__ namespace akantu { /** * Material plastic with a Drucker-pruger yield criterion */ template class MaterialDruckerPrager : public MaterialPlastic { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialDruckerPrager(SolidMechanicsModel & model, const ID & id = ""); MaterialDruckerPrager(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); protected: using voigt_h = VoigtHelper; void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// constitutive law for all element of a type void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override; /// compute the tangent stiffness matrix for an element type - void computeTangentModuli(const ElementType & el_type, + void computeTangentModuli(ElementType el_type, Array & tangent_matrix, GhostType ghost_type = _not_ghost) override; protected: /// Infinitesimal deformations inline void computeStressOnQuad( const Matrix & grad_u, const Matrix & previous_grad_u, Matrix & sigma, const Matrix & previous_sigma, Matrix & inelas_strain, const Matrix & previous_inelas_strain, const Real & sigma_th, const Real & previous_sigma_th); /// Finite deformations inline void computeStressOnQuad( const Matrix & grad_u, const Matrix & previous_grad_u, Matrix & sigma, const Matrix & previous_sigma, Matrix & inelas_strain, const Matrix & previous_inelas_strain, const Real & sigma_th, const Real & previous_sigma_th, const Matrix & F_tensor); inline void computeTangentModuliOnQuad( Matrix & tangent, const Matrix & grad_u, const Matrix & previous_grad_u, const Matrix & sigma_tensor, const Matrix & previous_sigma_tensor) const; inline Real computeYieldFunction(const Matrix & sigma); inline Real computeYieldStress(const Matrix & sigma); inline void computeDeviatoricStress(const Matrix & sigma, Matrix & sigma_dev); /// rcompute the alpha and k parameters void updateInternalParameters() override; public: // closet point projection method to compute stress state on the // yield surface inline void computeGradientAndPlasticMultplier( const Matrix & sigma_tr, Real & plastic_multiplier_guess, Vector & gradient_f, Vector & delta_inelastic_strain, UInt max_iterations = 100, Real tolerance = 1e-10); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: // Internal friction angle of the material Real phi; // Compressive strength of the material Real fc; // modified friction angle for Drucker-Prager Real alpha; // modified compressive strength for Drucker-Prager Real k; // radial return mapping bool radial_return_mapping; }; } // namespace akantu #include "material_drucker_prager_inline_impl.hh" #endif /*__AKANTU_MATERIAL_DRUCKER_PRAGER_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager_inline_impl.hh b/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager_inline_impl.hh index 779b97f5c..6e0bb33b9 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager_inline_impl.hh +++ b/src/model/solid_mechanics/materials/material_plastic/material_drucker_prager_inline_impl.hh @@ -1,468 +1,468 @@ /** * @file material_linear_isotropic_hardening_inline_impl.hh * * @author Mohit Pundir * * @date creation: Wed Sep 09 2020 * @date last modification: Wed Sep 09 2020 * * @brief Implementation of the inline functions of the material * Drucker-Prager * * * Copyright (©) 2014-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ #include "material_drucker_prager.hh" namespace akantu { /* -------------------------------------------------------------------------- */ /// Deviatoric Stress template inline void MaterialDruckerPrager::computeDeviatoricStress(const Matrix & sigma, Matrix & sigma_dev){ for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) sigma_dev(i, j) = sigma(i, j); sigma_dev -= Matrix::eye(dim, sigma.trace() / dim); } /* -------------------------------------------------------------------------- */ /// Yield Stress template inline Real MaterialDruckerPrager::computeYieldStress(const Matrix & sigma) { return this->alpha * sigma.trace() - this->k; } /* -------------------------------------------------------------------------- */ /// Yield function template inline Real MaterialDruckerPrager::computeYieldFunction(const Matrix & sigma) { Matrix sigma_dev(dim, dim, 0); this->computeDeviatoricStress(sigma, sigma_dev); // compute deviatoric invariant J2 Real j2 = (1./ 2.) * sigma_dev.doubleDot(sigma_dev); Real sigma_dev_eff = std::sqrt(3. * j2); Real modified_yield_stress = computeYieldStress(sigma); return sigma_dev_eff + modified_yield_stress; } /* -------------------------------------------------------------------------- */ template inline void MaterialDruckerPrager::computeGradientAndPlasticMultplier( const Matrix & sigma_trial, Real & plastic_multiplier_guess, Vector & gradient_f, Vector & delta_inelastic_strain, UInt max_iterations, Real tolerance) { UInt size = voigt_h::size; // guess stress state at each iteration, initial guess is the trial state Matrix sigma_guess(sigma_trial); // plastic multiplier guess at each iteration, initial guess is zero plastic_multiplier_guess = 0.; // gradient of yield surface in voigt notation - gradient_f.clear(); + gradient_f.zero(); // plastic strain increment at each iteration - delta_inelastic_strain.clear(); + delta_inelastic_strain.zero(); // variation in sigma at each iteration Vector delta_sigma(size, 0.); // krocker delta vector in voigt notation Vector kronecker_delta(size, 0.); for(auto i : arange(dim)) kronecker_delta[i] = 1.; // hessian matrix of yield surface Matrix hessian_f(size, size, 0.); // scaling matrix for computing gradient and hessian from voigt notation Matrix scaling_matrix(size, size, 0.); scaling_matrix.eye(1.); for(auto i : arange(dim, size)) for(auto j : arange(dim, size)) scaling_matrix(i, j) *= 2.; // elastic stifnness tensor Matrix De(size, size, 0.); MaterialElastic::computeTangentModuliOnQuad(De); // elastic compliance tensor Matrix Ce(size, size, 0.); Ce.inverse(De); // objective function to be computed Vector f(size, 0.); // yield function value at each iteration Real yield_function; // if sigma is above the threshold value auto above_threshold = [&sigma_guess](Real & k, Real & alpha) { Real I1 = sigma_guess.trace(); return I1 >= k/alpha; }; // to project stress state at origin of yield function if first // invariant is greater than the threshold if(above_threshold(k, alpha) and this->alpha > 0) { auto update_first_obj = [&sigma_guess]() { //const UInt dimension = sigma_guess.cols(); Matrix sigma_dev(dim, dim, 0); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) sigma_dev(i, j) = sigma_guess(i, j); sigma_dev -= Matrix::eye(dim, sigma_guess.trace() / dim); auto error = (1./2) *sigma_dev.doubleDot(sigma_dev); return error; }; auto update_sec_obj = [&sigma_guess](Real & k, Real & alpha) { auto error = alpha*sigma_guess.trace() - k; return error; }; auto projection_error = update_first_obj(); while(tolerance < projection_error) { Matrix delta_sigma(dim, dim); Matrix jacobian(dim, dim); Matrix jacobian_inv(dim, dim); Matrix sigma_dev(dim, dim, 0); this->computeDeviatoricStress(sigma_guess, sigma_dev); jacobian_inv.inverse(sigma_dev); delta_sigma = -projection_error * jacobian_inv; sigma_guess += delta_sigma; projection_error = update_first_obj(); } projection_error = update_sec_obj(k, alpha); while(tolerance < projection_error) { Matrix delta_sigma(dim, dim); Matrix jacobian(dim, dim); Matrix jacobian_inv(dim, dim); jacobian = this->alpha * Matrix::eye(dim, dim); jacobian_inv.inverse(jacobian); delta_sigma += -projection_error * jacobian_inv; sigma_guess += delta_sigma; projection_error = update_sec_obj(k, alpha); } auto delta_sigma_final = sigma_trial - sigma_guess; auto delta_sigma_voigt = voigt_h::matrixToVoigt(delta_sigma_final); delta_inelastic_strain.mul(Ce, delta_sigma_voigt); return; } // lambda function to compute gradient of yield surface in voigt notation auto compute_gradient_f = [&sigma_guess, &scaling_matrix, &kronecker_delta, &gradient_f](Real & alpha){ //const UInt dimension = sigma_guess.cols(); Matrix sigma_dev(dim, dim, 0); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) sigma_dev(i, j) = sigma_guess(i, j); sigma_dev -= Matrix::eye(dim, sigma_guess.trace() / dim); Vector sigma_dev_voigt = voigt_h::matrixToVoigt(sigma_dev); // compute deviatoric invariant Real j2 = (1./2.) * sigma_dev.doubleDot(sigma_dev); gradient_f.mul(scaling_matrix, sigma_dev_voigt, 3./ (2. * std::sqrt(3. * j2)) ); gradient_f += alpha * kronecker_delta; }; // lambda function to compute hessian matrix of yield surface auto compute_hessian_f = [&sigma_guess, &hessian_f, &scaling_matrix, &kronecker_delta](){ Matrix sigma_dev(dim, dim, 0); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) sigma_dev(i, j) = sigma_guess(i, j); sigma_dev -= Matrix::eye(dim, sigma_guess.trace() / dim); auto sigma_dev_voigt = voigt_h::matrixToVoigt(sigma_dev); // compute deviatoric invariant J2 Real j2 = (1./2.) * sigma_dev.doubleDot(sigma_dev); Vector temp(sigma_dev_voigt.size()); temp.mul(scaling_matrix, sigma_dev_voigt); Matrix id(kronecker_delta.size(), kronecker_delta.size()); id.outerProduct(kronecker_delta, kronecker_delta); id *= -1./3.; id += Matrix::eye(kronecker_delta.size(), 1.); Matrix tmp3(kronecker_delta.size(), kronecker_delta.size()); tmp3.mul(scaling_matrix, id); hessian_f.outerProduct(temp, temp); hessian_f *= -9./(4.* pow(3.*j2, 3./2.)); hessian_f += (3./(2.* pow(3.*j2, 1./2.)))*tmp3; }; /* --------------------------- */ /* init before iteration loop */ /* --------------------------- */ auto update_f = [&f, &sigma_guess, &sigma_trial, &plastic_multiplier_guess, &Ce, &De, &yield_function, &gradient_f, &delta_inelastic_strain, &compute_gradient_f](Real & k, Real & alpha){ // compute gradient compute_gradient_f(alpha); // compute yield function Matrix sigma_dev(dim, dim, 0); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) sigma_dev(i, j) = sigma_guess(i, j); sigma_dev -= Matrix::eye(dim, sigma_guess.trace() / dim); Real j2 = (1./ 2.) * sigma_dev.doubleDot(sigma_dev); Real sigma_dev_eff = std::sqrt(3. * j2); Real modified_yield_stress = alpha * sigma_guess.trace() - k; yield_function = sigma_dev_eff + modified_yield_stress; // compute increment strain auto sigma_trial_voigt = voigt_h::matrixToVoigt(sigma_trial); auto sigma_guess_voigt = voigt_h::matrixToVoigt(sigma_guess); auto tmp = sigma_trial_voigt - sigma_guess_voigt; delta_inelastic_strain.mul(Ce, tmp); // compute objective function f.mul(De, gradient_f, plastic_multiplier_guess); f = tmp - f; // compute error auto error = std::max(f.norm(), std::abs(yield_function)); return error; }; Real alpha_tmp{alpha}; Real k_tmp{k}; if(radial_return_mapping){ alpha_tmp = 0; k_tmp = std::abs(alpha*sigma_guess.trace() - k); } auto projection_error = update_f(k_tmp , alpha_tmp); /* --------------------------- */ /* iteration loop */ /* --------------------------- */ Matrix xi(size, size); Matrix xi_inv(size, size); Vector tmp(size); Vector tmp1(size); Matrix tmp2(size, size); UInt iterations{0}; while(tolerance < projection_error and iterations < max_iterations) { // compute hessian at previous step compute_hessian_f(); // compute inverse matrix Xi xi = Ce + plastic_multiplier_guess * hessian_f; // compute inverse matrix Xi xi_inv.inverse(xi); tmp.mul(xi_inv, gradient_f); auto denominator = gradient_f.dot(tmp); // compute plastic multplier guess tmp1.mul(xi_inv, delta_inelastic_strain); plastic_multiplier_guess = gradient_f.dot(tmp1); plastic_multiplier_guess += yield_function; plastic_multiplier_guess /= denominator; // compute delta sigma tmp2.outerProduct(tmp, tmp); tmp2 /= denominator; tmp2 = xi_inv - tmp2; delta_sigma.mul(tmp2, delta_inelastic_strain); delta_sigma -= tmp*yield_function/denominator; // compute sigma_guess Matrix delta_sigma_mat(dim, dim); voigt_h::voigtToMatrix(delta_sigma, delta_sigma_mat); sigma_guess += delta_sigma_mat; projection_error = update_f(k_tmp, alpha_tmp); iterations++; } } /* -------------------------------------------------------------------------- */ /// Infinitesimal deformations template inline void MaterialDruckerPrager::computeStressOnQuad( const Matrix & grad_u, const Matrix & previous_grad_u, Matrix & sigma, const Matrix & previous_sigma, Matrix & inelastic_strain, const Matrix & previous_inelastic_strain, const Real & sigma_th, const Real & previous_sigma_th) { Real delta_sigma_th = sigma_th - previous_sigma_th; Matrix grad_delta_u(grad_u); grad_delta_u -= previous_grad_u; // Compute trial stress, sigma_tr Matrix sigma_tr(dim, dim); MaterialElastic::computeStressOnQuad(grad_delta_u, sigma_tr, delta_sigma_th); sigma_tr += previous_sigma; // Compute the yielding sress /*Real yield_stress = computeYieldStress(sigma_tr); Matrix sigma_tr_dev(dim, dim, 0); this->computeDeviatoricStress(sigma_tr, sigma_tr_dev); Real j2 = (1./ 2.) * sigma_tr_dev.doubleDot(sigma_tr_dev); Real sigma_tr_dev_eff = std::sqrt(3. * j2); bool initial_yielding = ((sigma_tr_dev_eff + yield_stress) > 0);*/ bool initial_yielding = (this->computeYieldFunction(sigma_tr) > 0); // use closet point projection to compute the plastic multiplier and // gradient and inealstic strain at the surface for the given trial stress state Matrix delta_inelastic_strain(dim, dim, 0.); if(initial_yielding) { UInt size = voigt_h::size; // plastic multiplier Real dp{0.}; // gradient of yield surface in voigt notation Vector gradient_f(size, 0.); // inelastic strain in voigt notation Vector delta_inelastic_strain_voigt(size, 0.); // compute using closet-point projection this->computeGradientAndPlasticMultplier(sigma_tr, dp, gradient_f, delta_inelastic_strain_voigt); for(auto i: arange(dim, size)) delta_inelastic_strain_voigt[i] /= 2.; voigt_h::voigtToMatrix(delta_inelastic_strain_voigt, delta_inelastic_strain); } // Compute the increment in inelastic strain MaterialPlastic::computeStressAndInelasticStrainOnQuad( grad_delta_u, sigma, previous_sigma, inelastic_strain, previous_inelastic_strain, delta_inelastic_strain); } /* -------------------------------------------------------------------------- */ /// Finite deformations template inline void MaterialDruckerPrager::computeStressOnQuad( __attribute__((unused)) const Matrix & grad_u, __attribute__((unused)) const Matrix & previous_grad_u, __attribute__((unused)) Matrix & sigma, __attribute__((unused)) const Matrix & previous_sigma, __attribute__((unused)) Matrix & inelastic_strain, __attribute__((unused)) const Matrix & previous_inelastic_strain, __attribute__((unused)) const Real & sigma_th, __attribute__((unused)) const Real & previous_sigma_th, __attribute__((unused)) const Matrix & F_tensor) { } /* -------------------------------------------------------------------------- */ template inline void MaterialDruckerPrager::computeTangentModuliOnQuad( __attribute__((unused)) Matrix & tangent, __attribute__((unused)) const Matrix & grad_u, __attribute__((unused)) const Matrix & previous_grad_u, __attribute__((unused)) const Matrix & sigma_tensor, __attribute__((unused)) const Matrix & previous_sigma_tensor) const { } } diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc index d163d49e2..839381543 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear_friction.cc @@ -1,280 +1,280 @@ /** * @file material_cohesive_linear_friction.cc * * @author Mauro Corrado * * @date creation: Tue Jan 12 2016 * @date last modification: Wed Feb 21 2018 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * * Copyright (©) 2015-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear_friction.hh" #include "solid_mechanics_model_cohesive.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template MaterialCohesiveLinearFriction:: MaterialCohesiveLinearFriction(SolidMechanicsModel & model, const ID & id) : MaterialParent(model, id), residual_sliding("residual_sliding", *this), friction_force("friction_force", *this) { AKANTU_DEBUG_IN(); this->registerParam("mu", mu_max, Real(0.), _pat_parsable | _pat_readable, "Maximum value of the friction coefficient"); this->registerParam("penalty_for_friction", friction_penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty parameter for the friction behavior"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinearFriction::initMaterial() { AKANTU_DEBUG_IN(); MaterialParent::initMaterial(); friction_force.initialize(spatial_dimension); residual_sliding.initialize(1); residual_sliding.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinearFriction::computeTraction( __attribute__((unused)) const Array & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); residual_sliding.resize(); friction_force.resize(); /// define iterators auto traction_it = this->tractions(el_type, ghost_type).begin(spatial_dimension); auto traction_end = this->tractions(el_type, ghost_type).end(spatial_dimension); auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); auto previous_opening_it = this->opening.previous(el_type, ghost_type).begin(spatial_dimension); auto contact_traction_it = this->contact_tractions(el_type, ghost_type).begin(spatial_dimension); auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = this->normal.begin(spatial_dimension); auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); auto delta_max_it = this->delta_max(el_type, ghost_type).begin(); auto delta_max_prev_it = this->delta_max.previous(el_type, ghost_type).begin(); auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); auto damage_it = this->damage(el_type, ghost_type).begin(); auto insertion_stress_it = this->insertion_stress(el_type, ghost_type).begin(spatial_dimension); auto res_sliding_it = this->residual_sliding(el_type, ghost_type).begin(); auto res_sliding_prev_it = this->residual_sliding.previous(el_type, ghost_type).begin(); auto friction_force_it = this->friction_force(el_type, ghost_type).begin(spatial_dimension); Vector normal_opening(spatial_dimension); Vector tangential_opening(spatial_dimension); if (not this->model->isDefaultSolverExplicit()) { this->delta_max(el_type, ghost_type) .copy(this->delta_max.previous(el_type, ghost_type)); } /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, ++delta_max_prev_it, ++res_sliding_it, ++res_sliding_prev_it, ++friction_force_it, ++previous_opening_it) { Real normal_opening_norm; Real tangential_opening_norm; bool penetration; this->computeTractionOnQuad( *traction_it, *opening_it, *normal_it, *delta_max_it, *delta_c_it, *insertion_stress_it, *sigma_c_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *contact_traction_it, *contact_opening_it); if (penetration) { /// the friction coefficient mu increases with the damage. It /// equals the maximum value when damage = 1. // Real damage = std::min(*delta_max_prev_it / *delta_c_it, // Real(1.)); Real mu = mu_max; // * damage; /// the definition of tau_max refers to the opening /// (penetration) of the previous incremental step - Real normal_opening_prev_norm = - std::min(previous_opening_it->dot(*normal_it), Real(0.)); + //Real normal_opening_prev_norm = + // std::min(previous_opening_it->dot(*normal_it), Real(0.)); // Vector normal_opening_prev = (*normal_it); // normal_opening_prev *= normal_opening_prev_norm; Real tau_max = mu * this->penalty * (std::abs(normal_opening_norm)); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); /// tau is the norm of the friction force, acting tangentially to the /// surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if ((tangential_opening_norm - *res_sliding_prev_it) < 0.0) { tau = -tau; } /// from tau get the x and y components of friction, to be added in the /// force vector Vector tangent_unit_vector(spatial_dimension); tangent_unit_vector = tangential_opening / tangential_opening_norm; *friction_force_it = tau * tangent_unit_vector; /// update residual_sliding *res_sliding_it = tangential_opening_norm - (std::abs(tau) / friction_penalty); } else { friction_force_it->zero(); } *traction_it += *friction_force_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinearFriction::computeTangentTraction( ElementType el_type, Array & tangent_matrix, __attribute__((unused)) const Array & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); auto tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); auto normal_it = this->normal.begin(spatial_dimension); auto opening_it = this->opening(el_type, ghost_type).begin(spatial_dimension); auto previous_opening_it = this->opening.previous(el_type, ghost_type).begin(spatial_dimension); /** * NB: delta_max_it points on delta_max_previous, i.e. the * delta_max related to the solution of the previous incremental * step */ auto delta_max_it = this->delta_max.previous(el_type, ghost_type).begin(); auto sigma_c_it = this->sigma_c_eff(el_type, ghost_type).begin(); auto delta_c_it = this->delta_c_eff(el_type, ghost_type).begin(); auto damage_it = this->damage(el_type, ghost_type).begin(); auto contact_opening_it = this->contact_opening(el_type, ghost_type).begin(spatial_dimension); auto res_sliding_prev_it = this->residual_sliding.previous(el_type, ghost_type).begin(); Vector normal_opening(spatial_dimension); Vector tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++previous_opening_it, ++delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it, ++res_sliding_prev_it) { Real normal_opening_norm; Real tangential_opening_norm; bool penetration; this->computeTangentTractionOnQuad( *tangent_it, *delta_max_it, *delta_c_it, *sigma_c_it, *opening_it, *normal_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *contact_opening_it); if (penetration) { // Real damage = std::min(*delta_max_it / *delta_c_it, Real(1.)); Real mu = mu_max; // * damage; Real normal_opening_prev_norm = std::min(previous_opening_it->dot(*normal_it), Real(0.)); // Vector normal_opening_prev = (*normal_it); // normal_opening_prev *= normal_opening_prev_norm; Real tau_max = mu * this->penalty * (std::abs(normal_opening_prev_norm)); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); // tau is the norm of the friction force, acting tangentially to the // surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if (tau < tau_max && tau_max > Math::getTolerance()) { Matrix I(spatial_dimension, spatial_dimension); I.eye(1.); Matrix n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); Matrix nn(n_outer_n); I -= nn; *tangent_it += I * friction_penalty; } } // check if the tangential stiffness matrix is symmetric // for (UInt h = 0; h < spatial_dimension; ++h){ // for (UInt l = h; l < spatial_dimension; ++l){ // if (l > h){ // Real k_ls = (*tangent_it)[spatial_dimension*h+l]; // Real k_us = (*tangent_it)[spatial_dimension*l+h]; // // std::cout << "k_ls = " << k_ls << std::endl; // // std::cout << "k_us = " << k_us << std::endl; // if (std::abs(k_ls) > 1e-13 && std::abs(k_us) > 1e-13){ // Real error = std::abs((k_ls - k_us) / k_us); // if (error > 1e-10){ // std::cout << "non symmetric cohesive matrix" << std::endl; // // std::cout << "error " << error << std::endl; // } // } // } // } // } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(cohesive_linear_friction, MaterialCohesiveLinearFriction); } // namespace akantu