diff --git a/.gitignore b/.gitignore index a3fea6cfd..be850e87b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,17 @@ build* .dir-locals.el TAGS third-party/blackdynamite/ third-party/pybind11 third-party/google-test third-party/cpp-array/ *~ release .*.swp *.tar.gz *.tgz *.tbz *.tar.bz2 .idea -__pycache__ \ No newline at end of file +__pycache__ +.mailmap diff --git a/cmake/AkantuTestsMacros.cmake b/cmake/AkantuTestsMacros.cmake index 5bb3036fd..98d765e38 100644 --- a/cmake/AkantuTestsMacros.cmake +++ b/cmake/AkantuTestsMacros.cmake @@ -1,624 +1,624 @@ #=============================================================================== # @file AkantuTestsMacros.cmake # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Fri Sep 03 2010 # @date last modification: Fri Jan 22 2016 # # @brief macros for tests # # @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 <http://www.gnu.org/licenses/>. # #=============================================================================== #[=======================================================================[.rst: AkantuTestsMacros ----------------- This modules provides the functions to helper to declare tests and folders containing tests in akantu .. command:: add_test_tree add_test_tree(<test_direcotry>) ``<test_directory>`` is the entry direcroty of the full structure of subfolders containing tests .. command:: add_akantu_test add_akantu_test(<dir> <desc>) This function add a subdirectory ``<dir>`` of tests that will be conditionnaly activable and will be visible only if the parent folder as been activated An option ``AKANTU_BUILD_TEST_<dir>`` will appear in ccmake with the description ``<desc>``. The compilation of all tests can be forced with the option ``AKANTU_BUILD_ALL_TESTS`` .. command:: register_test register_test(<test_name> SOURCES <sources>... PACKAGE <akantu_packages>... SCRIPT <scirpt> [FILES_TO_COPY <filenames>...] [DEPENDS <targets>...] [DIRECTORIES_TO_CREATE <directories>...] [COMPILE_OPTIONS <flags>...] [EXTRA_FILES <filnames>...] [LINK_LIBRARIES <libraries>...] [INCLUDE_DIRECTORIES <include>...] [UNSABLE] [PARALLEL] [PARALLEL_LEVEL <procs>...] ) This function defines a test ``<test_name>_run`` this test could be of different nature depending on the context. If Just sources are provided the test consist of running the executable generated. If a file ``<test_name>.sh`` is present the test will execute the script. And if a ``<test_name>.verified`` exists the output of the test will be compared to this reference file The options are: ``SOURCES <sources>...`` The list of source files to compile to generate the executable of the test ``PACKAGE <akantu_packages>...`` The list of package to which this test belongs. The test will be activable only of all the packages listed are activated ``SCRIPT <script>`` The script to execute instead of the executable ``FILES_TO_COPY <filenames>...`` List of files to copy from the source directory to the build directory ``DEPENDS <targets>...`` List of targets the test depends on, for example if a mesh as to be generated ``DIRECTORIES_TO_CREATE <directories>...`` Obsolete. This specifies a list of directories that have to be created in the build folder ``COMPILE_OPTIONS <flags>...`` List of extra compilations options to pass to the compiler ``EXTRA_FILES <filnames>...`` Files to consider when generating a package_source ``UNSABLE`` If this option is specified the test can be unacitivated by the glocal option ``AKANTU_BUILD_UNSTABLE_TESTS``, this is mainly intendeed to remove test under developement from the continious integration ``PARALLEL`` This specifies that this test should be run in parallel. It will generate a series of test for different number of processors. This automaticaly adds a dependency to the package ``AKANTU_PARALLEL`` ``PARALLEL_LEVEL`` This defines the different processor numbers to use, if not defined the macro tries to determine it in a "clever" way ]=======================================================================] set(AKANTU_DRIVER_SCRIPT ${AKANTU_CMAKE_DIR}/akantu_test_driver.sh) # ============================================================================== macro(add_test_tree dir) if(AKANTU_TESTS) enable_testing() include(CTest) mark_as_advanced(BUILD_TESTING) set(_akantu_current_parent_test ${dir} CACHE INTERNAL "Current test folder" FORCE) set(_akantu_${dir}_tests_count 0 CACHE INTERNAL "" FORCE) string(TOUPPER ${dir} _u_dir) set(AKANTU_BUILD_${_u_dir} ON CACHE INTERNAL "${desc}" FORCE) package_get_all_test_folders(_test_dirs) foreach(_dir ${_test_dirs}) add_subdirectory(${_dir}) endforeach() endif() endmacro() set(_test_flags UNSTABLE PARALLEL PYTHON HEADER_ONLY ) set(_test_one_variables POSTPROCESS SCRIPT ) set(_test_multi_variables SOURCES FILES_TO_COPY DEPENDS DIRECTORIES_TO_CREATE COMPILE_OPTIONS EXTRA_FILES LINK_LIBRARIES INCLUDE_DIRECTORIES PACKAGE PARALLEL_LEVEL ) # ============================================================================== function(add_akantu_test dir desc) if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}) return() endif() set(_my_parent_dir ${_akantu_current_parent_test}) # initialize variables set(_akantu_current_parent_test ${dir} CACHE INTERNAL "Current test folder" FORCE) set(_akantu_${dir}_tests_count 0 CACHE INTERNAL "" FORCE) # set the option for this directory string(TOUPPER ${dir} _u_dir) option(AKANTU_BUILD_${_u_dir} "${desc}") mark_as_advanced(AKANTU_BUILD_${_u_dir}) # add the sub-directory add_subdirectory(${dir}) # if no test can be activated make the option disappear set(_force_deactivate_count FALSE) if(${_akantu_${dir}_tests_count} EQUAL 0) set(_force_deactivate_count TRUE) endif() # if parent off make the option disappear set(_force_deactivate_parent FALSE) string(TOUPPER ${_my_parent_dir} _u_parent_dir) if(NOT AKANTU_BUILD_${_u_parent_dir}) set(_force_deactivate_parent TRUE) endif() if(_force_deactivate_parent OR _force_deactivate_count OR AKANTU_BUILD_ALL_TESTS) if(NOT DEFINED _AKANTU_BUILD_${_u_dir}_SAVE) set(_AKANTU_BUILD_${_u_dir}_SAVE ${AKANTU_BUILD_${_u_dir}} CACHE INTERNAL "" FORCE) endif() unset(AKANTU_BUILD_${_u_dir} CACHE) if(AKANTU_BUILD_ALL_TESTS AND NOT _force_deactivate_count) set(AKANTU_BUILD_${_u_dir} ON CACHE INTERNAL "${desc}" FORCE) else() set(AKANTU_BUILD_${_u_dir} OFF CACHE INTERNAL "${desc}" FORCE) endif() else() if(DEFINED _AKANTU_BUILD_${_u_dir}_SAVE) unset(AKANTU_BUILD_${_u_dir} CACHE) set(AKANTU_BUILD_${_u_dir} ${_AKANTU_BUILD_${_u_dir}_SAVE} CACHE BOOL "${desc}") unset(_AKANTU_BUILD_${_u_dir}_SAVE CACHE) endif() endif() # adding up to the parent count math(EXPR _tmp_parent_count "${_akantu_${dir}_tests_count} + ${_akantu_${_my_parent_dir}_tests_count}") set(_akantu_${_my_parent_dir}_tests_count ${_tmp_parent_count} CACHE INTERNAL "" FORCE) # restoring the parent current dir set(_akantu_current_parent_test ${_my_parent_dir} CACHE INTERNAL "Current test folder" FORCE) endfunction() function(is_test_active is_active) cmake_parse_arguments(_register_test "${_test_flags}" "${_test_one_variables}" "${_test_multi_variables}" ${ARGN} ) if(NOT _register_test_PACKAGE) message(FATAL_ERROR "No reference package was defined for the test" " ${test_name} in folder ${CMAKE_CURRENT_SOURCE_DIR}") endif() set(_test_act TRUE) # Activate the test anly if all packages associated to the test are activated foreach(_package ${_register_test_PACKAGE}) package_is_activated(${_package} _act) if(NOT _act) set(_test_act FALSE) endif() endforeach() # check if the test is marked unstable and if the unstable test should be run if(_register_test_UNSTABLE AND NOT AKANTU_BUILD_UNSTABLE_TESTS) set(_test_act FALSE) endif() if(_test_act) # todo this should be checked for the build package_sources since the file will not be listed. math(EXPR _tmp_parent_count "${_akantu_${_akantu_current_parent_test}_tests_count} + 1") set(_akantu_${_akantu_current_parent_test}_tests_count ${_tmp_parent_count} CACHE INTERNAL "" FORCE) endif() string(TOUPPER ${_akantu_current_parent_test} _u_parent) if(NOT (AKANTU_BUILD_${_u_parent} OR AKANTU_BUILD_ALL_TESTS)) set(_test_act FALSE) endif() set(${is_active} ${_test_act} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ function(register_gtest_sources) cmake_parse_arguments(_register_test "${_test_flags}" "${_test_one_variables}" "${_test_multi_variables}" ${ARGN} ) is_test_active(_is_active ${ARGN}) register_test_files_to_package(${ARGN}) if(NOT _is_active) return() endif() if(_register_test_PACKAGE) set(_list ${_gtest_PACKAGE}) list(APPEND _list ${_register_test_PACKAGE}) list(REMOVE_DUPLICATES _list) set(_gtest_PACKAGE ${_list} PARENT_SCOPE) endif() foreach (_var ${_test_flags}) if(_var STREQUAL "HEADER_ONLY") if(NOT DEFINED_register_test_${_var}) set(_gtest_${_var} OFF PARENT_SCOPE) elseif(NOT DEFINED _gtest_${_var}) set(_gtest_${_var} ON PARENT_SCOPE) endif() continue() endif() if(_register_test_${_var}) set(_gtest_${_var} ON PARENT_SCOPE) else() if(_gtest_${_var}) message("Another gtest file required ${_var} to be ON it will be globally set for this folder...") endif() endif() endforeach() if(_register_test_UNPARSED_ARGUMENTS) list(APPEND _register_test_SOURCES ${_register_test_UNPARSED_ARGUMENTS}) endif() foreach (_var ${_test_multi_variables}) if(_register_test_${_var}) set(_list ${_gtest_${_var}}) list(APPEND _list ${_register_test_${_var}}) list(REMOVE_DUPLICATES _list) set(_gtest_${_var} ${_list} PARENT_SCOPE) endif() endforeach() endfunction() # ============================================================================== function(akantu_pybind11_add_module target) package_is_activated(pybind11 _pybind11_act) if(_pybind11_act) package_get_all_external_informations( INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR ) pybind11_add_module(${target} ${ARGN}) target_include_directories(${target} SYSTEM PRIVATE ${PYBIND11_INCLUDE_DIR} ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR}) set_property(TARGET ${target} PROPERTY DEBUG_POSTFIX "") endif() endfunction() # ============================================================================== function(register_gtest_test test_name) if(NOT _gtest_PACKAGE) return() endif() set(_argn ${test_name}_gtest) set(_link_libraries GTest::GTest GTest::Main) list(FIND _gtest_PACKAGE pybind11 _pos) package_is_activated(pybind11 _pybind11_act) if(_pybind11_act AND (NOT _pos EQUAL -1)) list(APPEND _link_libraries pybind11::embed) set(_compile_flags COMPILE_OPTIONS "AKANTU_TEST_USE_PYBIND11") endif() is_test_active(_is_active ${ARGN} PACKAGE ${_gtest_PACKAGE}) if(NOT _is_active) return() endif() register_gtest_sources(${ARGN} SOURCES ${PROJECT_SOURCE_DIR}/test/test_gtest_main.cc LINK_LIBRARIES ${_link_libraries} PACKAGE ${_gtest_PACKAGE} ${_compile_flags} ) foreach (_var ${_test_flags}) if(_gtest_${_var}) list(APPEND _argn ${_var}) unset(_gtest_${_var}) endif() endforeach() foreach (_var ${_test_multi_variables}) if(_gtest_${_var}) list(APPEND _argn ${_var} ${_gtest_${_var}}) unset(_gtest_${_var}) endif() endforeach() register_test(${_argn}) target_include_directories(${test_name}_gtest PRIVATE ${PROJECT_SOURCE_DIR}/test) endfunction() # ============================================================================== function(register_test test_name) cmake_parse_arguments(_register_test "${_test_flags}" "${_test_one_variables}" "${_test_multi_variables}" ${ARGN} ) register_test_files_to_package(${ARGN}) is_test_active(_test_act ${ARGN}) if(NOT _test_act) return() endif() set(_extra_args) # check that the sources are files that need to be compiled if(_register_test_SOURCES} OR _register_test_UNPARSED_ARGUMENTS) set(_need_to_compile TRUE) else() set(_need_to_compile FALSE) endif() set(_compile_source) foreach(_file ${_register_test_SOURCES} ${_register_test_UNPARSED_ARGUMENTS}) if(_file MATCHES "\\.cc$" OR _file MATCHES "\\.hh$") list(APPEND _compile_source ${_file}) endif() endforeach() if(_compile_source) # get the include directories for sources in activated directories package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) # get the external packages compilation and linking informations package_get_all_external_informations( INTERFACE_INCLUDE AKANTU_EXTERNAL_INCLUDE_DIR ) foreach(_pkg ${_register_test_PACKAGE}) package_get_nature(${_pkg} _nature) if(_nature MATCHES "^external.*") package_get_include_dir(${_pkg} _incl) package_get_libraries(${_pkg} _libs) list(APPEND _register_test_INCLUDE_DIRECTORIES ${_incl}) list(APPEND _register_test_LINK_LIBRARIES ${_libs}) endif() endforeach() # Register the executable to compile add_executable(${test_name} ${_compile_source}) # set the proper includes to build most of the tests target_include_directories(${test_name} PRIVATE ${AKANTU_LIBRARY_INCLUDE_DIRS} ${AKANTU_EXTERNAL_INCLUDE_DIR} ${PROJECT_BINARY_DIR}/src ${_register_test_INCLUDE_DIRECTORIES}) if(NOT _register_test_HEADER_ONLY) target_link_libraries(${test_name} PRIVATE akantu ${_register_test_LINK_LIBRARIES}) else() get_target_property(_features akantu INTERFACE_COMPILE_FEATURES) target_link_libraries(${test_name} ${_register_test_LINK_LIBRARIES}) target_compile_features(${test_name} PRIVATE ${_features}) endif() # add the extra compilation options if(_register_test_COMPILE_OPTIONS) set_target_properties(${test_name} PROPERTIES COMPILE_DEFINITIONS "${_register_test_COMPILE_OPTIONS}") endif() if(AKANTU_EXTRA_CXX_FLAGS) set_target_properties(${test_name} PROPERTIES COMPILE_FLAGS "${AKANTU_EXTRA_CXX_FLAGS}") endif() else() add_custom_target(${test_name} ALL) if(_register_test_UNPARSED_ARGUMENTS AND NOT _register_test_SCRIPT) set(_register_test_SCRIPT ${_register_test_UNPARSED_ARGUMENTS}) endif() endif() if(_register_test_DEPENDS) add_dependencies(${test_name} ${_register_test_DEPENDS}) endif() # copy the needed files to the build folder if(_register_test_FILES_TO_COPY) foreach(_file ${_register_test_FILES_TO_COPY}) file(COPY "${_file}" DESTINATION .) endforeach() endif() # create the needed folders in the build folder if(_register_test_DIRECTORIES_TO_CREATE) foreach(_dir ${_register_test_DIRECTORIES_TO_CREATE}) if(IS_ABSOLUTE ${dir}) file(MAKE_DIRECTORY "${_dir}") else() file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_dir}") endif() endforeach() endif() # register the test for ctest set(_arguments -n "${test_name}") if(_register_test_SCRIPT) file(COPY ${_register_test_SCRIPT} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION . ) if(_register_test_PYTHON) if(NOT PYTHONINTERP_FOUND) find_package(PythonInterp ${AKANTU_PREFERRED_PYTHON_VERSION} REQUIRED) endif() list(APPEND _arguments -e "${PYTHON_EXECUTABLE}") list(APPEND _extra_args "${_register_test_SCRIPT}") else() - list(APPEND _arguments -e "${_register_test_SCRIPT}") + list(APPEND _arguments -e "./${_register_test_SCRIPT}") endif() elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.sh") file(COPY ${test_name}.sh DESTINATION .) - list(APPEND _arguments -e "${test_name}.sh") + list(APPEND _arguments -e "./${test_name}.sh") else() - list(APPEND _arguments -e "${test_name}") + list(APPEND _arguments -e "./${test_name}") endif() list(APPEND _arguments -E "${PROJECT_BINARY_DIR}/akantu_environement.sh") package_is_activated(parallel _is_parallel) if(_is_parallel AND AKANTU_TESTS_ALWAYS_USE_MPI AND NOT _register_test_PARALLEL) set(_register_test_PARALLEL TRUE) set(_register_test_PARALLEL_LEVEL 1) endif() if(_register_test_PARALLEL) list(APPEND _arguments -p "${MPIEXEC} ${MPIEXEC_PREFLAGS} ${MPIEXEC_NUMPROC_FLAG}") if(_register_test_PARALLEL_LEVEL) set(_procs "${_register_test_PARALLEL_LEVEL}") elseif(CMAKE_VERSION VERSION_GREATER "3.0") set(_procs) include(ProcessorCount) ProcessorCount(N) while(N GREATER 1) list(APPEND _procs ${N}) math(EXPR N "${N} / 2") endwhile() endif() if(NOT _procs) set(_procs 2) endif() endif() if(_register_test_POSTPROCESS) list(APPEND _arguments -s "${_register_test_POSTPROCESS}") file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${_register_test_POSTPROCESS} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) endif() list(APPEND _arguments -w "${CMAKE_CURRENT_BINARY_DIR}") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified") list(APPEND _arguments -r "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified") endif() string(REPLACE ";" " " _command "${_arguments}") # register them test if(_procs) foreach(p ${_procs}) add_test(NAME ${test_name}_${p} COMMAND ${AKANTU_DRIVER_SCRIPT} ${_arguments} -N ${p} ${_extra_args}) endforeach() else() add_test(NAME ${test_name} COMMAND ${AKANTU_DRIVER_SCRIPT} ${_arguments} ${_extra_args}) endif() endfunction() function(register_test_files_to_package) set(_test_all_files) # add the source files in the list of all files foreach(_file ${_register_test_SOURCES} ${_register_test_UNPARSED_ARGUMENTS} ${_register_test_EXTRA_FILES} ${_register_test_SOURCES} ${_register_test_SCRIPT} ${_register_test_POSTPROCESS} ${_register_test_FILES_TO_COPY}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_file} OR EXISTS ${_file}) list(APPEND _test_all_files "${_file}") else() message("The file \"${_file}\" registred by the test \"${test_name}\" does not exists") endif() endforeach() # add the different dependencies files (meshes, local libraries, ...) foreach(_dep ${_register_test_DEPENDS}) get_target_list_of_associated_files(${_dep} _dep_ressources) if(_dep_ressources) list(APPEND _test_all_files "${_dep_ressources}") endif() endforeach() # add extra files to the list of files referenced by a given test if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.sh") list(APPEND _test_all_files "${test_name}.sh") endif() if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified") list(APPEND _test_all_files "${test_name}.verified") endif() if(_register_test_SCRIPT) list(APPEND _test_all_files "${_register_test_SCRIPT}") endif() # clean the list of all files for this test and add them in the total list foreach(_file ${_test_all_files}) get_filename_component(_full ${_file} ABSOLUTE) file(RELATIVE_PATH __file ${PROJECT_SOURCE_DIR} ${_full}) list(APPEND _tmp "${__file}") endforeach() foreach(_pkg ${_register_test_PACKAGE}) package_get_name(${_pkg} _pkg_name) _package_add_to_variable(TESTS_FILES ${_pkg_name} ${_tmp}) endforeach() endfunction() diff --git a/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake b/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake index f7910d299..2d8c1a484 100644 --- a/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake +++ b/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake @@ -1,138 +1,132 @@ #=============================================================================== # @file CMakePackagesSystemGlobalFunctions.cmake # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Sat Jul 18 2015 # @date last modification: Mon Jan 18 2016 # # @brief Set of macros used by the package system to set internal variables # # @section LICENSE # # Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory # (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see <http://www.gnu.org/licenses/>. # #=============================================================================== # ============================================================================== # Package system meta functions # ============================================================================== function(package_set_project_variable variable) string(TOUPPER ${PROJECT_NAME} _u_project) set(${_u_project}_${variable} "${ARGN}" CACHE INTERNAL "" FORCE) endfunction() function(package_get_project_variable variable value_out) string(TOUPPER ${PROJECT_NAME} _u_project) set(${value_out} ${${_u_project}_${variable}} PARENT_SCOPE) endfunction() function(package_add_to_project_variable variable) package_get_project_variable(${variable} _tmp_list) list(APPEND _tmp_list ${ARGN}) if(_tmp_list) list(REMOVE_DUPLICATES _tmp_list) endif() package_set_project_variable(${variable} ${_tmp_list}) endfunction() # ============================================================================== function(_package_set_variable variable pkg_name) set(${pkg_name}_${variable} ${ARGN} CACHE INTERNAL "" FORCE) endfunction() function(_package_get_variable variable pkg_name value) #unset(${value} PARENT_SCOPE) if(DEFINED ${pkg_name}_${variable}) set(${value} ${${pkg_name}_${variable}} PARENT_SCOPE) elseif(DEFINED ARGN) set(${value} ${ARGN} PARENT_SCOPE) else() set(${value} PARENT_SCOPE) endif() endfunction() # ============================================================================== function(_package_variable_unset variable pkg_name) unset(${pkg_name}_${variable} CACHE) endfunction() # ============================================================================== function(_package_add_to_variable variable pkg_name) _package_get_variable(${variable} ${pkg_name} _tmp_list) list(APPEND _tmp_list ${ARGN}) if(_tmp_list) list(REMOVE_DUPLICATES _tmp_list) endif() _package_set_variable(${variable} ${pkg_name} ${_tmp_list}) endfunction() function(_package_remove_from_variable variable pkg_name value) _package_get_variable(${variable} ${pkg_name} _tmp_list) list(LENGTH _tmp_list _length) if(_length GREATER 0) list(REMOVE_ITEM _tmp_list ${value}) _package_set_variable(${variable} ${pkg_name} ${_tmp_list}) endif() endfunction() # ============================================================================== function(_package_get_variable_for_packages variable values) set(_list_values) foreach(_pkg_name ${ARGN}) _package_get_variable(${variable} ${_pkg_name} _value) list(APPEND _list_values ${_value}) endforeach() if (_list_values) list(REMOVE_DUPLICATES _list_values) endif() set(${values} ${_list_values} PARENT_SCOPE) endfunction() # ============================================================================== function(_package_get_variable_for_activated variable values) package_get_all_activated_packages(_activated_list) _package_get_variable_for_packages(${variable} _list_values ${_activated_list}) set(${values} ${_list_values} PARENT_SCOPE) endfunction() # ============================================================================== function(_package_get_variable_for_external_dependencies variable type values) set(_list_packages) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_list}) _package_get_nature(${_pkg_name} _nature) - if(NOT _nature MATCHES "^external.*") - _package_get_dependencies(${_pkg_name} ${type} _deps) - foreach(_dep ${_deps}) - _package_get_nature(${_dep} _nature) - if(_nature MATCHES "^external.*") - list(APPEND _list_packages ${_dep}) - endif() - endforeach() + if(_nature MATCHES "^external.*") + list(APPEND _list_packages ${_pkg_name}) endif() endforeach() if (_list_packages) list(REMOVE_DUPLICATES _list_packages) _package_get_variable_for_packages(${variable} _list_values_deps ${_list_packages}) set(${values} ${_list_values_deps} PARENT_SCOPE) endif() endfunction() # ============================================================================== diff --git a/examples/python/CMakeLists.txt b/examples/python/CMakeLists.txt index e7439f6f2..9bea05474 100644 --- a/examples/python/CMakeLists.txt +++ b/examples/python/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(plate-hole) -add_subdirectory(custom-material-dynamics) +add_subdirectory(custom-material) package_add_files_to_package( examples/python/README.rst ) diff --git a/examples/python/custom-material/CMakeLists.txt b/examples/python/custom-material/CMakeLists.txt index b9e6e0952..abaacb68f 100644 --- a/examples/python/custom-material/CMakeLists.txt +++ b/examples/python/custom-material/CMakeLists.txt @@ -1,3 +1,7 @@ -register_example(newmark - SCRIPT newmark.py +register_example(bi-material + SCRIPT bi-material.py + FILES_TO_COPY material.dat square.geo) + +register_example(custom-material + SCRIPT custom-material.py FILES_TO_COPY material.dat bar.geo) diff --git a/examples/python/custom-material/bi-material.py b/examples/python/custom-material/bi-material.py index b2be031d3..017acc202 100644 --- a/examples/python/custom-material/bi-material.py +++ b/examples/python/custom-material/bi-material.py @@ -1,192 +1,192 @@ from __future__ import print_function # ------------------------------------------------------------- # import akantu import subprocess import numpy as np import time # ------------------------------------------------------------- # class LocalElastic: # declares all the internals def initMaterial(self, internals, params): self.E = params['E'] self.nu = params['nu'] self.rho = params['rho'] # print(self.__dict__) # First Lame coefficient self.lame_lambda = self.nu * self.E / ( (1. + self.nu) * (1. - 2. * self.nu)) # Second Lame coefficient (shear modulus) self.lame_mu = self.E / (2. * (1. + self.nu)) all_factor = internals['factor'] all_quad_coords = internals['quad_coordinates'] for elem_type in all_factor.keys(): factor = all_factor[elem_type] quad_coords = all_quad_coords[elem_type] factor[:] = 1. factor[quad_coords[:, 1] < 0.5] = .5 # declares all the internals @staticmethod def registerInternals(): return ['potential', 'factor'] # declares all the internals @staticmethod def registerInternalSizes(): return [1, 1] # declares all the parameters that could be parsed @staticmethod def registerParam(): return ['E', 'nu'] # declares all the parameters that are needed def getPushWaveSpeed(self, params): return np.sqrt((self.lame_lambda + 2 * self.lame_mu) / self.rho) # compute small deformation tensor @staticmethod def computeEpsilon(grad_u): return 0.5 * (grad_u + np.einsum('aij->aji', grad_u)) # constitutive law def computeStress(self, grad_u, sigma, internals, params): n_quads = grad_u.shape[0] grad_u = grad_u.reshape((n_quads, 2, 2)) factor = internals['factor'].reshape(n_quads) epsilon = self.computeEpsilon(grad_u) sigma = sigma.reshape((n_quads, 2, 2)) trace = np.einsum('aii->a', grad_u) sigma[:, :, :] = ( np.einsum('a,ij->aij', trace, self.lame_lambda * np.eye(2)) + 2. * self.lame_mu * epsilon) # print(sigma.reshape((n_quads, 4))) # print(grad_u.reshape((n_quads, 4))) sigma[:, :, :] = np.einsum('aij, a->aij', sigma, factor) # constitutive law tangent modulii def computeTangentModuli(self, grad_u, tangent, internals, params): n_quads = tangent.shape[0] tangent = tangent.reshape(n_quads, 3, 3) factor = internals['factor'].reshape(n_quads) Miiii = self.lame_lambda + 2 * self.lame_mu Miijj = self.lame_lambda Mijij = self.lame_mu tangent[:, 0, 0] = Miiii tangent[:, 1, 1] = Miiii tangent[:, 0, 1] = Miijj tangent[:, 1, 0] = Miijj tangent[:, 2, 2] = Mijij tangent[:, :, :] = np.einsum('aij, a->aij', tangent, factor) # computes the energy density def getEnergyDensity(self, energy_type, energy_density, grad_u, stress, internals, params): nquads = stress.shape[0] stress = stress.reshape(nquads, 2, 2) grad_u = grad_u.reshape((nquads, 2, 2)) if energy_type != 'potential': raise RuntimeError('not known energy') epsilon = self.computeEpsilon(grad_u) energy_density[:, 0] = ( 0.5 * np.einsum('aij,aij->a', stress, epsilon)) # applies manually the boundary conditions def applyBC(model): nbNodes = model.getMesh().getNbNodes() position = model.getMesh().getNodes() displacement = model.getDisplacement() blocked_dofs = model.getBlockedDOFs() width = 1. height = 1. epsilon = 1e-8 for node in range(0, nbNodes): if((np.abs(position[node, 0]) < epsilon) or # left side (np.abs(position[node, 0] - width) < epsilon)): # right side blocked_dofs[node, 0] = True displacement[node, 0] = 0 * position[node, 0] + 0. if(np.abs(position[node, 1]) < epsilon): # lower side blocked_dofs[node, 1] = True displacement[node, 1] = - 1. if(np.abs(position[node, 1] - height) < epsilon): # upper side blocked_dofs[node, 1] = True displacement[node, 1] = 1. ################################################################ # main ################################################################ # main paraeters spatial_dimension = 2 mesh_file = 'square.msh' # call gmsh to generate the mesh ret = subprocess.call(['gmsh', '-2', 'square.geo', '-optimize', 'square.msh']) if ret != 0: raise Exception( 'execution of GMSH failed: do you have it installed ?') time.sleep(1) # read mesh mesh = akantu.Mesh(spatial_dimension) mesh.read(mesh_file) # create the custom material mat = LocalElastic() akantu.registerNewPythonMaterial(mat, "local_elastic") # init akantu akantu.initialize('material.dat') # init the SolidMechanicsModel model = akantu.SolidMechanicsModel(mesh) -model.initFull(akantu.SolidMechanicsModelOptions(akantu._static)) +model.initFull(_analysis_method=akantu._static) # configure the solver solver = model.getNonLinearSolver() solver.set("max_iterations", 2) solver.set("threshold", 1e-3) solver.set("convergence_type", akantu._scc_solution) # prepare the dumper model.setBaseName("bimaterial") model.addDumpFieldVector("displacement") model.addDumpFieldVector("internal_force") model.addDumpFieldVector("external_force") model.addDumpField("strain") model.addDumpField("stress") model.addDumpField("factor") model.addDumpField("blocked_dofs") # Boundary conditions applyBC(model) # solve the problem model.solveStep() # dump paraview files model.dump() # shutdown akantu akantu.finalize() diff --git a/examples/python/custom-material/custom-material.py b/examples/python/custom-material/custom-material.py index 398804f49..199d51dbe 100644 --- a/examples/python/custom-material/custom-material.py +++ b/examples/python/custom-material/custom-material.py @@ -1,213 +1,210 @@ #!/usr/bin/env python3 from __future__ import print_function ################################################################ import os import subprocess import numpy as np import akantu ################################################################ class FixedValue: def __init__(self, value, axis): self.value = value self.axis = axis def operator(self, node, flags, disp, coord): # sets the displacement to the desired value in the desired axis disp[self.axis] = self.value # sets the blocked dofs vector to true in the desired axis flags[self.axis] = True ################################################################ class LocalElastic: # declares all the internals def initMaterial(self, internals, params): self.E = params['E'] self.nu = params['nu'] self.rho = params['rho'] # First Lame coefficient self.lame_lambda = self.nu * self.E / ( (1 + self.nu) * (1 - 2 * self.nu)) # Second Lame coefficient (shear modulus) self.lame_mu = self.E / (2 * (1 + self.nu)) # declares all the internals @staticmethod def registerInternals(): return ['potential'] # declares all the internals @staticmethod def registerInternalSizes(): return [1] # declares all the parameters that could be parsed @staticmethod def registerParam(): return ['E', 'nu'] # declares all the parameters that are needed def getPushWaveSpeed(self, params): return np.sqrt((self.lame_lambda + 2 * self.lame_mu) / self.rho) # compute small deformation tensor @staticmethod def computeEpsilon(grad_u): return 0.5 * (grad_u + np.einsum('aij->aji', grad_u)) # constitutive law def computeStress(self, grad_u, sigma, internals, params): nquads = grad_u.shape[0] grad_u = grad_u.reshape((nquads, 2, 2)) epsilon = self.computeEpsilon(grad_u) sigma = sigma.reshape((nquads, 2, 2)) trace = np.trace(grad_u, axis1=1, axis2=2) sigma[:, :, :] = ( np.einsum('a,ij->aij', trace, self.lame_lambda * np.eye(2)) + 2.*self.lame_mu * epsilon) # constitutive law tangent modulii def computeTangentModuli(self, grad_u, tangent, internals, params): n_quads = tangent.shape[0] tangent = tangent.reshape(n_quads, 3, 3) Miiii = self.lame_lambda + 2 * self.lame_mu Miijj = self.lame_lambda Mijij = self.lame_mu tangent[:, 0, 0] = Miiii tangent[:, 1, 1] = Miiii tangent[:, 0, 1] = Miijj tangent[:, 1, 0] = Miijj tangent[:, 2, 2] = Mijij # computes the energy density def getEnergyDensity(self, energy_type, energy_density, grad_u, stress, internals, params): nquads = stress.shape[0] stress = stress.reshape(nquads, 2, 2) grad_u = grad_u.reshape((nquads, 2, 2)) if energy_type != 'potential': raise RuntimeError('not known energy') epsilon = self.computeEpsilon(grad_u) energy_density[:, 0] = ( 0.5 * np.einsum('aij,aij->a', stress, epsilon)) ################################################################ # main ################################################################ spatial_dimension = 2 akantu.initialize('material.dat') mesh_file = 'bar.msh' max_steps = 250 time_step = 1e-3 # if mesh was not created the calls gmsh to generate it if not os.path.isfile(mesh_file): ret = subprocess.call('gmsh -2 bar.geo bar.msh', shell=True) if ret != 0: raise Exception( 'execution of GMSH failed: do you have it installed ?') ################################################################ # Initialization ################################################################ mesh = akantu.Mesh(spatial_dimension) mesh.read(mesh_file) mat = LocalElastic() akantu.registerNewPythonMaterial(mat, "local_elastic") model = akantu.SolidMechanicsModel(mesh) -model.initFull(akantu.SolidMechanicsModelOptions( - akantu._explicit_lumped_mass)) - -# model.initFull(akantu.SolidMechanicsModelOptions( -# akantu._implicit_dynamic)) +model.initFull(_analysis_method=akantu._explicit_lumped_mass) +# model.initFull(_analysis_method=akantu._implicit_dynamic) model.setBaseName("waves") model.addDumpFieldVector("displacement") model.addDumpFieldVector("acceleration") model.addDumpFieldVector("velocity") model.addDumpFieldVector("internal_force") model.addDumpFieldVector("external_force") model.addDumpField("strain") model.addDumpField("stress") model.addDumpField("blocked_dofs") ################################################################ # boundary conditions ################################################################ model.applyDirichletBC(FixedValue(0, akantu._x), "XBlocked") model.applyDirichletBC(FixedValue(0, akantu._y), "YBlocked") ################################################################ # initial conditions ################################################################ displacement = model.getDisplacement() nb_nodes = mesh.getNbNodes() position = mesh.getNodes() pulse_width = 1 A = 0.01 for i in range(0, nb_nodes): # Sinus * Gaussian x = position[i, 0] - 5. L = pulse_width k = 0.1 * 2 * np.pi * 3 / L displacement[i, 0] = A * \ np.sin(k * x) * np.exp(-(k * x) * (k * x) / (L * L)) ################################################################ # timestep value computation ################################################################ time_factor = 0.8 stable_time_step = model.getStableTimeStep() * time_factor print("Stable Time Step = {0}".format(stable_time_step)) print("Required Time Step = {0}".format(time_step)) time_step = stable_time_step * time_factor model.setTimeStep(time_step) ################################################################ # loop for evolution of motion dynamics ################################################################ model.assembleInternalForces() print("step,step * time_step,epot,ekin,epot + ekin") for step in range(0, max_steps + 1): model.solveStep() if step % 10 == 0: model.dump() epot = model.getEnergy('potential') ekin = model.getEnergy('kinetic') # output energy calculation to screen print("{0},{1},{2},{3},{4}".format(step, step * time_step, epot, ekin, (epot + ekin))) akantu.finalize() diff --git a/examples/python/dynamics/dynamics.py b/examples/python/dynamics/dynamics.py index bb92576e7..23d34898e 100644 --- a/examples/python/dynamics/dynamics.py +++ b/examples/python/dynamics/dynamics.py @@ -1,133 +1,130 @@ #!/usr/bin/env python3 from __future__ import print_function ################################################################ import os import subprocess import numpy as np import akantu ################################################################ class FixedValue: def __init__(self, value, axis): self.value = value self.axis = axis def operator(self, node, flags, disp, coord): # sets the displacement to the desired value in the desired axis disp[self.axis] = self.value # sets the blocked dofs vector to true in the desired axis flags[self.axis] = True ################################################################ def main(): spatial_dimension = 2 akantu.initialize('material.dat') mesh_file = 'bar.msh' max_steps = 250 time_step = 1e-3 # if mesh was not created the calls gmsh to generate it if not os.path.isfile(mesh_file): ret = subprocess.call('gmsh -2 bar.geo bar.msh', shell=True) if ret != 0: raise Exception( 'execution of GMSH failed: do you have it installed ?') ################################################################ # Initialization ################################################################ mesh = akantu.Mesh(spatial_dimension) mesh.read(mesh_file) model = akantu.SolidMechanicsModel(mesh) - model.initFull(akantu.SolidMechanicsModelOptions( - akantu._explicit_lumped_mass)) - - # model.initFull(akantu.SolidMechanicsModelOptions( - # akantu._implicit_dynamic)) + model.initFull(_analysis_method=akantu._explicit_lumped_mass) + # model.initFull(_analysis_method=akantu._implicit_dynamic) model.setBaseName("waves") model.addDumpFieldVector("displacement") model.addDumpFieldVector("acceleration") model.addDumpFieldVector("velocity") model.addDumpFieldVector("internal_force") model.addDumpFieldVector("external_force") model.addDumpField("strain") model.addDumpField("stress") model.addDumpField("blocked_dofs") ################################################################ # boundary conditions ################################################################ model.applyDirichletBC(FixedValue(0, akantu._x), "XBlocked") model.applyDirichletBC(FixedValue(0, akantu._y), "YBlocked") ################################################################ # initial conditions ################################################################ displacement = model.getDisplacement() nb_nodes = mesh.getNbNodes() position = mesh.getNodes() pulse_width = 1 A = 0.01 for i in range(0, nb_nodes): # Sinus * Gaussian x = position[i, 0] - 5. L = pulse_width k = 0.1 * 2 * np.pi * 3 / L displacement[i, 0] = A * \ np.sin(k * x) * np.exp(-(k * x) * (k * x) / (L * L)) ################################################################ # timestep value computation ################################################################ time_factor = 0.8 stable_time_step = model.getStableTimeStep() * time_factor print("Stable Time Step = {0}".format(stable_time_step)) print("Required Time Step = {0}".format(time_step)) time_step = stable_time_step * time_factor model.setTimeStep(time_step) ################################################################ # loop for evolution of motion dynamics ################################################################ model.assembleInternalForces() print("step,step * time_step,epot,ekin,epot + ekin") for step in range(0, max_steps + 1): model.solveStep() if step % 10 == 0: model.dump() epot = model.getEnergy('potential') ekin = model.getEnergy('kinetic') # output energy calculation to screen print("{0},{1},{2},{3},{4}".format(step, step * time_step, epot, ekin, (epot + ekin))) akantu.finalize() return ################################################################ if __name__ == "__main__": main() diff --git a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc index fbf0ccf69..2dcdbaab9 100644 --- a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc +++ b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc @@ -1,196 +1,196 @@ /** * @file material_FE2.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @brief Material for multi-scale simulations. It stores an * underlying RVE on each integration point of the material. * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "material_FE2.hh" #include "communicator.hh" #include "solid_mechanics_model_RVE.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialFE2<spatial_dimension>::MaterialFE2(SolidMechanicsModel & model, const ID & id) : Parent(model, id), C("material_stiffness", *this) { AKANTU_DEBUG_IN(); this->C.initialize(voigt_h::size * voigt_h::size); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialFE2<spatial_dimension>::~MaterialFE2() = default; /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialFE2<dim>::initialize() { this->registerParam("element_type", el_type, _triangle_3, _pat_parsable | _pat_modifiable, "element type in RVE mesh"); this->registerParam("mesh_file", mesh_file, _pat_parsable | _pat_modifiable, "the mesh file for the RVE"); this->registerParam("nb_gel_pockets", nb_gel_pockets, _pat_parsable | _pat_modifiable, "the number of gel pockets in each RVE"); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialFE2<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); Parent::initMaterial(); /// create a Mesh and SolidMechanicsModel on each integration point of the /// material const auto & comm = this->model.getMesh().getCommunicator(); UInt prank = comm.whoAmI(); auto C_it = this->C(this->el_type).begin(voigt_h::size, voigt_h::size); for (auto && data : enumerate(make_view(C(this->el_type), voigt_h::size, voigt_h::size))) { auto q = std::get<0>(data); auto & C = std::get<1>(data); meshes.emplace_back(std::make_unique<Mesh>( spatial_dimension, "RVE_mesh_" + std::to_string(prank), q + 1)); auto & mesh = *meshes.back(); mesh.read(mesh_file); RVEs.emplace_back(std::make_unique<SolidMechanicsModelRVE>( mesh, true, this->nb_gel_pockets, _all_dimensions, "SMM_RVE_" + std::to_string(prank), q + 1)); auto & RVE = *RVEs.back(); - RVE.initFull(); + RVE.initFull(_analysis_method = _static); /// compute intial stiffness of the RVE RVE.homogenizeStiffness(C); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialFE2<spatial_dimension>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); // Compute thermal stresses first Parent::computeStress(el_type, ghost_type); Array<Real>::const_scalar_iterator sigma_th_it = this->sigma_th(el_type, ghost_type).begin(); // Wikipedia convention: // 2*eps_ij (i!=j) = voigt_eps_I // http://en.wikipedia.org/wiki/Voigt_notation Array<Real>::const_matrix_iterator C_it = this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size); // create vectors to store stress and strain in Voigt notation // for efficient computation of stress Vector<Real> voigt_strain(voigt_h::size); Vector<Real> voigt_stress(voigt_h::size); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); const Matrix<Real> & C_mat = *C_it; const Real & sigma_th = *sigma_th_it; /// copy strains in Voigt notation for (UInt I = 0; I < voigt_h::size; ++I) { /// copy stress in Real voigt_factor = voigt_h::factors[I]; UInt i = voigt_h::vec[I][0]; UInt j = voigt_h::vec[I][1]; voigt_strain(I) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.; } // compute stresses in Voigt notation voigt_stress.mul<false>(C_mat, voigt_strain); /// copy stresses back in full vectorised notation for (UInt I = 0; I < voigt_h::size; ++I) { UInt i = voigt_h::vec[I][0]; UInt j = voigt_h::vec[I][1]; sigma(i, j) = sigma(j, i) = voigt_stress(I) + (i == j) * sigma_th; } ++C_it; ++sigma_th_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialFE2<spatial_dimension>::computeTangentModuli( const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::const_matrix_iterator C_it = this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); tangent.copy(*C_it); ++C_it; MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialFE2<spatial_dimension>::advanceASR( const Matrix<Real> & prestrain) { AKANTU_DEBUG_IN(); for (auto && data : zip(RVEs, make_view(this->gradu(this->el_type), spatial_dimension, spatial_dimension), make_view(this->eigengradu(this->el_type), spatial_dimension, spatial_dimension), make_view(this->C(this->el_type), voigt_h::size, voigt_h::size))) { auto & RVE = *(std::get<0>(data)); /// apply boundary conditions based on the current macroscopic displ. /// gradient RVE.applyBoundaryConditions(std::get<1>(data)); /// advance the ASR in every RVE RVE.advanceASR(prestrain); /// compute the average eigen_grad_u RVE.homogenizeEigenGradU(std::get<2>(data)); /// compute the new effective stiffness of the RVE RVE.homogenizeStiffness(std::get<3>(data)); } AKANTU_DEBUG_OUT(); } INSTANTIATE_MATERIAL(material_FE2, MaterialFE2); } // namespace akantu diff --git a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc index 4eb79aec2..27306a2ed 100644 --- a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc +++ b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc @@ -1,552 +1,553 @@ /** * @file solid_mechanics_model_RVE.cc * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Wed Jan 13 15:32:35 2016 * * @brief Implementation of SolidMechanicsModelRVE * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_RVE.hh" #include "element_group.hh" #include "material_damage_iterative.hh" #include "node_group.hh" #include "non_linear_solver.hh" #include "parser.hh" +#include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SolidMechanicsModelRVE::SolidMechanicsModelRVE(Mesh & mesh, bool use_RVE_mat_selector, UInt nb_gel_pockets, UInt dim, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, dim, id, memory_id), volume(0.), use_RVE_mat_selector(use_RVE_mat_selector), nb_gel_pockets(nb_gel_pockets), nb_dumps(0) { AKANTU_DEBUG_IN(); - /// create node groups for PBCs - mesh.createGroupsFromMeshData<std::string>("physical_names"); /// find the four corner nodes of the RVE findCornerNodes(); /// remove the corner nodes from the surface node groups: /// This most be done because corner nodes a not periodic mesh.getElementGroup("top").removeNode(corner_nodes(2)); mesh.getElementGroup("top").removeNode(corner_nodes(3)); mesh.getElementGroup("left").removeNode(corner_nodes(3)); mesh.getElementGroup("left").removeNode(corner_nodes(0)); mesh.getElementGroup("bottom").removeNode(corner_nodes(1)); mesh.getElementGroup("bottom").removeNode(corner_nodes(0)); mesh.getElementGroup("right").removeNode(corner_nodes(2)); mesh.getElementGroup("right").removeNode(corner_nodes(1)); const auto & bottom = mesh.getElementGroup("bottom").getNodeGroup(); bottom_nodes.insert(bottom.begin(), bottom.end()); const auto & left = mesh.getElementGroup("left").getNodeGroup(); left_nodes.insert(left.begin(), left.end()); // /// enforce periodicity on the displacement fluctuations // auto surface_pair_1 = std::make_pair("top", "bottom"); // auto surface_pair_2 = std::make_pair("right", "left"); // SurfacePairList surface_pairs_list; // surface_pairs_list.push_back(surface_pair_1); // surface_pairs_list.push_back(surface_pair_2); // TODO: To Nicolas correct the PBCs // this->setPBC(surface_pairs_list); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModelRVE::~SolidMechanicsModelRVE() = default; /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::initFullImpl(const ModelOptions & options) { AKANTU_DEBUG_IN(); auto options_cp(options); options_cp.analysis_method = AnalysisMethod::_static; - SolidMechanicsModel::initFullImpl(options); + SolidMechanicsModel::initFullImpl(options_cp); this->initMaterials(); auto & fem = this->getFEEngine("SolidMechanicsFEEngine"); /// compute the volume of the RVE - for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) { + GhostType gt = _not_ghost; + for (auto element_type : this->mesh.elementTypes(spatial_dimension, gt, _ek_not_defined)) { Array<Real> Volume(this->mesh.getNbElement(element_type) * fem.getNbIntegrationPoints(element_type), 1, 1.); this->volume = fem.integrate(Volume, element_type); } std::cout << "The volume of the RVE is " << this->volume << std::endl; /// dumping std::stringstream base_name; base_name << this->id; // << this->memory_id - 1; this->setBaseName(base_name.str()); this->addDumpFieldVector("displacement"); this->addDumpField("stress"); this->addDumpField("grad_u"); this->addDumpField("eigen_grad_u"); this->addDumpField("blocked_dofs"); this->addDumpField("material_index"); this->addDumpField("damage"); this->addDumpField("Sc"); - this->addDumpField("force"); + this->addDumpField("external_force"); this->addDumpField("equivalent_stress"); - this->addDumpField("internal_forces"); + this->addDumpField("internal_force"); this->dump(); this->nb_dumps += 1; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::applyBoundaryConditions( const Matrix<Real> & displacement_gradient) { AKANTU_DEBUG_IN(); /// get the position of the nodes const Array<Real> & pos = mesh.getNodes(); /// storage for the coordinates of a given node and the displacement that will /// be applied Vector<Real> x(spatial_dimension); Vector<Real> appl_disp(spatial_dimension); /// fix top right node UInt node = this->corner_nodes(2); x(0) = pos(node, 0); x(1) = pos(node, 1); appl_disp.mul<false>(displacement_gradient, x); (*this->blocked_dofs)(node, 0) = true; (*this->displacement)(node, 0) = appl_disp(0); (*this->blocked_dofs)(node, 1) = true; (*this->displacement)(node, 1) = appl_disp(1); // (*this->blocked_dofs)(node,0) = true; (*this->displacement)(node,0) = 0.; // (*this->blocked_dofs)(node,1) = true; (*this->displacement)(node,1) = 0.; /// apply Hx at all the other corner nodes; H: displ. gradient node = this->corner_nodes(0); x(0) = pos(node, 0); x(1) = pos(node, 1); appl_disp.mul<false>(displacement_gradient, x); (*this->blocked_dofs)(node, 0) = true; (*this->displacement)(node, 0) = appl_disp(0); (*this->blocked_dofs)(node, 1) = true; (*this->displacement)(node, 1) = appl_disp(1); node = this->corner_nodes(1); x(0) = pos(node, 0); x(1) = pos(node, 1); appl_disp.mul<false>(displacement_gradient, x); (*this->blocked_dofs)(node, 0) = true; (*this->displacement)(node, 0) = appl_disp(0); (*this->blocked_dofs)(node, 1) = true; (*this->displacement)(node, 1) = appl_disp(1); node = this->corner_nodes(3); x(0) = pos(node, 0); x(1) = pos(node, 1); appl_disp.mul<false>(displacement_gradient, x); (*this->blocked_dofs)(node, 0) = true; (*this->displacement)(node, 0) = appl_disp(0); (*this->blocked_dofs)(node, 1) = true; (*this->displacement)(node, 1) = appl_disp(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::findCornerNodes() { AKANTU_DEBUG_IN(); // find corner nodes const auto & position = mesh.getNodes(); const auto & lower_bounds = mesh.getLowerBounds(); const auto & upper_bounds = mesh.getUpperBounds(); AKANTU_DEBUG_ASSERT(spatial_dimension == 2, "This is 2D only!"); corner_nodes.resize(4); corner_nodes.set(UInt(-1)); for (auto && data : enumerate(make_view(position, spatial_dimension))) { auto node = std::get<0>(data); const auto & X = std::get<1>(data); auto distance = X.distance(lower_bounds); // node 1 if (Math::are_float_equal(distance, 0)) { corner_nodes(0) = node; } // node 2 else if (Math::are_float_equal(X(_x), upper_bounds(_x)) && Math::are_float_equal(X(_y), lower_bounds(_y))) { corner_nodes(1) = node; } // node 3 else if (Math::are_float_equal(X(_x), upper_bounds(_x)) && Math::are_float_equal(X(_y), upper_bounds(_y))) { corner_nodes(2) = node; } // node 4 else if (Math::are_float_equal(X(_x), lower_bounds(_x)) && Math::are_float_equal(X(_y), upper_bounds(_y))) { corner_nodes(3) = node; } } for (UInt i = 0; i < corner_nodes.size(); ++i) { if (corner_nodes(i) == UInt(-1)) AKANTU_DEBUG_ERROR("The corner node " << i + 1 << " wasn't found"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::advanceASR(const Matrix<Real> & prestrain) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(spatial_dimension == 2, "This is 2D only!"); /// apply the new eigenstrain for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) { Array<Real> & prestrain_vect = const_cast<Array<Real> &>(this->getMaterial("gel").getInternal<Real>( "eigen_grad_u")(element_type)); auto prestrain_it = prestrain_vect.begin(spatial_dimension, spatial_dimension); auto prestrain_end = prestrain_vect.end(spatial_dimension, spatial_dimension); for (; prestrain_it != prestrain_end; ++prestrain_it) (*prestrain_it) = prestrain; } /// advance the damage MaterialDamageIterative<2> & mat_paste = dynamic_cast<MaterialDamageIterative<2> &>(*this->materials[1]); MaterialDamageIterative<2> & mat_aggregate = dynamic_cast<MaterialDamageIterative<2> &>(*this->materials[0]); UInt nb_damaged_elements = 0; Real max_eq_stress_aggregate = 0; Real max_eq_stress_paste = 0; auto & solver = this->getNonLinearSolver(); solver.set("max_iterations", 2); solver.set("threshold", 1e-6); solver.set("convergence_type", _scc_solution); do { this->solveStep(); /// compute damage max_eq_stress_aggregate = mat_aggregate.getNormMaxEquivalentStress(); max_eq_stress_paste = mat_paste.getNormMaxEquivalentStress(); nb_damaged_elements = 0; if (max_eq_stress_aggregate > max_eq_stress_paste) nb_damaged_elements = mat_aggregate.updateDamage(); else if (max_eq_stress_aggregate < max_eq_stress_paste) nb_damaged_elements = mat_paste.updateDamage(); else nb_damaged_elements = (mat_paste.updateDamage() + mat_aggregate.updateDamage()); std::cout << "the number of damaged elements is " << nb_damaged_elements << std::endl; } while (nb_damaged_elements); if (this->nb_dumps % 10 == 0) { this->dump(); } this->nb_dumps += 1; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModelRVE::averageTensorField(UInt row_index, UInt col_index, const ID & field_type) { AKANTU_DEBUG_IN(); auto & fem = this->getFEEngine("SolidMechanicsFEEngine"); Real average = 0; for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) { if (field_type == "stress") { for (UInt m = 0; m < this->materials.size(); ++m) { const auto & stress_vec = this->materials[m]->getStress(element_type); const auto & elem_filter = this->materials[m]->getElementFilter(element_type); Array<Real> int_stress_vec(elem_filter.size(), spatial_dimension * spatial_dimension, "int_of_stress"); fem.integrate(stress_vec, int_stress_vec, spatial_dimension * spatial_dimension, element_type, _not_ghost, elem_filter); for (UInt k = 0; k < elem_filter.size(); ++k) average += int_stress_vec( k, row_index * spatial_dimension + col_index); // 3 is the value // for the yy (in // 3D, the value is // 4) } } else if (field_type == "strain") { for (UInt m = 0; m < this->materials.size(); ++m) { const auto & gradu_vec = this->materials[m]->getGradU(element_type); const auto & elem_filter = this->materials[m]->getElementFilter(element_type); Array<Real> int_gradu_vec(elem_filter.size(), spatial_dimension * spatial_dimension, "int_of_gradu"); fem.integrate(gradu_vec, int_gradu_vec, spatial_dimension * spatial_dimension, element_type, _not_ghost, elem_filter); for (UInt k = 0; k < elem_filter.size(); ++k) /// averaging is done only for normal components, so stress and strain /// are equal average += 0.5 * (int_gradu_vec(k, row_index * spatial_dimension + col_index) + int_gradu_vec(k, col_index * spatial_dimension + row_index)); } } else if (field_type == "eigen_grad_u") { for (UInt m = 0; m < this->materials.size(); ++m) { const auto & eigen_gradu_vec = this->materials[m]->getInternal<Real>("eigen_grad_u")(element_type); const auto & elem_filter = this->materials[m]->getElementFilter(element_type); Array<Real> int_eigen_gradu_vec(elem_filter.size(), spatial_dimension * spatial_dimension, "int_of_gradu"); fem.integrate(eigen_gradu_vec, int_eigen_gradu_vec, spatial_dimension * spatial_dimension, element_type, _not_ghost, elem_filter); for (UInt k = 0; k < elem_filter.size(); ++k) /// averaging is done only for normal components, so stress and strain /// are equal average += int_eigen_gradu_vec(k, row_index * spatial_dimension + col_index); } } else { AKANTU_DEBUG_ERROR("Averaging not implemented for this field!!!"); } } return average / this->volume; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::homogenizeStiffness(Matrix<Real> & C_macro) { AKANTU_DEBUG_IN(); const UInt dim = 2; AKANTU_DEBUG_ASSERT(this->spatial_dimension == dim, "Is only implemented for 2D!!!"); /// apply three independent loading states to determine C /// 1. eps_el = (1;0;0) 2. eps_el = (0,1,0) 3. eps_el = (0,0,0.5) /// clear the eigenstrain Matrix<Real> zero_eigengradu(dim, dim, 0.); - for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) { + GhostType gt = _not_ghost; + for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) { auto & prestrain_vect = const_cast<Array<Real> &>(this->getMaterial("gel").getInternal<Real>( "eigen_grad_u")(element_type)); auto prestrain_it = prestrain_vect.begin(spatial_dimension, spatial_dimension); auto prestrain_end = prestrain_vect.end(spatial_dimension, spatial_dimension); for (; prestrain_it != prestrain_end; ++prestrain_it) (*prestrain_it) = zero_eigengradu; } /// storage for results of 3 different loading states UInt voigt_size = VoigtHelper<dim>::size; Matrix<Real> stresses(voigt_size, voigt_size, 0.); Matrix<Real> strains(voigt_size, voigt_size, 0.); Matrix<Real> H(dim, dim, 0.); /// save the damage state before filling up cracks // ElementTypeMapReal saved_damage("saved_damage"); // saved_damage.initialize(getFEEngine(), _nb_component = 1, _default_value = // 0); // this->fillCracks(saved_damage); /// virtual test 1: H(0, 0) = 0.01; this->performVirtualTesting(H, stresses, strains, 0); /// virtual test 2: H.clear(); H(1, 1) = 0.01; this->performVirtualTesting(H, stresses, strains, 1); /// virtual test 3: H.clear(); H(0, 1) = 0.01; this->performVirtualTesting(H, stresses, strains, 2); /// drain cracks // this->drainCracks(saved_damage); /// compute effective stiffness Matrix<Real> eps_inverse(voigt_size, voigt_size); eps_inverse.inverse(strains); C_macro.mul<false, false>(stresses, eps_inverse); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::performVirtualTesting(const Matrix<Real> & H, Matrix<Real> & eff_stresses, Matrix<Real> & eff_strains, const UInt test_no) { AKANTU_DEBUG_IN(); this->applyBoundaryConditions(H); - auto & solver = this->getNonLinearSolver("static"); + auto & solver = this->getNonLinearSolver(); solver.set("max_iterations", 2); solver.set("threshold", 1e-6); solver.set("convergence_type", _scc_solution); - this->solveStep("static"); + this->solveStep(); /// get average stress and strain eff_stresses(0, test_no) = this->averageTensorField(0, 0, "stress"); eff_strains(0, test_no) = this->averageTensorField(0, 0, "strain"); eff_stresses(1, test_no) = this->averageTensorField(1, 1, "stress"); eff_strains(1, test_no) = this->averageTensorField(1, 1, "strain"); eff_stresses(2, test_no) = this->averageTensorField(1, 0, "stress"); eff_strains(2, test_no) = 2. * this->averageTensorField(1, 0, "strain"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::homogenizeEigenGradU( Matrix<Real> & eigen_gradu_macro) { AKANTU_DEBUG_IN(); eigen_gradu_macro(0, 0) = this->averageTensorField(0, 0, "eigen_grad_u"); eigen_gradu_macro(1, 1) = this->averageTensorField(1, 1, "eigen_grad_u"); eigen_gradu_macro(0, 1) = this->averageTensorField(0, 1, "eigen_grad_u"); eigen_gradu_macro(1, 0) = this->averageTensorField(1, 0, "eigen_grad_u"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::initMaterials() { AKANTU_DEBUG_IN(); // make sure the material are instantiated if (!are_materials_instantiated) instantiateMaterials(); if (use_RVE_mat_selector) { const Vector<Real> & lowerBounds = mesh.getLowerBounds(); const Vector<Real> & upperBounds = mesh.getUpperBounds(); Real bottom = lowerBounds(1); Real top = upperBounds(1); Real box_size = std::abs(top - bottom); Real eps = box_size * 1e-6; auto tmp = std::make_shared<GelMaterialSelector>(*this, box_size, "gel", this->nb_gel_pockets, eps); tmp->setFallback(material_selector); material_selector = tmp; } SolidMechanicsModel::initMaterials(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::fillCracks(ElementTypeMapReal & saved_damage) { const auto & mat_gel = this->getMaterial("gel"); Real E_gel = mat_gel.get("E"); Real E_homogenized = 0.; for (auto && mat : materials) { if (mat->getName() == "gel" || mat->getName() == "FE2_mat") continue; Real E = mat->get("E"); auto & damage = mat->getInternal<Real>("damage"); for (auto && type : damage.elementTypes()) { const auto & elem_filter = mat->getElementFilter(type); auto nb_integration_point = getFEEngine().getNbIntegrationPoints(type); auto sav_dam_it = make_view(saved_damage(type), nb_integration_point).begin(); for (auto && data : zip(elem_filter, make_view(damage(type), nb_integration_point))) { auto el = std::get<0>(data); auto & dam = std::get<1>(data); Vector<Real> sav_dam = sav_dam_it[el]; sav_dam = dam; for (auto q : arange(dam.size())) { E_homogenized = (E_gel - E) * dam(q) + E; dam(q) = 1. - (E_homogenized / E); } } } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelRVE::drainCracks( const ElementTypeMapReal & saved_damage) { for (auto && mat : materials) { if (mat->getName() == "gel" || mat->getName() == "FE2_mat") continue; auto & damage = mat->getInternal<Real>("damage"); for (auto && type : damage.elementTypes()) { const auto & elem_filter = mat->getElementFilter(type); auto nb_integration_point = getFEEngine().getNbIntegrationPoints(type); auto sav_dam_it = make_view(saved_damage(type), nb_integration_point).begin(); for (auto && data : zip(elem_filter, make_view(damage(type), nb_integration_point))) { auto el = std::get<0>(data); auto & dam = std::get<1>(data); Vector<Real> sav_dam = sav_dam_it[el]; dam = sav_dam; } } } } } // namespace akantu diff --git a/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc b/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc index 5c0102369..485abb338 100644 --- a/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc +++ b/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc @@ -1,40 +1,40 @@ /** * @file material_damage_iterative.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * * @brief Implementation of MaterialDamageIterativeNonLocal * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ #include "material_damage_iterative_non_local.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialDamageIterativeNonLocal<spatial_dimension>::computeNonLocalStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); /// reset normalized maximum equivalent stress if(ghost_type==_not_ghost) this->norm_max_equivalent_stress = 0; MaterialDamageIterativeNonLocalParent::computeNonLocalStresses(ghost_type); /// find global Gauss point with highest stress - StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); - comm.allReduce(&(this->norm_max_equivalent_stress), 1, _so_max); + const auto & comm = this->model.getMesh().getCommunicator(); + comm.allReduce(this->norm_max_equivalent_stress, SynchronizerOperation::_max); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -INSTANTIATE_MATERIAL(MaterialDamageIterativeNonLocal); +INSTANTIATE_MATERIAL(damage_iterative_non_local, MaterialDamageIterativeNonLocal); } // namespace akantu diff --git a/packages/embedded.cmake b/packages/embedded.cmake index b223dfbb5..75c2a1243 100644 --- a/packages/embedded.cmake +++ b/packages/embedded.cmake @@ -1,60 +1,57 @@ #=============================================================================== # @file embedded.cmake # # @author Lucas Frerot <lucas.frerot@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Tue Oct 16 2012 # @date last modification: Mon Dec 14 2015 # # @brief package descrition for embedded model use # # @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 <http://www.gnu.org/licenses/>. # #=============================================================================== package_declare(embedded DESCRIPTION "Add support for the embedded solid mechanics model" DEPENDS CGAL) package_declare_sources(embedded model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.cc model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.hh model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.hh - model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh + model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh - model/solid_mechanics/materials/material_embedded/material_reinforcement.cc model/solid_mechanics/materials/material_embedded/material_reinforcement.hh - model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc - model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh - model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh + model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh ) package_declare_material_infos(embedded LIST AKANTU_EMBEDDED_MATERIAL_LIST INCLUDE material_embedded_includes.hh ) package_declare_documentation(embedded "This package allows the use of the embedded model in solid mechanics. This package depends on the CGAL package." ) #add_example(embedded "Example on how to run embedded model simulation" PACKAGE embedded) diff --git a/packages/solid_mechanics.cmake b/packages/solid_mechanics.cmake index c64a05a82..27a98df70 100644 --- a/packages/solid_mechanics.cmake +++ b/packages/solid_mechanics.cmake @@ -1,128 +1,129 @@ #=============================================================================== # @file solid_mechanics.cmake # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Nov 21 2011 # @date last modification: Mon Jan 18 2016 # # @brief package description for core # # @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 <http://www.gnu.org/licenses/>. # #=============================================================================== package_declare(solid_mechanics DEFAULT ON DESCRIPTION "Solid mechanics model" DEPENDS core ) package_declare_sources(solid_mechanics model/solid_mechanics/material.cc model/solid_mechanics/material.hh model/solid_mechanics/material_inline_impl.cc model/solid_mechanics/material_selector.hh model/solid_mechanics/material_selector_tmpl.hh model/solid_mechanics/materials/internal_field.hh model/solid_mechanics/materials/internal_field_tmpl.hh model/solid_mechanics/materials/random_internal_field.hh model/solid_mechanics/materials/random_internal_field_tmpl.hh model/solid_mechanics/solid_mechanics_model.cc model/solid_mechanics/solid_mechanics_model.hh model/solid_mechanics/solid_mechanics_model_inline_impl.cc model/solid_mechanics/solid_mechanics_model_io.cc model/solid_mechanics/solid_mechanics_model_mass.cc model/solid_mechanics/solid_mechanics_model_material.cc model/solid_mechanics/solid_mechanics_model_tmpl.hh model/solid_mechanics/solid_mechanics_model_event_handler.hh model/solid_mechanics/materials/plane_stress_toolbox.hh model/solid_mechanics/materials/plane_stress_toolbox_tmpl.hh model/solid_mechanics/materials/material_core_includes.hh model/solid_mechanics/materials/material_elastic.cc model/solid_mechanics/materials/material_elastic.hh model/solid_mechanics/materials/material_elastic_inline_impl.cc model/solid_mechanics/materials/material_thermal.cc model/solid_mechanics/materials/material_thermal.hh model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh + model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc model/solid_mechanics/materials/material_elastic_orthotropic.cc model/solid_mechanics/materials/material_elastic_orthotropic.hh model/solid_mechanics/materials/material_damage/material_damage.hh model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh model/solid_mechanics/materials/material_damage/material_marigo.cc model/solid_mechanics/materials/material_damage/material_marigo.hh model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc model/solid_mechanics/materials/material_damage/material_mazars.cc model/solid_mechanics/materials/material_damage/material_mazars.hh model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc model/solid_mechanics/materials/material_plastic/material_plastic.cc model/solid_mechanics/materials/material_plastic/material_plastic.hh model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh model/solid_mechanics/materials/material_non_local.hh model/solid_mechanics/materials/material_non_local_tmpl.hh model/solid_mechanics/materials/material_non_local_includes.hh ) package_declare_material_infos(solid_mechanics LIST AKANTU_CORE_MATERIAL_LIST INCLUDE material_core_includes.hh ) package_declare_documentation_files(solid_mechanics manual-solidmechanicsmodel.tex manual-constitutive-laws.tex manual-lumping.tex manual-appendix-materials.tex figures/dynamic_analysis.png figures/explicit_dynamic.pdf figures/explicit_dynamic.svg figures/static.pdf figures/static.svg figures/hooke_law.pdf figures/implicit_dynamic.pdf figures/implicit_dynamic.svg figures/problemDomain.pdf_tex figures/problemDomain.pdf figures/static_analysis.png figures/stress_strain_el.pdf figures/tangent.pdf figures/tangent.svg figures/stress_strain_neo.pdf figures/visco_elastic_law.pdf figures/isotropic_hardening_plasticity.pdf figures/stress_strain_visco.pdf ) package_declare_extra_files_to_package(solid_mechanics SOURCES model/solid_mechanics/material_list.hh.in ) diff --git a/python/swig/model.i b/python/swig/model.i index 321fac529..365a13d2b 100644 --- a/python/swig/model.i +++ b/python/swig/model.i @@ -1,132 +1,131 @@ /** * @file model.i * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Dec 12 2014 * @date last modification: Wed Nov 11 2015 * * @brief model wrapper * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ %{ #include "boundary_condition_python_functor.hh" #include "model_solver.hh" #include "non_linear_solver.hh" %} namespace akantu { %ignore Model::createSynchronizerRegistry; %ignore Model::getSynchronizerRegistry; %ignore Model::createParallelSynch; %ignore Model::getDOFSynchronizer; %ignore Model::registerFEEngineObject; %ignore Model::unregisterFEEngineObject; %ignore Model::getFEEngineBoundary; // %ignore Model::getFEEngine; %ignore Model::getFEEngineClass; %ignore Model::getFEEngineClassBoundary; %ignore Model::setParser; %ignore Model::updateDataForNonLocalCriterion; %ignore IntegrationPoint::operator=; %ignore FEEngine::getNbIntegrationPoints; %ignore FEEngine::getShapes; %ignore FEEngine::getShapesDerivatives; %ignore FEEngine::getIntegrationPoints; %ignore FEEngine::getIGFEMElementTypes; %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,ElementTypeMapArray<Real> &,const ElementTypeMapArray<UInt> *) const; %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,ElementTypeMapArray<Real> &) const; %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,Array<Real> &,UInt,const ElementType&,const GhostType &,const Array< UInt > &) const; %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,Array<Real> &,UInt,const ElementType&,const GhostType &) const; %ignore FEEngine::onNodesAdded; %ignore FEEngine::onNodesRemoved; %ignore FEEngine::onElementsAdded; %ignore FEEngine::onElementsChanged; %ignore FEEngine::onElementsRemoved; %ignore FEEngine::elementTypes; } %include "sparse_matrix.i" %include "fe_engine.hh" %rename(FreeBoundaryDirichlet) akantu::BC::Dirichlet::FreeBoundary; %rename(FreeBoundaryNeumann) akantu::BC::Neumann::FreeBoundary; %rename(PythonBoundary) akantu::BC::Dirichlet::PythonFunctor; %include "boundary_condition_functor.hh" %include "boundary_condition.hh" %include "boundary_condition_python_functor.hh" %include "communication_buffer.hh" %include "data_accessor.hh" //%include "synchronizer.hh" //%include "synchronizer_registry.hh" %include "model.hh" %include "non_linear_solver.hh" %extend akantu::Model { void initFullImpl( const akantu::ModelOptions & options = akantu::ModelOptions()){ $self->initFull(options); }; %insert("python") %{ def initFull(self, *args, **kwargs): if len(args) == 0: import importlib as __aka_importlib _module = __aka_importlib.import_module(self.__module__) _cls = getattr(_module, "{0}Options".format(self.__class__.__name__)) options = _cls() if len(kwargs) > 0: for key, val in kwargs.items(): if key[0] == '_': key = key[1:] - _attr = getattr(options, key) - _attr = val + setattr(options, key, val) else: options = args[0] self.initFullImpl(options) %} void solveStep(){ $self->solveStep(); } akantu::NonLinearSolver & getNonLinearSolver(){ return $self->getNonLinearSolver(); } } %extend akantu::NonLinearSolver { void set(const std::string & id, akantu::Real val){ if (id == "max_iterations") $self->set(id, int(val)); else if (id == "convergence_type") $self->set(id, akantu::SolveConvergenceCriteria(UInt(val))); else $self->set(id, val); } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c753e1594..c3ec182d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,217 +1,216 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Jun 14 2010 # @date last modification: Wed Jan 20 2016 # # @brief CMake file for the library # # @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 <http://www.gnu.org/licenses/>. # #=============================================================================== #=============================================================================== # Package Management #=============================================================================== package_get_all_source_files( AKANTU_LIBRARY_SRCS AKANTU_LIBRARY_PUBLIC_HDRS AKANTU_LIBRARY_PRIVATE_HDRS ) package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) package_get_all_external_informations( PRIVATE_INCLUDE AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR LIBRARIES AKANTU_EXTERNAL_LIBRARIES ) package_get_all_compilation_flags(CXX _cxx_flags) set(AKANTU_EXTRA_CXX_FLAGS "${_cxx_flags}" CACHE STRING "Extra flags defined by loaded packages" FORCE) mark_as_advanced(AKANTU_EXTRA_CXX_FLAGS) foreach(src_ ${AKANTU_SPIRIT_SOURCES}) set_property(SOURCE ${src_} PROPERTY COMPILE_FLAGS "-g0 -Werror") endforeach() #=========================================================================== # header for blas/lapack (any other fortran libraries) #=========================================================================== package_is_activated(BLAS _blas_activated) package_is_activated(LAPACK _lapack_activated) if(_blas_activated OR _lapack_activated) if(CMAKE_Fortran_COMPILER) # ugly hack set(CMAKE_Fortran_COMPILER_LOADED TRUE) endif() include(FortranCInterface) FortranCInterface_HEADER( "${CMAKE_CURRENT_BINARY_DIR}/aka_fortran_mangling.hh" MACRO_NAMESPACE "AKA_FC_") mark_as_advanced(CDEFS) endif() list(APPEND AKANTU_LIBRARY_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}") set(AKANTU_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} ${AKANTU_LIBRARY_INCLUDE_DIRS} CACHE INTERNAL "Internal include directories to link with Akantu as a subproject") #=========================================================================== # configurations #=========================================================================== package_get_all_material_includes(AKANTU_MATERIAL_INCLUDES) package_get_all_material_lists(AKANTU_MATERIAL_LISTS) configure_file(model/solid_mechanics/material_list.hh.in "${CMAKE_CURRENT_BINARY_DIR}/material_list.hh" @ONLY) package_get_element_lists() configure_file(common/aka_element_classes_info.hh.in "${CMAKE_CURRENT_BINARY_DIR}/aka_element_classes_info.hh" @ONLY) configure_file(common/aka_config.hh.in "${CMAKE_CURRENT_BINARY_DIR}/aka_config.hh" @ONLY) #=============================================================================== # Debug infos #=============================================================================== set(AKANTU_GDB_DIR ${PROJECT_SOURCE_DIR}/cmake) if(UNIX) string(TOUPPER "${CMAKE_BUILD_TYPE}" _u_build_type) if(_u_build_type STREQUAL "DEBUG" OR _u_build_type STREQUAL "RELWITHDEBINFO") configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in "${PROJECT_BINARY_DIR}/libakantu-gdb.py" @ONLY) configure_file(${PROJECT_SOURCE_DIR}/cmake/akantu-debug.cc.in "${PROJECT_BINARY_DIR}/akantu-debug.cc" @ONLY) list(APPEND AKANTU_LIBRARY_SRCS ${PROJECT_BINARY_DIR}/akantu-debug.cc) endif() else() find_program(GDB_EXECUTABLE gdb) if(GDB_EXECUTABLE) execute_process(COMMAND ${GDB_EXECUTABLE} --batch -x "${PROJECT_SOURCE_DIR}/cmake/gdb_python_path" OUTPUT_VARIABLE AKANTU_PYTHON_GDB_DIR ERROR_QUIET RESULT_VARIABLE _res) if(_res EQUAL 0 AND UNIX) set(GDB_USER_CONFIG $ENV{HOME}/.gdb/auto-load) file(MAKE_DIRECTORY ${GDB_USER_CONFIG}) configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in "${GDB_USER_CONFIG}/${CMAKE_SHARED_LIBRARY_PREFIX}akantu${CMAKE_SHARED_LIBRARY_SUFFIX}.${AKANTU_VERSION}-gdb.py" @ONLY) endif() endif() endif() #=============================================================================== # Library generation #=============================================================================== add_library(akantu ${AKANTU_LIBRARY_SRCS}) target_include_directories(akantu PRIVATE $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}> INTERFACE $<INSTALL_INTERFACE:include/akantu> ) # small trick for build includes in public set_property(TARGET akantu APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}>) target_include_directories(akantu SYSTEM - PUBLIC $<BUILD_INTERFACE:${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR}> - $<INSTALL_INTERFACE:${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR}> + PUBLIC ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR} ) target_include_directories(akantu SYSTEM PRIVATE ${AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR} ) target_link_libraries(akantu ${AKANTU_EXTERNAL_LIBRARIES}) set_target_properties(akantu PROPERTIES ${AKANTU_LIBRARY_PROPERTIES} # this contains the version COMPILE_FLAGS "${_cxx_flags}" ) if(NOT CMAKE_VERSION VERSION_LESS 3.1) package_get_all_features_public(_PUBLIC_features) package_get_all_features_private(_PRIVATE_features) foreach(_type PRIVATE PUBLIC) if(_${_type}_features) target_compile_features(akantu ${_type} ${_${_type}_features}) endif() endforeach() else() set_target_properties(akantu PROPERTIES CXX_STANDARD 14 ) endif() package_get_all_extra_dependencies(_extra_target_dependencies) if(_extra_target_dependencies) # This only adding todo: find a solution for when a dependency was add the is removed... add_dependencies(akantu ${_extra_target_dependencies}) endif() package_get_all_export_list(AKANTU_EXPORT_LIST) list(APPEND AKANTU_EXPORT_LIST akantu) # TODO separate public from private headers install(TARGETS akantu EXPORT ${AKANTU_TARGETS_EXPORT} LIBRARY DESTINATION lib COMPONENT lib ARCHIVE DESTINATION lib COMPONENT lib RUNTIME DESTINATION bin COMPONENT bin PUBLIC_HEADER DESTINATION include/akantu/ COMPONENT dev ) if("${AKANTU_TARGETS_EXPORT}" STREQUAL "AkantuTargets") install(EXPORT AkantuTargets DESTINATION share/cmake/${PROJECT_NAME} COMPONENT dev) #Export for build tree export(EXPORT AkantuTargets FILE "${CMAKE_BINARY_DIR}/AkantuTargets.cmake") export(PACKAGE Akantu) endif() # print out the list of materials generate_material_list() register_target_to_tidy(akantu) diff --git a/src/common/aka_extern.cc b/src/common/aka_extern.cc index ca6b5a5e7..78ae76cfa 100644 --- a/src/common/aka_extern.cc +++ b/src/common/aka_extern.cc @@ -1,109 +1,109 @@ /** * @file aka_extern.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 * @date last modification: Thu Nov 19 2015 * * @brief initialisation of all global variables * to insure the order of creation * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "aka_math.hh" #include "aka_named_argument.hh" #include "aka_random_generator.hh" #include "communication_tag.hh" #include "cppargparse.hh" #include "parser.hh" #include "solid_mechanics_model.hh" #if defined(AKANTU_COHESIVE_ELEMENT) #include "solid_mechanics_model_cohesive.hh" #endif /* -------------------------------------------------------------------------- */ #include <iostream> #include <limits> /* -------------------------------------------------------------------------- */ #if defined(AKANTU_DEBUG_TOOLS) #include "aka_debug_tools.hh" #endif namespace akantu { /* -------------------------------------------------------------------------- */ /* error.hpp variables */ /* -------------------------------------------------------------------------- */ namespace debug { /** \todo write function to get this * values from the environment or a config file */ /// standard output for debug messages std::ostream * _akantu_debug_cout = &std::cerr; /// standard output for normal messages std::ostream & _akantu_cout = std::cout; /// parallel context used in debug messages std::string _parallel_context = ""; Debugger debugger; #if defined(AKANTU_DEBUG_TOOLS) DebugElementManager element_manager; #endif } // namespace debug /* -------------------------------------------------------------------------- */ /// list of ghost iterable types ghost_type_t ghost_types(_casper); /* -------------------------------------------------------------------------- */ /// Paser for commandline arguments ::cppargparse::ArgumentParser static_argparser; /// Parser containing the information parsed by the input file given to initFull Parser static_parser; bool Parser::permissive_parser = false; /* -------------------------------------------------------------------------- */ -Real Math::tolerance = std::numeric_limits<Real>::epsilon(); +Real Math::tolerance = 1e2 * std::numeric_limits<Real>::epsilon(); /* -------------------------------------------------------------------------- */ const UInt _all_dimensions = UInt(-1); /* -------------------------------------------------------------------------- */ const Array<UInt> empty_filter(0, 1, "empty_filter"); /* -------------------------------------------------------------------------- */ template <> long int RandomGenerator<UInt>::_seed = 5489u; template <> std::default_random_engine RandomGenerator<UInt>::generator(5489u); /* -------------------------------------------------------------------------- */ int Tag::max_tag = 0; /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/common/aka_types.hh b/src/common/aka_types.hh index 62d998fde..203d4d318 100644 --- a/src/common/aka_types.hh +++ b/src/common/aka_types.hh @@ -1,1302 +1,1302 @@ /** * @file aka_types.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 17 2011 * @date last modification: Fri Jan 22 2016 * * @brief description of the "simple" types * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_error.hh" #include "aka_fwd.hh" #include "aka_math.hh" /* -------------------------------------------------------------------------- */ #include <initializer_list> #include <iomanip> #include <type_traits> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_TYPES_HH__ #define __AKANTU_AKA_TYPES_HH__ namespace akantu { enum NormType { L_1 = 1, L_2 = 2, L_inf = UInt(-1) }; /** * DimHelper is a class to generalize the setup of a dim array from 3 * values. This gives a common interface in the TensorStorage class * independently of its derived inheritance (Vector, Matrix, Tensor3) * @tparam dim */ template <UInt dim> struct DimHelper { static inline void setDims(UInt m, UInt n, UInt p, UInt dims[dim]); }; /* -------------------------------------------------------------------------- */ template <> struct DimHelper<1> { static inline void setDims(UInt m, __attribute__((unused)) UInt n, __attribute__((unused)) UInt p, UInt dims[1]) { dims[0] = m; } }; /* -------------------------------------------------------------------------- */ template <> struct DimHelper<2> { static inline void setDims(UInt m, UInt n, __attribute__((unused)) UInt p, UInt dims[2]) { dims[0] = m; dims[1] = n; } }; /* -------------------------------------------------------------------------- */ template <> struct DimHelper<3> { static inline void setDims(UInt m, UInt n, UInt p, UInt dims[3]) { dims[0] = m; dims[1] = n; dims[2] = p; } }; /* -------------------------------------------------------------------------- */ template <typename T, UInt ndim, class RetType> class TensorStorage; /* -------------------------------------------------------------------------- */ /* Proxy classes */ /* -------------------------------------------------------------------------- */ namespace tensors { template <class A, class B> struct is_copyable { enum : bool { value = false }; }; template <class A> struct is_copyable<A, A> { enum : bool { value = true }; }; template <class A> struct is_copyable<A, typename A::RetType> { enum : bool { value = true }; }; template <class A> struct is_copyable<A, typename A::RetType::proxy> { enum : bool { value = true }; }; } // namespace tensors /** * @class TensorProxy aka_types.hh * @desc The TensorProxy class is a proxy class to the TensorStorage it handles * the * wrapped case. That is to say if an accessor should give access to a Tensor * wrapped on some data, like the Array<T>::iterator they can return a * TensorProxy that will be automatically transformed as a TensorStorage wrapped * on the same data * @tparam T stored type * @tparam ndim order of the tensor * @tparam RetType real derived type */ template <typename T, UInt ndim, class _RetType> class TensorProxy { protected: using RetTypeProxy = typename _RetType::proxy; constexpr TensorProxy(T * data, UInt m, UInt n, UInt p) { DimHelper<ndim>::setDims(m, n, p, this->n); this->values = data; } #ifndef SWIG template <class Other, typename = std::enable_if_t< tensors::is_copyable<TensorProxy, Other>::value>> explicit TensorProxy(const Other & other) { this->values = other.storage(); for (UInt i = 0; i < ndim; ++i) this->n[i] = other.size(i); } #endif public: using RetType = _RetType; UInt size(UInt i) const { AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim << " dimensions, not " << (i + 1)); return n[i]; } inline UInt size() const { UInt _size = 1; for (UInt d = 0; d < ndim; ++d) _size *= this->n[d]; return _size; } T * storage() const { return values; } #ifndef SWIG template <class Other, typename = std::enable_if_t< tensors::is_copyable<TensorProxy, Other>::value>> inline TensorProxy & operator=(const Other & other) { AKANTU_DEBUG_ASSERT( other.size() == this->size(), "You are trying to copy two tensors with different sizes"); memcpy(this->values, other.storage(), this->size() * sizeof(T)); return *this; } #endif // template <class Other, typename = std::enable_if_t< // tensors::is_copyable<TensorProxy, Other>::value>> // inline TensorProxy & operator=(const Other && other) { // AKANTU_DEBUG_ASSERT( // other.size() == this->size(), // "You are trying to copy two tensors with different sizes"); // memcpy(this->values, other.storage(), this->size() * sizeof(T)); // return *this; // } template <typename O> inline RetTypeProxy & operator*=(const O & o) { RetType(*this) *= o; return static_cast<RetTypeProxy &>(*this); } template <typename O> inline RetTypeProxy & operator/=(const O & o) { RetType(*this) /= o; return static_cast<RetTypeProxy &>(*this); } protected: T * values; UInt n[ndim]; }; /* -------------------------------------------------------------------------- */ template <typename T> class VectorProxy : public TensorProxy<T, 1, Vector<T>> { using parent = TensorProxy<T, 1, Vector<T>>; using type = Vector<T>; public: constexpr VectorProxy(T * data, UInt n) : parent(data, n, 0, 0) {} template <class Other> explicit VectorProxy(Other & src) : parent(src) {} /* ---------------------------------------------------------------------- */ template <class Other> inline VectorProxy<T> & operator=(const Other & other) { parent::operator=(other); return *this; } // inline VectorProxy<T> & operator=(const VectorProxy && other) { // parent::operator=(other); // return *this; // } /* ------------------------------------------------------------------------ */ T & operator()(UInt index) { return this->values[index]; }; const T & operator()(UInt index) const { return this->values[index]; }; }; template <typename T> class MatrixProxy : public TensorProxy<T, 2, Matrix<T>> { using parent = TensorProxy<T, 2, Matrix<T>>; using type = Matrix<T>; public: MatrixProxy(T * data, UInt m, UInt n) : parent(data, m, n, 0) {} template <class Other> explicit MatrixProxy(Other & src) : parent(src) {} /* ---------------------------------------------------------------------- */ template <class Other> inline MatrixProxy<T> & operator=(const Other & other) { parent::operator=(other); return *this; } }; template <typename T> class Tensor3Proxy : public TensorProxy<T, 3, Tensor3<T>> { using parent = TensorProxy<T, 3, Tensor3<T>>; using type = Tensor3<T>; public: Tensor3Proxy(const T * data, UInt m, UInt n, UInt k) : parent(data, m, n, k) {} Tensor3Proxy(const Tensor3Proxy & src) : parent(src) {} Tensor3Proxy(const Tensor3<T> & src) : parent(src) {} /* ---------------------------------------------------------------------- */ template <class Other> inline Tensor3Proxy<T> & operator=(const Other & other) { parent::operator=(other); return *this; } }; /* -------------------------------------------------------------------------- */ /* Tensor base class */ /* -------------------------------------------------------------------------- */ template <typename T, UInt ndim, class RetType> class TensorStorage : public TensorTrait { public: using value_type = T; friend class Array<T>; protected: template <class TensorType> void copySize(const TensorType & src) { for (UInt d = 0; d < ndim; ++d) this->n[d] = src.size(d); this->_size = src.size(); } TensorStorage() : values(nullptr) { for (UInt d = 0; d < ndim; ++d) this->n[d] = 0; _size = 0; } TensorStorage(const TensorProxy<T, ndim, RetType> & proxy) { this->copySize(proxy); this->values = proxy.storage(); this->wrapped = true; } public: TensorStorage(const TensorStorage & src) = delete; TensorStorage(const TensorStorage & src, bool deep_copy) : values(nullptr) { if (deep_copy) this->deepCopy(src); else this->shallowCopy(src); } protected: TensorStorage(UInt m, UInt n, UInt p, const T & def) { static_assert(std::is_trivially_constructible<T>{}, "Cannot create a tensor on non trivial types"); DimHelper<ndim>::setDims(m, n, p, this->n); this->computeSize(); this->values = new T[this->_size]; this->set(def); this->wrapped = false; } TensorStorage(T * data, UInt m, UInt n, UInt p) { DimHelper<ndim>::setDims(m, n, p, this->n); this->computeSize(); this->values = data; this->wrapped = true; } public: /* ------------------------------------------------------------------------ */ template <class TensorType> inline void shallowCopy(const TensorType & src) { this->copySize(src); if (!this->wrapped) delete[] this->values; this->values = src.storage(); this->wrapped = true; } /* ------------------------------------------------------------------------ */ template <class TensorType> inline void deepCopy(const TensorType & src) { this->copySize(src); if (!this->wrapped) delete[] this->values; static_assert(std::is_trivially_constructible<T>{}, "Cannot create a tensor on non trivial types"); this->values = new T[this->_size]; static_assert(std::is_trivially_copyable<T>{}, "Cannot copy a tensor on non trivial types"); memcpy((void *)this->values, (void *)src.storage(), this->_size * sizeof(T)); this->wrapped = false; } virtual ~TensorStorage() { if (!this->wrapped) delete[] this->values; } /* ------------------------------------------------------------------------ */ inline TensorStorage & operator=(const TensorStorage & src) { return this->operator=(dynamic_cast<RetType &>(src)); } /* ------------------------------------------------------------------------ */ inline TensorStorage & operator=(const RetType & src) { if (this != &src) { if (this->wrapped) { static_assert(std::is_trivially_copyable<T>{}, "Cannot copy a tensor on non trivial types"); // this test is not sufficient for Tensor of order higher than 1 AKANTU_DEBUG_ASSERT(this->_size == src.size(), "Tensors of different size"); memcpy((void *)this->values, (void *)src.storage(), this->_size * sizeof(T)); } else { deepCopy(src); } } return *this; } /* ------------------------------------------------------------------------ */ template <class R> inline RetType & operator+=(const TensorStorage<T, ndim, R> & other) { T * a = this->storage(); T * b = other.storage(); AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); for (UInt i = 0; i < _size; ++i) *(a++) += *(b++); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ template <class R> inline RetType & operator-=(const TensorStorage<T, ndim, R> & other) { T * a = this->storage(); T * b = other.storage(); AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); for (UInt i = 0; i < _size; ++i) *(a++) -= *(b++); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator+=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) += x; return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator-=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) -= x; return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator*=(const T & x) { T * a = this->storage(); for (UInt i = 0; i < _size; ++i) *(a++) *= x; return *(static_cast<RetType *>(this)); } /* ---------------------------------------------------------------------- */ inline RetType & operator/=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) /= x; return *(static_cast<RetType *>(this)); } /// Y = \alpha X + Y inline RetType & aXplusY(const TensorStorage & other, const T & alpha = 1.) { AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); Math::aXplusY(this->_size, alpha, other.storage(), this->storage()); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ T * storage() const { return values; } UInt size() const { return _size; } UInt size(UInt i) const { AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim << " dimensions, not " << (i + 1)); return n[i]; }; /* ------------------------------------------------------------------------ */ inline void clear() { memset(values, 0, _size * sizeof(T)); }; inline void set(const T & t) { std::fill_n(values, _size, t); }; template <class TensorType> inline void copy(const TensorType & other) { AKANTU_DEBUG_ASSERT( _size == other.size(), "The two tensors do not have the same size, they cannot be copied"); memcpy(values, other.storage(), _size * sizeof(T)); } bool isWrapped() const { return this->wrapped; } protected: inline void computeSize() { _size = 1; for (UInt d = 0; d < ndim; ++d) _size *= this->n[d]; } protected: template <typename R, NormType norm_type> struct NormHelper { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += std::pow(std::abs(*it), norm_type); return std::pow(_norm, 1. / norm_type); } }; template <typename R> struct NormHelper<R, L_1> { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += std::abs(*it); return _norm; } }; template <typename R> struct NormHelper<R, L_2> { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += *it * *it; return sqrt(_norm); } }; template <typename R> struct NormHelper<R, L_inf> { template <class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm = std::max(std::abs(*it), _norm); return _norm; } }; public: /*----------------------------------------------------------------------- */ /// "Entrywise" norm norm<L_p> @f[ \|\boldsymbol{T}\|_p = \left( /// \sum_i^{n[0]}\sum_j^{n[1]}\sum_k^{n[2]} |T_{ijk}|^p \right)^{\frac{1}{p}} /// @f] template <NormType norm_type> inline T norm() const { return NormHelper<T, norm_type>::norm(*this); } protected: UInt n[ndim]; UInt _size; T * values; bool wrapped{false}; }; /* -------------------------------------------------------------------------- */ /* Vector */ /* -------------------------------------------------------------------------- */ template <typename T> class Vector : public TensorStorage<T, 1, Vector<T>> { using parent = TensorStorage<T, 1, Vector<T>>; public: using value_type = typename parent::value_type; using proxy = VectorProxy<T>; public: Vector() : parent() {} explicit Vector(UInt n, const T & def = T()) : parent(n, 0, 0, def) {} Vector(T * data, UInt n) : parent(data, n, 0, 0) {} Vector(const Vector & src, bool deep_copy = true) : parent(src, deep_copy) {} Vector(const TensorProxy<T, 1, Vector> & src) : parent(src) {} Vector(std::initializer_list<T> list) : parent(list.size(), 0, 0, T()) { UInt i = 0; for (auto val : list) { operator()(i++) = val; } } public: ~Vector() override = default; /* ------------------------------------------------------------------------ */ inline Vector & operator=(const Vector & src) { parent::operator=(src); return *this; } /* ------------------------------------------------------------------------ */ inline T & operator()(UInt i) { AKANTU_DEBUG_ASSERT((i < this->n[0]), "Access out of the vector! " << "Index (" << i << ") is out of the vector of size (" << this->n[0] << ")"); return *(this->values + i); } inline const T & operator()(UInt i) const { AKANTU_DEBUG_ASSERT((i < this->n[0]), "Access out of the vector! " << "Index (" << i << ") is out of the vector of size (" << this->n[0] << ")"); return *(this->values + i); } inline T & operator[](UInt i) { return this->operator()(i); } inline const T & operator[](UInt i) const { return this->operator()(i); } /* ------------------------------------------------------------------------ */ inline Vector<T> & operator*=(Real x) { return parent::operator*=(x); } inline Vector<T> & operator/=(Real x) { return parent::operator/=(x); } /* ------------------------------------------------------------------------ */ inline Vector<T> & operator*=(const Vector<T> & vect) { T * a = this->storage(); T * b = vect.storage(); for (UInt i = 0; i < this->_size; ++i) *(a++) *= *(b++); return *this; } /* ------------------------------------------------------------------------ */ inline Real dot(const Vector<T> & vect) const { return Math::vectorDot(this->values, vect.storage(), this->_size); } /* ------------------------------------------------------------------------ */ inline Real mean() const { Real mean = 0; T * a = this->storage(); for (UInt i = 0; i < this->_size; ++i) mean += *(a++); return mean / this->_size; } /* ------------------------------------------------------------------------ */ inline Vector & crossProduct(const Vector<T> & v1, const Vector<T> & v2) { AKANTU_DEBUG_ASSERT(this->size() == 3, "crossProduct is only defined in 3D (n=" << this->size() << ")"); AKANTU_DEBUG_ASSERT( this->size() == v1.size() && this->size() == v2.size(), "crossProduct is not a valid operation non matching size vectors"); Math::vectorProduct3(v1.storage(), v2.storage(), this->values); return *this; } inline Vector crossProduct(const Vector<T> & v) { Vector<T> tmp(this->size()); tmp.crossProduct(*this, v); return tmp; } /* ------------------------------------------------------------------------ */ inline void solve(const Matrix<T> & A, const Vector<T> & b) { AKANTU_DEBUG_ASSERT( this->size() == A.rows() && this->_size == A.cols(), "The size of the solution vector mismatches the size of the matrix"); AKANTU_DEBUG_ASSERT( this->_size == b._size, "The rhs vector has a mismatch in size with the matrix"); Math::solve(this->_size, A.storage(), this->values, b.storage()); } /* ------------------------------------------------------------------------ */ template <bool tr_A> inline void mul(const Matrix<T> & A, const Vector<T> & x, Real alpha = 1.0); /* ------------------------------------------------------------------------ */ inline Real norm() const { return parent::template norm<L_2>(); } template <NormType nt> inline Real norm() const { return parent::template norm<nt>(); } /* ------------------------------------------------------------------------ */ inline Vector<Real> & normalize() { Real n = norm(); operator/=(n); return *this; } /* ------------------------------------------------------------------------ */ /// norm of (*this - x) inline Real distance(const Vector<T> & y) const { Real * vx = this->values; Real * vy = y.storage(); Real sum_2 = 0; for (UInt i = 0; i < this->_size; ++i, ++vx, ++vy) sum_2 += (*vx - *vy) * (*vx - *vy); return sqrt(sum_2); } /* ------------------------------------------------------------------------ */ inline bool equal(const Vector<T> & v, Real tolerance = Math::getTolerance()) const { T * a = this->storage(); T * b = v.storage(); UInt i = 0; while (i < this->_size && (std::abs(*(a++) - *(b++)) < tolerance)) ++i; return i == this->_size; } /* ------------------------------------------------------------------------ */ inline short compare(const Vector<T> & v, Real tolerance = Math::getTolerance()) const { T * a = this->storage(); T * b = v.storage(); for (UInt i(0); i < this->_size; ++i, ++a, ++b) { if (std::abs(*a - *b) > tolerance) return (((*a - *b) > tolerance) ? 1 : -1); } return 0; } /* ------------------------------------------------------------------------ */ inline bool operator==(const Vector<T> & v) const { return equal(v); } inline bool operator!=(const Vector<T> & v) const { return !operator==(v); } inline bool operator<(const Vector<T> & v) const { return compare(v) == -1; } inline bool operator>(const Vector<T> & v) const { return compare(v) == 1; } /* ------------------------------------------------------------------------ */ /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << "["; for (UInt i = 0; i < this->_size; ++i) { if (i != 0) stream << ", "; stream << this->values[i]; } stream << "]"; } // friend class ::akantu::Array<T>; }; using RVector = Vector<Real>; /* ------------------------------------------------------------------------ */ template <> inline bool Vector<UInt>::equal(const Vector<UInt> & v, __attribute__((unused)) Real tolerance) const { UInt * a = this->storage(); UInt * b = v.storage(); UInt i = 0; while (i < this->_size && (*(a++) == *(b++))) ++i; return i == this->_size; } /* ------------------------------------------------------------------------ */ /* Matrix */ /* ------------------------------------------------------------------------ */ template <typename T> class Matrix : public TensorStorage<T, 2, Matrix<T>> { using parent = TensorStorage<T, 2, Matrix<T>>; public: using value_type = typename parent::value_type; using proxy = MatrixProxy<T>; public: Matrix() : parent() {} Matrix(UInt m, UInt n, const T & def = T()) : parent(m, n, 0, def) {} Matrix(T * data, UInt m, UInt n) : parent(data, m, n, 0) {} Matrix(const Matrix & src, bool deep_copy = true) : parent(src, deep_copy) {} Matrix(const MatrixProxy<T> & src) : parent(src) {} Matrix(std::initializer_list<std::initializer_list<T>> list) { static_assert(std::is_trivially_copyable<T>{}, "Cannot create a tensor on non trivial types"); std::size_t n = 0; std::size_t m = list.size(); for (auto row : list) { n = std::max(n, row.size()); } DimHelper<2>::setDims(m, n, 0, this->n); this->computeSize(); this->values = new T[this->_size]; this->set(0); UInt i = 0, j = 0; for (auto & row : list) { for (auto & val : row) { at(i, j++) = val; } ++i; j = 0; } } ~Matrix() override = default; /* ------------------------------------------------------------------------ */ inline Matrix & operator=(const Matrix & src) { parent::operator=(src); return *this; } public: /* ---------------------------------------------------------------------- */ UInt rows() const { return this->n[0]; } UInt cols() const { return this->n[1]; } /* ---------------------------------------------------------------------- */ inline T & at(UInt i, UInt j) { AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])), "Access out of the matrix! " << "Index (" << i << ", " << j << ") is out of the matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return *(this->values + i + j * this->n[0]); } inline const T & at(UInt i, UInt j) const { AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])), "Access out of the matrix! " << "Index (" << i << ", " << j << ") is out of the matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return *(this->values + i + j * this->n[0]); } /* ------------------------------------------------------------------------ */ inline T & operator()(UInt i, UInt j) { return this->at(i, j); } inline const T & operator()(UInt i, UInt j) const { return this->at(i, j); } /// give a line vector wrapped on the column i inline VectorProxy<T> operator()(UInt j) { AKANTU_DEBUG_ASSERT(j < this->n[1], "Access out of the matrix! " << "You are trying to access the column vector " << j << " in a matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return VectorProxy<T>(this->values + j * this->n[0], this->n[0]); } inline const VectorProxy<T> operator()(UInt j) const { AKANTU_DEBUG_ASSERT(j < this->n[1], "Access out of the matrix! " << "You are trying to access the column vector " << j << " in a matrix of size (" << this->n[0] << ", " << this->n[1] << ")"); return VectorProxy<T>(this->values + j * this->n[0], this->n[0]); } - inline void block(Matrix & block, UInt pos_i, UInt pos_j) { + inline void block(const Matrix & block, UInt pos_i, UInt pos_j) { AKANTU_DEBUG_ASSERT(pos_i + block.rows() <= rows(), "The block size or position are not correct"); AKANTU_DEBUG_ASSERT(pos_i + block.cols() <= cols(), "The block size or position are not correct"); for (UInt i = 0; i < block.rows(); ++i) for (UInt j = 0; j < block.cols(); ++j) this->at(i + pos_i, j + pos_j) = block(i, j); } inline Matrix block(UInt pos_i, UInt pos_j, UInt block_rows, UInt block_cols) const { AKANTU_DEBUG_ASSERT(pos_i + block_rows <= rows(), "The block size or position are not correct"); AKANTU_DEBUG_ASSERT(pos_i + block_cols <= cols(), "The block size or position are not correct"); Matrix block(block_rows, block_cols); for (UInt i = 0; i < block_rows; ++i) for (UInt j = 0; j < block_cols; ++j) block(i, j) = this->at(i + pos_i, j + pos_j); return block; } inline T & operator[](UInt idx) { return *(this->values + idx); }; inline const T & operator[](UInt idx) const { return *(this->values + idx); }; /* ---------------------------------------------------------------------- */ inline Matrix operator*(const Matrix & B) { Matrix C(this->rows(), B.cols()); C.mul<false, false>(*this, B); return C; } /* ----------------------------------------------------------------------- */ inline Matrix & operator*=(const T & x) { return parent::operator*=(x); } inline Matrix & operator*=(const Matrix & B) { Matrix C(*this); this->mul<false, false>(C, B); return *this; } /* ---------------------------------------------------------------------- */ template <bool tr_A, bool tr_B> inline void mul(const Matrix & A, const Matrix & B, T alpha = 1.0) { UInt k = A.cols(); if (tr_A) k = A.rows(); #ifndef AKANTU_NDEBUG if (tr_B) { AKANTU_DEBUG_ASSERT(k == B.cols(), "matrices to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->cols() == B.rows(), "matrices to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(k == B.rows(), "matrices to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->cols() == B.cols(), "matrices to multiply have no fit dimensions"); } if (tr_A) { AKANTU_DEBUG_ASSERT(this->rows() == A.cols(), "matrices to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(this->rows() == A.rows(), "matrices to multiply have no fit dimensions"); } #endif // AKANTU_NDEBUG Math::matMul<tr_A, tr_B>(this->rows(), this->cols(), k, alpha, A.storage(), B.storage(), 0., this->storage()); } /* ---------------------------------------------------------------------- */ inline void outerProduct(const Vector<T> & A, const Vector<T> & B) { AKANTU_DEBUG_ASSERT( A.size() == this->rows() && B.size() == this->cols(), "A and B are not compatible with the size of the matrix"); for (UInt i = 0; i < this->rows(); ++i) { for (UInt j = 0; j < this->cols(); ++j) { this->values[i + j * this->rows()] += A[i] * B[j]; } } } private: class EigenSorter { public: EigenSorter(const Vector<T> & eigs) : eigs(eigs) {} bool operator()(const UInt & a, const UInt & b) const { return (eigs(a) > eigs(b)); } private: const Vector<T> & eigs; }; public: /* ---------------------------------------------------------------------- */ inline void eig(Vector<T> & eigenvalues, Matrix<T> & eigenvectors) const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "eig is not a valid operation on a rectangular matrix"); AKANTU_DEBUG_ASSERT(eigenvalues.size() == this->cols(), "eigenvalues should be of size " << this->cols() << "."); #ifndef AKANTU_NDEBUG if (eigenvectors.storage() != nullptr) AKANTU_DEBUG_ASSERT((eigenvectors.rows() == eigenvectors.cols()) && (eigenvectors.rows() == this->cols()), "Eigenvectors needs to be a square matrix of size " << this->cols() << " x " << this->cols() << "."); #endif Matrix<T> tmp = *this; Vector<T> tmp_eigs(eigenvalues.size()); Matrix<T> tmp_eig_vects(eigenvectors.rows(), eigenvectors.cols()); if (tmp_eig_vects.rows() == 0 || tmp_eig_vects.cols() == 0) Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage()); else Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage(), tmp_eig_vects.storage()); Vector<UInt> perm(eigenvalues.size()); for (UInt i = 0; i < perm.size(); ++i) perm(i) = i; std::sort(perm.storage(), perm.storage() + perm.size(), EigenSorter(tmp_eigs)); for (UInt i = 0; i < perm.size(); ++i) eigenvalues(i) = tmp_eigs(perm(i)); if (tmp_eig_vects.rows() != 0 && tmp_eig_vects.cols() != 0) for (UInt i = 0; i < perm.size(); ++i) { for (UInt j = 0; j < eigenvectors.rows(); ++j) { eigenvectors(j, i) = tmp_eig_vects(j, perm(i)); } } } /* ---------------------------------------------------------------------- */ inline void eig(Vector<T> & eigenvalues) const { Matrix<T> empty; eig(eigenvalues, empty); } /* ---------------------------------------------------------------------- */ inline void eye(T alpha = 1.) { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "eye is not a valid operation on a rectangular matrix"); this->clear(); for (UInt i = 0; i < this->cols(); ++i) { this->values[i + i * this->rows()] = alpha; } } /* ---------------------------------------------------------------------- */ static inline Matrix<T> eye(UInt m, T alpha = 1.) { Matrix<T> tmp(m, m); tmp.eye(alpha); return tmp; } /* ---------------------------------------------------------------------- */ inline T trace() const { AKANTU_DEBUG_ASSERT( this->cols() == this->rows(), "trace is not a valid operation on a rectangular matrix"); T trace = 0.; for (UInt i = 0; i < this->rows(); ++i) { trace += this->values[i + i * this->rows()]; } return trace; } /* ---------------------------------------------------------------------- */ inline Matrix transpose() const { Matrix tmp(this->cols(), this->rows()); for (UInt i = 0; i < this->rows(); ++i) { for (UInt j = 0; j < this->cols(); ++j) { tmp(j, i) = operator()(i, j); } } return tmp; } /* ---------------------------------------------------------------------- */ inline void inverse(const Matrix & A) { AKANTU_DEBUG_ASSERT(A.cols() == A.rows(), "inv is not a valid operation on a rectangular matrix"); AKANTU_DEBUG_ASSERT(this->cols() == A.cols(), "the matrix should have the same size as its inverse"); if (this->cols() == 1) *this->values = 1. / *A.storage(); else if (this->cols() == 2) Math::inv2(A.storage(), this->values); else if (this->cols() == 3) Math::inv3(A.storage(), this->values); else Math::inv(this->cols(), A.storage(), this->values); } inline Matrix inverse() { Matrix inv(this->rows(), this->cols()); inv.inverse(*this); return inv; } /* --------------------------------------------------------------------- */ inline T det() const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "inv is not a valid operation on a rectangular matrix"); if (this->cols() == 1) return *(this->values); else if (this->cols() == 2) return Math::det2(this->values); else if (this->cols() == 3) return Math::det3(this->values); else return Math::det(this->cols(), this->values); } /* --------------------------------------------------------------------- */ inline T doubleDot(const Matrix<T> & other) const { AKANTU_DEBUG_ASSERT( this->cols() == this->rows(), "doubleDot is not a valid operation on a rectangular matrix"); if (this->cols() == 1) return *(this->values) * *(other.storage()); else if (this->cols() == 2) return Math::matrixDoubleDot22(this->values, other.storage()); else if (this->cols() == 3) return Math::matrixDoubleDot33(this->values, other.storage()); else AKANTU_DEBUG_ERROR("doubleDot is not defined for other spatial dimensions" << " than 1, 2 or 3."); return T(); } /* ---------------------------------------------------------------------- */ /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << "["; for (UInt i = 0; i < this->n[0]; ++i) { if (i != 0) stream << ", "; stream << "["; for (UInt j = 0; j < this->n[1]; ++j) { if (j != 0) stream << ", "; stream << operator()(i, j); } stream << "]"; } stream << "]"; }; }; /* ------------------------------------------------------------------------ */ template <typename T> template <bool tr_A> inline void Vector<T>::mul(const Matrix<T> & A, const Vector<T> & x, Real alpha) { #ifndef AKANTU_NDEBUG UInt n = x.size(); if (tr_A) { AKANTU_DEBUG_ASSERT(n == A.rows(), "matrix and vector to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->size() == A.cols(), "matrix and vector to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(n == A.cols(), "matrix and vector to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->size() == A.rows(), "matrix and vector to multiply have no fit dimensions"); } #endif Math::matVectMul<tr_A>(A.rows(), A.cols(), alpha, A.storage(), x.storage(), 0., this->storage()); } /* -------------------------------------------------------------------------- */ template <typename T> inline std::ostream & operator<<(std::ostream & stream, const Matrix<T> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ template <typename T> inline std::ostream & operator<<(std::ostream & stream, const Vector<T> & _this) { _this.printself(stream); return stream; } /* ------------------------------------------------------------------------ */ /* Tensor3 */ /* ------------------------------------------------------------------------ */ template <typename T> class Tensor3 : public TensorStorage<T, 3, Tensor3<T>> { using parent = TensorStorage<T, 3, Tensor3<T>>; public: using value_type = typename parent::value_type; using proxy = Tensor3Proxy<T>; public: Tensor3() : parent(){}; Tensor3(UInt m, UInt n, UInt p, const T & def = T()) : parent(m, n, p, def) {} Tensor3(T * data, UInt m, UInt n, UInt p) : parent(data, m, n, p) {} Tensor3(const Tensor3 & src, bool deep_copy = true) : parent(src, deep_copy) {} Tensor3(const proxy & src) : parent(src) {} public: /* ------------------------------------------------------------------------ */ inline Tensor3 & operator=(const Tensor3 & src) { parent::operator=(src); return *this; } /* ---------------------------------------------------------------------- */ inline T & operator()(UInt i, UInt j, UInt k) { AKANTU_DEBUG_ASSERT( (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the element " << "(" << i << ", " << j << ", " << k << ") in a tensor of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return *(this->values + (k * this->n[0] + i) * this->n[1] + j); } inline const T & operator()(UInt i, UInt j, UInt k) const { AKANTU_DEBUG_ASSERT( (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the element " << "(" << i << ", " << j << ", " << k << ") in a tensor of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return *(this->values + (k * this->n[0] + i) * this->n[1] + j); } inline MatrixProxy<T> operator()(UInt k) { AKANTU_DEBUG_ASSERT((k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the slice " << k << " in a tensor3 of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } inline const MatrixProxy<T> operator()(UInt k) const { AKANTU_DEBUG_ASSERT((k < this->n[2]), "Access out of the tensor3! " << "You are trying to access the slice " << k << " in a tensor3 of size (" << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")"); return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } inline MatrixProxy<T> operator[](UInt k) { return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } inline const MatrixProxy<T> operator[](UInt k) const { return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1], this->n[0], this->n[1]); } }; /* -------------------------------------------------------------------------- */ // support operations for the creation of other vectors /* -------------------------------------------------------------------------- */ template <typename T> Vector<T> operator*(const T & scalar, const Vector<T> & a) { Vector<T> r(a); r *= scalar; return r; } template <typename T> Vector<T> operator*(const Vector<T> & a, const T & scalar) { Vector<T> r(a); r *= scalar; return r; } template <typename T> Vector<T> operator/(const Vector<T> & a, const T & scalar) { Vector<T> r(a); r /= scalar; return r; } template <typename T> Vector<T> operator*(const Vector<T> & a, const Vector<T> & b) { Vector<T> r(a); r *= b; return r; } template <typename T> Vector<T> operator+(const Vector<T> & a, const Vector<T> & b) { Vector<T> r(a); r += b; return r; } template <typename T> Vector<T> operator-(const Vector<T> & a, const Vector<T> & b) { Vector<T> r(a); r -= b; return r; } template <typename T> Vector<T> operator*(const Matrix<T> & A, const Vector<T> & b) { Vector<T> r(b.size()); r.template mul<false>(A, b); return r; } /* -------------------------------------------------------------------------- */ template <typename T> Matrix<T> operator*(const T & scalar, const Matrix<T> & a) { Matrix<T> r(a); r *= scalar; return r; } template <typename T> Matrix<T> operator*(const Matrix<T> & a, const T & scalar) { Matrix<T> r(a); r *= scalar; return r; } template <typename T> Matrix<T> operator/(const Matrix<T> & a, const T & scalar) { Matrix<T> r(a); r /= scalar; return r; } template <typename T> Matrix<T> operator+(const Matrix<T> & a, const Matrix<T> & b) { Matrix<T> r(a); r += b; return r; } template <typename T> Matrix<T> operator-(const Matrix<T> & a, const Matrix<T> & b) { Matrix<T> r(a); r -= b; return r; } } // namespace akantu #endif /* __AKANTU_AKA_TYPES_HH__ */ diff --git a/src/fe_engine/element_class_structural.hh b/src/fe_engine/element_class_structural.hh index 1e3a79b47..3dbefe93d 100644 --- a/src/fe_engine/element_class_structural.hh +++ b/src/fe_engine/element_class_structural.hh @@ -1,277 +1,250 @@ /** * @file element_class_structural.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Thu Feb 21 2013 * @date last modification: Thu Oct 22 2015 * * @brief Specialization of the element classes for structural elements * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_class.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__ #define __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__ namespace akantu { /// Macro to generate the InterpolationProperty structures for different /// interpolation types #define AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY( \ - itp_type, itp_geom_type, ndof, nb_stress) \ + itp_type, itp_geom_type, ndof, nb_stress, nb_dnds_cols) \ template <> struct InterpolationProperty<itp_type> { \ static const InterpolationKind kind{_itk_structural}; \ static const UInt nb_nodes_per_element{ \ InterpolationProperty<itp_geom_type>::nb_nodes_per_element}; \ static const InterpolationType itp_geometry_type{itp_geom_type}; \ static const UInt natural_space_dimension{ \ InterpolationProperty<itp_geom_type>::natural_space_dimension}; \ static const UInt nb_degree_of_freedom{ndof}; \ static const UInt nb_stress_components{nb_stress}; \ + static const UInt dnds_columns{nb_dnds_cols}; \ } /* -------------------------------------------------------------------------- */ template <InterpolationType interpolation_type> class InterpolationElement<interpolation_type, _itk_structural> { public: using interpolation_property = InterpolationProperty<interpolation_type>; /// compute the shape values for a given set of points in natural coordinates static inline void computeShapes(const Matrix<Real> & natural_coord, const Matrix<Real> & real_coord, Tensor3<Real> & N) { for (UInt i = 0; i < natural_coord.cols(); ++i) { Matrix<Real> n_t = N(i); computeShapes(natural_coord(i), real_coord, n_t); } } /// compute the shape values for a given point in natural coordinates static inline void computeShapes(const Vector<Real> & natural_coord, const Matrix<Real> & real_coord, Matrix<Real> & N); /// compute shape derivatives (input is dxds) for a set of points static inline void computeShapeDerivatives(const Tensor3<Real> & Js, const Tensor3<Real> & DNDSs, const Matrix<Real> & R, Tensor3<Real> & Bs) { for (UInt i = 0; i < Js.size(2); ++i) { Matrix<Real> J = Js(i); Matrix<Real> DNDS = DNDSs(i); - Matrix<Real> DNDS_R(DNDS.rows(), DNDS.cols()); - DNDS_R.mul<false, false>(DNDS, R); - Matrix<Real> B = Bs(i); + Matrix<Real> DNDX(DNDS.rows(), DNDS.cols()); auto inv_J = J.inverse(); - Matrix<Real> inv_J_full(DNDS.rows(), DNDS.rows()); - - // Gotta repeat J^-1 for each stress component - for (UInt k = 0, pos = 0; k < getNbStressComponents(); - k++, pos += inv_J.rows()) { - inv_J_full.block(inv_J, pos, pos); - } - - B.mul<false, false>(inv_J_full, DNDS_R); + DNDX.mul<false, false>(inv_J, DNDS); + Matrix<Real> B_R = Bs(i); + Matrix<Real> B(B_R.rows(), B_R.cols()); + arrangeInVoigt(DNDX, B); + B_R.mul<false, false>(B, R); } } /** * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of * shape functions along with variation of natural coordinates on a given set * of points in natural coordinates */ static inline void computeDNDS(const Matrix<Real> & natural_coord, const Matrix<Real> & real_coord, Tensor3<Real> & dnds) { for (UInt i = 0; i < natural_coord.cols(); ++i) { Matrix<Real> dnds_t = dnds(i); computeDNDS(natural_coord(i), real_coord, dnds_t); } } /** * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of * shape functions along with * variation of natural coordinates on a given point in natural * coordinates */ static inline void computeDNDS(const Vector<Real> & natural_coord, const Matrix<Real> & real_coord, Matrix<Real> & dnds); + /** + * arrange B in Voigt notation from DNDS + */ + static inline void arrangeInVoigt(const Matrix<Real> & dnds, + Matrix<Real> & B) { + // Default implementation assumes dnds is already in Voigt notation + B.deepCopy(dnds); + } + public: static AKANTU_GET_MACRO_NOT_CONST( NbNodesPerInterpolationElement, interpolation_property::nb_nodes_per_element, UInt); static AKANTU_GET_MACRO_NOT_CONST( ShapeSize, (interpolation_property::nb_nodes_per_element * interpolation_property::nb_degree_of_freedom * interpolation_property::nb_degree_of_freedom), UInt); static AKANTU_GET_MACRO_NOT_CONST( ShapeDerivativesSize, (interpolation_property::nb_nodes_per_element * interpolation_property::nb_degree_of_freedom * interpolation_property::nb_stress_components), UInt); static AKANTU_GET_MACRO_NOT_CONST( NaturalSpaceDimension, interpolation_property::natural_space_dimension, UInt); static AKANTU_GET_MACRO_NOT_CONST( NbDegreeOfFreedom, interpolation_property::nb_degree_of_freedom, UInt); static AKANTU_GET_MACRO_NOT_CONST( NbStressComponents, interpolation_property::nb_stress_components, UInt); }; /// Macro to generate the element class structures for different structural /// element types /* -------------------------------------------------------------------------- */ #define AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY( \ elem_type, geom_type, interp_type, parent_el_type, elem_kind, sp, \ gauss_int_type, min_int_order) \ template <> struct ElementClassProperty<elem_type> { \ static const GeometricalType geometrical_type{geom_type}; \ static const InterpolationType interpolation_type{interp_type}; \ static const ElementType parent_element_type{parent_el_type}; \ static const ElementKind element_kind{elem_kind}; \ static const UInt spatial_dimension{sp}; \ static const GaussIntegrationType gauss_integration_type{gauss_int_type}; \ static const UInt polynomial_degree{min_int_order}; \ } /* -------------------------------------------------------------------------- */ /* ElementClass for structural elements */ /* -------------------------------------------------------------------------- */ template <ElementType element_type> class ElementClass<element_type, _ek_structural> : public GeometricalElement< ElementClassProperty<element_type>::geometrical_type>, public InterpolationElement< ElementClassProperty<element_type>::interpolation_type> { protected: using geometrical_element = GeometricalElement<ElementClassProperty<element_type>::geometrical_type>; using interpolation_element = InterpolationElement< ElementClassProperty<element_type>::interpolation_type>; using parent_element = ElementClass<ElementClassProperty<element_type>::parent_element_type>; public: static inline void computeRotationMatrix(Matrix<Real> & /*R*/, const Matrix<Real> & /*X*/, const Vector<Real> & /*extra_normal*/) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute jacobian (or integration variable change factor) for a given point - static inline void computeJMat(const Matrix<Real> & DNDS, + static inline void computeJMat(const Vector<Real> & natural_coords, const Matrix<Real> & Xs, Matrix<Real> & J) { - auto nb_nodes = Xs.cols(); - auto dim = Xs.rows(); - auto nb_dof = - interpolation_element::interpolation_property::nb_degree_of_freedom; - Matrix<Real> B(dim, nb_nodes); - for (UInt s = 0; s < dim; ++s) { - for (UInt n = 0; n < nb_nodes; ++n) { - B(s, n) = DNDS(s, n * nb_dof + s); - } - } - - J.mul<false, true>(B, Xs); + Matrix<Real> dnds(Xs.rows(), Xs.cols()); + parent_element::computeDNDS(natural_coords, dnds); + J.mul<false, true>(dnds, Xs); } - static inline void computeJMat(const Tensor3<Real> & DNDSs, + static inline void computeJMat(const Matrix<Real> & natural_coords, const Matrix<Real> & Xs, Tensor3<Real> & Js) { - using itp = typename interpolation_element::interpolation_property; - auto nb_nodes = Xs.cols(); - auto dim = Xs.rows(); - auto nb_dof = itp::nb_degree_of_freedom; - Matrix<Real> B(dim, nb_nodes); - - for (UInt i = 0; i < Xs.cols(); ++i) { - Matrix<Real> DNDS = DNDSs(i); + for (UInt i = 0 ; i < natural_coords.cols(); ++i) { + // because non-const l-value reference does not bind to r-value Matrix<Real> J = Js(i); - - B.clear(); - for (UInt s = 0; s < dim; ++s) { - for (UInt n = 0; n < nb_nodes; ++n) { - B(s, n) = DNDS(s, n * nb_dof + s); - } - } - - parent_element::computeJMat(B, Xs, J); - // computeJMat(DNDS, Xs, J); + computeJMat(Vector<Real>(natural_coords(i)), Xs, J); } } static inline void computeJacobian(const Matrix<Real> & natural_coords, const Matrix<Real> & node_coords, Vector<Real> & jacobians) { using itp = typename interpolation_element::interpolation_property; - UInt nb_points = natural_coords.cols(); - Matrix<Real> dnds(itp::natural_space_dimension, itp::nb_nodes_per_element); - Matrix<Real> J(natural_coords.rows(), itp::natural_space_dimension); - - // Extract relevant first lines - auto x = node_coords.block(0, 0, itp::natural_space_dimension, - itp::nb_nodes_per_element); - - for (UInt p = 0; p < nb_points; ++p) { - Vector<Real> ncoord_p(natural_coords(p)); - parent_element::computeDNDS(ncoord_p, dnds); - parent_element::computeJMat(dnds, x, J); - jacobians(p) = J.det(); + Tensor3<Real> Js(itp::natural_space_dimension, itp::natural_space_dimension, + natural_coords.cols()); + computeJMat(natural_coords, node_coords, Js); + for (UInt i = 0; i < natural_coords.cols(); ++i) { + Matrix<Real> J = Js(i); + jacobians(i) = J.det(); } } static inline void computeRotation(const Matrix<Real> & node_coords, Matrix<Real> & rotation); public: static AKANTU_GET_MACRO_NOT_CONST(Kind, _ek_structural, ElementKind); static AKANTU_GET_MACRO_NOT_CONST(P1ElementType, _not_defined, ElementType); static AKANTU_GET_MACRO_NOT_CONST(FacetType, _not_defined, ElementType); static constexpr auto getFacetType(__attribute__((unused)) UInt t = 0) { return _not_defined; } static constexpr AKANTU_GET_MACRO_NOT_CONST( SpatialDimension, ElementClassProperty<element_type>::spatial_dimension, UInt); static constexpr auto getFacetTypes() { return ElementClass<_not_defined>::getFacetTypes(); } }; } // namespace akantu /* -------------------------------------------------------------------------- */ #include "element_classes/element_class_hermite_inline_impl.cc" /* keep order */ #include "element_classes/element_class_bernoulli_beam_inline_impl.cc" #include "element_classes/element_class_kirchhoff_shell_inline_impl.cc" /* -------------------------------------------------------------------------- */ #endif /* __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__ */ diff --git a/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc b/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc index f7ca15021..407cb0af0 100644 --- a/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc @@ -1,202 +1,222 @@ /** * @file element_class_bernoulli_beam_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Sun Oct 19 2014 * * @brief Specialization of the element_class class for the type _bernoulli_beam_2 * * @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 <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim --x-----q1----|----q2-----x---> x -1 0 1 @endverbatim * */ /* -------------------------------------------------------------------------- */ #include "aka_static_if.hh" #include "element_class_structural.hh" //#include "aka_element_classes_info.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__ #define __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_bernoulli_beam_2, _itp_lagrange_segment_2, 3, - 2); + 2, 6); AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_bernoulli_beam_3, _itp_lagrange_segment_2, 6, - 4); + 4, 6); AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_bernoulli_beam_2, _gt_segment_2, _itp_bernoulli_beam_2, _segment_2, _ek_structural, 2, _git_segment, 3); AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_bernoulli_beam_3, _gt_segment_2, _itp_bernoulli_beam_3, _segment_2, _ek_structural, 3, _git_segment, 3); /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeShapes( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & N) { Vector<Real> L(2); InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeShapes( natural_coords, L); Matrix<Real> H(2, 4); InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes( natural_coords, real_coord, H); // clang-format off // u1 v1 t1 u2 v2 t2 N = {{L(0), 0 , 0 , L(1), 0 , 0 }, // u {0 , H(0, 0), H(0, 1), 0 , H(0, 2), H(0, 3)}, // v {0 , H(1, 0), H(1, 1), 0 , H(1, 2), H(1, 3)}}; // theta // clang-format on } template <> inline void InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::computeShapes( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & N) { Vector<Real> L(2); InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeShapes( natural_coords, L); Matrix<Real> H(2, 4); InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes( natural_coords, real_coord, H); // clang-format off // u1 v1 w1 x1 y1 z1 u2 v2 w2 x2 y2 z2 N = {{L(0), 0 , 0 , 0 , 0 , 0 , L(1), 0 , 0 , 0 , 0 , 0 }, // u {0 , H(0, 0), 0 , 0 , H(0, 1), 0 , 0 , H(0, 2), 0 , 0 , H(0, 3), 0 }, // v {0 , 0 , H(0, 0), 0 , 0 , H(0, 1), 0 , 0 , H(0, 2), 0 , 0 , H(0, 3)}, // w {0 , 0 , 0 , L(0), 0 , 0 , 0 , 0 , 0 , L(1), 0 , 0 }, // thetax {0 , H(1, 0), 0 , 0 , H(1, 1), 0 , 0 , H(1, 2), 0 , 0 , H(1, 3), 0 }, // thetay {0 , 0 , H(1, 0), 0 , 0 , H(1, 1), 0 , 0 , H(1, 2), 0 , 0 , H(1, 3)}}; // thetaz // clang-format on } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeDNDS( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, - Matrix<Real> & B) { + Matrix<Real> & dnds) { Matrix<Real> L(1, 2); InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeDNDS( natural_coords, L); Matrix<Real> H(1, 4); InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS( natural_coords, real_coord, H); + // Storing the derivatives in dnds + dnds.block(L, 0, 0); + dnds.block(H, 0, 2); +} + +/* -------------------------------------------------------------------------- */ +template <> +inline void +InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::arrangeInVoigt( + const Matrix<Real> & dnds, Matrix<Real> & B) { + auto L = dnds.block(0, 0, 1, 2); // Lagrange shape derivatives + auto H = dnds.block(0, 2, 1, 4); // Hermite shape derivatives // clang-format off - // u1 v1 t1 u2 v2 t2 - B = {{L(0, 0), 0 , 0 , L(0, 1), 0 , 0 }, // epsilon - {0 , H(0, 0), H(0, 1), 0 , H(0, 2), H(0, 3)}}; // chi (curv.) + // u1 v1 t1 u2 v2 t2 + B = {{L(0, 0), 0, 0, L(0, 1), 0, 0 }, + {0, H(0, 0), H(0, 1), 0, H(0, 2), H(0, 3)}}; // clang-format on } +/* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::computeDNDS( - const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & B) { - Matrix<Real> L(1, 2); - InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeDNDS( - natural_coords, L); - Matrix<Real> H(1, 4); - InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS( - natural_coords, real_coord, H); + const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, + Matrix<Real> & dnds) { + InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeDNDS( + natural_coords, real_coord, dnds); +} + +/* -------------------------------------------------------------------------- */ +template <> +inline void +InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::arrangeInVoigt( + const Matrix<Real> & dnds, Matrix<Real> & B) { + auto L = dnds.block(0, 0, 1, 2); // Lagrange shape derivatives + auto H = dnds.block(0, 2, 1, 4); // Hermite shape derivatives + // clang-format off // u1 v1 w1 x1 y1 z1 u2 v2 w2 x2 y2 z2 B = {{L(0, 0), 0 , 0 , 0 , 0 , 0 , L(0, 1), 0 , 0 , 0 , 0 , 0 }, // eps {0 , H(0, 0), 0 , 0 , 0 , H(0, 1), 0 , H(0, 2), 0 , 0 , 0 , H(0, 3)}, // chi strong axis {0 , 0 ,-H(0, 0), 0 , H(0, 1), 0 , 0 , 0 ,-H(0, 2), 0 , H(0, 3), 0 }, // chi weak axis {0 , 0 , 0 , L(0, 0), 0 , 0 , 0 , 0 , 0 , L(0, 1), 0 , 0 }}; // chi torsion // clang-format on } /* -------------------------------------------------------------------------- */ template <> inline void ElementClass<_bernoulli_beam_2>::computeRotationMatrix( Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> &) { Vector<Real> x2 = X(1); // X2 Vector<Real> x1 = X(0); // X1 auto cs = (x2 - x1); cs.normalize(); auto c = cs(0); auto s = cs(1); // clang-format off /// Definition of the rotation matrix R = {{ c, s, 0.}, {-s, c, 0.}, { 0., 0., 1.}}; // clang-format on } /* -------------------------------------------------------------------------- */ template <> inline void ElementClass<_bernoulli_beam_3>::computeRotationMatrix( Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> & n) { Vector<Real> x2 = X(1); // X2 Vector<Real> x1 = X(0); // X1 auto dim = X.rows(); auto x = (x2 - x1); x.normalize(); auto x_n = x.crossProduct(n); Matrix<Real> Pe = {{1., 0., 0.}, {0., -1., 0.}, {0., 0., 1.}}; Matrix<Real> Pg(dim, dim); Pg(0) = x; Pg(1) = x_n; Pg(2) = n; Pe *= Pg.inverse(); R.clear(); /// Definition of the rotation matrix for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) R(i + dim, j + dim) = R(i, j) = Pe(i, j); } } // namespace akantu #endif /* __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc b/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc index ba268905d..8d79e01c5 100644 --- a/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc @@ -1,180 +1,180 @@ /** * @file element_class_hermite_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Sun Oct 19 2014 * * @brief Specialization of the element_class class for the type _hermite * * @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 <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * @verbatim --x-----q1----|----q2-----x---> x -1 0 1 @endverbatim * * @subsection shapes Shape functions * @f[ * \begin{array}{ll} * M_1(\xi) &= 1/4(\xi^{3}/-3\xi+2)\\ * M_2(\xi) &= -1/4(\xi^{3}-3\xi-2) * \end{array} * * \begin{array}{ll} * L_1(\xi) &= 1/4(\xi^{3}-\xi^{2}-\xi+1)\\ * L_2(\xi) &= 1/4(\xi^{3}+\xi^{2}-\xi-1) * \end{array} * * \begin{array}{ll} * M'_1(\xi) &= 3/4(\xi^{2}-1)\\ * M'_2(\xi) &= -3/4(\xi^{2}-1) * \end{array} * * \begin{array}{ll} * L'_1(\xi) &= 1/4(3\xi^{2}-2\xi-1)\\ * L'_2(\xi) &= 1/4(3\xi^{2}+2\xi-1) * \end{array} *@f] * * @subsection dnds Shape derivatives * *@f[ * \begin{array}{ll} * N'_1(\xi) &= -1/2\\ * N'_2(\xi) &= 1/2 * \end{array}] * * \begin{array}{ll} * -M''_1(\xi) &= -3\xi/2\\ * -M''_2(\xi) &= 3\xi/2\\ * \end{array} * * \begin{array}{ll} * -L''_1(\xi) &= -1/2a(3\xi/a-1)\\ * -L''_2(\xi) &= -1/2a(3\xi/a+1) * \end{array} *@f] * */ /* -------------------------------------------------------------------------- */ #include "aka_static_if.hh" #include "element_class_structural.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__ #define __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_hermite_2, _itp_lagrange_segment_2, 2, - 1); + 1, 4); /* -------------------------------------------------------------------------- */ namespace { namespace details { inline Real computeLength(const Matrix<Real> & real_coord) { Vector<Real> x1 = real_coord(0); Vector<Real> x2 = real_coord(1); return x1.distance(x2); } inline void computeShapes(const Vector<Real> & natural_coords, Real a, Matrix<Real> & N) { /// natural coordinate Real xi = natural_coords(0); // Cubic Hermite splines interpolating displacement auto M1 = 1. / 4. * Math::pow<2>(xi - 1) * (xi + 2); auto M2 = 1. / 4. * Math::pow<2>(xi + 1) * (2 - xi); auto L1 = a / 4. * Math::pow<2>(xi - 1) * (xi + 1); auto L2 = a / 4. * Math::pow<2>(xi + 1) * (xi - 1); #if 1 // Version where we also interpolate the rotations // Derivatives (with respect to x) of previous functions interpolating // rotations auto M1_ = 3. / (4. * a) * (xi * xi - 1); auto M2_ = 3. / (4. * a) * (1 - xi * xi); auto L1_ = 1 / 4. * (3 * xi * xi - 2 * xi - 1); auto L2_ = 1 / 4. * (3 * xi * xi + 2 * xi - 1); // clang-format off // v1 t1 v2 t2 N = {{M1 , L1 , M2 , L2}, // displacement interpolation {M1_, L1_, M2_, L2_}}; // rotation interpolation // clang-format on #else // Version where we only interpolate displacements // clang-format off // v1 t1 v2 t2 N = {{M1, L1, M2, L2}}; // clang-format on #endif } /* ---------------------------------------------------------------------- */ inline void computeDNDS(const Vector<Real> & natural_coords, Real a, Matrix<Real> & B) { // natural coordinate Real xi = natural_coords(0); // Derivatives with respect to xi for rotations auto M1__ = 3. / 2. * xi; auto M2__ = 3. / 2. * (-xi); auto L1__ = a / 2. * (3 * xi - 1); auto L2__ = a / 2. * (3 * xi + 1); // v1 t1 v2 t2 B = {{M1__, L1__, M2__, L2__}}; // computing curvature : {chi} = [B]{d} B /= a; // to account for first order deriv w/r to x } } // namespace details } // namespace /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & N) { auto L = details::computeLength(real_coord); details::computeShapes(natural_coords, L / 2, N); } /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS( const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & B) { auto L = details::computeLength(real_coord); details::computeDNDS(natural_coords, L / 2, B); } } // namespace akantu #endif /* __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc index 29f1760f7..4769bf237 100644 --- a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc +++ b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc @@ -1,288 +1,211 @@ /** * @file element_class_kirchhoff_shell_inline_impl.cc * * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 04 2014 * @date last modification: Sun Oct 19 2014 * * @brief Element class Kirchhoff Shell * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_class_structural.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ #define __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ -AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_discrete_kirchhoff_triangle_18, - _itp_lagrange_triangle_3, - 6, 6); -AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_discrete_kirchhoff_triangle_18, - _gt_triangle_3, - _itp_discrete_kirchhoff_triangle_18, - _triangle_3, _ek_structural, 3, - _git_triangle, 2); +AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY( + _itp_discrete_kirchhoff_triangle_18, _itp_lagrange_triangle_3, 6, 6, 21); +AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY( + _discrete_kirchhoff_triangle_18, _gt_triangle_3, + _itp_discrete_kirchhoff_triangle_18, _triangle_3, _ek_structural, 3, + _git_triangle, 2); + +/* -------------------------------------------------------------------------- */ +namespace detail { + inline void computeBasisChangeMatrix(Matrix<Real> & P, + const Matrix<Real> & X) { + Vector<Real> X1 = X(0); + Vector<Real> X2 = X(1); + Vector<Real> X3 = X(2); + + Vector<Real> a1 = X2 - X1; + Vector<Real> a2 = X3 - X1; + + a1.normalize(); + Vector<Real> e3 = a1.crossProduct(a2); + e3.normalize(); + Vector<Real> e2 = e3.crossProduct(a1); + + P(0) = a1; + P(1) = e2; + P(2) = e3; + } +} + +/* -------------------------------------------------------------------------- */ +template <> +inline void +ElementClass<_discrete_kirchhoff_triangle_18>::computeRotationMatrix( + Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> &) { + auto dim = X.rows(); + Matrix<Real> P(dim, dim); + detail::computeBasisChangeMatrix(P, X); + + R.clear(); + for (UInt i = 0; i < dim; ++i) + for (UInt j = 0; j < dim; ++j) + R(i + dim, j + dim) = R(i, j) = P(j, i); +} /* -------------------------------------------------------------------------- */ template <> inline void InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeShapes( const Vector<Real> & /*natural_coords*/, - const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*N*/) { -// // projected_coord (x1 x2 x3) (y1 y2 y3) + const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*N*/) {} -#if 0 - // natural coordinate +/* -------------------------------------------------------------------------- */ +template <> +inline void +InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeDNDS( + const Vector<Real> & natural_coords, const Matrix<Real> & real_coordinates, + Matrix<Real> & B) { + + auto dim = real_coordinates.cols(); + Matrix<Real> P(dim, dim); + detail::computeBasisChangeMatrix(P, real_coordinates); + auto X = P * real_coordinates; + Vector<Real> X1 = X(0); + Vector<Real> X2 = X(1); + Vector<Real> X3 = X(2); + + std::array<Vector<Real>, 3> A = {X2 - X1, X3 - X2, X1 - X3}; + std::array<Real, 3> L, C, S; + + // Setting all last coordinates to 0 + std::for_each(A.begin(), A.end(), [](auto & a) { a(2) = 0; }); + // Computing lengths + std::transform(A.begin(), A.end(), L.begin(), + [](Vector<Real> & a) { return a.norm<L_2>(); }); + // Computing cosines + std::transform(A.begin(), A.end(), L.begin(), C.begin(), + [](Vector<Real> & a, Real & l) { return a(0) / l; }); + // Computing sines + std::transform(A.begin(), A.end(), L.begin(), S.begin(), + [](Vector<Real> & a, Real & l) { return a(1) / l; }); + + // Natural coordinates Real xi = natural_coords(0); Real eta = natural_coords(1); - Real x21 = projected_coord(0, 0) - projected_coord(0, 1); // x1-x2 - Real x32 = projected_coord(0, 1) - projected_coord(0, 2); - Real x13 = projected_coord(0, 2) - projected_coord(0, 0); - - Real y21 = projected_coord(1, 0) - projected_coord(1, 1); // y1-y2 - Real y32 = projected_coord(1, 1) - projected_coord(1, 2); - Real y13 = projected_coord(1, 2) - projected_coord(1, 0); - - /* Real x21=projected_coord(0,1)-projected_coord(0,0); - Real x32=projected_coord(0,2)-projected_coord(0,1); - Real x13=projected_coord(0,0)-projected_coord(0,2); - - Real y21=projected_coord(1,1)-projected_coord(1,0); - Real y32=projected_coord(1,2)-projected_coord(1,1); - Real y13=projected_coord(1,0)-projected_coord(1,2);*/ - - // natural triangle side length - Real L4 = std::sqrt(x21 * x21 + y21 * y21); - Real L5 = std::sqrt(x32 * x32 + y32 * y32); - Real L6 = std::sqrt(x13 * x13 + y13 * y13); - - // sinus and cosinus - Real C4 = x21 / L4; // 1. - Real C5 = x32 / L5; //-1./std::sqrt(2); - Real C6 = x13 / L6; // 0. - Real S4 = y21 / L4; // 0.; - Real S5 = y32 / L5; // 1./std::sqrt(2); - Real S6 = y13 / L6; //-1.; - - Real N1 = 1. - xi - eta; - Real N2 = xi; - Real N3 = eta; - - Real P4 = 4. * xi * (1. - xi - eta); - Real P5 = 4. * xi * eta; - Real P6 = 4. * eta * (1. - xi - eta); - - Vector<Real> N0{N1, N2, N3}; - Vector<Real> Nw2{-(1. / 8.) * P4 * L4 * C4 + (1. / 8.) * P6 * L6 * C6, - -(1. / 8.) * P5 * L5 * C5 + (1. / 8.) * P4 * L4 * C4, - -(1. / 8.) * P6 * L6 * C6 + (1. / 8.) * P5 * L5 * C5}; - Vector<Real> Nw3{-(1. / 8.) * P4 * L4 * S4 + (1. / 8.) * P6 * L6 * S6, - -(1. / 8.) * P5 * L5 * S5 + (1. / 8.) * P4 * L4 * S4, - -(1. / 8.) * P6 * L6 * S6 + (1. / 8.) * P5 * L5 * S5}; - Vector<Real> Nx1{3. / (2. * L4) * P4 * C4 - 3. / (2. * L6) * P6 * C6, - 3. / (2. * L5) * P5 * C5 - 3. / (2. * L4) * P4 * C4, - 3. / (2. * L6) * P6 * C6 - 3. / (2. * L5) * P5 * C5}; - Vector<Real> Nx2{N1 - (3. / 4.) * P4 * C4 * C4 - (3. / 4.) * P6 * C6 * C6, - N2 - (3. / 4.) * P5 * C5 * C5 - (3. / 4.) * P4 * C4 * C4, - N3 - (3. / 4.) * P6 * C6 * C6 - (3. / 4.) * P5 * C5 * C5}; - Vector<Real> Nx3{-(3. / 4.) * P4 * C4 * S4 - (3. / 4.) * P6 * C6 * S6, - -(3. / 4.) * P5 * C5 * S5 - (3. / 4.) * P4 * C4 * S4, - -(3. / 4.) * P6 * C6 * S6 - (3. / 4.) * P5 * C5 * S5}; - Vector<Real> Ny1{3. / (2. * L4) * P4 * S4 - 3. / (2. * L6) * P6 * S6, - 3. / (2. * L5) * P5 * S5 - 3. / (2. * L4) * P4 * S4, - 3. / (2. * L6) * P6 * S6 - 3. / (2. * L5) * P5 * S5}; - Vector<Real> Ny2{-(3. / 4.) * P4 * C4 * S4 - (3. / 4.) * P6 * C6 * S6, - -(3. / 4.) * P5 * C5 * S5 - (3. / 4.) * P4 * C4 * S4, - -(3. / 4.) * P6 * C6 * S6 - (3. / 4.) * P5 * C5 * S5}; - Vector<Real> Ny3{N1 - (3. / 4.) * P4 * S4 * S4 - (3. / 4.) * P6 * S6 * S6, - N2 - (3. / 4.) * P5 * S5 * S5 - (3. / 4.) * P4 * S4 * S4, - N3 - (3. / 4.) * P6 * S6 * S6 - (3. / 4.) * P5 * S5 * S5}; - - // clang-format off - N = Matrix<Real> { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - {N0(0), 0., 0., 0., 0., N0(1), 0., 0., 0., 0., N0(2), 0., 0., 0., 0.}, // 0 - { 0., N0(0), 0., 0., 0., 0., N0(1), 0., 0., 0., 0., N0(2), 0., 0., 0.}, // 1 - { 0., 0., N0(0), Nw2(0), Nw3(0), 0., 0., N0(1), Nw2(1), Nw3(1), 0., 0., N0(2), Nw2(2), Nw3(2)}, // 2 - { 0., 0., Nx1(0), Nx2(0), Nx3(0), 0., 0., Nx1(1), Nx2(1), Nx3(1), 0., 0., Nx1(2), Nx2(2), Nx3(2)}, // 3 - { 0., 0., Ny1(0), Ny2(0), Ny3(0), 0., 0., Ny1(1), Ny2(1), Ny3(1), 0., 0., Ny1(2), Ny2(2), Ny3(2)}, // 4 - { 0, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}}; // 5 ??? + // Derivative of quadratic interpolation functions + Matrix<Real> dP = {{4 * (1 - 2 * xi - eta), 4 * eta, -4 * eta}, + {-4 * xi, 4 * xi, 4 * (1 - xi - 2 * eta)}}; + + Matrix<Real> dNx1 = { + {3. / 2 * (dP(0, 0) * C[0] / L[0] - dP(0, 2) * C[2] / L[2]), + 3. / 2 * (dP(0, 1) * C[1] / L[1] - dP(0, 0) * C[0] / L[0]), + 3. / 2 * (dP(0, 2) * C[2] / L[2] - dP(0, 1) * C[1] / L[1])}, + {3. / 2 * (dP(1, 0) * C[0] / L[0] - dP(1, 2) * C[2] / L[2]), + 3. / 2 * (dP(1, 1) * C[1] / L[1] - dP(1, 0) * C[0] / L[0]), + 3. / 2 * (dP(1, 2) * C[2] / L[2] - dP(1, 1) * C[1] / L[1])}}; + Matrix<Real> dNx2 = { + // clang-format off + {-1 - 3. / 4 * (dP(0, 0) * C[0] * C[0] + dP(0, 2) * C[2] * C[2]), + 1 - 3. / 4 * (dP(0, 1) * C[1] * C[1] + dP(0, 0) * C[0] * C[0]), + -3. / 4 * (dP(0, 2) * C[2] * C[2] + dP(0, 1) * C[1] * C[1])}, + {-1 - 3. / 4 * (dP(1, 0) * C[0] * C[0] + dP(1, 2) * C[2] * C[2]), + -3. / 4 * (dP(1, 1) * C[1] * C[1] + dP(1, 0) * C[0] * C[0]), + 1 - 3. / 4 * (dP(1, 2) * C[2] * C[2] + dP(1, 1) * C[1] * C[1])}}; + // clang-format on + Matrix<Real> dNx3 = { + {-3. / 4 * (dP(0, 0) * C[0] * S[0] + dP(0, 2) * C[2] * S[2]), + -3. / 4 * (dP(0, 1) * C[1] * S[1] + dP(0, 0) * C[0] * S[0]), + -3. / 4 * (dP(0, 2) * C[2] * S[2] + dP(0, 1) * C[1] * S[1])}, + {-3. / 4 * (dP(1, 0) * C[0] * S[0] + dP(1, 2) * C[2] * S[2]), + -3. / 4 * (dP(1, 1) * C[1] * S[1] + dP(1, 0) * C[0] * S[0]), + -3. / 4 * (dP(1, 2) * C[2] * S[2] + dP(1, 1) * C[1] * S[1])}}; + Matrix<Real> dNy1 = { + {3. / 2 * (dP(0, 0) * S[0] / L[0] - dP(0, 2) * S[2] / L[2]), + 3. / 2 * (dP(0, 1) * S[1] / L[1] - dP(0, 0) * S[0] / L[0]), + 3. / 2 * (dP(0, 2) * S[2] / L[2] - dP(0, 1) * S[1] / L[1])}, + {3. / 2 * (dP(1, 0) * S[0] / L[0] - dP(1, 2) * S[2] / L[2]), + 3. / 2 * (dP(1, 1) * S[1] / L[1] - dP(1, 0) * S[0] / L[0]), + 3. / 2 * (dP(1, 2) * S[2] / L[2] - dP(1, 1) * S[1] / L[1])}}; + Matrix<Real> dNy2 = dNx3; + Matrix<Real> dNy3 = { + // clang-format off + {-1 - 3. / 4 * (dP(0, 0) * S[0] * S[0] + dP(0, 2) * S[2] * S[2]), + 1 - 3. / 4 * (dP(0, 1) * S[1] * S[1] + dP(0, 0) * S[0] * S[0]), + -3. / 4 * (dP(0, 2) * S[2] * S[2] + dP(0, 1) * S[1] * S[1])}, + {-1 - 3. / 4 * (dP(1, 0) * S[0] * S[0] + dP(1, 2) * S[2] * S[2]), + -3. / 4 * (dP(1, 1) * S[1] * S[1] + dP(1, 0) * S[0] * S[0]), + 1 - 3. / 4 * (dP(1, 2) * S[2] * S[2] + dP(1, 1) * S[1] * S[1])}}; // clang-format on -#endif + // Derivative of linear (membrane mode) functions + Matrix<Real> dNm(2, 3); + InterpolationElement<_itp_lagrange_triangle_3, _itk_lagrangian>::computeDNDS( + natural_coords, dNm); + + UInt i = 0; + for (const Matrix<Real> & mat : {dNm, dNx1, dNx2, dNx3, dNy1, dNy2, dNy3}) { + B.block(mat, 0, i); + i += mat.cols(); + } } - /* -------------------------------------------------------------------------- */ template <> inline void -InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeDNDS( - const Vector<Real> & /*natural_coords*/, - const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*B*/) { - -#if 0 - // natural coordinate - Real xi = natural_coords(0); - Real eta = natural_coords(1); - - // projected_coord (x1 x2 x3) (y1 y2 y3) - - // donne juste pour pour le patch test 4_5_5 mais donne quelque changement - // de signe dans la matrice de rotation - - Real x21 = projected_coord(0, 0) - projected_coord(0, 1); // x1-x2 - Real x32 = projected_coord(0, 1) - projected_coord(0, 2); - Real x13 = projected_coord(0, 2) - projected_coord(0, 0); - - Real y21 = projected_coord(1, 0) - projected_coord(1, 1); // y1-y2 - Real y32 = projected_coord(1, 1) - projected_coord(1, 2); - Real y13 = projected_coord(1, 2) - projected_coord(1, 0); - - // donne juste pour la matrice de rigidité... mais pas pour le patch test - // 4_5_5 - - /* Real x21=projected_coord(0,1)-projected_coord(0,0); - Real x32=projected_coord(0,2)-projected_coord(0,1); - Real x13=projected_coord(0,0)-projected_coord(0,2); - - Real y21=projected_coord(1,1)-projected_coord(1,0); - Real y32=projected_coord(1,2)-projected_coord(1,1); - Real y13=projected_coord(1,0)-projected_coord(1,2);*/ - - // natural triangle side length - Real L4 = std::sqrt(x21 * x21 + y21 * y21); - Real L5 = std::sqrt(x32 * x32 + y32 * y32); - Real L6 = std::sqrt(x13 * x13 + y13 * y13); - - // sinus and cosinus - Real C4 = x21 / L4; - Real C5 = x32 / L5; - Real C6 = x13 / L6; - Real S4 = y21 / L4; - Real S5 = y32 / L5; - Real S6 = y13 / L6; - - Real dN1xi = -1; - Real dN2xi = 1; - Real dN3xi = 0; - - Real dN1eta = -1; - Real dN2eta = 0; - Real dN3eta = 1; - - Real dP4xi = 4 - 8. * xi - 4 * eta; - Real dP5xi = 4 * eta; - Real dP6xi = -4 * eta; - - Real dP4eta = -4 * xi; - Real dP5eta = 4 * xi; - Real dP6eta = 4 - 4 * xi - 8. * eta; - - // N'xi - auto Np00 = dN1xi; - auto Np01 = dN2xi; - auto Np02 = dN3xi; - // N'eta - auto Np10 = dN1eta; - auto Np11 = dN2eta; - auto Np12 = dN3eta; - - // Nxi1'xi - auto Nx1p00 = 3. / (2 * L4) * dP4xi * C4 - 3. / (2. * L6) * dP6xi * C6; - auto Nx1p01 = 3. / (2 * L5) * dP5xi * C5 - 3. / (2. * L4) * dP4xi * C4; - auto Nx1p02 = 3. / (2 * L6) * dP6xi * C6 - 3. / (2. * L5) * dP5xi * C5; - // Nxi1'eta - auto Nx1p10 = 3. / (2 * L4) * dP4eta * C4 - 3. / (2. * L6) * dP6eta * C6; - auto Nx1p11 = 3. / (2 * L5) * dP5eta * C5 - 3. / (2. * L4) * dP4eta * C4; - auto Nx1p12 = 3. / (2 * L6) * dP6eta * C6 - 3. / (2. * L5) * dP5eta * C5; - - // Nxi2'xi - auto Nx2p00 = -1 - (3. / 4.) * dP4xi * C4 * C4 - (3. / 4.) * dP6xi * C6 * C6; - auto Nx2p01 = 1 - (3. / 4.) * dP5xi * C5 * C5 - (3. / 4.) * dP4xi * C4 * C4; - auto Nx2p02 = -(3. / 4.) * dP6xi * C6 * C6 - (3. / 4.) * dP5xi * C5 * C5; - // Nxi2'eta - auto Nx2p10 = - -1 - (3. / 4.) * dP4eta * C4 * C4 - (3. / 4.) * dP6eta * C6 * C6; - auto Nx2p11 = -(3. / 4.) * dP5eta * C5 * C5 - (3. / 4.) * dP4eta * C4 * C4; - auto Nx2p12 = 1 - (3. / 4.) * dP6eta * C6 * C6 - (3. / 4.) * dP5eta * C5 * C5; - - // Nxi3'xi - auto Nx3p00 = -(3. / 4.) * dP4xi * C4 * S4 - (3. / 4.) * dP6xi * C6 * S6; - auto Nx3p01 = -(3. / 4.) * dP5xi * C5 * S5 - (3. / 4.) * dP4xi * C4 * S4; - auto Nx3p02 = -(3. / 4.) * dP6xi * C6 * S6 - (3. / 4.) * dP5xi * C5 * S5; - // Nxi3'eta - auto Nx3p10 = -(3. / 4.) * dP4eta * C4 * S4 - (3. / 4.) * dP6eta * C6 * S6; - auto Nx3p11 = -(3. / 4.) * dP5eta * C5 * S5 - (3. / 4.) * dP4eta * C4 * S4; - auto Nx3p12 = -(3. / 4.) * dP6eta * C6 * S6 - (3. / 4.) * dP5eta * C5 * S5; - - // Nyi1'xi - auto Ny1p00 = 3 / (2 * L4) * dP4xi * S4 - 3 / (2 * L6) * dP6xi * S6; - auto Ny1p01 = 3 / (2 * L5) * dP5xi * S5 - 3 / (2 * L4) * dP4xi * S4; - auto Ny1p02 = 3 / (2 * L6) * dP6xi * S6 - 3 / (2 * L5) * dP5xi * S5; - // Nyi1'eta - auto Ny1p10 = 3 / (2 * L4) * dP4eta * S4 - 3 / (2 * L6) * dP6eta * S6; - auto Ny1p11 = 3 / (2 * L5) * dP5eta * S5 - 3 / (2 * L4) * dP4eta * S4; - auto Ny1p12 = 3 / (2 * L6) * dP6eta * S6 - 3 / (2 * L5) * dP5eta * S5; - - // Nyi2'xi - auto Ny2p00 = -(3. / 4.) * dP4xi * C4 * S4 - (3. / 4.) * dP6xi * C6 * S6; - auto Ny2p01 = -(3. / 4.) * dP5xi * C5 * S5 - (3. / 4.) * dP4xi * C4 * S4; - auto Ny2p02 = -(3. / 4.) * dP6xi * C6 * S6 - (3. / 4.) * dP5xi * C5 * S5; - // Nyi2'eta - auto Ny2p10 = -(3. / 4.) * dP4eta * C4 * S4 - (3. / 4.) * dP6eta * C6 * S6; - auto Ny2p11 = -(3. / 4.) * dP5eta * C5 * S5 - (3. / 4.) * dP4eta * C4 * S4; - auto Ny2p12 = -(3. / 4.) * dP6eta * C6 * S6 - (3. / 4.) * dP5eta * C5 * S5; - - // Nyi3'xi - auto Ny3p00 = - dN1xi - (3. / 4.) * dP4xi * S4 * S4 - (3. / 4.) * dP6xi * S6 * S6; - auto Ny3p01 = - dN2xi - (3. / 4.) * dP5xi * S5 * S5 - (3. / 4.) * dP4xi * S4 * S4; - auto Ny3p02 = - dN3xi - (3. / 4.) * dP6xi * S6 * S6 - (3. / 4.) * dP5xi * S5 * S5; - // Nyi3'eta - auto Ny3p10 = - dN1eta - (3. / 4.) * dP4eta * S4 * S4 - (3. / 4.) * dP6eta * S6 * S6; - auto Ny3p11 = - dN2eta - (3. / 4.) * dP5eta * S5 * S5 - (3. / 4.) * dP4eta * S4 * S4; - auto Ny3p12 = - dN3eta - (3. / 4.) * dP6eta * S6 * S6 - (3. / 4.) * dP5eta * S5 * S5; +InterpolationElement<_itp_discrete_kirchhoff_triangle_18, + _itk_structural>::arrangeInVoigt(const Matrix<Real> & dnds, + Matrix<Real> & B) { + Matrix<Real> dNm(2, 3), dNx1(2, 3), dNx2(2, 3), dNx3(2, 3), dNy1(2, 3), + dNy2(2, 3), dNy3(2, 3); + UInt i = 0; + for (Matrix<Real> * mat : {&dNm, &dNx1, &dNx2, &dNx3, &dNy1, &dNy2, &dNy3}) { + *mat = dnds.block(0, i, 2, 3); + i += mat->cols(); + } // clang-format off - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - B = {{Np00, 0., 0., 0., 0., Np01, 0., 0., 0., 0., Np02, 0., 0., 0., 0.}, // 0 - { 0., Np10, 0., 0., 0., 0., Np11, 0., 0., 0., 0., Np12, 0., 0., 0.}, // 1 - {Np10, Np00, 0., 0., 0., Np11, Np01, 0., 0., 0., Np12, Np02, 0., 0., 0.}, // 2 - { 0., 0., Nx1p00, Nx2p00, Nx3p00, 0., 0., Nx1p01, Nx2p01, Nx3p01, 0., 0., Nx1p02, Nx2p02, Nx3p02}, // 3 - { 0., 0., Ny1p10, Ny2p10, Ny3p10, 0., 0., Ny1p11, Ny2p11, Ny3p11, 0., 0., Ny1p12, Ny2p12, Ny3p12}, // 4 - { 0., 0., Nx1p10 + Ny1p00, Nx2p10 + Ny2p00, Nx3p10 + Ny3p00, 0., 0., Nx1p11 + Ny1p01, Nx2p11 + Ny2p01, Nx3p11 + Ny3p01, 0., 0., Nx1p12 + Ny1p02, Nx2p12 + Ny2p02, Nx3p12 + Ny3p02}}; // 5 + B = { + // Membrane shape functions; TODO use the triangle_3 shapes + {dNm(0, 0), 0, 0, 0, 0, 0, dNm(0, 1), 0, 0, 0, 0, 0, dNm(0, 2), 0, 0, 0, 0, 0}, + {0, dNm(1, 0), 0, 0, 0, 0, 0, dNm(1, 1), 0, 0, 0, 0, 0, dNm(1, 2), 0, 0, 0, 0}, + {dNm(1, 0), dNm(0, 0), 0, 0, 0, 0, dNm(1, 1), dNm(0, 1), 0, 0, 0, 0, dNm(1, 2), dNm(0, 2), 0, 0, 0, 0}, + + // Bending shape functions + {0, 0, dNx1(0, 0), -dNx3(0, 0), dNx2(0, 0), 0, 0, 0, dNx1(0, 1), -dNx3(0, 1), dNx2(0, 1), 0, 0, 0, dNx1(0, 2), -dNx3(0, 2), dNx2(0, 2), 0}, + {0, 0, dNy1(1, 0), -dNy3(1, 0), dNy2(1, 0), 0, 0, 0, dNy1(1, 1), -dNy3(1, 1), dNy2(1, 1), 0, 0, 0, dNy1(1, 2), -dNy3(1, 2), dNy2(1, 2), 0}, + {0, 0, dNx1(1, 0) + dNy1(0, 0), -dNx3(1, 0) - dNy3(0, 0), dNx2(1, 0) + dNy2(1, 0), 0, 0, 0, dNx1(1, 1) + dNy1(0, 1), -dNx3(1, 1) - dNy3(0, 0), dNx2(1, 1) + dNy2(1, 1), 0, 0, 0, dNx1(1, 2) + dNy1(0, 2), -dNx3(1, 2) - dNy3(0, 2), dNx2(1, 2) + dNy2(1, 2), 0}}; // clang-format on -#endif } } // namespace akantu #endif /* __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/fe_engine_template_cohesive.cc b/src/fe_engine/fe_engine_template_cohesive.cc index b9475e0e1..d247ac9d5 100644 --- a/src/fe_engine/fe_engine_template_cohesive.cc +++ b/src/fe_engine/fe_engine_template_cohesive.cc @@ -1,177 +1,133 @@ /** * @file fe_engine_template_cohesive.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Oct 31 2012 * @date last modification: Thu Oct 15 2015 * * @brief Specialization of the FEEngineTemplate for cohesive element * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fe_engine_template.hh" #include "shape_cohesive.hh" #include "integrator_gauss.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* compatibility functions */ /* -------------------------------------------------------------------------- */ template <> Real FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive, DefaultIntegrationOrderFunctor>:: integrate(const Array<Real> & f, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); #ifndef AKANTU_NDEBUG UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements != empty_filter) nb_element = filter_elements.size(); UInt nb_quadrature_points = getNbIntegrationPoints(type); AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << ") has not the good size."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == 1, "The vector f(" << f.getID() << ") has not the good number of component."); #endif Real integral = 0.; #define INTEGRATE(type) \ integral = integrator.integrate<type>(f, ghost_type, filter_elements); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE AKANTU_DEBUG_OUT(); return integral; } /* -------------------------------------------------------------------------- */ template <> void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive, DefaultIntegrationOrderFunctor>:: integrate(const Array<Real> & f, Array<Real> & intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { #ifndef AKANTU_NDEBUG UInt nb_element = mesh.getNbElement(type, ghost_type); if (filter_elements == filter_elements) nb_element = filter_elements.size(); UInt nb_quadrature_points = getNbIntegrationPoints(type); AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points, "The vector f(" << f.getID() << " size " << f.size() << ") has not the good size (" << nb_element << ")."); AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom, "The vector f(" << f.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom, "The vector intf(" << intf.getID() << ") has not the good number of component."); AKANTU_DEBUG_ASSERT(intf.size() == nb_element, "The vector intf(" << intf.getID() << ") has not the good size."); #endif #define INTEGRATE(type) \ integrator.integrate<type>(f, intf, nb_degree_of_freedom, ghost_type, \ filter_elements); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE); #undef INTEGRATE } /* -------------------------------------------------------------------------- */ template <> void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive, DefaultIntegrationOrderFunctor>:: gradientOnIntegrationPoints(const Array<Real> &, Array<Real> &, const UInt, const ElementType &, const GhostType &, const Array<UInt> &) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ -template <> -template <> -void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive, - DefaultIntegrationOrderFunctor>:: - computeNormalsOnIntegrationPoints<_cohesive_1d_2>( - const Array<Real> &, Array<Real> & normal, - const GhostType & ghost_type) const { - AKANTU_DEBUG_IN(); - - AKANTU_DEBUG_ASSERT( - mesh.getSpatialDimension() == 1, - "Mesh dimension must be 1 to compute normals on 1D cohesive elements!"); - const ElementType type = _cohesive_1d_2; - const ElementType facet_type = Mesh::getFacetType(type); - - UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); - normal.resize(nb_element); - - Array<Element> & facets = - mesh.getMeshFacets().getSubelementToElement(type, ghost_type); - Array<std::vector<Element> > & segments = - mesh.getMeshFacets().getElementToSubelement(facet_type, ghost_type); - - Real values[2]; - - for (UInt elem = 0; elem < nb_element; ++elem) { - - for (UInt p = 0; p < 2; ++p) { - Element f = facets(elem, p); - Element seg = segments(f.element)[0]; - Vector<Real> barycenter(values + p, 1); - mesh.getBarycenter(seg, barycenter); - } - - Real difference = values[0] - values[1]; - - AKANTU_DEBUG_ASSERT(difference != 0., - "Error in normal computation for cohesive elements"); - - normal(elem) = difference / std::abs(difference); - } - - AKANTU_DEBUG_OUT(); -} } // akantu diff --git a/src/fe_engine/shape_cohesive_inline_impl.cc b/src/fe_engine/shape_cohesive_inline_impl.cc index 9477d6021..df81e9a8f 100644 --- a/src/fe_engine/shape_cohesive_inline_impl.cc +++ b/src/fe_engine/shape_cohesive_inline_impl.cc @@ -1,301 +1,328 @@ /** * @file shape_cohesive_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Feb 03 2012 * @date last modification: Thu Oct 15 2015 * * @brief ShapeCohesive inline implementation * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "shape_cohesive.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__ #define __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline ShapeLagrange<_ek_cohesive>::ShapeLagrange(const Mesh & mesh, const ID & id, const MemoryID & memory_id) : ShapeLagrangeBase(mesh, _ek_cohesive, id, memory_id) {} #define INIT_SHAPE_FUNCTIONS(type) \ setIntegrationPointsByType<type>(integration_points, ghost_type); \ precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type); \ precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type); /* -------------------------------------------------------------------------- */ inline void ShapeLagrange<_ek_cohesive>::initShapeFunctions( const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type) { AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeLagrange<_ek_cohesive>::computeShapeDerivativesOnIntegrationPoints( const Array<Real> &, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); - UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize(); - UInt spatial_dimension = ElementClass<type>::getNaturalSpaceDimension(); - UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); + UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize(); + UInt spatial_dimension = ElementClass<type>::getNaturalSpaceDimension(); + UInt nb_nodes_per_element = + ElementClass<type>::getNbNodesPerInterpolationElement(); UInt nb_points = integration_points.cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); AKANTU_DEBUG_ASSERT(shape_derivatives.getNbComponent() == size_of_shapesd, "The shapes_derivatives array does not have the correct " << "number of component"); shape_derivatives.resize(nb_element * nb_points); Real * shapesd_val = shape_derivatives.storage(); auto compute = [&](const auto & el) { auto ptr = shapesd_val + el * nb_points * size_of_shapesd; Tensor3<Real> B(ptr, spatial_dimension, nb_nodes_per_element, nb_points); ElementClass<type>::computeDNDS(integration_points, B); }; for_each_element(nb_element, filter_elements, compute); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void ShapeLagrange<_ek_cohesive>::computeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shape_derivatives, const ElementType & type, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { #define AKANTU_COMPUTE_SHAPES(type) \ computeShapeDerivativesOnIntegrationPoints<type>( \ nodes, integration_points, shape_derivatives, ghost_type, \ filter_elements); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES); #undef AKANTU_COMPUTE_SHAPES } /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeLagrange<_ek_cohesive>::precomputeShapesOnIntegrationPoints( const Array<Real> & nodes, GhostType ghost_type) { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; Matrix<Real> & natural_coords = integration_points(type, ghost_type); UInt size_of_shapes = ElementClass<type>::getShapeSize(); Array<Real> & shapes_tmp = shapes.alloc(0, size_of_shapes, itp_type, ghost_type); this->computeShapesOnIntegrationPoints<type>(nodes, natural_coords, shapes_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void ShapeLagrange<_ek_cohesive>::precomputeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, GhostType ghost_type) { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; Matrix<Real> & natural_coords = integration_points(type, ghost_type); UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize(); Array<Real> & shapes_derivatives_tmp = shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); this->computeShapeDerivativesOnIntegrationPoints<type>( nodes, natural_coords, shapes_derivatives_tmp, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::extractNodalToElementField( const Array<Real> & nodal_f, Array<Real> & elemental_f, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_nodes_per_itp_element = ElementClass<type>::getNbNodesPerInterpolationElement(); UInt nb_degree_of_freedom = nodal_f.getNbComponent(); UInt nb_element = this->mesh.getNbElement(type, ghost_type); const auto & conn_array = this->mesh.getConnectivity(type, ghost_type); auto conn = conn_array.begin(conn_array.getNbComponent() / 2, 2); if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } elemental_f.resize(nb_element); Array<Real>::matrix_iterator u_it = elemental_f.begin(nb_degree_of_freedom, nb_nodes_per_itp_element); ReduceFunction reduce_function; auto compute = [&](const auto & el) { Matrix<Real> & u = *u_it; Matrix<UInt> el_conn(conn[el]); // compute the average/difference of the nodal field loaded from cohesive // element for (UInt n = 0; n < el_conn.rows(); ++n) { UInt node_plus = el_conn(n, 0); UInt node_minus = el_conn(n, 1); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { Real u_plus = nodal_f(node_plus, d); Real u_minus = nodal_f(node_minus, d); u(d, n) = reduce_function(u_plus, u_minus); } } ++u_it; }; for_each_element(nb_element, filter_elements, compute); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::interpolateOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; AKANTU_DEBUG_ASSERT(this->shapes.exists(itp_type, ghost_type), "No shapes for the type " << this->shapes.printType(itp_type, ghost_type)); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element); this->extractNodalToElementField<type, ReduceFunction>(in_u, u_el, ghost_type, filter_elements); this->template interpolateElementalFieldOnIntegrationPoints<type>( u_el, out_uq, ghost_type, shapes(itp_type, ghost_type), filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::variationOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & nablauq, UInt nb_degree_of_freedom, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); InterpolationType itp_type = ElementClassProperty<type>::interpolation_type; AKANTU_DEBUG_ASSERT( this->shapes_derivatives.exists(itp_type, ghost_type), "No shapes for the type " << this->shapes_derivatives.printType(itp_type, ghost_type)); UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement(); Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element); this->extractNodalToElementField<type, ReduceFunction>(in_u, u_el, ghost_type, filter_elements); this->template gradientElementalFieldOnIntegrationPoints<type>( u_el, nablauq, ghost_type, shapes_derivatives(itp_type, ghost_type), filter_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ - template <ElementType type, class ReduceFunction> void ShapeLagrange<_ek_cohesive>::computeNormalsOnIntegrationPoints( const Array<Real> & u, Array<Real> & normals_u, GhostType ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_element = this->mesh.getNbElement(type, ghost_type); UInt nb_points = this->integration_points(type, ghost_type).cols(); UInt spatial_dimension = this->mesh.getSpatialDimension(); if (filter_elements != empty_filter) nb_element = filter_elements.size(); normals_u.resize(nb_points * nb_element); - Array<Real> tangents_u(nb_element * nb_points, - (spatial_dimension * (spatial_dimension - 1))); - - this->template variationOnIntegrationPoints<type, ReduceFunction>( - u, tangents_u, spatial_dimension, ghost_type, filter_elements); + Array<Real> tangents_u(0, (spatial_dimension * (spatial_dimension - 1))); - Array<Real>::vector_iterator normal = normals_u.begin(spatial_dimension); - Array<Real>::vector_iterator normal_end = normals_u.end(spatial_dimension); + if (spatial_dimension > 1) { + tangents_u.resize(nb_element * nb_points); + this->template variationOnIntegrationPoints<type, ReduceFunction>( + u, tangents_u, spatial_dimension, ghost_type, filter_elements); + } Real * tangent = tangents_u.storage(); - if (spatial_dimension == 3) - for (; normal != normal_end; ++normal) { + if (spatial_dimension == 3) { + for (auto & normal : make_view(normals_u, spatial_dimension)) { Math::vectorProduct3(tangent, tangent + spatial_dimension, - normal->storage()); + normal.storage()); - (*normal) /= normal->norm(); + normal /= normal.norm(); tangent += spatial_dimension * 2; } - else if (spatial_dimension == 2) - for (; normal != normal_end; ++normal) { + } else if (spatial_dimension == 2) { + for (auto & normal : make_view(normals_u, spatial_dimension)) { Vector<Real> a1(tangent, spatial_dimension); - (*normal)(0) = -a1(1); - (*normal)(1) = a1(0); - (*normal) /= normal->norm(); + normal(0) = -a1(1); + normal(1) = a1(0); + normal.normalize(); tangent += spatial_dimension; } + } else if (spatial_dimension == 1) { + const auto facet_type = Mesh::getFacetType(type); + const auto & mesh_facets = mesh.getMeshFacets(); + const auto & facets = mesh_facets.getSubelementToElement(type, ghost_type); + const auto & segments = + mesh_facets.getElementToSubelement(facet_type, ghost_type); + + Real values[2]; + + for (auto el : arange(nb_element)) { + if (filter_elements != empty_filter) + el = filter_elements(el); + + for (UInt p = 0; p < 2; ++p) { + Element facet = facets(el, p); + Element segment = segments(facet.element)[0]; + Vector<Real> barycenter(values + p, 1); + mesh.getBarycenter(segment, barycenter); + } + + Real difference = values[0] - values[1]; + + AKANTU_DEBUG_ASSERT(difference != 0., + "Error in normal computation for cohesive elements"); + + normals_u(el) = difference / std::abs(difference); + } + } AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__ */ diff --git a/src/fe_engine/shape_structural_inline_impl.cc b/src/fe_engine/shape_structural_inline_impl.cc index 0eefa86d8..207ab5bea 100644 --- a/src/fe_engine/shape_structural_inline_impl.cc +++ b/src/fe_engine/shape_structural_inline_impl.cc @@ -1,383 +1,431 @@ /** * @file shape_structural_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 * @date last modification: Thu Oct 15 2015 * * @brief ShapeStructural inline implementation * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_iterators.hh" #include "shape_structural.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ #define __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ namespace akantu { namespace { /// Extract nodal coordinates per elements template <ElementType type> std::unique_ptr<Array<Real>> getNodesPerElement(const Mesh & mesh, const Array<Real> & nodes, const GhostType & ghost_type) { const auto dim = ElementClass<type>::getSpatialDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nodes_per_element = std::make_unique<Array<Real>>(0, dim * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, *nodes_per_element, type, ghost_type); return nodes_per_element; } } template <ElementKind kind> inline void ShapeStructural<kind>::initShapeFunctions( const Array<Real> & /* unused */, const Matrix<Real> & /* unused */, const ElementType & /* unused */, const GhostType & /* unused */) { AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ #define INIT_SHAPE_FUNCTIONS(type) \ setIntegrationPointsByType<type>(integration_points, ghost_type); \ precomputeRotationMatrices<type>(nodes, ghost_type); \ precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type); \ precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type); template <> inline void ShapeStructural<_ek_structural>::initShapeFunctions( const Array<Real> & nodes, const Matrix<Real> & integration_points, const ElementType & type, const GhostType & ghost_type) { AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS); } #undef INIT_SHAPE_FUNCTIONS /* -------------------------------------------------------------------------- */ template <> template <ElementType type> void ShapeStructural<_ek_structural>::computeShapesOnIntegrationPoints( const Array<Real> & nodes, const Matrix<Real> & integration_points, Array<Real> & shapes, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { UInt nb_points = integration_points.cols(); UInt nb_element = mesh.getConnectivity(type, ghost_type).size(); shapes.resize(nb_element * nb_points); UInt ndof = ElementClass<type>::getNbDegreeOfFreedom(); #if !defined(AKANTU_NDEBUG) UInt size_of_shapes = ElementClass<type>::getShapeSize(); AKANTU_DEBUG_ASSERT(shapes.getNbComponent() == size_of_shapes, "The shapes array does not have the correct " << "number of component"); #endif auto shapes_it = shapes.begin_reinterpret( ElementClass<type>::getNbNodesPerInterpolationElement(), ndof, nb_points, nb_element); auto shapes_begin = shapes_it; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); } auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type); auto nodes_it = nodes_per_element->begin(mesh.getSpatialDimension(), Mesh::getNbNodesPerElement(type)); auto nodes_begin = nodes_it; for (UInt elem = 0; elem < nb_element; ++elem) { if (filter_elements != empty_filter) { shapes_it = shapes_begin + filter_elements(elem); nodes_it = nodes_begin + filter_elements(elem); } Tensor3<Real> & N = *shapes_it; auto & real_coord = *nodes_it; ElementClass<type>::computeShapes(integration_points, real_coord, N); if (filter_elements == empty_filter) ++shapes_it; } } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::precomputeRotationMatrices( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const auto spatial_dimension = mesh.getSpatialDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto nb_element = mesh.getNbElement(type, ghost_type); const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom(); if (not this->rotation_matrices.exists(type, ghost_type)) { this->rotation_matrices.alloc(0, nb_dof * nb_dof, type, ghost_type); } auto & rot_matrices = this->rotation_matrices(type, ghost_type); rot_matrices.resize(nb_element); Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type); bool has_extra_normal = mesh.hasData<Real>("extra_normal", type, ghost_type); Array<Real>::const_vector_iterator extra_normal; if (has_extra_normal) extra_normal = mesh.getData<Real>("extra_normal", type, ghost_type) .begin(spatial_dimension); for (auto && tuple : zip(make_view(x_el, spatial_dimension, nb_nodes_per_element), make_view(rot_matrices, nb_dof, nb_dof))) { // compute shape derivatives auto & X = std::get<0>(tuple); auto & R = std::get<1>(tuple); if (has_extra_normal) { ElementClass<type>::computeRotationMatrix(R, X, *extra_normal); ++extra_normal; } else { ElementClass<type>::computeRotationMatrix( R, X, Vector<Real>(spatial_dimension)); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::precomputeShapesOnIntegrationPoints( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const auto & natural_coords = integration_points(type, ghost_type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_points = integration_points(type, ghost_type).cols(); auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom(); const auto dim = ElementClass<type>::getSpatialDimension(); auto itp_type = FEEngine::getInterpolationType(type); if (not shapes.exists(itp_type, ghost_type)) { auto size_of_shapes = this->getShapeSize(type); this->shapes.alloc(0, size_of_shapes, itp_type, ghost_type); } auto & shapes_ = this->shapes(itp_type, ghost_type); shapes_.resize(nb_element * nb_points); auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type); for (auto && tuple : zip(make_view(shapes_, nb_dof, nb_dof * nb_nodes_per_element, nb_points), make_view(*nodes_per_element, dim, nb_nodes_per_element))) { auto & N = std::get<0>(tuple); auto & real_coord = std::get<1>(tuple); ElementClass<type>::computeShapes(natural_coords, real_coord, N); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::precomputeShapeDerivativesOnIntegrationPoints( const Array<Real> & nodes, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const auto & natural_coords = integration_points(type, ghost_type); const auto spatial_dimension = mesh.getSpatialDimension(); const auto natural_spatial_dimension = ElementClass<type>::getNaturalSpaceDimension(); const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto nb_points = natural_coords.cols(); const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom(); const auto nb_element = mesh.getNbElement(type, ghost_type); const auto nb_stress_components = ElementClass<type>::getNbStressComponents(); auto itp_type = FEEngine::getInterpolationType(type); if (not this->shapes_derivatives.exists(itp_type, ghost_type)) { auto size_of_shapesd = this->getShapeDerivativesSize(type); this->shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); } auto & rot_matrices = this->rotation_matrices(type, ghost_type); Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element); FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type); auto & shapesd = this->shapes_derivatives(itp_type, ghost_type); shapesd.resize(nb_element * nb_points); for (auto && tuple : zip(make_view(x_el, spatial_dimension, nb_nodes_per_element), make_view(shapesd, nb_stress_components, nb_nodes_per_element * nb_dof, nb_points), make_view(rot_matrices, nb_dof, nb_dof))) { // compute shape derivatives auto & X = std::get<0>(tuple); auto & B = std::get<1>(tuple); auto & RDOFs = std::get<2>(tuple); + + // /!\ This is a temporary variable with no specified size for columns ! + // It is up to the element to resize + Tensor3<Real> dnds(natural_spatial_dimension, + ElementClass<type>::interpolation_property::dnds_columns, + B.size(2)); + ElementClass<type>::computeDNDS(natural_coords, X, dnds); + + Tensor3<Real> J(natural_spatial_dimension, natural_coords.rows(), natural_coords.cols()); + + // Computing the coordinates of the element in the natural space auto R = RDOFs.block(0, 0, spatial_dimension, spatial_dimension); Matrix<Real> T(B.size(1), B.size(1)); T.block(RDOFs, 0, 0); T.block(RDOFs, RDOFs.rows(), RDOFs.rows()); // Rotate to local basis auto x = (R * X).block(0, 0, natural_spatial_dimension, nb_nodes_per_element); - Tensor3<Real> dnds(B.size(0), B.size(1), B.size(2)); - ElementClass<type>::computeDNDS(natural_coords, X, dnds); - - Tensor3<Real> J(x.rows(), natural_coords.rows(), natural_coords.cols()); - - ElementClass<type>::computeJMat(dnds, x, J); + ElementClass<type>::computeJMat(natural_coords, x, J); ElementClass<type>::computeShapeDerivatives(J, dnds, T, B); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::interpolateOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_dof, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(out_uq.getNbComponent() == nb_dof, "The output array shape is not correct"); auto itp_type = FEEngine::getInterpolationType(type); const auto & shapes_ = shapes(itp_type, ghost_type); auto nb_element = mesh.getNbElement(type, ghost_type); auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement(); auto nb_quad_points_per_element = integration_points(type, ghost_type).cols(); Array<Real> u_el(0, nb_nodes_per_element * nb_dof); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); auto nb_quad_points = nb_quad_points_per_element * u_el.size(); out_uq.resize(nb_quad_points); auto out_it = out_uq.begin_reinterpret(nb_dof, 1, nb_quad_points_per_element, u_el.size()); auto shapes_it = shapes_.begin_reinterpret(nb_dof, nb_dof * nb_nodes_per_element, nb_quad_points_per_element, nb_element); auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1, nb_quad_points_per_element, u_el.size()); for_each_element(nb_element, filter_elements, [&](auto && el) { auto & uq = *out_it; const auto & u = *u_it; auto N = Tensor3<Real>(shapes_it[el]); for (auto && q : arange(uq.size(2))) { auto uq_q = Matrix<Real>(uq(q)); auto u_q = Matrix<Real>(u(q)); auto N_q = Matrix<Real>(N(q)); uq_q.mul<false, false>(N_q, u_q); } ++out_it; ++u_it; }); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementKind kind> template <ElementType type> void ShapeStructural<kind>::gradientOnIntegrationPoints( const Array<Real> & in_u, Array<Real> & out_nablauq, UInt nb_dof, const GhostType & ghost_type, const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); auto itp_type = FEEngine::getInterpolationType(type); const auto & shapesd = shapes_derivatives(itp_type, ghost_type); auto nb_element = mesh.getNbElement(type, ghost_type); auto element_dimension = ElementClass<type>::getSpatialDimension(); auto nb_quad_points_per_element = integration_points(type, ghost_type).cols(); auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement(); Array<Real> u_el(0, nb_nodes_per_element * nb_dof); FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type, filter_elements); auto nb_quad_points = nb_quad_points_per_element * u_el.size(); out_nablauq.resize(nb_quad_points); auto out_it = out_nablauq.begin_reinterpret( element_dimension, 1, nb_quad_points_per_element, u_el.size()); auto shapesd_it = shapesd.begin_reinterpret( element_dimension, nb_dof * nb_nodes_per_element, nb_quad_points_per_element, nb_element); auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1, nb_quad_points_per_element, u_el.size()); for_each_element(nb_element, filter_elements, [&](auto && el) { auto & nablau = *out_it; const auto & u = *u_it; auto B = Tensor3<Real>(shapesd_it[el]); for (auto && q : arange(nablau.size(2))) { auto nablau_q = Matrix<Real>(nablau(q)); auto u_q = Matrix<Real>(u(q)); auto B_q = Matrix<Real>(B(q)); nablau_q.mul<false, false>(B_q, u_q); } ++out_it; ++u_it; }); AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +template <> +template <ElementType type> +void ShapeStructural<_ek_structural>::computeBtD( + const Array<Real> & Ds, Array<Real> & BtDs, + GhostType ghost_type, const Array<UInt> & filter_elements) const { + auto itp_type = ElementClassProperty<type>::interpolation_type; + + auto nb_stress = ElementClass<type>::getNbStressComponents(); + auto nb_dof_per_element = ElementClass<type>::getNbDegreeOfFreedom() * + mesh.getNbNodesPerElement(type); + + const auto & shapes_derivatives = + this->shapes_derivatives(itp_type, ghost_type); + + Array<Real> shapes_derivatives_filtered(0, + shapes_derivatives.getNbComponent()); + auto && view = make_view(shapes_derivatives, nb_stress, nb_dof_per_element); + auto B_it = view.begin(); + auto B_end = view.end(); + + if (filter_elements != empty_filter) { + FEEngine::filterElementalData(this->mesh, shapes_derivatives, + shapes_derivatives_filtered, type, ghost_type, + filter_elements); + auto && view = + make_view(shapes_derivatives_filtered, nb_stress, nb_dof_per_element); + B_it = view.begin(); + B_end = view.end(); + } + + for (auto && values : + zip(range(B_it, B_end), + make_view(Ds, nb_stress), + make_view(BtDs, BtDs.getNbComponent()))) { + const auto & B = std::get<0>(values); + const auto & D = std::get<1>(values); + auto & Bt_D = std::get<2>(values); + Bt_D.template mul<true>(B, D); + } +} + } // namespace akantu #endif /* __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ */ diff --git a/src/io/dumper/dumper_iohelper.cc b/src/io/dumper/dumper_iohelper.cc index 9ea6c8642..534c2bad2 100644 --- a/src/io/dumper/dumper_iohelper.cc +++ b/src/io/dumper/dumper_iohelper.cc @@ -1,302 +1,305 @@ /** * @file dumper_iohelper.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Oct 26 2012 * @date last modification: Thu Sep 17 2015 * * @brief implementation of DumperIOHelper * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <io_helper.hh> #include "dumper_iohelper.hh" #include "dumper_elemental_field.hh" #include "dumper_nodal_field.hh" #include "dumper_filtered_connectivity.hh" #include "dumper_variable.hh" #include "mesh.hh" #if defined(AKANTU_IGFEM) #include "dumper_igfem_connectivity.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ DumperIOHelper::DumperIOHelper() = default; /* -------------------------------------------------------------------------- */ DumperIOHelper::~DumperIOHelper() { for (auto it = fields.begin(); it != fields.end(); ++it) { delete it->second; } delete dumper; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setParallelContext(bool is_parallel) { UInt whoami = Communicator::getStaticCommunicator().whoAmI(); UInt nb_proc = Communicator::getStaticCommunicator().getNbProc(); if(is_parallel) dumper->setParallelContext(whoami, nb_proc); else dumper->setParallelContext(0, 1); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setDirectory(const std::string & directory) { this->directory = directory; dumper->setPrefix(directory); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setBaseName(const std::string & basename) { filename = basename; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setTimeStep(Real time_step) { if(!time_activated) this->dumper->activateTimeDescFiles(time_step); else this->dumper->setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump() { try { dumper->dump(filename, count); } catch (iohelper::IOHelperException & e) { AKANTU_DEBUG_ERROR("I was not able to dump your data with a Dumper: " << e.what()); } ++count; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(UInt step) { this->count = step; this->dump(); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(Real current_time, UInt step) { this->dumper->setCurrentTime(current_time); this->dump(step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerMesh(const Mesh & mesh, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { #if defined(AKANTU_IGFEM) if (element_kind == _ek_igfem) { registerField("connectivities", new dumper::IGFEMConnectivityField(mesh.getConnectivities(), spatial_dimension, ghost_type)); } else #endif registerField("connectivities", new dumper::ElementalField<UInt>(mesh.getConnectivities(), spatial_dimension, ghost_type, element_kind)); registerField("positions", new dumper::NodalField<Real>(mesh.getNodes())); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerFilteredMesh(const Mesh & mesh, const ElementTypeMapArray<UInt> & elements_filter, const Array<UInt> & nodes_filter, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { auto * f_connectivities = new ElementTypeMapArrayFilter<UInt>( mesh.getConnectivities(), elements_filter); this->registerField("connectivities", new dumper::FilteredConnectivityField(*f_connectivities, nodes_filter, spatial_dimension, ghost_type, element_kind)); this->registerField("positions",new dumper::NodalField<Real,true>( mesh.getNodes(), 0, 0, &nodes_filter)); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerField(const std::string & field_id, dumper::Field * field) { auto it = fields.find(field_id); if(it != fields.end()) { AKANTU_DEBUG_WARNING("The field " << field_id << " is already registered in this Dumper. Field ignored."); return; } fields[field_id] = field; field->registerToDumper(field_id, *dumper); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::unRegisterField(const std::string & field_id) { auto it = fields.find(field_id); if(it == fields.end()) { AKANTU_DEBUG_WARNING("The field " << field_id << " is not registered in this Dumper. Nothing to do."); return; } delete it->second; fields.erase(it); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerVariable(const std::string & variable_id, dumper::VariableBase * variable) { auto it = variables.find(variable_id); if(it != variables.end()) { AKANTU_DEBUG_WARNING("The Variable " << variable_id << " is already registered in this Dumper. Variable ignored."); return; } variables[variable_id] = variable; variable->registerToDumper(variable_id, *dumper); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::unRegisterVariable(const std::string & variable_id) { auto it = variables.find(variable_id); if(it == variables.end()) { AKANTU_DEBUG_WARNING("The variable " << variable_id << " is not registered in this Dumper. Nothing to do."); return; } delete it->second; variables.erase(it); } /* -------------------------------------------------------------------------- */ template <ElementType type> iohelper::ElemType getIOHelperType() { AKANTU_DEBUG_TO_IMPLEMENT(); return iohelper::MAX_ELEM_TYPE; } template <> iohelper::ElemType getIOHelperType<_point_1>() { return iohelper::POINT_SET; } template <> iohelper::ElemType getIOHelperType<_segment_2>() { return iohelper::LINE1; } template <> iohelper::ElemType getIOHelperType<_segment_3>() { return iohelper::LINE2; } template <> iohelper::ElemType getIOHelperType<_triangle_3>() { return iohelper::TRIANGLE1; } template <> iohelper::ElemType getIOHelperType<_triangle_6>() { return iohelper::TRIANGLE2; } template <> iohelper::ElemType getIOHelperType<_quadrangle_4>() { return iohelper::QUAD1; } template <> iohelper::ElemType getIOHelperType<_quadrangle_8>() { return iohelper::QUAD2; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_4>() { return iohelper::TETRA1; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_10>() { return iohelper::TETRA2; } template <> iohelper::ElemType getIOHelperType<_hexahedron_8>() { return iohelper::HEX1; } template <> iohelper::ElemType getIOHelperType<_hexahedron_20>() { return iohelper::HEX2; } template <> iohelper::ElemType getIOHelperType<_pentahedron_6>() { return iohelper::PRISM1; } template <> iohelper::ElemType getIOHelperType<_pentahedron_15>() { return iohelper::PRISM2; } #if defined(AKANTU_COHESIVE_ELEMENT) +template <> +iohelper::ElemType getIOHelperType<_cohesive_1d_2>() { return iohelper::COH1D2; } + template <> iohelper::ElemType getIOHelperType<_cohesive_2d_4>() { return iohelper::COH2D4; } template <> iohelper::ElemType getIOHelperType<_cohesive_2d_6>() { return iohelper::COH2D6; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_6>() { return iohelper::COH3D6; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_12>() { return iohelper::COH3D12; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_8>() { return iohelper::COH3D8; } //template <> //iohelper::ElemType getIOHelperType<_cohesive_3d_16>() { return iohelper::COH3D16; } #endif #if defined(AKANTU_STRUCTURAL_MECHANICS) template <> iohelper::ElemType getIOHelperType<_bernoulli_beam_2>() { return iohelper::BEAM2; } template <> iohelper::ElemType getIOHelperType<_bernoulli_beam_3>() { return iohelper::BEAM3; } #endif /* -------------------------------------------------------------------------- */ UInt getIOHelperType(ElementType type) { UInt ioh_type = iohelper::MAX_ELEM_TYPE; #define GET_IOHELPER_TYPE(type) \ ioh_type = getIOHelperType<type>(); AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_IOHELPER_TYPE); #undef GET_IOHELPER_TYPE return ioh_type; } /* -------------------------------------------------------------------------- */ } // akantu namespace iohelper { template<> DataType getDataType<akantu::NodeType>() { return _int; } } diff --git a/src/mesh/element_type_map.cc b/src/mesh/element_type_map.cc index 10ed4c342..ee0fc8cca 100644 --- a/src/mesh/element_type_map.cc +++ b/src/mesh/element_type_map.cc @@ -1,59 +1,71 @@ /** * @file element_type_map.cc * * @author Nicolas Richart * * @date creation Tue Jun 27 2017 * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { -FEEngineElementTypeMapArrayInializer::FEEngineElementTypeMapArrayInializer( +FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer( const FEEngine & fe_engine, UInt nb_component, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) - : MeshElementTypeMapArrayInializer( - fe_engine.getMesh(), - nb_component, + : MeshElementTypeMapArrayInitializer( + fe_engine.getMesh(), nb_component, spatial_dimension == UInt(-2) ? fe_engine.getMesh().getSpatialDimension() : spatial_dimension, ghost_type, element_kind, true, false), fe_engine(fe_engine) {} -UInt FEEngineElementTypeMapArrayInializer::size( +FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer( + const FEEngine & fe_engine, + const ElementTypeMapArrayInitializer::CompFunc & nb_component, + UInt spatial_dimension, const GhostType & ghost_type, + const ElementKind & element_kind) + : MeshElementTypeMapArrayInitializer( + fe_engine.getMesh(), nb_component, + spatial_dimension == UInt(-2) + ? fe_engine.getMesh().getSpatialDimension() + : spatial_dimension, + ghost_type, element_kind, true, false), + fe_engine(fe_engine) {} + +UInt FEEngineElementTypeMapArrayInitializer::size( const ElementType & type) const { - return MeshElementTypeMapArrayInializer::size(type) * + return MeshElementTypeMapArrayInitializer::size(type) * fe_engine.getNbIntegrationPoints(type, this->ghost_type); } -FEEngineElementTypeMapArrayInializer::ElementTypesIteratorHelper -FEEngineElementTypeMapArrayInializer::elementTypes() const { +FEEngineElementTypeMapArrayInitializer::ElementTypesIteratorHelper +FEEngineElementTypeMapArrayInitializer::elementTypes() const { return this->fe_engine.elementTypes(spatial_dimension, ghost_type, element_kind); } } // namespace akantu diff --git a/src/mesh/element_type_map.hh b/src/mesh/element_type_map.hh index c6fc7a798..f3aefd368 100644 --- a/src/mesh/element_type_map.hh +++ b/src/mesh/element_type_map.hh @@ -1,437 +1,449 @@ /** * @file element_type_map.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 31 2011 * @date last modification: Fri Oct 02 2015 * * @brief storage class by element type * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_memory.hh" #include "aka_named_argument.hh" #include "element.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_TYPE_MAP_HH__ #define __AKANTU_ELEMENT_TYPE_MAP_HH__ namespace akantu { class FEEngine; } // namespace akantu namespace akantu { namespace { DECLARE_NAMED_ARGUMENT(all_ghost_types); DECLARE_NAMED_ARGUMENT(default_value); DECLARE_NAMED_ARGUMENT(element_kind); DECLARE_NAMED_ARGUMENT(ghost_type); DECLARE_NAMED_ARGUMENT(nb_component); + DECLARE_NAMED_ARGUMENT(nb_component_functor); DECLARE_NAMED_ARGUMENT(with_nb_element); DECLARE_NAMED_ARGUMENT(with_nb_nodes_per_element); DECLARE_NAMED_ARGUMENT(spatial_dimension); DECLARE_NAMED_ARGUMENT(do_not_default); } // namespace template <class Stored, typename SupportType = ElementType> class ElementTypeMap; /* -------------------------------------------------------------------------- */ /* ElementTypeMapBase */ /* -------------------------------------------------------------------------- */ /// Common non templated base class for the ElementTypeMap class class ElementTypeMapBase { public: virtual ~ElementTypeMapBase() = default; }; /* -------------------------------------------------------------------------- */ /* ElementTypeMap */ /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> class ElementTypeMap : public ElementTypeMapBase { public: ElementTypeMap(); ~ElementTypeMap() override; inline static std::string printType(const SupportType & type, const GhostType & ghost_type); /*! Tests whether a type is present in the object * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return true if the type is present. */ inline bool exists(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /*! get the stored data corresponding to a type * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ inline const Stored & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /*! get the stored data corresponding to a type * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ inline Stored & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost); /*! insert data of a new type (not yet present) into the map. THIS METHOD IS * NOT ARRAY SAFE, when using ElementTypeMapArray, use setArray instead * @param data to insert * @param type type of data (if this type is already present in the map, * an exception is thrown). * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ - inline Stored & operator()(const Stored & insert, const SupportType & type, + template <typename U> + inline Stored & operator()(U && insertee, const SupportType & type, const GhostType & ghost_type = _not_ghost); +public: /// print helper virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ /*! iterator allows to iterate over type-data pairs of the map. The interface * expects the SupportType to be ElementType. */ using DataMap = std::map<SupportType, Stored>; class type_iterator : private std::iterator<std::forward_iterator_tag, const SupportType> { public: using value_type = const SupportType; using pointer = const SupportType *; using reference = const SupportType &; protected: using DataMapIterator = typename ElementTypeMap<Stored>::DataMap::const_iterator; public: type_iterator(DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek); type_iterator(const type_iterator & it); type_iterator() = default; inline reference operator*(); inline reference operator*() const; inline type_iterator & operator++(); type_iterator operator++(int); inline bool operator==(const type_iterator & other) const; inline bool operator!=(const type_iterator & other) const; type_iterator & operator=(const type_iterator & other); private: DataMapIterator list_begin; DataMapIterator list_end; UInt dim; ElementKind kind; }; /// helper class to use in range for constructions class ElementTypesIteratorHelper { public: using Container = ElementTypeMap<Stored, SupportType>; using iterator = typename Container::type_iterator; ElementTypesIteratorHelper(const Container & container, UInt dim, GhostType ghost_type, ElementKind kind) : container(std::cref(container)), dim(dim), ghost_type(ghost_type), kind(kind) {} template <typename... pack> ElementTypesIteratorHelper(const Container & container, use_named_args_t, pack &&... _pack) : ElementTypesIteratorHelper( container, OPTIONAL_NAMED_ARG(spatial_dimension, _all_dimensions), OPTIONAL_NAMED_ARG(ghost_type, _not_ghost), OPTIONAL_NAMED_ARG(element_kind, _ek_regular)) {} ElementTypesIteratorHelper(const ElementTypesIteratorHelper &) = default; ElementTypesIteratorHelper & operator=(const ElementTypesIteratorHelper &) = default; ElementTypesIteratorHelper & operator=(ElementTypesIteratorHelper &&) = default; iterator begin() { return container.get().firstType(dim, ghost_type, kind); } iterator end() { return container.get().lastType(dim, ghost_type, kind); } private: std::reference_wrapper<const Container> container; UInt dim; GhostType ghost_type; ElementKind kind; }; private: ElementTypesIteratorHelper elementTypesImpl(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const; template <typename... pack> ElementTypesIteratorHelper elementTypesImpl(const use_named_args_t & /*unused*/, pack &&... _pack) const; public: + /*! + * \param _spatial_dimension optional: filter for elements of given spatial + * dimension + * \param _ghost_type optional: filter for a certain ghost_type + * \param _element_kind optional: filter for elements of given kind + */ template <typename... pack> std::enable_if_t<are_named_argument<pack...>::value, ElementTypesIteratorHelper> elementTypes(pack &&... _pack) const { return elementTypesImpl(use_named_args, std::forward<decltype(_pack)>(_pack)...); } template <typename... pack> std::enable_if_t<not are_named_argument<pack...>::value, ElementTypesIteratorHelper> elementTypes(pack &&... _pack) const { return elementTypesImpl(std::forward<decltype(_pack)>(_pack)...); } public: /*! Get an iterator to the beginning of a subset datamap. This method expects * the SupportType to be ElementType. * @param dim optional: iterate over data of dimension dim (e.g. when * iterating over (surface) facets of a 3D mesh, dim would be 2). * by default, all dimensions are considered. * @param ghost_type optional: by default, the data map for non-ghost * elements is iterated over. * @param kind optional: the kind of element to search for (see * aka_common.hh), by default all kinds are considered * @return an iterator to the first stored data matching the filters * or an iterator to the end of the map if none match*/ inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; /*! Get an iterator to the end of a subset datamap. This method expects * the SupportType to be ElementType. * @param dim optional: iterate over data of dimension dim (e.g. when * iterating over (surface) facets of a 3D mesh, dim would be 2). * by default, all dimensions are considered. * @param ghost_type optional: by default, the data map for non-ghost * elements is iterated over. * @param kind optional: the kind of element to search for (see * aka_common.hh), by default all kinds are considered * @return an iterator to the last stored data matching the filters * or an iterator to the end of the map if none match */ inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; protected: /*! Direct access to the underlying data map. for internal use by daughter * classes only * @param ghost_type whether to return the data map or the ghost_data map * @return the raw map */ inline DataMap & getData(GhostType ghost_type); /*! Direct access to the underlying data map. for internal use by daughter * classes only * @param ghost_type whether to return the data map or the ghost_data map * @return the raw map */ inline const DataMap & getData(GhostType ghost_type) const; /* ------------------------------------------------------------------------ */ protected: DataMap data; DataMap ghost_data; }; /* -------------------------------------------------------------------------- */ /* Some typedefs */ /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> class ElementTypeMapArray : public ElementTypeMap<Array<T> *, SupportType>, public Memory { public: using type = T; using array_type = Array<T>; protected: using parent = ElementTypeMap<Array<T> *, SupportType>; using DataMap = typename parent::DataMap; public: using type_iterator = typename parent::type_iterator; /// standard assigment (copy) operator void operator=(const ElementTypeMapArray &) = delete; ElementTypeMapArray(const ElementTypeMapArray &) = delete; + /// explicit copy + void copy(const ElementTypeMapArray & other); + /*! Constructor * @param id optional: identifier (string) * @param parent_id optional: parent identifier. for organizational purposes * only * @param memory_id optional: choose a specific memory, defaults to memory 0 */ ElementTypeMapArray(const ID & id = "by_element_type_array", const ID & parent_id = "no_parent", const MemoryID & memory_id = 0) : parent(), Memory(parent_id + ":" + id, memory_id), name(id){}; /*! allocate memory for a new array * @param size number of tuples of the new array * @param nb_component tuple size * @param type the type under which the array is indexed in the map * @param ghost_type whether to add the field to the data map or the * ghost_data map * @return a reference to the allocated array */ inline Array<T> & alloc(UInt size, UInt nb_component, const SupportType & type, const GhostType & ghost_type, const T & default_value = T()); /*! allocate memory for a new array in both the data and the ghost_data map * @param size number of tuples of the new array * @param nb_component tuple size * @param type the type under which the array is indexed in the map*/ inline void alloc(UInt size, UInt nb_component, const SupportType & type, const T & default_value = T()); /* get a reference to the array of certain type * @param type data filed under type is returned * @param ghost_type optional: by default the non-ghost map is searched * @return a reference to the array */ inline const Array<T> & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /// access the data of an element, this combine the map and array accessor - inline const T & operator()(const Element & element, UInt component = 0) const; + inline const T & operator()(const Element & element, + UInt component = 0) const; /// access the data of an element, this combine the map and array accessor inline T & operator()(const Element & element, UInt component = 0); /* get a reference to the array of certain type * @param type data filed under type is returned * @param ghost_type optional: by default the non-ghost map is searched * @return a const reference to the array */ inline Array<T> & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost); /*! insert data of a new type (not yet present) into the map. * @param type type of data (if this type is already present in the map, * an exception is thrown). * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @param vect the vector to include into the map * @return stored data corresponding to type. */ inline void setArray(const SupportType & type, const GhostType & ghost_type, const Array<T> & vect); /*! frees all memory related to the data*/ inline void free(); /*! set all values in the ElementTypeMap to zero*/ inline void clear(); /*! set all values in the ElementTypeMap to value */ - template<typename ST> - inline void set(const ST & value); + template <typename ST> inline void set(const ST & value); /*! deletes and reorders entries in the stored arrays * @param new_numbering a ElementTypeMapArray of new indices. UInt(-1) * indicates * deleted entries. */ inline void onElementsRemoved(const ElementTypeMapArray<UInt> & new_numbering); /// text output helper void printself(std::ostream & stream, int indent = 0) const override; /*! set the id * @param id the new name */ inline void setID(const ID & id) { this->id = id; } ElementTypeMap<UInt> getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const { ElementTypeMap<UInt> nb_components; for (auto & type : this->elementTypes(dim, ghost_type, kind)) { UInt nb_comp = (*this)(type, ghost_type).getNbComponent(); nb_components(type, ghost_type) = nb_comp; } return nb_components; } /* ------------------------------------------------------------------------ */ /* more evolved allocators */ /* ------------------------------------------------------------------------ */ public: /// initialize the arrays in accordance to a functor template <class Func> void initialize(const Func & f, const T & default_value, bool do_not_default); /// initialize with sizes and number of components in accordance of a mesh /// content template <typename... pack> void initialize(const Mesh & mesh, pack &&... _pack); /// initialize with sizes and number of components in accordance of a fe /// engine content (aka integration points) template <typename... pack> void initialize(const FEEngine & fe_engine, pack &&... _pack); /* ------------------------------------------------------------------------ */ /* Accesssors */ /* ------------------------------------------------------------------------ */ public: /// get the name of the internal field AKANTU_GET_MACRO(Name, name, ID); /// name of the elment type map: e.g. connectivity, grad_u ID name; }; /// to store data Array<Real> by element type using ElementTypeMapReal = ElementTypeMapArray<Real>; /// to store data Array<Int> by element type using ElementTypeMapInt = ElementTypeMapArray<Int>; /// to store data Array<UInt> by element type using ElementTypeMapUInt = ElementTypeMapArray<UInt, ElementType>; /// Map of data of type UInt stored in a mesh using UIntDataMap = std::map<std::string, Array<UInt> *>; using ElementTypeMapUIntDataMap = ElementTypeMap<UIntDataMap, ElementType>; } // namespace akantu #endif /* __AKANTU_ELEMENT_TYPE_MAP_HH__ */ diff --git a/src/mesh/element_type_map_tmpl.hh b/src/mesh/element_type_map_tmpl.hh index af2a331d6..23a34e1fe 100644 --- a/src/mesh/element_type_map_tmpl.hh +++ b/src/mesh/element_type_map_tmpl.hh @@ -1,661 +1,747 @@ /** * @file element_type_map_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 31 2011 * @date last modification: Fri Oct 02 2015 * * @brief implementation of template functions of the ElementTypeMap and * ElementTypeMapArray classes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_static_if.hh" #include "element_type_map.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include "element_type_conversion.hh" /* -------------------------------------------------------------------------- */ +#include <functional> +/* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ #define __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* ElementTypeMap */ /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline std::string ElementTypeMap<Stored, SupportType>::printType(const SupportType & type, const GhostType & ghost_type) { std::stringstream sstr; sstr << "(" << ghost_type << ":" << type << ")"; return sstr.str(); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline bool ElementTypeMap<Stored, SupportType>::exists( const SupportType & type, const GhostType & ghost_type) const { return this->getData(ghost_type).find(type) != this->getData(ghost_type).end(); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline const Stored & ElementTypeMap<Stored, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) const { auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMap::printType(type, ghost_type) << " in this ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> class"); return it->second; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline Stored & ElementTypeMap<Stored, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) { return this->getData(ghost_type)[type]; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> +template <typename U> inline Stored & ElementTypeMap<Stored, SupportType>:: -operator()(const Stored & insert, const SupportType & type, +operator()(U && insertee, const SupportType & type, const GhostType & ghost_type) { auto it = this->getData(ghost_type).find(type); if (it != this->getData(ghost_type).end()) { AKANTU_SILENT_EXCEPTION("Element of type " << ElementTypeMap::printType(type, ghost_type) << " already in this ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> class"); } else { auto & data = this->getData(ghost_type); const auto & res = - data.insert(std::pair<ElementType, Stored>(type, insert)); + data.insert(std::make_pair(type, std::forward<U>(insertee))); it = res.first; } return it->second; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::DataMap & ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) { if (ghost_type == _not_ghost) return data; return ghost_data; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline const typename ElementTypeMap<Stored, SupportType>::DataMap & ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) const { if (ghost_type == _not_ghost) return data; return ghost_data; } /* -------------------------------------------------------------------------- */ /// Works only if stored is a pointer to a class with a printself method template <class Stored, typename SupportType> void ElementTypeMap<Stored, SupportType>::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> [" << std::endl; for (auto gt : ghost_types) { const DataMap & data = getData(gt); for (auto & pair : data) { stream << space << space << ElementTypeMap::printType(pair.first, gt) << std::endl; } } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::ElementTypeMap() = default; /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::~ElementTypeMap() = default; /* -------------------------------------------------------------------------- */ /* ElementTypeMapArray */ +/* -------------------------------------------------------------------------- */ +template <typename T, typename SupportType> +void ElementTypeMapArray<T, SupportType>::copy( + const ElementTypeMapArray & other) { + for (auto && ghost_type : ghost_types) { + for (auto && type : + this->elementTypes(_all_dimensions, ghost_types, _ek_not_defined)) { + const auto & array_to_copy = other(type, ghost_type); + auto & array = + this->alloc(0, array_to_copy.getNbComponent(), type, ghost_type); + array.copy(array_to_copy); + } + } +} + /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline Array<T> & ElementTypeMapArray<T, SupportType>::alloc( UInt size, UInt nb_component, const SupportType & type, const GhostType & ghost_type, const T & default_value) { std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; Array<T> * tmp; auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) { std::stringstream sstr; sstr << this->id << ":" << type << ghost_id; tmp = &(Memory::alloc<T>(sstr.str(), size, nb_component, default_value)); std::stringstream sstrg; sstrg << ghost_type; // tmp->setTag(sstrg.str()); this->getData(ghost_type)[type] = tmp; } else { AKANTU_DEBUG_INFO( "The vector " << this->id << this->printType(type, ghost_type) << " already exists, it is resized instead of allocated."); tmp = it->second; it->second->resize(size); } return *tmp; } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::alloc(UInt size, UInt nb_component, const SupportType & type, const T & default_value) { this->alloc(size, nb_component, type, _not_ghost, default_value); this->alloc(size, nb_component, type, _ghost, default_value); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::free() { AKANTU_DEBUG_IN(); for (auto gt : ghost_types) { auto & data = this->getData(gt); for (auto & pair : data) { dealloc(pair.second->getID()); } data.clear(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::clear() { for (auto gt : ghost_types) { auto & data = this->getData(gt); for (auto & vect : data) { vect.second->clear(); } } } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> -template<typename ST> +template <typename ST> inline void ElementTypeMapArray<T, SupportType>::set(const ST & value) { for (auto gt : ghost_types) { auto & data = this->getData(gt); for (auto & vect : data) { vect.second->set(value); } } } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline const Array<T> & ElementTypeMapArray<T, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) const { auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMapArray::printType(type, ghost_type) << " in this const ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> class(\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline Array<T> & ElementTypeMapArray<T, SupportType>:: operator()(const SupportType & type, const GhostType & ghost_type) { auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMapArray::printType(type, ghost_type) << " in this ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> class (\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::setArray(const SupportType & type, const GhostType & ghost_type, const Array<T> & vect) { auto it = this->getData(ghost_type).find(type); if (AKANTU_DEBUG_TEST(dblWarning) && it != this->getData(ghost_type).end() && it->second != &vect) { AKANTU_DEBUG_WARNING( "The Array " << this->printType(type, ghost_type) << " is already registred, this call can lead to a memory leak."); } this->getData(ghost_type)[type] = &(const_cast<Array<T> &>(vect)); } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> inline void ElementTypeMapArray<T, SupportType>::onElementsRemoved( const ElementTypeMapArray<UInt> & new_numbering) { for (auto gt : ghost_types) { for (auto & type : new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) { auto support_type = convertType<ElementType, SupportType>(type); if (this->exists(support_type, gt)) { const auto & renumbering = new_numbering(type, gt); if (renumbering.size() == 0) continue; auto & vect = this->operator()(support_type, gt); auto nb_component = vect.getNbComponent(); Array<T> tmp(renumbering.size(), nb_component); UInt new_size = 0; for (UInt i = 0; i < vect.size(); ++i) { UInt new_i = renumbering(i); if (new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component, vect.storage() + i * nb_component, nb_component * sizeof(T)); ++new_size; } } tmp.resize(new_size); vect.copy(tmp); } } } } /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> void ElementTypeMapArray<T, SupportType>::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; for (UInt g = _not_ghost; g <= _ghost; ++g) { auto gt = (GhostType)g; const DataMap & data = this->getData(gt); typename DataMap::const_iterator it; for (it = data.begin(); it != data.end(); ++it) { stream << space << space << ElementTypeMapArray::printType(it->first, gt) << " [" << std::endl; it->second->printself(stream, indent + 3); stream << space << space << " ]" << std::endl; } } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /* SupportType Iterator */ /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator( DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek) : list_begin(list_begin), list_end(list_end), dim(dim), kind(ek) {} /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator( const type_iterator & it) : list_begin(it.list_begin), list_end(it.list_end), dim(it.dim), kind(it.kind) {} /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> typename ElementTypeMap<Stored, SupportType>::type_iterator & ElementTypeMap<Stored, SupportType>::type_iterator:: operator=(const type_iterator & it) { if (this != &it) { list_begin = it.list_begin; list_end = it.list_end; dim = it.dim; kind = it.kind; } return *this; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference ElementTypeMap<Stored, SupportType>::type_iterator::operator*() { return list_begin->first; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference ElementTypeMap<Stored, SupportType>::type_iterator::operator*() const { return list_begin->first; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator & ElementTypeMap<Stored, SupportType>::type_iterator::operator++() { ++list_begin; while ((list_begin != list_end) && (((dim != _all_dimensions) && (dim != Mesh::getSpatialDimension(list_begin->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(list_begin->first))))) ++list_begin; return *this; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> typename ElementTypeMap<Stored, SupportType>::type_iterator ElementTypeMap<Stored, SupportType>::type_iterator::operator++(int) { type_iterator tmp(*this); operator++(); return tmp; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline bool ElementTypeMap<Stored, SupportType>::type_iterator:: operator==(const type_iterator & other) const { return this->list_begin == other.list_begin; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline bool ElementTypeMap<Stored, SupportType>::type_iterator:: operator!=(const type_iterator & other) const { return this->list_begin != other.list_begin; } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper ElementTypeMap<Stored, SupportType>::elementTypesImpl(UInt dim, GhostType ghost_type, ElementKind kind) const { return ElementTypesIteratorHelper(*this, dim, ghost_type, kind); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> template <typename... pack> typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper ElementTypeMap<Stored, SupportType>::elementTypesImpl( const use_named_args_t & unused, pack &&... _pack) const { return ElementTypesIteratorHelper(*this, unused, _pack...); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator ElementTypeMap<Stored, SupportType>::firstType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator b, e; b = getData(ghost_type).begin(); e = getData(ghost_type).end(); // loop until the first valid type while ((b != e) && (((dim != _all_dimensions) && (dim != Mesh::getSpatialDimension(b->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(b->first))))) ++b; return typename ElementTypeMap<Stored, SupportType>::type_iterator(b, e, dim, kind); } /* -------------------------------------------------------------------------- */ template <class Stored, typename SupportType> inline typename ElementTypeMap<Stored, SupportType>::type_iterator ElementTypeMap<Stored, SupportType>::lastType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator e; e = getData(ghost_type).end(); return typename ElementTypeMap<Stored, SupportType>::type_iterator(e, e, dim, kind); } /* -------------------------------------------------------------------------- */ /// standard output stream operator template <class Stored, typename SupportType> inline std::ostream & operator<<(std::ostream & stream, const ElementTypeMap<Stored, SupportType> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ -class ElementTypeMapArrayInializer { +class ElementTypeMapArrayInitializer { +protected: + using CompFunc = std::function<UInt(const ElementType &, const GhostType &)>; + public: - ElementTypeMapArrayInializer(UInt spatial_dimension = _all_dimensions, - UInt nb_component = 1, - const GhostType & ghost_type = _not_ghost, - const ElementKind & element_kind = _ek_regular) - : spatial_dimension(spatial_dimension), nb_component(nb_component), + ElementTypeMapArrayInitializer(const CompFunc & comp_func, + UInt spatial_dimension = _all_dimensions, + const GhostType & ghost_type = _not_ghost, + const ElementKind & element_kind = _ek_regular) + : comp_func(comp_func), spatial_dimension(spatial_dimension), ghost_type(ghost_type), element_kind(element_kind) {} const GhostType & ghostType() const { return ghost_type; } + virtual UInt nbComponent(const ElementType & type) const { + return comp_func(type, ghostType()); + } + protected: + CompFunc comp_func; UInt spatial_dimension; - UInt nb_component; GhostType ghost_type; ElementKind element_kind; }; /* -------------------------------------------------------------------------- */ -class MeshElementTypeMapArrayInializer : public ElementTypeMapArrayInializer { +class MeshElementTypeMapArrayInitializer + : public ElementTypeMapArrayInitializer { + using CompFunc = ElementTypeMapArrayInitializer::CompFunc; + public: - MeshElementTypeMapArrayInializer( + MeshElementTypeMapArrayInitializer( const Mesh & mesh, UInt nb_component = 1, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular, bool with_nb_element = false, bool with_nb_nodes_per_element = false) - : ElementTypeMapArrayInializer(spatial_dimension, nb_component, - ghost_type, element_kind), + : MeshElementTypeMapArrayInitializer( + mesh, + [nb_component](const ElementType &, const GhostType &) -> UInt { + return nb_component; + }, + spatial_dimension, ghost_type, element_kind, with_nb_element, + with_nb_nodes_per_element) {} + + MeshElementTypeMapArrayInitializer( + const Mesh & mesh, const CompFunc & comp_func, + UInt spatial_dimension = _all_dimensions, + const GhostType & ghost_type = _not_ghost, + const ElementKind & element_kind = _ek_regular, + bool with_nb_element = false, bool with_nb_nodes_per_element = false) + : ElementTypeMapArrayInitializer(comp_func, spatial_dimension, ghost_type, + element_kind), mesh(mesh), with_nb_element(with_nb_element), with_nb_nodes_per_element(with_nb_nodes_per_element) {} decltype(auto) elementTypes() const { return mesh.elementTypes(this->spatial_dimension, this->ghost_type, this->element_kind); } virtual UInt size(const ElementType & type) const { if (with_nb_element) return mesh.getNbElement(type, this->ghost_type); return 0; } - UInt nbComponent(const ElementType & type) const { + UInt nbComponent(const ElementType & type) const override { + UInt res = ElementTypeMapArrayInitializer::nbComponent(type); if (with_nb_nodes_per_element) - return (this->nb_component * mesh.getNbNodesPerElement(type)); + return (res * mesh.getNbNodesPerElement(type)); - return this->nb_component; + return res; } protected: const Mesh & mesh; bool with_nb_element; bool with_nb_nodes_per_element; }; /* -------------------------------------------------------------------------- */ -class FEEngineElementTypeMapArrayInializer - : public MeshElementTypeMapArrayInializer { +class FEEngineElementTypeMapArrayInitializer + : public MeshElementTypeMapArrayInitializer { public: - FEEngineElementTypeMapArrayInializer( + FEEngineElementTypeMapArrayInitializer( const FEEngine & fe_engine, UInt nb_component = 1, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular); + FEEngineElementTypeMapArrayInitializer( + const FEEngine & fe_engine, + const ElementTypeMapArrayInitializer::CompFunc & nb_component, + UInt spatial_dimension = _all_dimensions, + const GhostType & ghost_type = _not_ghost, + const ElementKind & element_kind = _ek_regular); + UInt size(const ElementType & type) const override; using ElementTypesIteratorHelper = ElementTypeMapArray<Real, ElementType>::ElementTypesIteratorHelper; ElementTypesIteratorHelper elementTypes() const; protected: const FEEngine & fe_engine; }; /* -------------------------------------------------------------------------- */ template <typename T, typename SupportType> template <class Func> void ElementTypeMapArray<T, SupportType>::initialize(const Func & f, const T & default_value, bool do_not_default) { + auto ghost_type = f.ghostType(); for (auto & type : f.elementTypes()) { - if (not this->exists(type, f.ghostType())) + if (not this->exists(type, ghost_type)) if (do_not_default) { - auto & array = this->alloc(0, f.nbComponent(type), type, f.ghostType()); + auto & array = this->alloc(0, f.nbComponent(type), type, ghost_type); array.resize(f.size(type)); } else { - this->alloc(f.size(type), f.nbComponent(type), type, f.ghostType(), + this->alloc(f.size(type), f.nbComponent(type), type, ghost_type, default_value); } else { - auto & array = this->operator()(type, f.ghostType()); + auto & array = this->operator()(type, ghost_type); if (not do_not_default) array.resize(f.size(type), default_value); else array.resize(f.size(type)); } } } /* -------------------------------------------------------------------------- */ +/** + * All parameters are named optionals + * \param _nb_component a functor giving the number of components per + * (ElementType, GhostType) pair or a scalar giving a unique number of + * components + * regardless of type + * \param _spatial_dimension a filter for the elements of a specific dimension + * \param _element_kind filter with element kind (_ek_regular, _ek_structural, + * ...) + * \param _with_nb_element allocate the arrays with the number of elements for + * each + * type in the mesh + * \param _with_nb_nodes_per_element multiply the number of components by the + * number of nodes per element + * \param _default_value default inital value + * \param _do_not_default do not initialize the allocated arrays + * \param _ghost_type filter a type of ghost + */ template <typename T, typename SupportType> template <typename... pack> void ElementTypeMapArray<T, SupportType>::initialize(const Mesh & mesh, pack &&... _pack) { GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _casper); bool all_ghost_types = requested_ghost_type == _casper; for (auto ghost_type : ghost_types) { if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types)) continue; - this->initialize( - MeshElementTypeMapArrayInializer( - mesh, OPTIONAL_NAMED_ARG(nb_component, 1), - OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()), - ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular), - OPTIONAL_NAMED_ARG(with_nb_element, false), - OPTIONAL_NAMED_ARG(with_nb_nodes_per_element, false)), - OPTIONAL_NAMED_ARG(default_value, T()), - OPTIONAL_NAMED_ARG(do_not_default, false)); + // This thing should have a UInt or functor type + auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1); + auto functor = MeshElementTypeMapArrayInitializer( + mesh, std::forward<decltype(nb_components)>(nb_components), + OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()), + ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular), + OPTIONAL_NAMED_ARG(with_nb_element, false), + OPTIONAL_NAMED_ARG(with_nb_nodes_per_element, false)); + + this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()), + OPTIONAL_NAMED_ARG(do_not_default, false)); } } /* -------------------------------------------------------------------------- */ +/** + * All parameters are named optionals + * \param _nb_component a functor giving the number of components per + * (ElementType, GhostType) pair or a scalar giving a unique number of + * components + * regardless of type + * \param _spatial_dimension a filter for the elements of a specific dimension + * \param _element_kind filter with element kind (_ek_regular, _ek_structural, + * ...) + * \param _default_value default inital value + * \param _do_not_default do not initialize the allocated arrays + * \param _ghost_type filter a specific ghost type + * \param _all_ghost_types get all ghost types + */ template <typename T, typename SupportType> template <typename... pack> void ElementTypeMapArray<T, SupportType>::initialize(const FEEngine & fe_engine, pack &&... _pack) { bool all_ghost_types = OPTIONAL_NAMED_ARG(all_ghost_types, true); GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _not_ghost); for (auto ghost_type : ghost_types) { if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types)) continue; - this->initialize(FEEngineElementTypeMapArrayInializer( - fe_engine, OPTIONAL_NAMED_ARG(nb_component, 1), - OPTIONAL_NAMED_ARG(spatial_dimension, UInt(-2)), - ghost_type, - OPTIONAL_NAMED_ARG(element_kind, _ek_regular)), - OPTIONAL_NAMED_ARG(default_value, T()), + auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1); + auto functor = FEEngineElementTypeMapArrayInitializer( + fe_engine, std::forward<decltype(nb_components)>(nb_components), + OPTIONAL_NAMED_ARG(spatial_dimension, UInt(-2)), ghost_type, + OPTIONAL_NAMED_ARG(element_kind, _ek_regular)); + + this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()), OPTIONAL_NAMED_ARG(do_not_default, false)); } } /* -------------------------------------------------------------------------- */ template <class T, typename SupportType> inline T & ElementTypeMapArray<T, SupportType>:: operator()(const Element & element, UInt component) { return this->operator()(element.type, element.ghost_type)(element.element, component); } /* -------------------------------------------------------------------------- */ template <class T, typename SupportType> inline const T & ElementTypeMapArray<T, SupportType>:: operator()(const Element & element, UInt component) const { return this->operator()(element.type, element.ghost_type)(element.element, component); } } // namespace akantu #endif /* __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ */ diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc index 0991360f0..49cd44069 100644 --- a/src/mesh/mesh.cc +++ b/src/mesh/mesh.cc @@ -1,545 +1,571 @@ /** * @file mesh.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Jan 22 2016 * * @brief class handling meshes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_config.hh" /* -------------------------------------------------------------------------- */ #include "element_class.hh" #include "group_manager_inline_impl.cc" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_iterators.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "element_synchronizer.hh" #include "facet_synchronizer.hh" #include "mesh_utils_distribution.hh" #include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumper_field.hh" #include "dumper_internal_material_field.hh" #endif /* -------------------------------------------------------------------------- */ #include <limits> #include <sstream> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id, Communicator & communicator) : Memory(id, memory_id), GroupManager(*this, id + ":group_manager", memory_id), nodes_type(0, 1, id + ":nodes_type"), connectivities("connectivities", id, memory_id), ghosts_counters("ghosts_counters", id, memory_id), normals("normals", id, memory_id), spatial_dimension(spatial_dimension), lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.), size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.), local_upper_bounds(spatial_dimension, 0.), mesh_data("mesh_data", id, memory_id), communicator(&communicator) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, Communicator & communicator, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, communicator) { AKANTU_DEBUG_IN(); this->nodes = std::make_shared<Array<Real>>(0, spatial_dimension, id + ":coordinates"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, Communicator::getStaticCommunicator(), id, memory_id) {} /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const std::shared_ptr<Array<Real>> & nodes, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, Communicator::getStaticCommunicator()) { this->nodes = nodes; this->nb_global_nodes = this->nodes->size(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique<std::set<Element>>(); } this->computeBoundingBox(); } +/* -------------------------------------------------------------------------- */ +void Mesh::getBarycenters(Array<Real> & barycenter, const ElementType & type, + const GhostType & ghost_type) const { + barycenter.resize(getNbElement(type, ghost_type)); + for (auto && data : enumerate(make_view(barycenter, spatial_dimension))) { + getBarycenter(Element{type, UInt(std::get<0>(data)), ghost_type}, + std::get<1>(data)); + } +} + /* -------------------------------------------------------------------------- */ Mesh & Mesh::initMeshFacets(const ID & id) { AKANTU_DEBUG_IN(); if (!mesh_facets) { mesh_facets = std::make_unique<Mesh>(spatial_dimension, this->nodes, getID() + ":" + id, getMemoryID()); mesh_facets->mesh_parent = this; mesh_facets->is_mesh_facets = true; MeshUtils::buildAllFacets(*this, *mesh_facets, 0); if (mesh.isDistributed()) { mesh_facets->is_distributed = true; mesh_facets->element_synchronizer = std::make_unique<FacetSynchronizer>( *mesh_facets, mesh.getElementSynchronizer()); } /// transfers the the mesh physical names to the mesh facets if (not this->hasData("physical_names")) { AKANTU_DEBUG_OUT(); return *mesh_facets; } if (not mesh_facets->hasData("physical_names")) { mesh_facets->registerData<std::string>("physical_names"); } auto & mesh_phys_data = this->getData<std::string>("physical_names"); auto & phys_data = mesh_facets->getData<std::string>("physical_names"); phys_data.initialize(*mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true); + ElementTypeMapArray<Real> barycenters(getID(), "temporary_barycenters"); + barycenters.initialize(*mesh_facets, _nb_component = spatial_dimension, + _spatial_dimension = spatial_dimension - 1, + _with_nb_element = true); + + for (auto && ghost_type : ghost_types) { + for (auto && type : barycenters.elementTypes( + spatial_dimension - 1, ghost_type)) { + mesh_facets->getBarycenters(barycenters(type, ghost_type), type, + ghost_type); + } + } + for_each_element( mesh, [&](auto && element) { Vector<Real> barycenter(spatial_dimension); mesh.getBarycenter(element, barycenter); auto norm_barycenter = barycenter.norm(); + auto tolerance = Math::getTolerance(); + if (norm_barycenter > tolerance) + tolerance *= norm_barycenter; const auto & element_to_facet = mesh_facets->getElementToSubelement( element.type, element.ghost_type); Vector<Real> barycenter_facet(spatial_dimension); - auto nb_facet = - mesh_facets->getNbElement(element.type, element.ghost_type); - auto range = arange(nb_facet); + auto range = + enumerate(make_view(barycenters(element.type, element.ghost_type), + spatial_dimension)); #ifndef AKANTU_NDEBUG auto min_dist = std::numeric_limits<Real>::max(); #endif // this is a spacial search coded the most inefficient way. auto facet = - std::find_if(range.begin(), range.end(), [&](auto && facet) { + std::find_if(range.begin(), range.end(), [&](auto && data) { + auto facet = std::get<0>(data); if (element_to_facet(facet)[1] == ElementNull) return false; - mesh_facets->getBarycenter( - Element{element.type, facet, element.ghost_type}, - barycenter_facet); - auto norm_distance = barycenter_facet.distance(barycenter); + auto norm_distance = barycenter.distance(std::get<1>(data)); #ifndef AKANTU_NDEBUG min_dist = std::min(min_dist, norm_distance); #endif - return (norm_distance < - (Math::getTolerance() * norm_barycenter)); + return (norm_distance < tolerance); }); + if (facet == range.end()) { - AKANTU_DEBUG_INFO( - "The element " - << element << " did not find its associated facet in the " - "mesh_facets! Try to decrease math tolerance. " - "The closest element was at a distance of " - << min_dist); + AKANTU_DEBUG_INFO("The element " + << element + << " did not find its associated facet in the " + "mesh_facets! Try to decrease math tolerance. " + "The closest element was at a distance of " + << min_dist); return; } // set physical name - phys_data(Element{element.type, *facet, element.ghost_type}) = - mesh_phys_data(element); + phys_data(Element{element.type, UInt(std::get<0>(*facet)), + element.ghost_type}) = mesh_phys_data(element); }, _spatial_dimension = spatial_dimension - 1); mesh_facets->createGroupsFromMeshData<std::string>("physical_names"); } AKANTU_DEBUG_OUT(); return *mesh_facets; } /* -------------------------------------------------------------------------- */ void Mesh::defineMeshParent(const Mesh & mesh) { AKANTU_DEBUG_IN(); this->mesh_parent = &mesh; this->is_mesh_facets = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::~Mesh() = default; /* -------------------------------------------------------------------------- */ void Mesh::read(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.read(filename, *this, mesh_io_type); type_iterator it = this->firstType(spatial_dimension, _not_ghost, _ek_not_defined); type_iterator last = this->lastType(spatial_dimension, _not_ghost, _ek_not_defined); if (it == last) AKANTU_EXCEPTION( "The mesh contained in the file " << filename << " does not seem to be of the good dimension." << " No element of dimension " << spatial_dimension << " where read."); this->nb_global_nodes = this->nodes->size(); this->computeBoundingBox(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique<std::set<Element>>(); } } /* -------------------------------------------------------------------------- */ void Mesh::write(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.write(filename, *this, mesh_io_type); } /* -------------------------------------------------------------------------- */ void Mesh::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Mesh [" << std::endl; stream << space << " + id : " << getID() << std::endl; stream << space << " + spatial dimension : " << this->spatial_dimension << std::endl; stream << space << " + nodes [" << std::endl; nodes->printself(stream, indent + 2); stream << space << " + connectivities [" << std::endl; connectivities.printself(stream, indent + 2); stream << space << " ]" << std::endl; GroupManager::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void Mesh::computeBoundingBox() { AKANTU_DEBUG_IN(); for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::numeric_limits<double>::max(); local_upper_bounds(k) = -std::numeric_limits<double>::max(); } for (UInt i = 0; i < nodes->size(); ++i) { // if(!isPureGhostNode(i)) for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::min(local_lower_bounds[k], (*nodes)(i, k)); local_upper_bounds(k) = std::max(local_upper_bounds[k], (*nodes)(i, k)); } } if (this->is_distributed) { Matrix<Real> reduce_bounds(spatial_dimension, 2); for (UInt k = 0; k < spatial_dimension; ++k) { reduce_bounds(k, 0) = local_lower_bounds(k); reduce_bounds(k, 1) = -local_upper_bounds(k); } communicator->allReduce(reduce_bounds, SynchronizerOperation::_min); for (UInt k = 0; k < spatial_dimension; ++k) { lower_bounds(k) = reduce_bounds(k, 0); upper_bounds(k) = -reduce_bounds(k, 1); } } else { this->lower_bounds = this->local_lower_bounds; this->upper_bounds = this->local_upper_bounds; } size = upper_bounds - lower_bounds; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::initNormals() { normals.initialize(*this, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined); } /* -------------------------------------------------------------------------- */ void Mesh::getGlobalConnectivity( ElementTypeMapArray<UInt> & global_connectivity) { AKANTU_DEBUG_IN(); for (auto && ghost_type : ghost_types) { for (auto type : - global_connectivity.elementTypes(_ghost_type = ghost_type)) { + global_connectivity.elementTypes(_spatial_dimension = _all_dimensions, + _element_kind = _ek_not_defined, + _ghost_type = ghost_type)) { if (not connectivities.exists(type, ghost_type)) continue; auto & local_conn = connectivities(type, ghost_type); auto & g_connectivity = global_connectivity(type, ghost_type); UInt nb_nodes = local_conn.size() * local_conn.getNbComponent(); if (not nodes_global_ids && is_mesh_facets) { std::transform( local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *mesh_parent->nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } else { std::transform(local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Mesh::getGroupDumper(const std::string & dumper_name, const std::string & group_name) { if (group_name == "all") return this->getDumper(dumper_name); else return element_groups[group_name]->getDumper(dumper_name); } /* -------------------------------------------------------------------------- */ template <typename T> ElementTypeMap<UInt> Mesh::getNbDataPerElem(ElementTypeMapArray<T> & arrays, const ElementKind & element_kind) { ElementTypeMap<UInt> nb_data_per_elem; for (auto type : elementTypes(spatial_dimension, _not_ghost, element_kind)) { UInt nb_elements = this->getNbElement(type); auto & array = arrays(type); nb_data_per_elem(type) = array.getNbComponent() * array.size(); nb_data_per_elem(type) /= nb_elements; } return nb_data_per_elem; } /* -------------------------------------------------------------------------- */ template ElementTypeMap<UInt> Mesh::getNbDataPerElem(ElementTypeMapArray<Real> & array, const ElementKind & element_kind); template ElementTypeMap<UInt> Mesh::getNbDataPerElem(ElementTypeMapArray<UInt> & array, const ElementKind & element_kind); /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER template <typename T> dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind) { dumper::Field * field = nullptr; ElementTypeMapArray<T> * internal = nullptr; try { internal = &(this->getData<T>(field_id)); } catch (...) { return nullptr; } ElementTypeMap<UInt> nb_data_per_elem = this->getNbDataPerElem(*internal, element_kind); field = this->createElementalField<T, dumper::InternalMaterialField>( *internal, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); return field; } template dumper::Field * Mesh::createFieldFromAttachedData<Real>(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); template dumper::Field * Mesh::createFieldFromAttachedData<UInt>(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); #endif /* -------------------------------------------------------------------------- */ void Mesh::distribute() { this->distribute(Communicator::getStaticCommunicator()); } /* -------------------------------------------------------------------------- */ void Mesh::distribute(Communicator & communicator) { AKANTU_DEBUG_ASSERT(is_distributed == false, "This mesh is already distribute"); this->communicator = &communicator; this->element_synchronizer = std::make_unique<ElementSynchronizer>( *this, this->getID() + ":element_synchronizer", this->getMemoryID(), true); this->node_synchronizer = std::make_unique<NodeSynchronizer>( *this, this->getID() + ":node_synchronizer", this->getMemoryID(), true); Int psize = this->communicator->getNbProc(); #ifdef AKANTU_USE_SCOTCH Int prank = this->communicator->whoAmI(); if (prank == 0) { MeshPartitionScotch partition(*this, spatial_dimension); partition.partitionate(psize); MeshUtilsDistribution::distributeMeshCentralized(*this, 0, partition); } else { MeshUtilsDistribution::distributeMeshCentralized(*this, 0); } #else if (!(psize == 1)) { AKANTU_DEBUG_ERROR("Cannot distribute a mesh without a partitioning tool"); } #endif this->is_distributed = true; this->computeBoundingBox(); } /* -------------------------------------------------------------------------- */ void Mesh::getAssociatedElements(const Array<UInt> & node_list, Array<Element> & elements) { for (const auto & node : node_list) for (const auto & element : *nodes_to_elements[node]) elements.push_back(element); } /* -------------------------------------------------------------------------- */ void Mesh::fillNodesToElements() { Element e; UInt nb_nodes = nodes->size(); for (UInt n = 0; n < nb_nodes; ++n) { if (this->nodes_to_elements[n]) this->nodes_to_elements[n]->clear(); else this->nodes_to_elements[n] = std::make_unique<std::set<Element>>(); } for (auto ghost_type : ghost_types) { e.ghost_type = ghost_type; for (const auto & type : elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { e.type = type; UInt nb_element = this->getNbElement(type, ghost_type); Array<UInt>::const_iterator<Vector<UInt>> conn_it = connectivities(type, ghost_type) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; const Vector<UInt> & conn = *conn_it; for (UInt n = 0; n < conn.size(); ++n) nodes_to_elements[conn(n)]->insert(e); } } } } /* -------------------------------------------------------------------------- */ void Mesh::eraseElements(const Array<Element> & elements) { ElementTypeMap<UInt> last_element; RemovedElementsEvent event(*this); auto & remove_list = event.getList(); auto & new_numbering = event.getNewNumbering(); for (auto && el : elements) { if (el.ghost_type != _not_ghost) { auto & count = ghosts_counters(el); --count; if (count > 0) continue; } remove_list.push_back(el); if (not last_element.exists(el.type, el.ghost_type)) { UInt nb_element = mesh.getNbElement(el.type, el.ghost_type); last_element(nb_element - 1, el.type, el.ghost_type); auto & numbering = new_numbering.alloc(nb_element, 1, el.type, el.ghost_type); for (auto && pair : enumerate(numbering)) { std::get<1>(pair) = std::get<0>(pair); } } UInt & pos = last_element(el.type, el.ghost_type); auto & numbering = new_numbering(el.type, el.ghost_type); numbering(el.element) = UInt(-1); numbering(pos) = el.element; --pos; } this->sendEvent(event); } } // namespace akantu diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh index 06d3a8481..ffdd11510 100644 --- a/src/mesh/mesh.hh +++ b/src/mesh/mesh.hh @@ -1,610 +1,613 @@ /** * @file mesh.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Jan 14 2016 * * @brief the class representing the meshes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_HH__ #define __AKANTU_MESH_HH__ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_event_handler_manager.hh" #include "aka_memory.hh" #include "dumpable.hh" #include "element.hh" #include "element_class.hh" #include "element_type_map.hh" #include "group_manager.hh" #include "mesh_data.hh" #include "mesh_events.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ namespace akantu { class Communicator; class ElementSynchronizer; class NodeSynchronizer; } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ /* Mesh */ /* -------------------------------------------------------------------------- */ /** * @class Mesh this contain the coordinates of the nodes in the Mesh.nodes * Array, and the connectivity. The connectivity are stored in by element * types. * * In order to loop on all element you have to loop on all types like this : * @code{.cpp} for(auto & type : mesh.elementTypes()) { UInt nb_element = mesh.getNbElement(type); const Array<UInt> & conn = mesh.getConnectivity(type); for(UInt e = 0; e < nb_element; ++e) { ... } } or for_each_element(mesh, [](Element & element) { std::cout << element << std::endl }); @endcode */ class Mesh : protected Memory, public EventHandlerManager<MeshEventHandler>, public GroupManager, public Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ private: /// default constructor used for chaining, the last parameter is just to /// differentiate constructors Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id, Communicator & communicator); public: /// constructor that create nodes coordinates array Mesh(UInt spatial_dimension, const ID & id = "mesh", const MemoryID & memory_id = 0); /// mesh not distributed and not using the default communicator Mesh(UInt spatial_dimension, Communicator & communicator, const ID & id = "mesh", const MemoryID & memory_id = 0); /// constructor that use an existing nodes coordinates array, by knowing its /// ID // Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, // const MemoryID & memory_id = 0); /** * constructor that use an existing nodes coordinates * array, by getting the vector of coordinates */ Mesh(UInt spatial_dimension, const std::shared_ptr<Array<Real>> & nodes, const ID & id = "mesh", const MemoryID & memory_id = 0); ~Mesh() override; /// @typedef ConnectivityTypeList list of the types present in a Mesh using ConnectivityTypeList = std::set<ElementType>; /// read the mesh from a file void read(const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); /// write the mesh to a file void write(const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); private: /// initialize the connectivity to NULL and other stuff void init(); /// function that computes the bounding box (fills xmin, xmax) void computeBoundingBox(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// patitionate the mesh among the processors involved in their computation virtual void distribute(Communicator & communicator); virtual void distribute(); /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; /// extract coordinates of nodes from an element template <typename T> inline void extractNodalValuesFromElement(const Array<T> & nodal_values, T * elemental_values, UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const; // /// extract coordinates of nodes from a reversed element // inline void extractNodalCoordinatesFromPBCElement(Real * local_coords, // UInt * connectivity, // UInt n_nodes); /// add a Array of connectivity for the type <type>. inline void addConnectivityType(const ElementType & type, const GhostType & ghost_type = _not_ghost); /* ------------------------------------------------------------------------ */ template <class Event> inline void sendEvent(Event & event) { // if(event.getList().size() != 0) EventHandlerManager<MeshEventHandler>::sendEvent<Event>(event); } /// prepare the event to remove the elements listed void eraseElements(const Array<Element> & elements); /* ------------------------------------------------------------------------ */ template <typename T> inline void removeNodesFromArray(Array<T> & vect, const Array<UInt> & new_numbering); /// initialize normals void initNormals(); /// init facets' mesh Mesh & initMeshFacets(const ID & id = "mesh_facets"); /// define parent mesh void defineMeshParent(const Mesh & mesh); /// get global connectivity array void getGlobalConnectivity(ElementTypeMapArray<UInt> & global_connectivity); public: void getAssociatedElements(const Array<UInt> & node_list, Array<Element> & elements); private: /// fills the nodes_to_elements structure void fillNodesToElements(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the id of the mesh AKANTU_GET_MACRO(ID, Memory::id, const ID &); /// get the id of the mesh AKANTU_GET_MACRO(MemoryID, Memory::memory_id, const MemoryID &); /// get the spatial dimension of the mesh = number of component of the /// coordinates AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the nodes Array aka coordinates AKANTU_GET_MACRO(Nodes, *nodes, const Array<Real> &); AKANTU_GET_MACRO_NOT_CONST(Nodes, *nodes, Array<Real> &); /// get the normals for the elements AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Normals, normals, Real); /// get the number of nodes AKANTU_GET_MACRO(NbNodes, nodes->size(), UInt); /// get the Array of global ids of the nodes (only used in parallel) AKANTU_GET_MACRO(GlobalNodesIds, *nodes_global_ids, const Array<UInt> &); AKANTU_GET_MACRO_NOT_CONST(GlobalNodesIds, *nodes_global_ids, Array<UInt> &); /// get the global id of a node inline UInt getNodeGlobalId(UInt local_id) const; /// get the global id of a node inline UInt getNodeLocalId(UInt global_id) const; /// get the global number of nodes inline UInt getNbGlobalNodes() const; /// get the nodes type Array AKANTU_GET_MACRO(NodesType, nodes_type, const Array<NodeType> &); protected: AKANTU_GET_MACRO_NOT_CONST(NodesType, nodes_type, Array<NodeType> &); public: inline NodeType getNodeType(UInt local_id) const; /// say if a node is a pure ghost node inline bool isPureGhostNode(UInt n) const; /// say if a node is pur local or master node inline bool isLocalOrMasterNode(UInt n) const; inline bool isLocalNode(UInt n) const; inline bool isMasterNode(UInt n) const; inline bool isSlaveNode(UInt n) const; AKANTU_GET_MACRO(LowerBounds, lower_bounds, const Vector<Real> &); AKANTU_GET_MACRO(UpperBounds, upper_bounds, const Vector<Real> &); AKANTU_GET_MACRO(LocalLowerBounds, local_lower_bounds, const Vector<Real> &); AKANTU_GET_MACRO(LocalUpperBounds, local_upper_bounds, const Vector<Real> &); /// get the connectivity Array for a given type AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Connectivity, connectivities, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Connectivity, connectivities, UInt); AKANTU_GET_MACRO(Connectivities, connectivities, const ElementTypeMapArray<UInt> &); /// get the number of element of a type in the mesh inline UInt getNbElement(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /// get the number of element for a given ghost_type and a given dimension inline UInt getNbElement(const UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & kind = _ek_not_defined) const; // /// get the connectivity list either for the elements or the ghost elements // inline const ConnectivityTypeList & // getConnectivityTypeList(const GhostType & ghost_type = _not_ghost) const; /// compute the barycenter of a given element private: inline void getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type = _not_ghost) const; public: inline void getBarycenter(const Element & element, Vector<Real> & barycenter) const; + void getBarycenters(Array<Real> & barycenter, const ElementType & type, + const GhostType & ghost_type) const; + #ifndef SWIG /// get the element connected to a subelement const auto & getElementToSubelement() const; - + /// get the element connected to a subelement const auto & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the element connected to a subelement auto & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get the subelement connected to an element const auto & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the subelement connected to an element auto & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); #endif /// register a new ElementalTypeMap in the MeshData template <typename T> inline ElementTypeMapArray<T> & registerData(const std::string & data_name); template <typename T> inline bool hasData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template <typename T> inline const Array<T> & getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template <typename T> inline Array<T> & getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// tells if the data data_name is contained in the mesh or not inline bool hasData(const ID & data_name) const; /// get a name field associated to the mesh template <typename T> inline const ElementTypeMapArray<T> & getData(const ID & data_name) const; /// get a name field associated to the mesh template <typename T> inline ElementTypeMapArray<T> & getData(const ID & data_name); template <typename T> ElementTypeMap<UInt> getNbDataPerElem(ElementTypeMapArray<T> & array, const ElementKind & element_kind); template <typename T> dumper::Field * createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); /// templated getter returning the pointer to data in MeshData (modifiable) template <typename T> inline Array<T> & getDataPointer(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost, UInt nb_component = 1, bool size_to_nb_element = true, bool resize_with_parent = false); /// Facets mesh accessor inline const Mesh & getMeshFacets() const; inline Mesh & getMeshFacets(); /// Parent mesh accessor inline const Mesh & getMeshParent() const; inline bool isMeshFacets() const { return this->is_mesh_facets; } /// defines is the mesh is distributed or not inline bool isDistributed() const { return this->is_distributed; } #ifndef SWIG /// return the dumper from a group and and a dumper name DumperIOHelper & getGroupDumper(const std::string & dumper_name, const std::string & group_name); #endif /* ------------------------------------------------------------------------ */ /* Wrappers on ElementClass functions */ /* ------------------------------------------------------------------------ */ public: /// get the number of nodes per element for a given element type static inline UInt getNbNodesPerElement(const ElementType & type); /// get the number of nodes per element for a given element type considered as /// a first order element static inline ElementType getP1ElementType(const ElementType & type); /// get the kind of the element type static inline ElementKind getKind(const ElementType & type); /// get spatial dimension of a type of element static inline UInt getSpatialDimension(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type, UInt t); #ifndef SWIG /// get local connectivity of a facet for a given facet type static inline auto getFacetLocalConnectivity(const ElementType & type, UInt t = 0); /// get connectivity of facets for a given element inline auto getFacetConnectivity(const Element & element, UInt t = 0) const; #endif /// get the number of type of the surface element associated to a given /// element type static inline UInt getNbFacetTypes(const ElementType & type, UInt t = 0); #ifndef SWIG /// get the type of the surface element associated to a given element static inline constexpr auto getFacetType(const ElementType & type, UInt t = 0); /// get all the type of the surface element associated to a given element static inline constexpr auto getAllFacetTypes(const ElementType & type); #endif /// get the number of nodes in the given element list static inline UInt getNbNodesPerElementList(const Array<Element> & elements); /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ using type_iterator = ElementTypeMapArray<UInt, ElementType>::type_iterator; using ElementTypesIteratorHelper = ElementTypeMapArray<UInt, ElementType>::ElementTypesIteratorHelper; template <typename... pack> ElementTypesIteratorHelper elementTypes(pack &&... _pack) const; inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.firstType(dim, ghost_type, kind); } inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.lastType(dim, ghost_type, kind); } AKANTU_GET_MACRO(ElementSynchronizer, *element_synchronizer, const ElementSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(ElementSynchronizer, *element_synchronizer, ElementSynchronizer &); AKANTU_GET_MACRO(NodeSynchronizer, *node_synchronizer, const NodeSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(NodeSynchronizer, *node_synchronizer, NodeSynchronizer &); // AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, StaticCommunicator // &); #ifndef SWIG AKANTU_GET_MACRO(Communicator, *communicator, const auto &); AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, auto &); #endif /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshAccessor; AKANTU_GET_MACRO(NodesPointer, *nodes, Array<Real> &); /// get a pointer to the nodes_global_ids Array<UInt> and create it if /// necessary inline Array<UInt> & getNodesGlobalIdsPointer(); /// get a pointer to the nodes_type Array<Int> and create it if necessary inline Array<NodeType> & getNodesTypePointer(); /// get a pointer to the connectivity Array for the given type and create it /// if necessary inline Array<UInt> & getConnectivityPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get the ghost element counter inline Array<UInt> & getGhostsCounters(const ElementType & type, const GhostType & ghost_type = _ghost) { AKANTU_DEBUG_ASSERT(ghost_type != _not_ghost, "No ghost counter for _not_ghost elements"); return ghosts_counters(type, ghost_type); } /// get a pointer to the element_to_subelement Array for the given type and /// create it if necessary inline Array<std::vector<Element>> & getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get a pointer to the subelement_to_element Array for the given type and /// create it if necessary inline Array<Element> & getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); AKANTU_GET_MACRO_NOT_CONST(MeshData, mesh_data, MeshData &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// array of the nodes coordinates std::shared_ptr<Array<Real>> nodes; /// global node ids std::unique_ptr<Array<UInt>> nodes_global_ids; /// node type, -3 pure ghost, -2 master for the node, -1 normal node, i in /// [0-N] slave node and master is proc i Array<NodeType> nodes_type; /// global number of nodes; UInt nb_global_nodes{0}; /// all class of elements present in this mesh (for heterogenous meshes) ElementTypeMapArray<UInt> connectivities; /// count the references on ghost elements ElementTypeMapArray<UInt> ghosts_counters; /// map to normals for all class of elements present in this mesh ElementTypeMapArray<Real> normals; /// list of all existing types in the mesh // ConnectivityTypeList type_set; /// the spatial dimension of this mesh UInt spatial_dimension{0}; /// types offsets // Array<UInt> types_offsets; // /// list of all existing types in the mesh // ConnectivityTypeList ghost_type_set; // /// ghost types offsets // Array<UInt> ghost_types_offsets; /// min of coordinates Vector<Real> lower_bounds; /// max of coordinates Vector<Real> upper_bounds; /// size covered by the mesh on each direction Vector<Real> size; /// local min of coordinates Vector<Real> local_lower_bounds; /// local max of coordinates Vector<Real> local_upper_bounds; /// Extra data loaded from the mesh file MeshData mesh_data; /// facets' mesh std::unique_ptr<Mesh> mesh_facets; /// parent mesh (this is set for mesh_facets meshes) const Mesh * mesh_parent{nullptr}; /// defines if current mesh is mesh_facets or not bool is_mesh_facets{false}; /// defines if the mesh is centralized or distributed bool is_distributed{false}; /// Communicator on which mesh is distributed Communicator * communicator; /// Element synchronizer std::unique_ptr<ElementSynchronizer> element_synchronizer; /// Node synchronizer std::unique_ptr<NodeSynchronizer> node_synchronizer; using NodesToElements = std::vector<std::unique_ptr<std::set<Element>>>; /// This info is stored to simplify the dynamic changes NodesToElements nodes_to_elements; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Mesh & _this) { _this.printself(stream); return stream; } } // namespace akantu /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ #include "element_type_map_tmpl.hh" #include "mesh_inline_impl.cc" #endif /* __AKANTU_MESH_HH__ */ diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc index 12bf9bdd4..7be630cf2 100644 --- a/src/mesh_utils/cohesive_element_inserter.cc +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -1,278 +1,281 @@ /** * @file cohesive_element_inserter.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 * @date last modification: Sun Oct 04 2015 * * @brief Cohesive element inserter functions * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "communicator.hh" #include "element_group.hh" #include "global_ids_updater.hh" #include "mesh_iterators.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <limits> /* -------------------------------------------------------------------------- */ namespace akantu { CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, const ID & id) : Parsable(ParserType::_cohesive_inserter), id(id), mesh(mesh), mesh_facets(mesh.initMeshFacets()), insertion_facets("insertion_facets", id), insertion_limits(mesh.getSpatialDimension(), 2), check_facets("check_facets", id) { this->registerParam("cohesive_surfaces", physical_groups, _pat_parsable, "List of groups to consider for insertion"); this->registerParam("bounding_box", insertion_limits, _pat_parsable, "Global limit for insertion"); UInt spatial_dimension = mesh.getSpatialDimension(); MeshUtils::resetFacetToDouble(mesh_facets); /// init insertion limits for (UInt dim = 0; dim < spatial_dimension; ++dim) { insertion_limits(dim, 0) = std::numeric_limits<Real>::max() * Real(-1.); insertion_limits(dim, 1) = std::numeric_limits<Real>::max(); } insertion_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); } /* -------------------------------------------------------------------------- */ CohesiveElementInserter::~CohesiveElementInserter() = default; /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::parseSection(const ParserSection & section) { Parsable::parseSection(section); if (is_extrinsic) limitCheckFacets(this->check_facets); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets() { limitCheckFacets(this->check_facets); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::setLimit(SpacialDirection axis, Real first_limit, Real second_limit) { AKANTU_DEBUG_ASSERT( axis < mesh.getSpatialDimension(), "You are trying to limit insertion in a direction that doesn't exist"); insertion_limits(axis, 0) = std::min(first_limit, second_limit); insertion_limits(axis, 1) = std::max(first_limit, second_limit); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertIntrinsicElements() { limitCheckFacets(insertion_facets); return insertElements(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets( ElementTypeMapArray<bool> & check_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = true); check_facets.set(true); // remove the pure ghost elements for_each_element( mesh_facets, [&](auto && facet) { const auto & element_to_facet = mesh_facets.getElementToSubelement( facet.type, facet.ghost_type)(facet.element); auto & left = element_to_facet[0]; auto & right = element_to_facet[1]; if (right == ElementNull || (left.ghost_type == _ghost && right.ghost_type == _ghost)) { check_facets(facet) = false; return; } if (left.kind() == _ek_cohesive or right.kind() == _ek_cohesive) { check_facets(facet) = false; } }, _spatial_dimension = spatial_dimension - 1); Vector<Real> bary_facet(spatial_dimension); // set the limits to the bounding box for_each_element(mesh_facets, [&](auto && facet) { auto & need_check = check_facets(facet); if (not need_check) return; mesh_facets.getBarycenter(facet, bary_facet); UInt coord_in_limit = 0; while (coord_in_limit < spatial_dimension && bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) ++coord_in_limit; if (coord_in_limit != spatial_dimension) need_check = false; }, _spatial_dimension = spatial_dimension - 1); if (not mesh_facets.hasData("physical_names")) { + AKANTU_DEBUG_ASSERT( + physical_groups.size() == 0, + "No physical names in the mesh but insertion limited to a group"); AKANTU_DEBUG_OUT(); return; } const auto & physical_ids = mesh_facets.getData<std::string>("physical_names"); // set the limits to the physical surfaces for_each_element(mesh_facets, - [&](auto && facet) { - auto & need_check = check_facets(facet); - if (not need_check) - return; - - const auto & physical_id = physical_ids(facet); - auto it = find(physical_groups.begin(), - physical_groups.end(), physical_id); - - need_check = (it != physical_groups.end()); - }, - _spatial_dimension = spatial_dimension - 1); + [&](auto && facet) { + auto & need_check = check_facets(facet); + if (not need_check) + return; + + const auto & physical_id = physical_ids(facet); + auto it = find(physical_groups.begin(), + physical_groups.end(), physical_id); + + need_check = (it != physical_groups.end()); + }, + _spatial_dimension = spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertElements(bool only_double_facets) { CohesiveNewNodesEvent node_event; NewElementsEvent element_event; Array<UInt> new_pairs(0, 2); UInt nb_new_elements = MeshUtils::insertCohesiveElements( mesh, mesh_facets, insertion_facets, new_pairs, element_event.getList(), only_double_facets); UInt nb_new_nodes = new_pairs.size(); node_event.getList().reserve(nb_new_nodes); node_event.getOldNodesList().reserve(nb_new_nodes); for (UInt n = 0; n < nb_new_nodes; ++n) { node_event.getList().push_back(new_pairs(n, 1)); node_event.getOldNodesList().push_back(new_pairs(n, 0)); } if (mesh.isDistributed()) { /// update nodes type updateNodesType(mesh, node_event); updateNodesType(mesh_facets, node_event); /// update global ids nb_new_nodes = this->updateGlobalIDs(node_event); /// compute total number of new elements const auto & comm = mesh.getCommunicator(); comm.allReduce(nb_new_elements, SynchronizerOperation::_sum); } if (nb_new_nodes > 0) mesh.sendEvent(node_event); if (nb_new_elements > 0) { updateInsertionFacets(); // mesh.updateTypesOffsets(_not_ghost); mesh.sendEvent(element_event); MeshUtils::resetFacetToDouble(mesh_facets); } if (mesh.isDistributed()) { /// update global ids this->synchronizeGlobalIDs(node_event); } return nb_new_elements; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::updateInsertionFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (auto && facet_gt : ghost_types) { for (auto && facet_type : mesh_facets.elementTypes(spatial_dimension - 1, facet_gt)) { auto & ins_facets = insertion_facets(facet_type, facet_gt); // this is the intrinsic case if (not is_extrinsic) continue; auto & f_check = check_facets(facet_type, facet_gt); for (auto && pair : zip(ins_facets, f_check)) { bool & ins = std::get<0>(pair); bool & check = std::get<1>(pair); if (ins) ins = check = false; } } } // resize for the newly added facets insertion_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); // resize for the newly added facets if (is_extrinsic) { check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); } else { insertion_facets.set(false); } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 1cb298d0d..93f8e8090 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2172 +1,2173 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Aug 20 2010 * @date last modification: Fri Jan 22 2016 * * @brief All mesh utils necessary for various tasks * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "fe_engine.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #include <limits> #include <numeric> #include <queue> #include <set> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<Element> & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); /// count number of occurrence of each node UInt nb_nodes = mesh.getNbNodes(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); AKANTU_DEBUG_ASSERT( mesh.firstType(spatial_dimension) != mesh.lastType(spatial_dimension), "Some elements must be found in right dimension to compute facets!"); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); for (; first != last; ++first) { ElementType type = *first; UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator<Vector<UInt>> conn_it = mesh.getConnectivity(type, *gt).begin( Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) for (UInt n = 0; n < conn_it->size(); ++n) ++node_to_elem.rowOffset((*conn_it)(n)); } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); /// rearrange element to get the node-element list Element e; node_to_elem.beginInsertions(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); e.ghost_type = *gt; for (; first != last; ++first) { ElementType type = *first; e.type = type; UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator<Vector<UInt>> conn_it = mesh.getConnectivity(type, *gt).begin( Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; for (UInt n = 0; n < conn_it->size(); ++n) node_to_elem.insertInRow((*conn_it)(n), e); } } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This function should disappear in the future (used in mesh partitioning) */ // void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<UInt> & // node_to_elem, // UInt spatial_dimension) { // AKANTU_DEBUG_IN(); // if (spatial_dimension == _all_dimensions) // spatial_dimension = mesh.getSpatialDimension(); // UInt nb_nodes = mesh.getNbNodes(); // const Mesh::ConnectivityTypeList & type_list = // mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator // it; // UInt nb_types = type_list.size(); // UInt nb_good_types = 0; // Vector<UInt> nb_nodes_per_element(nb_types); // UInt ** conn_val = new UInt *[nb_types]; // Vector<UInt> nb_element(nb_types); // for (it = type_list.begin(); it != type_list.end(); ++it) { // ElementType type = *it; // if (Mesh::getSpatialDimension(type) != spatial_dimension) // continue; // nb_nodes_per_element[nb_good_types] = Mesh::getNbNodesPerElement(type); // conn_val[nb_good_types] = mesh.getConnectivity(type, // _not_ghost).storage(); nb_element[nb_good_types] = // mesh.getConnectivity(type, _not_ghost).size(); // nb_good_types++; // } // AKANTU_DEBUG_ASSERT( // nb_good_types != 0, // "Some elements must be found in right dimension to compute facets!"); // /// array for the node-element list // node_to_elem.resizeRows(nb_nodes); // node_to_elem.clearRows(); // /// count number of occurrence of each node // for (UInt t = 0; t < nb_good_types; ++t) { // for (UInt el = 0; el < nb_element[t]; ++el) { // UInt el_offset = el * nb_nodes_per_element[t]; // for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) { // ++node_to_elem.rowOffset(conn_val[t][el_offset + n]); // } // } // } // node_to_elem.countToCSR(); // node_to_elem.resizeCols(); // node_to_elem.beginInsertions(); // /// rearrange element to get the node-element list // for (UInt t = 0, linearized_el = 0; t < nb_good_types; ++t) // for (UInt el = 0; el < nb_element[t]; ++el, ++linearized_el) { // UInt el_offset = el * nb_nodes_per_element[t]; // for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) // node_to_elem.insertInRow(conn_val[t][el_offset + n], linearized_el); // } // node_to_elem.endInsertions(); // delete[] conn_val; // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR<UInt> & node_to_elem, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, ghost_type).size(); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) ++node_to_elem.rowOffset(conn_val[el_offset + n]); } /// convert the occurrence array in a csr one node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { node_to_elem.insertInRow(conn_val[el_offset + n], el); } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { mesh.getConnectivity(*it, *gt).resize(0); // \todo inform the mesh event handler } } buildFacetsDimension(mesh, mesh, true, spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT( mesh_facets.isMeshFacets(), "The mesh_facets should be initialized with initMeshFacets"); /// generate facets buildFacetsDimension(mesh, mesh_facets, false, from_dimension); /// copy nodes type MeshAccessor mesh_accessor_facets(mesh_facets); mesh_accessor_facets.getNodesType().copy(mesh.getNodesType()); /// sort facets and generate sub-facets for (UInt i = from_dimension - 1; i > to_dimension; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i); } 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<Real> & mesh_facets_nodes = mesh_facets.getNodes(); const Array<Real>::const_vector_iterator mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); CSR<Element> node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array<UInt> counter; std::vector<Element> connected_elements; // init the SubelementToElement data to improve performance for (auto && ghost_type : ghost_types) { for (auto && type : mesh.elementTypes(dimension, ghost_type)) { mesh_accessor.getSubelementToElement(type, ghost_type); 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_facets.getElementToSubelement(facet_type, ghost_type); auto connectivity_facets = &mesh_facets.getConnectivity(facet_type, ghost_type); auto nb_facet_per_element = mesh.getNbFacetsPerElement(type, ft); const auto & element_connectivity = mesh.getConnectivity(type, ghost_type); Matrix<const UInt> facet_local_connectivity( mesh.getFacetLocalConnectivity(type, ft)); auto nb_nodes_per_facet = connectivity_facets->getNbComponent(); Vector<UInt> facet(nb_nodes_per_facet); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; for (UInt f = 0; f < nb_facet_per_element; ++f) { for (UInt n = 0; n < nb_nodes_per_facet; ++n) facet(n) = element_connectivity(el, facet_local_connectivity(f, n)); UInt first_node_nb_elements = node_to_elem.getNbCols(facet(0)); counter.resize(first_node_nb_elements); counter.clear(); // loop over the other nodes to search intersecting elements, // which are the elements that share another node with the // starting element after first_node UInt local_el = 0; auto first_node_elements = node_to_elem.begin(facet(0)); auto first_node_elements_end = node_to_elem.end(facet(0)); for (; first_node_elements != first_node_elements_end; ++first_node_elements, ++local_el) { for (UInt n = 1; n < nb_nodes_per_facet; ++n) { auto node_elements_begin = node_to_elem.begin(facet(n)); auto node_elements_end = node_to_elem.end(facet(n)); counter(local_el) += std::count(node_elements_begin, node_elements_end, *first_node_elements); } } // counting the number of elements connected to the facets and // taking the minimum element number, because the facet should // be inserted just once UInt nb_element_connected_to_facet = 0; Element minimum_el = ElementNull; connected_elements.clear(); for (UInt el_f = 0; el_f < first_node_nb_elements; el_f++) { Element real_el = node_to_elem(facet(0), el_f); if (not(counter(el_f) == nb_nodes_per_facet - 1)) continue; ++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 && 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<Element> elements; // build elements_on_facets: linearized_el must come first // in order to store the facet in the correct direction // and avoid to invert the sign in the normal computation elements.push_back(current_element); if (nb_element_connected_to_facet == 1) { /// boundary facet elements.push_back(ElementNull); } else if (nb_element_connected_to_facet == 2) { /// internal facet elements.push_back(connected_elements[1]); /// check if facet is in between ghost and normal /// elements: if it's the case, the facet is either /// ghost or not ghost. The criterion to decide this /// is arbitrary. It was chosen to check the processor /// id (prank) of the two neighboring elements. If /// prank of the ghost element is lower than prank of /// the normal one, the facet is not ghost, otherwise /// it's ghost GhostType gt[2] = {_not_ghost, _not_ghost}; for (UInt el = 0; el < connected_elements.size(); ++el) gt[el] = connected_elements[el].ghost_type; if (gt[0] != gt[1] and (gt[0] == _not_ghost or 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_facets.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_facets.getElementToSubelement( facet_type, facet_ghost_type); } } else { /// facet of facet for (UInt i = 1; i < nb_element_connected_to_facet; ++i) { elements.push_back(connected_elements[i]); } } element_to_subelement->push_back(elements); connectivity_facets->push_back(facet); /// current facet index UInt current_facet = connectivity_facets->size() - 1; /// loop on every element connected to current facet and /// insert current facet in the first free spot of the /// subelement_to_element vector for (UInt elem = 0; elem < elements.size(); ++elem) { Element loc_el = elements[elem]; if (loc_el.type == _not_defined) continue; Array<Element> & subelement_to_element = mesh_facets.getSubelementToElement(loc_el.type, loc_el.ghost_type); UInt nb_facet_per_loc_element = subelement_to_element.getNbComponent(); for (UInt f_in = 0; f_in < nb_facet_per_loc_element; ++f_in) { auto & el = subelement_to_element(loc_el.element, f_in); if (el.type != _not_defined) continue; el.type = facet_type; el.element = current_facet; el.ghost_type = facet_ghost_type; break; } } /// reset connectivity in case a facet was found in /// between ghost and normal elements if (facet_ghost_type != ghost_type) { facet_ghost_type = ghost_type; connectivity_facets = &mesh_accessor.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_accessor.getElementToSubelement( facet_type, facet_ghost_type); } } } } } } // restore the parent of mesh_facet if (mesh_facets_parent) mesh_facets.defineMeshParent(*mesh_facets_parent); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, Array<UInt> & local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array<UInt> & old_nodes_numbers) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map<UInt, UInt> 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); 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); 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<UInt> & list_nodes, UInt nb_nodes, std::map<UInt, UInt> & 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<UInt, UInt> renumbering_map; RemovedNodesEvent remove_nodes(mesh); Array<UInt> & nodes_removed = remove_nodes.getList(); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { auto ghost_type = (GhostType)gt; Mesh::type_iterator it = mesh.firstType(_all_dimensions, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != end; ++it) { ElementType type(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity.size()); renumberNodesInConnectivity( connectivity, nb_element * nb_nodes_per_element, renumbering_map); } } Array<UInt> & new_numbering = remove_nodes.getNewNumbering(); std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); auto it = renumbering_map.begin(); auto end = renumbering_map.end(); for (; it != end; ++it) { new_numbering(it->first) = it->second; } for (UInt i = 0; i < new_numbering.size(); ++i) { if (new_numbering(i) == UInt(-1)) nodes_removed.push_back(i); } mesh.sendEvent(remove_nodes); AKANTU_DEBUG_OUT(); } #if defined(AKANTU_COHESIVE_ELEMENT) /* -------------------------------------------------------------------------- */ UInt MeshUtils::insertCohesiveElements( Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion, Array<UInt> & doubled_nodes, Array<Element> & new_elements, bool only_double_facets) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt elements_to_insert = updateFacetToDouble(mesh_facets, facet_insertion); if (elements_to_insert > 0) { if (spatial_dimension == 1) { doublePointFacet(mesh, mesh_facets, doubled_nodes); } else { doubleFacet(mesh, mesh_facets, spatial_dimension - 1, doubled_nodes, true); findSubfacetToDouble<false>(mesh, mesh_facets); if (spatial_dimension == 2) { doubleSubfacet<2>(mesh, mesh_facets, doubled_nodes); } else if (spatial_dimension == 3) { doubleFacet(mesh, mesh_facets, 1, doubled_nodes, false); findSubfacetToDouble<true>(mesh, mesh_facets); doubleSubfacet<3>(mesh, mesh_facets, doubled_nodes); } } if (!only_double_facets) updateCohesiveData(mesh, mesh_facets, new_elements); } return elements_to_insert; } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doubleNodes(Mesh & mesh, const std::vector<UInt> & old_nodes, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); Array<Real> & position = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt old_nb_nodes = position.size(); UInt new_nb_nodes = old_nb_nodes + old_nodes.size(); UInt old_nb_doubled_nodes = doubled_nodes.size(); UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.size(); position.resize(new_nb_nodes); doubled_nodes.resize(new_nb_doubled_nodes); Array<Real>::iterator<Vector<Real>> position_begin = position.begin(spatial_dimension); for (UInt n = 0; n < old_nodes.size(); ++n) { UInt new_node = old_nb_nodes + n; /// store doubled nodes doubled_nodes(old_nb_doubled_nodes + n, 0) = old_nodes[n]; doubled_nodes(old_nb_doubled_nodes + n, 1) = new_node; /// update position std::copy(position_begin + old_nodes[n], position_begin + old_nodes[n] + 1, position_begin + new_node); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array<UInt> & doubled_nodes, bool facet_mode) { AKANTU_DEBUG_IN(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(facet_dimension, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(facet_dimension, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); const UInt nb_subfacet_per_facet = Mesh::getNbFacetsPerElement(type_facet); GhostType gt_subfacet = _casper; Array<std::vector<Element>> * f_to_subfacet = nullptr; Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); UInt nb_nodes_per_facet = conn_facet.getNbComponent(); UInt old_nb_facet = conn_facet.size(); UInt new_nb_facet = old_nb_facet + nb_facet_to_double; conn_facet.resize(new_nb_facet); subfacet_to_facet.resize(new_nb_facet); UInt new_facet = old_nb_facet - 1; Element new_facet_el{type_facet, 0, gt_facet}; Array<Element>::iterator<Vector<Element>> subfacet_to_facet_begin = subfacet_to_facet.begin(nb_subfacet_per_facet); Array<UInt>::iterator<Vector<UInt>> conn_facet_begin = conn_facet.begin(nb_nodes_per_facet); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); ++new_facet; /// adding a new facet by copying original one /// copy connectivity in new facet std::copy(conn_facet_begin + old_facet, conn_facet_begin + old_facet + 1, conn_facet_begin + new_facet); /// update subfacet_to_facet std::copy(subfacet_to_facet_begin + old_facet, subfacet_to_facet_begin + old_facet + 1, subfacet_to_facet_begin + new_facet); new_facet_el.element = new_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet_per_facet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; f_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, subfacet.ghost_type); } /// update facet_to_subfacet array (*f_to_subfacet)(subfacet.element).push_back(new_facet_el); } } /// update facet_to_subfacet and _segment_3 facets if any if (!facet_mode) { updateSubfacetToFacet(mesh_facets, type_facet, gt_facet, true); updateFacetToSubfacet(mesh_facets, type_facet, gt_facet, true); updateQuadraticSegments<true>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } else updateQuadraticSegments<false>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateFacetToDouble( Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); UInt nb_facets_to_double = 0.; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; const Array<bool> & f_insertion = facet_insertion(type_facet, gt_facet); Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); ElementType el_type = _not_defined; GhostType el_gt = _casper; UInt nb_facet_per_element = 0; Element old_facet_el{type_facet, 0, gt_facet}; Array<Element> * facet_to_element = nullptr; for (UInt f = 0; f < f_insertion.size(); ++f) { if (f_insertion(f) == false) continue; ++nb_facets_to_double; if (element_to_facet(f)[1].type == _not_defined #if defined(AKANTU_COHESIVE_ELEMENT) || element_to_facet(f)[1].kind() == _ek_cohesive #endif ) { AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary"); continue; } f_to_double.push_back(f); UInt new_facet = mesh_facets.getNbElement(type_facet, gt_facet) + f_to_double.size() - 1; old_facet_el.element = f; /// update facet_to_element vector Element & elem_to_update = element_to_facet(f)[1]; UInt el = elem_to_update.element; if (elem_to_update.ghost_type != el_gt || elem_to_update.type != el_type) { el_type = elem_to_update.type; el_gt = elem_to_update.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(el_type, el_gt); nb_facet_per_element = facet_to_element->getNbComponent(); } Element * f_update = std::find(facet_to_element->storage() + el * nb_facet_per_element, facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, old_facet_el); AKANTU_DEBUG_ASSERT( facet_to_element->storage() + el * nb_facet_per_element != facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, "Facet not found"); f_update->element = new_facet; /// update elements connected to facet std::vector<Element> first_facet_list = element_to_facet(f); element_to_facet.push_back(first_facet_list); /// set new and original facets as boundary facets element_to_facet(new_facet)[0] = element_to_facet(new_facet)[1]; element_to_facet(f)[1] = ElementNull; element_to_facet(new_facet)[1] = ElementNull; } } } AKANTU_DEBUG_OUT(); return nb_facets_to_double; } /* -------------------------------------------------------------------------- */ void MeshUtils::resetFacetToDouble(Mesh & mesh_facets) { AKANTU_DEBUG_IN(); for (UInt g = _not_ghost; g <= _ghost; ++g) { auto gt = (GhostType)g; Mesh::type_iterator it = mesh_facets.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh_facets.lastType(_all_dimensions, gt); for (; it != end; ++it) { ElementType type = *it; mesh_facets.getDataPointer<UInt>("facet_to_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "facets_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "elements_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element>>( "subfacets_to_subsubfacet_double", type, gt, 1, false); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool subsubfacet_mode> void MeshUtils::findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); GhostType gt_subfacet = _casper; ElementType type_subsubfacet = Mesh::getFacetType(type_subfacet); GhostType gt_subsubfacet = _casper; Array<UInt> * conn_subfacet = nullptr; Array<UInt> * sf_to_double = nullptr; Array<std::vector<Element>> * sf_to_subfacet_double = nullptr; Array<std::vector<Element>> * f_to_subfacet_double = nullptr; Array<std::vector<Element>> * el_to_subfacet_double = nullptr; UInt nb_subfacet = Mesh::getNbFacetsPerElement(type_facet); UInt nb_subsubfacet; UInt nb_nodes_per_sf_el; if (subsubfacet_mode) { nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subsubfacet); nb_subsubfacet = Mesh::getNbFacetsPerElement(type_subfacet); } else nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subfacet); Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array<Element> * subsubfacet_to_subfacet = nullptr; UInt old_nb_facet = subfacet_to_facet.size() - nb_facet_to_double; Element current_facet{type_facet, 0, gt_facet}; std::vector<Element> element_list; std::vector<Element> facet_list; std::vector<Element> * subfacet_list; if (subsubfacet_mode) subfacet_list = new std::vector<Element>; /// map to filter subfacets Array<std::vector<Element>> * facet_to_subfacet = nullptr; /// this is used to make sure that both new and old facets are /// checked UInt facets[2]; /// loop on every facet for (UInt f_index = 0; f_index < 2; ++f_index) { for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { facets[bool(f_index)] = f_to_double(facet); facets[!bool(f_index)] = old_nb_facet + facet; UInt old_facet = facets[0]; UInt new_facet = facets[1]; Element & starting_element = element_to_facet(new_facet)[0]; current_facet.element = old_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; if (subsubfacet_mode) { subsubfacet_to_subfacet = &mesh_facets.getSubelementToElement( type_subfacet, gt_subfacet); } else { conn_subfacet = &mesh_facets.getConnectivity(type_subfacet, gt_subfacet); sf_to_double = &mesh_facets.getData<UInt>( "facet_to_double", type_subfacet, gt_subfacet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subfacet, gt_subfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, gt_subfacet); } } if (subsubfacet_mode) { /// loop on every subsubfacet for (UInt ssf = 0; ssf < nb_subsubfacet; ++ssf) { Element & subsubfacet = (*subsubfacet_to_subfacet)(subfacet.element, ssf); if (subsubfacet == ElementNull) continue; if (gt_subsubfacet != subsubfacet.ghost_type) { gt_subsubfacet = subsubfacet.ghost_type; conn_subfacet = &mesh_facets.getConnectivity(type_subsubfacet, gt_subsubfacet); sf_to_double = &mesh_facets.getData<UInt>( "facet_to_double", type_subsubfacet, gt_subsubfacet); sf_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subsubfacet, gt_subsubfacet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subsubfacet, gt_subsubfacet); el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subsubfacet, gt_subsubfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subsubfacet, gt_subsubfacet); } UInt global_ssf = subsubfacet.element; Vector<UInt> subsubfacet_connectivity( conn_subfacet->storage() + global_ssf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subsubfacet is to be doubled if (findElementsAroundSubfacet<true>( mesh, mesh_facets, starting_element, current_facet, subsubfacet_connectivity, element_list, facet_list, subfacet_list) == false && removeElementsInVector(*subfacet_list, (*facet_to_subfacet)(global_ssf)) == false) { sf_to_double->push_back(global_ssf); sf_to_subfacet_double->push_back(*subfacet_list); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } else { const UInt global_sf = subfacet.element; Vector<UInt> subfacet_connectivity( conn_subfacet->storage() + global_sf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subfacet is to be doubled if (findElementsAroundSubfacet<false>( mesh, mesh_facets, starting_element, current_facet, subfacet_connectivity, element_list, facet_list) == false && removeElementsInVector( facet_list, (*facet_to_subfacet)(global_sf)) == false) { sf_to_double->push_back(global_sf); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } } } if (subsubfacet_mode) delete subfacet_list; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array<Element> & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; MeshAccessor mesh_facets_accessor(mesh_facets); for (auto gt_facet : ghost_types) { for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); auto & facet_to_coh_element = mesh_facets_accessor.getSubelementToElement(type_cohesive, gt_facet); auto & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); auto & conn_cohesive = mesh.getConnectivity(type_cohesive, gt_facet); UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); UInt old_nb_cohesive_elements = conn_cohesive.size(); UInt new_nb_cohesive_elements = conn_cohesive.size() + nb_facet_to_double; UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; facet_to_coh_element.resize(new_nb_cohesive_elements); conn_cohesive.resize(new_nb_cohesive_elements); UInt new_elements_old_size = new_elements.size(); new_elements.resize(new_elements_old_size + nb_facet_to_double); Element c_element{type_cohesive, 0, gt_facet}; Element f_element{type_facet, 0, gt_facet}; UInt facets[2]; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { /// (in 3D cohesive elements connectivity is inverted) facets[third_dimension] = f_to_double(facet); facets[!third_dimension] = old_nb_facet + facet; UInt cohesive_element = old_nb_cohesive_elements + facet; /// store doubled facets f_element.element = facets[0]; facet_to_coh_element(cohesive_element, 0) = f_element; f_element.element = facets[1]; facet_to_coh_element(cohesive_element, 1) = f_element; /// modify cohesive elements' connectivity for (UInt n = 0; n < nb_nodes_per_facet; ++n) { conn_cohesive(cohesive_element, n) = conn_facet(facets[0], n); conn_cohesive(cohesive_element, n + nb_nodes_per_facet) = conn_facet(facets[1], n); } /// update element_to_facet vectors c_element.element = cohesive_element; element_to_facet(facets[0])[1] = c_element; element_to_facet(facets[1])[1] = c_element; /// add cohesive element to the element event list new_elements(new_elements_old_size + facet) = c_element; } } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); if (spatial_dimension != 1) return; Array<Real> & position = mesh.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); const Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; UInt new_nb_facet = element_to_facet.size(); UInt old_nb_nodes = position.size(); UInt new_nb_nodes = old_nb_nodes + nb_facet_to_double; position.resize(new_nb_nodes); conn_facet.resize(new_nb_facet); UInt old_nb_doubled_nodes = doubled_nodes.size(); doubled_nodes.resize(old_nb_doubled_nodes + nb_facet_to_double); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt new_facet = old_nb_facet + facet; ElementType type = element_to_facet(new_facet)[0].type; UInt el = element_to_facet(new_facet)[0].element; GhostType gt = element_to_facet(new_facet)[0].ghost_type; UInt old_node = conn_facet(old_facet); UInt new_node = old_nb_nodes + facet; /// update position position(new_node) = position(old_node); conn_facet(new_facet) = new_node; Array<UInt> & conn_segment = mesh.getConnectivity(type, gt); UInt nb_nodes_per_segment = conn_segment.getNbComponent(); /// update facet connectivity UInt i; for (i = 0; conn_segment(el, i) != old_node && i <= nb_nodes_per_segment; ++i) ; conn_segment(el, i) = new_node; doubled_nodes(old_nb_doubled_nodes + facet, 0) = old_node; doubled_nodes(old_nb_doubled_nodes + facet, 1) = new_node; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_segments> void MeshUtils::updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (type_facet != _segment_3) return; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); UInt old_nb_facet = mesh_facets.getNbElement(type_facet, gt_facet) - nb_facet_to_double; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array<std::vector<Element>> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); /// this ones matter only for segments in 3D Array<std::vector<Element>> * el_to_subfacet_double = nullptr; Array<std::vector<Element>> * f_to_subfacet_double = nullptr; if (third_dim_segments) { el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_facet, gt_facet); f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_facet, gt_facet); } std::vector<UInt> middle_nodes; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt node = conn_facet(old_facet, 2); if (!mesh.isPureGhostNode(node)) middle_nodes.push_back(node); } UInt n = doubled_nodes.size(); doubleNodes(mesh, middle_nodes, doubled_nodes); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt old_node = conn_facet(old_facet, 2); if (mesh.isPureGhostNode(old_node)) continue; UInt new_node = doubled_nodes(n, 1); UInt new_facet = old_nb_facet + facet; conn_facet(new_facet, 2) = new_node; if (third_dim_segments) { updateElementalConnectivity(mesh_facets, old_node, new_node, element_to_facet(new_facet)); updateElementalConnectivity(mesh, old_node, new_node, (*el_to_subfacet_double)(facet), &(*f_to_subfacet_double)(facet)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_facet(new_facet)); } ++n; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); /// update subfacet_to_facet vector ElementType type_facet = _not_defined; GhostType gt_facet = _casper; Array<Element> * subfacet_to_facet = nullptr; UInt nb_subfacet_per_facet = 0; UInt old_nb_subfacet = mesh_facets.getNbElement(type_subfacet, gt_subfacet) - nb_subfacet_to_double; Array<std::vector<Element>> * facet_list = nullptr; if (facet_mode) facet_list = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); else facet_list = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); Element old_subfacet_el{type_subfacet, 0, gt_subfacet}; Element new_subfacet_el{type_subfacet, 0, gt_subfacet}; for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { old_subfacet_el.element = sf_to_double(sf); new_subfacet_el.element = old_nb_subfacet + sf; for (UInt f = 0; f < (*facet_list)(sf).size(); ++f) { Element & facet = (*facet_list)(sf)[f]; if (facet.type != type_facet || facet.ghost_type != gt_facet) { type_facet = facet.type; gt_facet = facet.ghost_type; subfacet_to_facet = &mesh_facets.getSubelementToElement(type_facet, gt_facet); nb_subfacet_per_facet = subfacet_to_facet->getNbComponent(); } Element * sf_update = std::find( subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet, subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, old_subfacet_el); AKANTU_DEBUG_ASSERT(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet != subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, "Subfacet not found"); *sf_update = new_subfacet_el; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); Array<std::vector<Element>> & facet_to_subfacet = mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); Array<std::vector<Element>> * facet_to_subfacet_double = nullptr; if (facet_mode) { facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "facets_to_subfacet_double", type_subfacet, gt_subfacet); } else { facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); } UInt old_nb_subfacet = facet_to_subfacet.size(); facet_to_subfacet.resize(old_nb_subfacet + nb_subfacet_to_double); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) facet_to_subfacet(old_nb_subfacet + sf) = (*facet_to_subfacet_double)(sf); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MeshUtils::doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_subfacet = *gt; Mesh::type_iterator it = mesh_facets.firstType(0, gt_subfacet); Mesh::type_iterator end = mesh_facets.lastType(0, gt_subfacet); for (; it != end; ++it) { ElementType type_subfacet = *it; Array<UInt> & sf_to_double = mesh_facets.getData<UInt>( "facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.size(); if (nb_subfacet_to_double == 0) continue; AKANTU_DEBUG_ASSERT( type_subfacet == _point_1, "Only _point_1 subfacet doubling is supported at the moment"); Array<UInt> & conn_subfacet = mesh_facets.getConnectivity(type_subfacet, gt_subfacet); UInt old_nb_subfacet = conn_subfacet.size(); UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double; conn_subfacet.resize(new_nb_subfacet); std::vector<UInt> nodes_to_double; UInt old_nb_doubled_nodes = doubled_nodes.size(); /// double nodes for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_subfacet = sf_to_double(sf); nodes_to_double.push_back(conn_subfacet(old_subfacet)); } doubleNodes(mesh, nodes_to_double, doubled_nodes); /// add new nodes in connectivity for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt new_subfacet = old_nb_subfacet + sf; UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); conn_subfacet(new_subfacet) = new_node; } /// update facet and element connectivity Array<std::vector<Element>> & f_to_subfacet_double = mesh_facets.getData<std::vector<Element>>("facets_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element>> & el_to_subfacet_double = mesh_facets.getData<std::vector<Element>>( "elements_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element>> * sf_to_subfacet_double = nullptr; if (spatial_dimension == 3) sf_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_node = doubled_nodes(old_nb_doubled_nodes + sf, 0); UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); updateElementalConnectivity(mesh, old_node, new_node, el_to_subfacet_double(sf), &f_to_subfacet_double(sf)); updateElementalConnectivity(mesh_facets, old_node, new_node, f_to_subfacet_double(sf)); if (spatial_dimension == 3) updateElementalConnectivity(mesh_facets, old_node, new_node, (*sf_to_subfacet_double)(sf)); } if (spatial_dimension == 2) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, true); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, true); } else if (spatial_dimension == 3) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, false); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::flipFacets( Mesh & mesh_facets, const ElementTypeMapArray<UInt> & global_connectivity, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); /// get global connectivity for local mesh ElementTypeMapArray<UInt> global_connectivity_tmp("global_connectivity_tmp", mesh_facets.getID(), mesh_facets.getMemoryID()); global_connectivity_tmp.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(global_connectivity_tmp); /// loop on every facet for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { auto & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet); const auto & g_connectivity = global_connectivity(type_facet, gt_facet); auto & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet); auto & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); UInt nb_subfacet_per_facet = subfacet_to_facet.getNbComponent(); UInt nb_nodes_per_facet = connectivity.getNbComponent(); UInt nb_facet = connectivity.size(); UInt nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); auto & global_conn_tmp = global_connectivity_tmp(type_facet, gt_facet); auto conn_it = connectivity.begin(nb_nodes_per_facet); auto gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet); auto conn_glob_it = g_connectivity.begin(nb_nodes_per_facet); auto subf_to_f = subfacet_to_facet.begin(nb_subfacet_per_facet); auto * conn_tmp_pointer = new UInt[nb_nodes_per_facet]; Vector<UInt> conn_tmp(conn_tmp_pointer, nb_nodes_per_facet); Element el_tmp; auto * subf_tmp_pointer = new Element[nb_subfacet_per_facet]; Vector<Element> subf_tmp(subf_tmp_pointer, nb_subfacet_per_facet); for (UInt f = 0; f < nb_facet; ++f, ++conn_it, ++gconn_tmp_it, ++subf_to_f, ++conn_glob_it) { Vector<UInt> & gconn_tmp = *gconn_tmp_it; const Vector<UInt> & conn_glob = *conn_glob_it; Vector<UInt> & conn_local = *conn_it; /// skip facet if connectivities are the same if (gconn_tmp == conn_glob) continue; /// re-arrange connectivity conn_tmp = conn_local; UInt * begin = conn_glob.storage(); UInt * end = conn_glob.storage() + nb_nodes_per_facet; for (UInt n = 0; n < nb_nodes_per_facet; ++n) { UInt * new_node = std::find(begin, end, gconn_tmp(n)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; conn_local(new_position) = conn_tmp(n); } /// if 3D, check if facets are just rotated if (spatial_dimension == 3) { /// find first node UInt * new_node = std::find(begin, end, gconn_tmp(0)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; UInt n = 1; /// count how many nodes in the received connectivity follow /// the same order of those in the local connectivity for (; n < nb_nodes_per_P1_facet && gconn_tmp(n) == conn_glob((new_position + n) % nb_nodes_per_P1_facet); ++n) ; /// skip the facet inversion if facet is just rotated if (n == nb_nodes_per_P1_facet) continue; } /// update data to invert facet el_tmp = el_to_f(f)[0]; el_to_f(f)[0] = el_to_f(f)[1]; el_to_f(f)[1] = el_tmp; subf_tmp = (*subf_to_f); (*subf_to_f)(0) = subf_tmp(1); (*subf_to_f)(1) = subf_tmp(0); } delete[] subf_tmp_pointer; delete[] conn_tmp_pointer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::fillElementToSubElementsData(Mesh & mesh) { AKANTU_DEBUG_IN(); if (mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) { AKANTU_DEBUG_INFO("There are not facets, add them in the mesh file or call " "the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray<Real> barycenters("barycenter_tmp", mesh.getID(), mesh.getMemoryID()); barycenters.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = _all_dimensions); // mesh.initElementTypeMapArray(barycenters, spatial_dimension, // _all_dimensions); Element element; for (auto ghost_type : ghost_types) { element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(_all_dimensions, ghost_type)) { element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array<Real> & barycenters_arr = barycenters(type, ghost_type); barycenters_arr.resize(nb_element); auto bary = barycenters_arr.begin(spatial_dimension); auto bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { element.element = el; mesh.getBarycenter(element, *bary); } } } MeshAccessor mesh_accessor(mesh); for (Int sp(spatial_dimension); sp >= 1; --sp) { if (mesh.getNbElement(sp) == 0) continue; for (auto ghost_type : ghost_types) { for (auto & type : mesh.elementTypes(sp, ghost_type)) { mesh_accessor.getSubelementToElement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh_accessor.getSubelementToElement(type, ghost_type).clear(); } for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { mesh_accessor.getElementToSubelement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh.getElementToSubelement(type, ghost_type).clear(); } } CSR<Element> nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (auto ghost_type : ghost_types) { facet_element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { facet_element.type = type; auto & element_to_subelement = mesh.getElementToSubelement(type, ghost_type); const auto & connectivity = mesh.getConnectivity(type, ghost_type); auto fit = connectivity.begin(mesh.getNbNodesPerElement(type)); auto fend = connectivity.end(mesh.getNbNodesPerElement(type)); UInt fid = 0; for (; fit != fend; ++fit, ++fid) { const Vector<UInt> & facet = *fit; facet_element.element = fid; std::map<Element, UInt> element_seen_counter; UInt nb_nodes_per_facet = mesh.getNbNodesPerElement(Mesh::getP1ElementType(type)); for (UInt n(0); n < nb_nodes_per_facet; ++n) { auto eit = nodes_to_elements.begin(facet(n)); auto eend = nodes_to_elements.end(facet(n)); for (; eit != eend; ++eit) { auto & elem = *eit; auto cit = element_seen_counter.find(elem); if (cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } std::vector<Element> connected_elements; auto cit = element_seen_counter.begin(); auto cend = element_seen_counter.end(); for (; cit != cend; ++cit) { if (cit->second == nb_nodes_per_facet) connected_elements.push_back(cit->first); } auto ceit = connected_elements.begin(); auto ceend = connected_elements.end(); for (; ceit != ceend; ++ceit) element_to_subelement(fid).push_back(*ceit); for (UInt ce = 0; ce < connected_elements.size(); ++ce) { Element & elem = connected_elements[ce]; Array<Element> & subelement_to_element = mesh_accessor.getSubelementToElement(elem.type, elem.ghost_type); UInt f(0); for (; f < mesh.getNbFacetsPerElement(elem.type) && subelement_to_element(elem.element, f) != ElementNull; ++f) ; AKANTU_DEBUG_ASSERT( f < mesh.getNbFacetsPerElement(elem.type), "The element " << elem << " seems to have too many facets!! (" << f << " < " << mesh.getNbFacetsPerElement(elem.type) << ")"); subelement_to_element(elem.element, f) = facet_element; } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_points> bool MeshUtils::findElementsAroundSubfacet( const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector<UInt> & subfacet_connectivity, std::vector<Element> & elem_list, std::vector<Element> & facet_list, std::vector<Element> * subfacet_list) { AKANTU_DEBUG_IN(); /// preallocated stuff before starting bool facet_matched = false; elem_list.clear(); facet_list.clear(); if (third_dim_points) subfacet_list->clear(); elem_list.push_back(starting_element); const Array<UInt> * facet_connectivity = nullptr; const Array<UInt> * sf_connectivity = nullptr; const Array<Element> * facet_to_element = nullptr; const Array<Element> * subfacet_to_facet = nullptr; ElementType current_type = _not_defined; GhostType current_ghost_type = _casper; ElementType current_facet_type = _not_defined; GhostType current_facet_ghost_type = _casper; ElementType current_subfacet_type = _not_defined; GhostType current_subfacet_ghost_type = _casper; const Array<std::vector<Element>> * element_to_facet = nullptr; const Element * opposing_el = nullptr; std::queue<Element> elements_to_check; elements_to_check.push(starting_element); /// keep going until there are elements to check while (!elements_to_check.empty()) { /// check current element Element & current_el = elements_to_check.front(); if (current_el.type != current_type || current_el.ghost_type != current_ghost_type) { current_type = current_el.type; current_ghost_type = current_el.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(current_type, current_ghost_type); } /// loop over each facet of the element for (UInt f = 0; f < facet_to_element->getNbComponent(); ++f) { const Element & current_facet = (*facet_to_element)(current_el.element, f); if (current_facet == ElementNull) continue; if (current_facet_type != current_facet.type || current_facet_ghost_type != current_facet.ghost_type) { current_facet_type = current_facet.type; current_facet_ghost_type = current_facet.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( current_facet_type, current_facet_ghost_type); facet_connectivity = &mesh_facets.getConnectivity( current_facet_type, current_facet_ghost_type); if (third_dim_points) subfacet_to_facet = &mesh_facets.getSubelementToElement( current_facet_type, current_facet_ghost_type); } /// check if end facet is reached if (current_facet == end_facet) facet_matched = true; /// add this facet if not already passed if (std::find(facet_list.begin(), facet_list.end(), current_facet) == facet_list.end() && hasElement(*facet_connectivity, current_facet, subfacet_connectivity)) { facet_list.push_back(current_facet); if (third_dim_points) { /// check subfacets for (UInt sf = 0; sf < subfacet_to_facet->getNbComponent(); ++sf) { const Element & current_subfacet = (*subfacet_to_facet)(current_facet.element, sf); if (current_subfacet == ElementNull) continue; if (current_subfacet_type != current_subfacet.type || current_subfacet_ghost_type != current_subfacet.ghost_type) { current_subfacet_type = current_subfacet.type; current_subfacet_ghost_type = current_subfacet.ghost_type; sf_connectivity = &mesh_facets.getConnectivity( current_subfacet_type, current_subfacet_ghost_type); } if (std::find(subfacet_list->begin(), subfacet_list->end(), current_subfacet) == subfacet_list->end() && hasElement(*sf_connectivity, current_subfacet, subfacet_connectivity)) subfacet_list->push_back(current_subfacet); } } } else continue; /// consider opposing element if ((*element_to_facet)(current_facet.element)[0] == current_el) opposing_el = &(*element_to_facet)(current_facet.element)[1]; else opposing_el = &(*element_to_facet)(current_facet.element)[0]; /// skip null elements since they are on a boundary if (*opposing_el == ElementNull) continue; /// skip this element if already added if (std::find(elem_list.begin(), elem_list.end(), *opposing_el) != elem_list.end()) continue; /// only regular elements have to be checked if (opposing_el->kind() == _ek_regular) elements_to_check.push(*opposing_el); elem_list.push_back(*opposing_el); #ifndef AKANTU_NDEBUG const Array<UInt> & conn_elem = mesh.getConnectivity(opposing_el->type, opposing_el->ghost_type); AKANTU_DEBUG_ASSERT( hasElement(conn_elem, *opposing_el, subfacet_connectivity), "Subfacet doesn't belong to this element"); #endif } /// erased checked element from the list elements_to_check.pop(); } AKANTU_DEBUG_OUT(); return facet_matched; } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateLocalMasterGlobalConnectivity(Mesh & mesh, UInt local_nb_new_nodes) { const auto & comm = mesh.getCommunicator(); Int rank = comm.whoAmI(); Int nb_proc = comm.getNbProc(); if (nb_proc == 1) return local_nb_new_nodes; /// resize global ids array Array<UInt> & nodes_global_ids = mesh.getGlobalNodesIds(); UInt old_nb_nodes = mesh.getNbNodes() - local_nb_new_nodes; nodes_global_ids.resize(mesh.getNbNodes()); /// compute the number of global nodes based on the number of old nodes Vector<UInt> old_local_master_nodes(nb_proc); for (UInt n = 0; n < old_nb_nodes; ++n) if (mesh.isLocalOrMasterNode(n)) ++old_local_master_nodes(rank); comm.allGather(old_local_master_nodes); UInt old_global_nodes = std::accumulate(old_local_master_nodes.storage(), old_local_master_nodes.storage() + nb_proc, 0); /// compute amount of local or master doubled nodes Vector<UInt> local_master_nodes(nb_proc); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) if (mesh.isLocalOrMasterNode(n)) ++local_master_nodes(rank); comm.allGather(local_master_nodes); /// update global number of nodes UInt total_nb_new_nodes = std::accumulate( local_master_nodes.storage(), local_master_nodes.storage() + nb_proc, 0); if (total_nb_new_nodes == 0) return 0; /// set global ids of local and master nodes UInt starting_index = std::accumulate(local_master_nodes.storage(), local_master_nodes.storage() + rank, old_global_nodes); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) { nodes_global_ids(n) = starting_index; ++starting_index; } } MeshAccessor mesh_accessor(mesh); mesh_accessor.setNbGlobalNodes(old_global_nodes + total_nb_new_nodes); return total_nb_new_nodes; } /* -------------------------------------------------------------------------- */ void MeshUtils::updateElementalConnectivity( Mesh & mesh, UInt old_node, UInt new_node, const std::vector<Element> & element_list, __attribute__((unused)) const std::vector<Element> * facet_list) { AKANTU_DEBUG_IN(); ElementType el_type = _not_defined; GhostType gt_type = _casper; Array<UInt> * conn_elem = nullptr; #if defined(AKANTU_COHESIVE_ELEMENT) const Array<Element> * cohesive_facets = nullptr; #endif UInt nb_nodes_per_element = 0; UInt * n_update = nullptr; for (UInt el = 0; el < element_list.size(); ++el) { const Element & elem = element_list[el]; if (elem.type == _not_defined) continue; if (elem.type != el_type || elem.ghost_type != gt_type) { el_type = elem.type; gt_type = elem.ghost_type; conn_elem = &mesh.getConnectivity(el_type, gt_type); nb_nodes_per_element = conn_elem->getNbComponent(); #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind() == _ek_cohesive) cohesive_facets = &mesh.getMeshFacets().getSubelementToElement(el_type, gt_type); #endif } #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind() == _ek_cohesive) { AKANTU_DEBUG_ASSERT( facet_list != nullptr, "Provide a facet list in order to update cohesive elements"); /// loop over cohesive element's facets for (UInt f = 0, n = 0; f < 2; ++f, n += nb_nodes_per_element / 2) { const Element & facet = (*cohesive_facets)(elem.element, f); /// skip facets if not present in the list if (std::find(facet_list->begin(), facet_list->end(), facet) == facet_list->end()) continue; n_update = std::find( conn_elem->storage() + elem.element * nb_nodes_per_element + n, conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, "Node not found in current element"); /// update connectivity *n_update = new_node; } } else { #endif n_update = std::find(conn_elem->storage() + elem.element * nb_nodes_per_element, conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, "Node not found in current element"); /// update connectivity *n_update = new_node; #if defined(AKANTU_COHESIVE_ELEMENT) } #endif } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/boundary_condition_functor.hh b/src/model/boundary_condition_functor.hh index 2c177874d..743bd322d 100644 --- a/src/model/boundary_condition_functor.hh +++ b/src/model/boundary_condition_functor.hh @@ -1,197 +1,217 @@ /** * @file boundary_condition_functor.hh * * @author Dana Christen <dana.christen@gmail.com> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri May 03 2013 * @date last modification: Thu Oct 15 2015 * * @brief Definitions of the functors to apply boundary conditions * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "fe_engine.hh" #include "integration_point.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ #define __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ namespace BC { using Axis = ::akantu::SpacialDirection; struct Functor { enum Type { _dirichlet, _neumann }; -}; - -/* ------------------------------------------------------------------------ */ -/* Dirichlet */ -/* ------------------------------------------------------------------------ */ -namespace Dirichlet { - /* ---------------------------------------------------------------------- */ - class DirichletFunctor : public Functor { - protected: - DirichletFunctor() = default; - explicit DirichletFunctor(Axis ax) : axis(ax) {} - - public: - void operator()(__attribute__((unused)) UInt node, - __attribute__((unused)) Vector<bool> & flags, - __attribute__((unused)) Vector<Real> & primal, - __attribute__((unused)) const Vector<Real> & coord) const { - AKANTU_DEBUG_TO_IMPLEMENT(); - } - - public: - static const Type type = _dirichlet; - - protected: - Axis axis{_x}; }; - /* ---------------------------------------------------------------------- */ - class FlagOnly : public DirichletFunctor { - public: - explicit FlagOnly(Axis ax = _x) : DirichletFunctor(ax) {} - - public: - inline void operator()(UInt node, Vector<bool> & flags, - Vector<Real> & primal, - const Vector<Real> & coord) const; - }; - - /* ---------------------------------------------------------------------- */ - class FreeBoundary : public DirichletFunctor { - public: - explicit FreeBoundary(Axis ax = _x) : DirichletFunctor(ax) {} - - public: - inline void operator()(UInt node, Vector<bool> & flags, - Vector<Real> & primal, - const Vector<Real> & coord) const; - }; - - /* ---------------------------------------------------------------------- */ - class FixedValue : public DirichletFunctor { - public: - FixedValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {} - - public: - inline void operator()(UInt node, Vector<bool> & flags, - Vector<Real> & primal, - const Vector<Real> & coord) const; - - protected: - Real value; - }; - - /* ---------------------------------------------------------------------- */ - class IncrementValue : public DirichletFunctor { - public: - IncrementValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {} - - public: - inline void operator()(UInt node, Vector<bool> & flags, - Vector<Real> & primal, - const Vector<Real> & coord) const; - - inline void setIncrement(Real val) { this->value = val; } - - protected: - Real value; - }; -} // end namespace Dirichlet - -/* ------------------------------------------------------------------------ */ -/* Neumann */ -/* ------------------------------------------------------------------------ */ -namespace Neumann { - /* ---------------------------------------------------------------------- */ - class NeumannFunctor : public Functor { - - protected: - NeumannFunctor() = default; - - public: - virtual void operator()(const IntegrationPoint & quad_point, - Vector<Real> & dual, const Vector<Real> & coord, - const Vector<Real> & normals) const = 0; - - virtual ~NeumannFunctor() = default; - - public: - static const Type type = _neumann; - }; - - /* ---------------------------------------------------------------------- */ - class FromHigherDim : public NeumannFunctor { - public: - explicit FromHigherDim(const Matrix<Real> & mat) : bc_data(mat) {} - ~FromHigherDim() override = default; - - public: - inline void operator()(const IntegrationPoint & quad_point, - Vector<Real> & dual, const Vector<Real> & coord, - const Vector<Real> & normals) const override; - - protected: - Matrix<Real> bc_data; - }; - - /* ---------------------------------------------------------------------- */ - class FromSameDim : public NeumannFunctor { - public: - explicit FromSameDim(const Vector<Real> & vec) : bc_data(vec) {} - ~FromSameDim() override = default; - - public: - inline void operator()(const IntegrationPoint & quad_point, - Vector<Real> & dual, const Vector<Real> & coord, - const Vector<Real> & normals) const override; - - protected: - Vector<Real> bc_data; - }; - - /* ---------------------------------------------------------------------- */ - class FreeBoundary : public NeumannFunctor { - public: - inline void operator()(const IntegrationPoint & quad_point, - Vector<Real> & dual, const Vector<Real> & coord, - const Vector<Real> & normals) const override; - }; -} // end namespace Neumann + /* ------------------------------------------------------------------------ */ + /* Dirichlet */ + /* ------------------------------------------------------------------------ */ + namespace Dirichlet { + /* ---------------------------------------------------------------------- */ + class DirichletFunctor : public Functor { + protected: + DirichletFunctor() = default; + explicit DirichletFunctor(Axis ax) : axis(ax) {} + + public: + void operator()(__attribute__((unused)) UInt node, + __attribute__((unused)) Vector<bool> & flags, + __attribute__((unused)) Vector<Real> & primal, + __attribute__((unused)) + const Vector<Real> & coord) const { + AKANTU_DEBUG_TO_IMPLEMENT(); + } + + public: + static const Type type = _dirichlet; + + protected: + Axis axis{_x}; + }; + + /* ---------------------------------------------------------------------- */ + class FlagOnly : public DirichletFunctor { + public: + explicit FlagOnly(Axis ax = _x) : DirichletFunctor(ax) {} + + public: + inline void operator()(UInt node, Vector<bool> & flags, + Vector<Real> & primal, + const Vector<Real> & coord) const; + }; + + /* ---------------------------------------------------------------------- */ + class FreeBoundary : public DirichletFunctor { + public: + explicit FreeBoundary(Axis ax = _x) : DirichletFunctor(ax) {} + + public: + inline void operator()(UInt node, Vector<bool> & flags, + Vector<Real> & primal, + const Vector<Real> & coord) const; + }; + + /* ---------------------------------------------------------------------- */ + class FixedValue : public DirichletFunctor { + public: + FixedValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {} + + public: + inline void operator()(UInt node, Vector<bool> & flags, + Vector<Real> & primal, + const Vector<Real> & coord) const; + + protected: + Real value; + }; + + /* ---------------------------------------------------------------------- */ + class IncrementValue : public DirichletFunctor { + public: + IncrementValue(Real val, Axis ax = _x) + : DirichletFunctor(ax), value(val) {} + + public: + inline void operator()(UInt node, Vector<bool> & flags, + Vector<Real> & primal, + const Vector<Real> & coord) const; + + inline void setIncrement(Real val) { this->value = val; } + + protected: + Real value; + }; + + /* ---------------------------------------------------------------------- */ + class Increment : public DirichletFunctor { + public: + explicit Increment(const Vector<Real> & val) + : DirichletFunctor(_x), value(val) {} + + public: + inline void operator()(UInt node, Vector<bool> & flags, + Vector<Real> & primal, + const Vector<Real> & coord) const; + + inline void setIncrement(const Vector<Real> & val) { this->value = val; } + + protected: + Vector<Real> value; + }; + + } // end namespace Dirichlet + + /* ------------------------------------------------------------------------ */ + /* Neumann */ + /* ------------------------------------------------------------------------ */ + namespace Neumann { + /* ---------------------------------------------------------------------- */ + class NeumannFunctor : public Functor { + + protected: + NeumannFunctor() = default; + + public: + virtual void operator()(const IntegrationPoint & quad_point, + Vector<Real> & dual, const Vector<Real> & coord, + const Vector<Real> & normals) const = 0; + + virtual ~NeumannFunctor() = default; + + public: + static const Type type = _neumann; + }; + + /* ---------------------------------------------------------------------- */ + class FromHigherDim : public NeumannFunctor { + public: + explicit FromHigherDim(const Matrix<Real> & mat) : bc_data(mat) {} + ~FromHigherDim() override = default; + + public: + inline void operator()(const IntegrationPoint & quad_point, + Vector<Real> & dual, const Vector<Real> & coord, + const Vector<Real> & normals) const override; + + protected: + Matrix<Real> bc_data; + }; + + /* ---------------------------------------------------------------------- */ + class FromSameDim : public NeumannFunctor { + public: + explicit FromSameDim(const Vector<Real> & vec) : bc_data(vec) {} + ~FromSameDim() override = default; + + public: + inline void operator()(const IntegrationPoint & quad_point, + Vector<Real> & dual, const Vector<Real> & coord, + const Vector<Real> & normals) const override; + + protected: + Vector<Real> bc_data; + }; + + /* ---------------------------------------------------------------------- */ + class FreeBoundary : public NeumannFunctor { + public: + inline void operator()(const IntegrationPoint & quad_point, + Vector<Real> & dual, const Vector<Real> & coord, + const Vector<Real> & normals) const override; + }; + } // end namespace Neumann } // end namespace BC } // akantu #include "boundary_condition_functor_inline_impl.cc" #endif /* __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ */ diff --git a/src/model/boundary_condition_functor_inline_impl.cc b/src/model/boundary_condition_functor_inline_impl.cc index 2d497c547..abe306794 100644 --- a/src/model/boundary_condition_functor_inline_impl.cc +++ b/src/model/boundary_condition_functor_inline_impl.cc @@ -1,144 +1,156 @@ /** * @file boundary_condition_functor_inline_impl.cc * * @author Dana Christen <dana.christen@gmail.com> * * @date creation: Fri May 03 2013 * @date last modification: Thu Oct 15 2015 * * @brief implementation of the BC::Functors * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition_functor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__ #define __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__ /* -------------------------------------------------------------------------- */ #define DIRICHLET_SANITY_CHECK \ AKANTU_DEBUG_ASSERT( \ coord.size() <= flags.size(), \ "The coordinates and flags vectors given to the boundary" \ << " condition functor have different sizes!"); \ AKANTU_DEBUG_ASSERT( \ primal.size() <= coord.size(), \ "The primal vector and coordinates vector given" \ << " to the boundary condition functor have different sizes!"); #define NEUMANN_SANITY_CHECK \ AKANTU_DEBUG_ASSERT( \ coord.size() <= normals.size(), \ "The coordinates and normals vectors given to the" \ << " boundary condition functor have different sizes!"); \ AKANTU_DEBUG_ASSERT( \ dual.size() <= coord.size(), \ "The dual vector and coordinates vector given to" \ << " the boundary condition functor have different sizes!"); namespace akantu { namespace BC { namespace Dirichlet { /* ---------------------------------------------------------------------- */ inline void FlagOnly:: operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, __attribute__((unused)) Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = true; } /* ---------------------------------------------------------------------- */ inline void FreeBoundary:: operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, __attribute__((unused)) Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = false; } /* ---------------------------------------------------------------------- */ inline void FixedValue::operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = true; primal(this->axis) = value; } /* ---------------------------------------------------------------------- */ inline void IncrementValue::operator()(__attribute__((unused)) UInt node, Vector<bool> & flags, Vector<Real> & primal, __attribute__((unused)) const Vector<Real> & coord) const { DIRICHLET_SANITY_CHECK; flags(this->axis) = true; primal(this->axis) += value; } + + /* ---------------------------------------------------------------------- */ + inline void Increment::operator()(__attribute__((unused)) UInt node, + Vector<bool> & flags, + Vector<Real> & primal, + __attribute__((unused)) + const Vector<Real> & coord) const { + DIRICHLET_SANITY_CHECK; + flags.set(true); + primal += value; + } + } // end namespace Dirichlet /* ------------------------------------------------------------------------ */ /* Neumann */ /* ------------------------------------------------------------------------ */ namespace Neumann { /* ---------------------------------------------------------------------- */ inline void FreeBoundary:: operator()(__attribute__((unused)) const IntegrationPoint & quad_point, Vector<Real> & dual, __attribute__((unused)) const Vector<Real> & coord, __attribute__((unused)) const Vector<Real> & normals) const { for (UInt i(0); i < dual.size(); ++i) { dual(i) = 0.0; } } /* ---------------------------------------------------------------------- */ inline void FromHigherDim::operator()(__attribute__((unused)) const IntegrationPoint & quad_point, Vector<Real> & dual, __attribute__((unused)) const Vector<Real> & coord, const Vector<Real> & normals) const { dual.mul<false>(this->bc_data, normals); } /* ---------------------------------------------------------------------- */ inline void FromSameDim:: operator()(__attribute__((unused)) const IntegrationPoint & quad_point, Vector<Real> & dual, __attribute__((unused)) const Vector<Real> & coord, __attribute__((unused)) const Vector<Real> & normals) const { dual = this->bc_data; } } // namespace Neumann } // namespace BC } // namespace akantu #endif /* __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 000762ce9..16058656f 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1553 +1,1554 @@ /** * @file material.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Nov 24 2015 * * @brief Implementation of the common part of the material class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Memory(id, model.getMemoryID()), Parsable(ParserType::_material, id), is_init(false), fem(model.getFEEngine()), finite_deformation(false), name(""), model(model), spatial_dimension(this->model.getSpatialDimension()), element_filter("element_filter", id, this->memory_id), stress("stress", *this), eigengradu("eigen_grad_u", *this), gradu("grad_u", *this), green_strain("green_strain", *this), piola_kirchhoff_2("piola_kirchhoff_2", *this), potential_energy("potential_energy", *this), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse coordinates", *this), interpolation_points_matrices("interpolation points matrices", *this) { AKANTU_DEBUG_IN(); /// for each connectivity types allocate the element filer array of the /// material element_filter.initialize(model.getMesh(), _spatial_dimension = spatial_dimension); // model.getMesh().initElementTypeMapArray(element_filter, 1, // spatial_dimension, // false, _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Memory(id, model.getMemoryID()), Parsable(ParserType::_material, id), - is_init(false), fem(model.getFEEngine()), finite_deformation(false), + is_init(false), fem(fe_engine), finite_deformation(false), name(""), model(model), spatial_dimension(dim), element_filter("element_filter", id, this->memory_id), stress("stress", *this, dim, fe_engine, this->element_filter), eigengradu("eigen_grad_u", *this, dim, fe_engine, this->element_filter), gradu("gradu", *this, dim, fe_engine, this->element_filter), green_strain("green_strain", *this, dim, fe_engine, this->element_filter), - piola_kirchhoff_2("poila_kirchhoff_2", *this, dim, fe_engine, + piola_kirchhoff_2("piola_kirchhoff_2", *this, dim, fe_engine, this->element_filter), potential_energy("potential_energy", *this, dim, fe_engine, this->element_filter), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse_coordinates", *this, dim, fe_engine, this->element_filter), interpolation_points_matrices("interpolation points matrices", *this, dim, fe_engine, this->element_filter) { AKANTU_DEBUG_IN(); element_filter.initialize(mesh, _spatial_dimension = spatial_dimension); // mesh.initElementTypeMapArray(element_filter, 1, spatial_dimension, false, // _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::~Material() = default; /* -------------------------------------------------------------------------- */ void Material::initialize() { registerParam("rho", rho, Real(0.), _pat_parsable | _pat_modifiable, "Density"); registerParam("name", name, std::string(), _pat_parsable | _pat_readable); registerParam("finite_deformation", finite_deformation, false, _pat_parsable | _pat_readable, "Is finite deformation"); registerParam("inelastic_deformation", inelastic_deformation, false, _pat_internal, "Is inelastic deformation"); /// allocate gradu stress for local elements eigengradu.initialize(spatial_dimension * spatial_dimension); gradu.initialize(spatial_dimension * spatial_dimension); stress.initialize(spatial_dimension * spatial_dimension); potential_energy.initialize(1); this->model.registerEventHandler(*this); } /* -------------------------------------------------------------------------- */ void Material::initMaterial() { AKANTU_DEBUG_IN(); if (finite_deformation) { this->piola_kirchhoff_2.initialize(spatial_dimension * spatial_dimension); if (use_previous_stress) this->piola_kirchhoff_2.initializeHistory(); this->green_strain.initialize(spatial_dimension * spatial_dimension); } if (use_previous_stress) this->stress.initializeHistory(); if (use_previous_gradu) this->gradu.initializeHistory(); for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); is_init = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { if (it->second->hasHistory()) it->second->saveCurrentValues(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the residual by assembling @f$\int_{e} \sigma_e \frac{\partial * \varphi}{\partial X} dX @f$ * * @param[in] displacements nodes displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ // void Material::updateResidual(GhostType ghost_type) { // AKANTU_DEBUG_IN(); // computeAllStresses(ghost_type); // assembleResidual(ghost_type); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); if (!finite_deformation) { auto & internal_force = const_cast<Array<Real> &>(model.getInternalForce()); // Mesh & mesh = fem.getMesh(); for (auto && type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by /// @f$\mathbf{B}^t \mathbf{\sigma}_q@f$ Array<Real> * sigma_dphi_dx = new Array<Real>(nb_element * nb_quadrature_points, size_of_shapes_derivatives, "sigma_x_dphi_/_dX"); fem.computeBtD(stress(type, ghost_type), *sigma_dphi_dx, type, ghost_type, elem_filter); // Array<Real> * shapesd_filtered = // new Array<Real>(0, size_of_shapes_derivatives, "filtered shapesd"); // FEEngine::filterElementalData(mesh, shapes_derivatives, // *shapesd_filtered, // *it, ghost_type, elem_filter); // Array<Real> & stress_vect = this->stress(*it, ghost_type); // Array<Real>::matrix_iterator sigma = // stress_vect.begin(spatial_dimension, spatial_dimension); // Array<Real>::matrix_iterator B = // shapesd_filtered->begin(spatial_dimension, nb_nodes_per_element); // Array<Real>::matrix_iterator Bt_sigma_it = // sigma_dphi_dx->begin(spatial_dimension, nb_nodes_per_element); // for (UInt q = 0; q < nb_element * nb_quadrature_points; // ++q, ++sigma, ++B, ++Bt_sigma_it) // Bt_sigma_it->mul<false, false>(*sigma, *B); // delete shapesd_filtered; /** * compute @f$\int \sigma * \frac{\partial \varphi}{\partial X}dX@f$ by * @f$ \sum_q \mathbf{B}^t * \mathbf{\sigma}_q \overline w_q J_q@f$ */ Array<Real> * int_sigma_dphi_dx = new Array<Real>(nb_element, nb_nodes_per_element * spatial_dimension, "int_sigma_x_dphi_/_dX"); fem.integrate(*sigma_dphi_dx, *int_sigma_dphi_dx, size_of_shapes_derivatives, type, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble model.getDOFManager().assembleElementalArrayLocalArray( *int_sigma_dphi_dx, internal_force, type, ghost_type, -1, elem_filter); delete int_sigma_dphi_dx; } } else { switch (spatial_dimension) { case 1: this->assembleInternalForces<1>(ghost_type); break; case 2: this->assembleInternalForces<2>(ghost_type); break; case 3: this->assembleInternalForces<3>(ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stress from the gradu * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (const auto & type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; Array<Real> & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, spatial_dimension, type, ghost_type, elem_filter); gradu_vect -= eigengradu(type, ghost_type); /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$ computeStress(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllCauchyStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(finite_deformation, "The Cauchy stress can only be " "computed if you are working in " "finite deformation."); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { switch (spatial_dimension) { case 1: this->computeCauchyStress<1>(type, ghost_type); break; case 2: this->computeCauchyStress<2>(type, ghost_type); break; case 3: this->computeCauchyStress<3>(type, ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::computeCauchyStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::matrix_iterator gradu_it = this->gradu(el_type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator gradu_end = this->gradu(el_type, ghost_type).end(dim, dim); Array<Real>::matrix_iterator piola_it = this->piola_kirchhoff_2(el_type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator stress_it = this->stress(el_type, ghost_type).begin(dim, dim); Matrix<Real> F_tensor(dim, dim); for (; gradu_it != gradu_end; ++gradu_it, ++piola_it, ++stress_it) { Matrix<Real> & grad_u = *gradu_it; Matrix<Real> & piola = *piola_it; Matrix<Real> & sigma = *stress_it; gradUToF<dim>(grad_u, F_tensor); this->computeCauchyStressOnQuad<dim>(F_tensor, piola, sigma); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::setToSteadyState(GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array<Real> & displacement = model.getDisplacement(); // resizeInternalArray(gradu); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); Array<Real> & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(displacement, gradu_vect, spatial_dimension, type, ghost_type, elem_filter); setToSteadyState(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stiffness matrix by assembling @f$\int_{\omega} B^t \times D * \times B d\omega @f$ * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { if (finite_deformation) { switch (spatial_dimension) { case 1: { assembleStiffnessMatrixNL<1>(type, ghost_type); assembleStiffnessMatrixL2<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrixNL<2>(type, ghost_type); assembleStiffnessMatrixL2<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrixNL<3>(type, ghost_type); assembleStiffnessMatrixL2<3>(type, ghost_type); break; } } } else { switch (spatial_dimension) { case 1: { assembleStiffnessMatrix<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrix<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrix<3>(type, ghost_type); break; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<UInt> & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) { AKANTU_DEBUG_OUT(); return; } // const Array<Real> & shapes_derivatives = // fem.getShapesDerivatives(type, ghost_type); Array<Real> & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array<Real> * tangent_stiffness_matrix = new Array<Real>(nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); // Array<Real> * shapesd_filtered = new Array<Real>( // nb_element, dim * nb_nodes_per_element, "filtered shapesd"); // fem.filterElementalData(fem.getMesh(), shapes_derivatives, // *shapesd_filtered, type, ghost_type, // elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array<Real> * bt_d_b = new Array<Real>(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); - fem.computeBtDB(*tangent_stiffness_matrix, *bt_d_b, 4, type, ghost_type); + fem.computeBtDB(*tangent_stiffness_matrix, *bt_d_b, 4, type, ghost_type, elem_filter); // Matrix<Real> B(tangent_size, dim * nb_nodes_per_element); // Matrix<Real> Bt_D(dim * nb_nodes_per_element, tangent_size); // Array<Real>::matrix_iterator shapes_derivatives_filtered_it = // shapesd_filtered->begin(dim, nb_nodes_per_element); // Array<Real>::matrix_iterator Bt_D_B_it = // bt_d_b->begin(dim * nb_nodes_per_element, dim * nb_nodes_per_element); // Array<Real>::matrix_iterator D_it = // tangent_stiffness_matrix->begin(tangent_size, tangent_size); // Array<Real>::matrix_iterator D_end = // tangent_stiffness_matrix->end(tangent_size, tangent_size); // for (; D_it != D_end; ++D_it, ++Bt_D_B_it, // ++shapes_derivatives_filtered_it) { // Matrix<Real> & D = *D_it; // Matrix<Real> & Bt_D_B = *Bt_D_B_it; // VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( // *shapes_derivatives_filtered_it, B, nb_nodes_per_element); // Bt_D.mul<true, false>(B, D); // Bt_D_B.mul<false, false>(Bt_D, B); // } delete tangent_stiffness_matrix; // delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * K_e = new Array<Real>(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); // Array<Real> & gradu_vect = delta_gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); Array<Real> * shapes_derivatives_filtered = new Array<Real>( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); fem.filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_s_b_size = dim * nb_nodes_per_element; Array<Real> * bt_s_b = new Array<Real>(nb_element * nb_quadrature_points, bt_s_b_size * bt_s_b_size, "B^t*D*B"); UInt piola_matrix_size = getCauchyStressMatrixSize(dim); Matrix<Real> B(piola_matrix_size, bt_s_b_size); Matrix<Real> Bt_S(bt_s_b_size, piola_matrix_size); Matrix<Real> S(piola_matrix_size, piola_matrix_size); auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); auto Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size); auto Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size); auto piola_it = piola_kirchhoff_2(type, ghost_type).begin(dim, dim); for (; Bt_S_B_it != Bt_S_B_end; ++Bt_S_B_it, ++shapes_derivatives_filtered_it, ++piola_it) { auto & Bt_S_B = *Bt_S_B_it; const auto & Piola_kirchhoff_matrix = *piola_it; setCauchyStressMatrix<dim>(Piola_kirchhoff_matrix, S); VoigtHelper<dim>::transferBMatrixToBNL(*shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_S.template mul<true, false>(B, S); Bt_S_B.template mul<false, false>(Bt_S, B); } delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * K_e = new Array<Real>(nb_element, bt_s_b_size * bt_s_b_size, "K_e"); fem.integrate(*bt_s_b, *K_e, bt_s_b_size * bt_s_b_size, type, ghost_type, elem_filter); delete bt_s_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); Array<Real> & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array<Real> * tangent_stiffness_matrix = new Array<Real>(nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); Array<Real> * shapes_derivatives_filtered = new Array<Real>( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); fem.filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array<Real> * bt_d_b = new Array<Real>(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix<Real> B(tangent_size, dim * nb_nodes_per_element); Matrix<Real> B2(tangent_size, dim * nb_nodes_per_element); Matrix<Real> Bt_D(dim * nb_nodes_per_element, tangent_size); auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); auto Bt_D_B_it = bt_d_b->begin(bt_d_b_size, bt_d_b_size); auto grad_u_it = gradu_vect.begin(dim, dim); auto D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); auto D_end = tangent_stiffness_matrix->end(tangent_size, tangent_size); for (; D_it != D_end; ++D_it, ++Bt_D_B_it, ++shapes_derivatives_filtered_it, ++grad_u_it) { const auto & grad_u = *grad_u_it; const auto & D = *D_it; auto & Bt_D_B = *Bt_D_B_it; // transferBMatrixToBL1<dim > (*shapes_derivatives_filtered_it, B, // nb_nodes_per_element); VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); VoigtHelper<dim>::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2, nb_nodes_per_element); B += B2; Bt_D.template mul<true, false>(B, D); Bt_D_B.template mul<false, false>(Bt_D, B); } delete tangent_stiffness_matrix; delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * K_e = new Array<Real>(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real> & internal_force = model.getInternalForce(); Mesh & mesh = fem.getMesh(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { const Array<Real> & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); Array<Real> * shapesd_filtered = new Array<Real>( nb_element, size_of_shapes_derivatives, "filtered shapesd"); fem.filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); // Set stress vectors UInt stress_size = getTangentStiffnessVoigtSize(dim); // Set matrices B and BNL* UInt bt_s_size = dim * nb_nodes_per_element; auto * bt_s = new Array<Real>(nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); auto grad_u_it = this->gradu(type, ghost_type).begin(dim, dim); auto grad_u_end = this->gradu(type, ghost_type).end(dim, dim); auto stress_it = this->piola_kirchhoff_2(type, ghost_type).begin(dim, dim); shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator bt_s_it = bt_s->begin(bt_s_size, 1); Matrix<Real> S_vect(stress_size, 1); Matrix<Real> B_tensor(stress_size, bt_s_size); Matrix<Real> B2_tensor(stress_size, bt_s_size); for (; grad_u_it != grad_u_end; ++grad_u_it, ++stress_it, ++shapes_derivatives_filtered_it, ++bt_s_it) { auto & grad_u = *grad_u_it; auto & r_it = *bt_s_it; auto & S_it = *stress_it; setCauchyStressArray<dim>(S_it, S_vect); VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B_tensor, nb_nodes_per_element); VoigtHelper<dim>::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2_tensor, nb_nodes_per_element); B_tensor += B2_tensor; r_it.template mul<true, false>(B_tensor, S_vect); } delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array<Real> * r_e = new Array<Real>(nb_element, bt_s_size, "r_e"); fem.integrate(*bt_s, *r_e, bt_s_size, type, ghost_type, elem_filter); delete bt_s; model.getDOFManager().assembleElementalArrayLocalArray( *r_e, internal_force, type, ghost_type, -1., elem_filter); delete r_e; } AKANTU_DEBUG_OUT(); } // /* -------------------------------------------------------------------------- */ // void Material::computeAllStressesFromTangentModuli(GhostType ghost_type) { // AKANTU_DEBUG_IN(); // UInt spatial_dimension = model.getSpatialDimension(); // for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { // switch (spatial_dimension) { // case 1: { // computeAllStressesFromTangentModuli<1>(type, ghost_type); // break; // } // case 2: { // computeAllStressesFromTangentModuli<2>(type, ghost_type); // break; // } // case 3: { // computeAllStressesFromTangentModuli<3>(type, ghost_type); // break; // } // } // } // AKANTU_DEBUG_OUT(); // } // /* -------------------------------------------------------------------------- */ // template <UInt dim> // void Material::computeAllStressesFromTangentModuli(const ElementType & type, // GhostType ghost_type) { // AKANTU_DEBUG_IN(); // const Array<Real> & shapes_derivatives = // fem.getShapesDerivatives(type, ghost_type); // Array<UInt> & elem_filter = element_filter(type, ghost_type); // Array<Real> & gradu_vect = gradu(type, ghost_type); // UInt nb_element = elem_filter.size(); // if (nb_element) { // UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); // UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); // gradu_vect.resize(nb_quadrature_points * nb_element); // Array<Real> & disp = model.getDisplacement(); // fem.gradientOnIntegrationPoints(disp, gradu_vect, dim, type, ghost_type, // elem_filter); // UInt tangent_moduli_size = getTangentStiffnessVoigtSize(dim); // Array<Real> * tangent_moduli_tensors = new Array<Real>( // nb_element * nb_quadrature_points, // tangent_moduli_size * tangent_moduli_size, "tangent_moduli_tensors"); // tangent_moduli_tensors->clear(); // computeTangentModuli(type, *tangent_moduli_tensors, ghost_type); // Array<Real> * shapesd_filtered = new Array<Real>( // nb_element, dim * nb_nodes_per_element, "filtered shapesd"); // FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, // *shapesd_filtered, type, ghost_type, // elem_filter); // Array<Real> filtered_u(nb_element, // nb_nodes_per_element * spatial_dimension); // fem.extractNodalToElementField(fem.getMesh(), disp, filtered_u, type, // ghost_type, elem_filter); // /// compute @f$\mathbf{D} \mathbf{B} \mathbf{u}@f$ // auto shapes_derivatives_filtered_it = // shapesd_filtered->begin(dim, nb_nodes_per_element); // auto D_it = // tangent_moduli_tensors->begin(tangent_moduli_size, tangent_moduli_size); // auto sigma_it = // stress(type, ghost_type).begin(spatial_dimension, spatial_dimension); // auto u_it = filtered_u.begin(spatial_dimension * nb_nodes_per_element); // Matrix<Real> B(tangent_moduli_size, // spatial_dimension * nb_nodes_per_element); // Vector<Real> Bu(tangent_moduli_size); // Vector<Real> DBu(tangent_moduli_size); // for (UInt e = 0; e < nb_element; ++e, ++u_it) { // for (UInt q = 0; q < nb_quadrature_points; // ++q, ++D_it, ++shapes_derivatives_filtered_it, ++sigma_it) { // const auto & u = *u_it; // const auto & D = *D_it; // auto & sigma = *sigma_it; // VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix( // *shapes_derivatives_filtered_it, B, nb_nodes_per_element); // Bu.mul<false>(B, u); // DBu.mul<false>(D, Bu); // // Voigt notation to full symmetric tensor // for (UInt i = 0; i < dim; ++i) // sigma(i, i) = DBu(i); // if (dim == 2) { // sigma(0, 1) = sigma(1, 0) = DBu(2); // } else if (dim == 3) { // sigma(1, 2) = sigma(2, 1) = DBu(3); // sigma(0, 2) = sigma(2, 0) = DBu(4); // sigma(0, 1) = sigma(1, 0) = DBu(5); // } // } // } // } // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergyByElements() { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { computePotentialEnergy(type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergy(ElementType, GhostType) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real epot = 0.; computePotentialEnergyByElements(); /// integrate the potential energy for each type of elements for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { epot += fem.integrate(potential_energy(type, _not_ghost), type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy(ElementType & type, UInt index) { AKANTU_DEBUG_IN(); Real epot = 0.; Vector<Real> epot_on_quad_points(fem.getNbIntegrationPoints(type)); computePotentialEnergyByElement(type, index, epot_on_quad_points); epot = fem.integrate(epot_on_quad_points, type, element_filter(type)(index)); AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(const std::string & type) { AKANTU_DEBUG_IN(); if (type == "potential") return getPotentialEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(const std::string & energy_id, ElementType type, UInt index) { AKANTU_DEBUG_IN(); if (energy_id == "potential") return getPotentialEnergy(type, index); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ void Material::initElementalFieldInterpolation( const ElementTypeMapArray<Real> & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); this->fem.initElementalFieldInterpolationFromIntegrationPoints( interpolation_points_coordinates, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, &(this->element_filter)); + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(ElementTypeMapArray<Real> & result, const GhostType ghost_type) { this->fem.interpolateElementalFieldFromIntegrationPoints( this->stress, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, result, ghost_type, &(this->element_filter)); } /* -------------------------------------------------------------------------- */ void Material::interpolateStressOnFacets( ElementTypeMapArray<Real> & result, ElementTypeMapArray<Real> & by_elem_result, const GhostType ghost_type) { interpolateStress(by_elem_result, ghost_type); UInt stress_size = this->stress.getNbComponent(); const Mesh & mesh = this->model.getMesh(); const Mesh & mesh_facets = mesh.getMeshFacets(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array<UInt> & elem_fil = element_filter(type, ghost_type); Array<Real> & by_elem_res = by_elem_result(type, ghost_type); UInt nb_element = elem_fil.size(); UInt nb_element_full = this->model.getMesh().getNbElement(type, ghost_type); UInt nb_interpolation_points_per_elem = by_elem_res.size() / nb_element_full; const Array<Element> & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); UInt nb_quad_per_facet = nb_interpolation_points_per_elem / nb_facet_per_elem; Element element_for_comparison{type, 0, ghost_type}; const Array<std::vector<Element>> * element_to_facet = nullptr; GhostType current_ghost_type = _casper; Array<Real> * result_vec = nullptr; Array<Real>::const_matrix_iterator result_it = by_elem_res.begin_reinterpret( stress_size, nb_interpolation_points_per_elem, nb_element_full); for (UInt el = 0; el < nb_element; ++el) { UInt global_el = elem_fil(el); element_for_comparison.element = global_el; for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element facet_elem = facet_to_element(global_el, f); UInt global_facet = facet_elem.element; if (facet_elem.ghost_type != current_ghost_type) { current_ghost_type = facet_elem.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( type_facet, current_ghost_type); result_vec = &result(type_facet, current_ghost_type); } bool is_second_element = (*element_to_facet)(global_facet)[0] != element_for_comparison; for (UInt q = 0; q < nb_quad_per_facet; ++q) { Vector<Real> result_local(result_vec->storage() + (global_facet * nb_quad_per_facet + q) * result_vec->getNbComponent() + is_second_element * stress_size, stress_size); const Matrix<Real> & result_tmp(result_it[global_el]); result_local = result_tmp(f * nb_quad_per_facet + q); } } } } } /* -------------------------------------------------------------------------- */ template <typename T> const Array<T> & Material::getArray(__attribute__((unused)) const ID & vect_id, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <typename T> Array<T> & Material::getArray(__attribute__((unused)) const ID & vect_id, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <> const Array<Real> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<Real>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> Array<Real> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<Real>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> const Array<UInt> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<UInt>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> Array<UInt> & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray<UInt>(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <typename T> const InternalField<T> & Material::getInternal(__attribute__((unused)) const ID & int_id) const { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <typename T> InternalField<T> & Material::getInternal(__attribute__((unused)) const ID & int_id) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <> const InternalField<Real> & Material::getInternal(const ID & int_id) const { auto it = internal_vectors_real.find(getID() + ":" + int_id); if (it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> InternalField<Real> & Material::getInternal(const ID & int_id) { auto it = internal_vectors_real.find(getID() + ":" + int_id); if (it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> const InternalField<UInt> & Material::getInternal(const ID & int_id) const { auto it = internal_vectors_uint.find(getID() + ":" + int_id); if (it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> InternalField<UInt> & Material::getInternal(const ID & int_id) { auto it = internal_vectors_uint.find(getID() + ":" + int_id); if (it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ void Material::addElements(const Array<Element> & elements_to_add) { AKANTU_DEBUG_IN(); UInt mat_id = model.getInternalIndexFromID(getID()); Array<Element>::const_iterator<Element> el_begin = elements_to_add.begin(); Array<Element>::const_iterator<Element> el_end = elements_to_add.end(); for (; el_begin != el_end; ++el_begin) { const Element & element = *el_begin; Array<UInt> & mat_indexes = model.getMaterialByElement(element.type, element.ghost_type); Array<UInt> & mat_loc_num = model.getMaterialLocalNumbering(element.type, element.ghost_type); UInt index = this->addElement(element.type, element.element, element.ghost_type); mat_indexes(element.element) = mat_id; mat_loc_num(element.element) = index; } this->resizeInternals(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::removeElements(const Array<Element> & elements_to_remove) { AKANTU_DEBUG_IN(); Array<Element>::const_iterator<Element> el_begin = elements_to_remove.begin(); Array<Element>::const_iterator<Element> el_end = elements_to_remove.end(); if (el_begin == el_end) return; ElementTypeMapArray<UInt> material_local_new_numbering( "remove mat filter elem", getID(), getMemoryID()); Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; element.ghost_type = ghost_type; ElementTypeMapArray<UInt>::type_iterator it = element_filter.firstType(_all_dimensions, ghost_type, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = element_filter.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; element.type = type; Array<UInt> & elem_filter = this->element_filter(type, ghost_type); Array<UInt> & mat_loc_num = this->model.getMaterialLocalNumbering(type, ghost_type); if (!material_local_new_numbering.exists(type, ghost_type)) material_local_new_numbering.alloc(elem_filter.size(), 1, type, ghost_type); Array<UInt> & mat_renumbering = material_local_new_numbering(type, ghost_type); UInt nb_element = elem_filter.size(); Array<UInt> elem_filter_tmp; UInt new_id = 0; for (UInt el = 0; el < nb_element; ++el) { element.element = elem_filter(el); if (std::find(el_begin, el_end, element) == el_end) { elem_filter_tmp.push_back(element.element); mat_renumbering(el) = new_id; mat_loc_num(element.element) = new_id; ++new_id; } else { mat_renumbering(el) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.size()); elem_filter.copy(elem_filter_tmp); } } for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::resizeInternals() { AKANTU_DEBUG_IN(); for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::onElementsAdded(const Array<Element> &, const NewElementsEvent &) { this->resizeInternals(); } /* -------------------------------------------------------------------------- */ void Material::onElementsRemoved( const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { UInt my_num = model.getInternalIndexFromID(getID()); ElementTypeMapArray<UInt> material_local_new_numbering( "remove mat filter elem", getID(), getMemoryID()); Array<Element>::const_iterator<Element> el_begin = element_list.begin(); Array<Element>::const_iterator<Element> el_end = element_list.end(); for (ghost_type_t::iterator g = ghost_type_t::begin(); g != ghost_type_t::end(); ++g) { GhostType gt = *g; ElementTypeMapArray<UInt>::type_iterator it = new_numbering.firstType(_all_dimensions, gt, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = new_numbering.lastType(_all_dimensions, gt, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; if (element_filter.exists(type, gt) && element_filter(type, gt).size()) { Array<UInt> & elem_filter = element_filter(type, gt); Array<UInt> & mat_indexes = this->model.getMaterialByElement(*it, gt); Array<UInt> & mat_loc_num = this->model.getMaterialLocalNumbering(*it, gt); UInt nb_element = this->model.getMesh().getNbElement(type, gt); // all materials will resize of the same size... mat_indexes.resize(nb_element); mat_loc_num.resize(nb_element); if (!material_local_new_numbering.exists(type, gt)) material_local_new_numbering.alloc(elem_filter.size(), 1, type, gt); Array<UInt> & mat_renumbering = material_local_new_numbering(type, gt); const Array<UInt> & renumbering = new_numbering(type, gt); Array<UInt> elem_filter_tmp; UInt ni = 0; Element el{type, 0, gt}; for (UInt i = 0; i < elem_filter.size(); ++i) { el.element = elem_filter(i); if (std::find(el_begin, el_end, el) == el_end) { UInt new_el = renumbering(el.element); AKANTU_DEBUG_ASSERT( new_el != UInt(-1), "A not removed element as been badly renumbered"); elem_filter_tmp.push_back(new_el); mat_renumbering(i) = ni; mat_indexes(new_el) = my_num; mat_loc_num(new_el) = ni; ++ni; } else { mat_renumbering(i) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.size()); elem_filter.copy(elem_filter_tmp); } } } for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); } /* -------------------------------------------------------------------------- */ void Material::beforeSolveStep() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::afterSolveStep() { for (auto & type : element_filter.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { this->updateEnergies(type, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDamageIteration() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::onDamageUpdate() { ElementTypeMapArray<UInt>::type_iterator it = this->element_filter.firstType( _all_dimensions, _not_ghost, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = element_filter.lastType(_all_dimensions, _not_ghost, _ek_not_defined); for (; it != end; ++it) { this->updateEnergiesAfterDamage(*it, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDump() { if (this->isFiniteDeformation()) this->computeAllCauchyStresses(_not_ghost); } /* -------------------------------------------------------------------------- */ void Material::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; std::string type = getID().substr(getID().find_last_of(':') + 1); stream << space << "Material " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /// extrapolate internal values void Material::extrapolateInternal(const ID & id, const Element & element, __attribute__((unused)) const Matrix<Real> & point, Matrix<Real> & extrapolated) { if (this->isInternal<Real>(id, element.kind())) { UInt nb_element = this->element_filter(element.type, element.ghost_type).size(); const ID name = this->getID() + ":" + id; UInt nb_quads = this->internal_vectors_real[name]->getFEEngine().getNbIntegrationPoints( element.type, element.ghost_type); const Array<Real> & internal = this->getArray<Real>(id, element.type, element.ghost_type); UInt nb_component = internal.getNbComponent(); Array<Real>::const_matrix_iterator internal_it = internal.begin_reinterpret(nb_component, nb_quads, nb_element); Element local_element = this->convertToLocalElement(element); /// instead of really extrapolating, here the value of the first GP /// is copied into the result vector. This works only for linear /// elements /// @todo extrapolate!!!! AKANTU_DEBUG_WARNING("This is a fix, values are not truly extrapolated"); const Matrix<Real> & values = internal_it[local_element.element]; UInt index = 0; Vector<Real> tmp(nb_component); for (UInt j = 0; j < values.cols(); ++j) { tmp = values(j); if (tmp.norm() > 0) { index = j; break; } } for (UInt i = 0; i < extrapolated.size(); ++i) { extrapolated(i) = values(index); } } else { Matrix<Real> default_values(extrapolated.rows(), extrapolated.cols(), 0.); extrapolated = default_values; } } /* -------------------------------------------------------------------------- */ void Material::applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u, const GhostType ghost_type) { for (auto && type : element_filter.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { if (!element_filter(type, ghost_type).size()) continue; auto eigen_it = this->eigengradu(type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto eigen_end = this->eigengradu(type, ghost_type) .end(spatial_dimension, spatial_dimension); for (; eigen_it != eigen_end; ++eigen_it) { auto & current_eigengradu = *eigen_it; current_eigengradu = prescribed_eigen_grad_u; } } } } // namespace akantu diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh index 0a0505dee..a3f68b552 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,681 +1,683 @@ + /** * @file material.hh * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Wed Nov 25 2015 * * @brief Mother class for all materials * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "aka_voigthelper.hh" #include "data_accessor.hh" #include "integration_point.hh" #include "parsable.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ #include "internal_field.hh" #include "random_internal_field.hh" /* -------------------------------------------------------------------------- */ #include "mesh_events.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_HH__ #define __AKANTU_MATERIAL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Model; class SolidMechanicsModel; } // namespace akantu namespace akantu { /** * Interface of all materials * Prerequisites for a new material * - inherit from this class * - implement the following methods: * \code * virtual Real getStableTimeStep(Real h, const Element & element = * ElementNull); * * virtual void computeStress(ElementType el_type, * GhostType ghost_type = _not_ghost); * * virtual void computeTangentStiffness(const ElementType & el_type, * Array<Real> & tangent_matrix, * GhostType ghost_type = _not_ghost); * \endcode * */ class Material : public Memory, public DataAccessor<Element>, public Parsable, public MeshEventHandler, protected SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: #if __cplusplus > 199711L Material(const Material & mat) = delete; Material & operator=(const Material & mat) = delete; #endif /// Initialize material with defaults Material(SolidMechanicsModel & model, const ID & id = ""); /// Initialize material with custom mesh & fe_engine Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); /// Destructor ~Material() override; protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Function that materials can/should reimplement */ /* ------------------------------------------------------------------------ */ protected: /// constitutive law virtual void computeStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the tangent stiffness matrix virtual void computeTangentModuli(__attribute__((unused)) const ElementType & el_type, __attribute__((unused)) Array<Real> & tangent_matrix, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the potential energy virtual void computePotentialEnergy(ElementType el_type, GhostType ghost_type = _not_ghost); /// compute the potential energy for an element virtual void computePotentialEnergyByElement(__attribute__((unused)) ElementType type, __attribute__((unused)) UInt index, __attribute__((unused)) Vector<Real> & epot_on_quad_points) { AKANTU_DEBUG_TO_IMPLEMENT(); } virtual void updateEnergies(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} virtual void updateEnergiesAfterDamage(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} /// set the material to steady state (to be implemented for materials that /// need it) virtual void setToSteadyState(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} /// function called to update the internal parameters when the modifiable /// parameters are modified virtual void updateInternalParameters() {} public: /// extrapolate internal values virtual void extrapolateInternal(const ID & id, const Element & element, const Matrix<Real> & points, Matrix<Real> & extrapolated); /// compute the p-wave speed in the material virtual Real getPushWaveSpeed(__attribute__((unused)) const Element & element) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the s-wave speed in the material virtual Real getShearWaveSpeed(__attribute__((unused)) const Element & element) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// get a material celerity to compute the stable time step (default: is the /// push wave speed) virtual Real getCelerity(const Element & element) const { return getPushWaveSpeed(element); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template <typename T> void registerInternal(__attribute__((unused)) InternalField<T> & vect) { AKANTU_DEBUG_TO_IMPLEMENT(); } template <typename T> void unregisterInternal(__attribute__((unused)) InternalField<T> & vect) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// initialize the material computed parameter virtual void initMaterial(); /// compute the residual for this material // virtual void updateResidual(GhostType ghost_type = _not_ghost); /// assemble the residual for this material virtual void assembleInternalForces(GhostType ghost_type); /// save the stress in the previous_stress if needed virtual void savePreviousState(); /// compute the stresses for this material virtual void computeAllStresses(GhostType ghost_type = _not_ghost); // virtual void // computeAllStressesFromTangentModuli(GhostType ghost_type = _not_ghost); virtual void computeAllCauchyStresses(GhostType ghost_type = _not_ghost); /// set material to steady state void setToSteadyState(GhostType ghost_type = _not_ghost); /// compute the stiffness matrix virtual void assembleStiffnessMatrix(GhostType ghost_type); /// add an element to the local mesh filter inline UInt addElement(const ElementType & type, UInt element, const GhostType & ghost_type); inline UInt addElement(const Element & element); /// add many elements at once void addElements(const Array<Element> & elements_to_add); /// remove many element at once void removeElements(const Array<Element> & elements_to_remove); /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override; /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points */ void interpolateStress(ElementTypeMapArray<Real> & result, const GhostType ghost_type = _not_ghost); /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points and store the * results per facet */ void interpolateStressOnFacets(ElementTypeMapArray<Real> & result, ElementTypeMapArray<Real> & by_elem_result, const GhostType ghost_type = _not_ghost); /** * function to initialize the elemental field interpolation * function by inverting the quadrature points' coordinates */ void initElementalFieldInterpolation( const ElementTypeMapArray<Real> & interpolation_points_coordinates); /* ------------------------------------------------------------------------ */ /* Common part */ /* ------------------------------------------------------------------------ */ protected: /* ------------------------------------------------------------------------ */ inline UInt getTangentStiffnessVoigtSize(UInt spatial_dimension) const; /// compute the potential energy by element void computePotentialEnergyByElements(); /// resize the intenals arrays virtual void resizeInternals(); /* ------------------------------------------------------------------------ */ /* Finite deformation functions */ /* This functions area implementing what is described in the paper of Bathe */ /* et al, in IJNME, Finite Element Formulations For Large Deformation */ /* Dynamic Analysis, Vol 9, 353-386, 1975 */ /* ------------------------------------------------------------------------ */ protected: /// assemble the residual template <UInt dim> void assembleInternalForces(GhostType ghost_type); /// Computation of Cauchy stress tensor in the case of finite deformation from /// the 2nd Piola-Kirchhoff for a given element type template <UInt dim> void computeCauchyStress(ElementType el_type, GhostType ghost_type = _not_ghost); /// Computation the Cauchy stress the 2nd Piola-Kirchhoff and the deformation /// gradient template <UInt dim> inline void computeCauchyStressOnQuad(const Matrix<Real> & F, const Matrix<Real> & S, Matrix<Real> & cauchy, const Real & C33 = 1.0) const; template <UInt dim> void computeAllStressesFromTangentModuli(const ElementType & type, GhostType ghost_type); template <UInt dim> void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// assembling in finite deformation template <UInt dim> void assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type); template <UInt dim> void assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type); /// Size of the Stress matrix for the case of finite deformation see: Bathe et /// al, IJNME, Vol 9, 353-386, 1975 inline UInt getCauchyStressMatrixSize(UInt spatial_dimension) const; /// Sets the stress matrix according to Bathe et al, IJNME, Vol 9, 353-386, /// 1975 template <UInt dim> inline void setCauchyStressMatrix(const Matrix<Real> & S_t, Matrix<Real> & sigma); /// write the stress tensor in the Voigt notation. template <UInt dim> inline void setCauchyStressArray(const Matrix<Real> & S_t, Matrix<Real> & sigma_voight); /* ------------------------------------------------------------------------ */ /* Conversion functions */ /* ------------------------------------------------------------------------ */ public: template <UInt dim> static inline void gradUToF(const Matrix<Real> & grad_u, Matrix<Real> & F); static inline void rightCauchy(const Matrix<Real> & F, Matrix<Real> & C); static inline void leftCauchy(const Matrix<Real> & F, Matrix<Real> & B); template <UInt dim> static inline void gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon); template <UInt dim> static inline void gradUToGreenStrain(const Matrix<Real> & grad_u, Matrix<Real> & epsilon); static inline Real stressToVonMises(const Matrix<Real> & stress); protected: /// converts global element to local element inline Element convertToLocalElement(const Element & global_element) const; /// converts local element to global element inline Element convertToGlobalElement(const Element & local_element) const; /// converts global quadrature point to local quadrature point inline IntegrationPoint convertToLocalPoint(const IntegrationPoint & global_point) const; /// converts local quadrature point to global quadrature point inline IntegrationPoint convertToGlobalPoint(const IntegrationPoint & local_point) const; /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; template <typename T> inline void packElementDataHelper(const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id = ID()) const; template <typename T> inline void unpackElementDataHelper(ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id = ID()); /* ------------------------------------------------------------------------ */ /* MeshEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) override{}; void onNodesRemoved(const Array<UInt> &, const Array<UInt> &, const RemovedNodesEvent &) override{}; void onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) override; void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; void onElementsChanged(const Array<Element> &, const Array<Element> &, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) override{}; /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void beforeSolveStep(); virtual void afterSolveStep(); void onDamageIteration() override; void onDamageUpdate() override; void onDump() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Name, name, const std::string &); AKANTU_GET_MACRO(Model, model, const SolidMechanicsModel &) AKANTU_GET_MACRO(ID, Memory::getID(), const ID &); AKANTU_GET_MACRO(Rho, rho, Real); AKANTU_SET_MACRO(Rho, rho, Real); AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// return the potential energy for the subset of elements contained by the /// material Real getPotentialEnergy(); /// return the potential energy for the provided element Real getPotentialEnergy(ElementType & type, UInt index); /// return the energy (identified by id) for the subset of elements contained /// by the material virtual Real getEnergy(const std::string & energy_id); /// return the energy (identified by id) for the provided element virtual Real getEnergy(const std::string & energy_id, ElementType type, UInt index); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementFilter, element_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(GradU, gradu, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PotentialEnergy, potential_energy, Real); AKANTU_GET_MACRO(GradU, gradu, const ElementTypeMapArray<Real> &); AKANTU_GET_MACRO(Stress, stress, const ElementTypeMapArray<Real> &); AKANTU_GET_MACRO(ElementFilter, element_filter, const ElementTypeMapArray<UInt> &); AKANTU_GET_MACRO(FEEngine, fem, FEEngine &); bool isNonLocal() const { return is_non_local; } template <typename T> const Array<T> & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; template <typename T> Array<T> & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost); template <typename T> const InternalField<T> & getInternal(const ID & id) const; template <typename T> InternalField<T> & getInternal(const ID & id); template <typename T> inline bool isInternal(const ID & id, const ElementKind & element_kind) const; template <typename T> ElementTypeMap<UInt> getInternalDataPerElem(const ID & id, const ElementKind & element_kind) const; bool isFiniteDeformation() const { return finite_deformation; } bool isInelasticDeformation() const { return inelastic_deformation; } template <typename T> inline void setParam(const ID & param, T value); + template <typename T> inline void setParamNoUpdate(const ID & param, T value); inline const Parameter & getParam(const ID & param) const; template <typename T> void flattenInternal(const std::string & field_id, ElementTypeMapArray<T> & internal_flat, const GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) const; /// apply a constant eigengrad_u everywhere in the material virtual void applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u, const GhostType = _not_ghost); /// specify if the matrix need to be recomputed for this material virtual bool hasStiffnessMatrixChanged() { return true; } protected: bool isInit() const { return is_init; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// boolean to know if the material has been initialized bool is_init; std::map<ID, InternalField<Real> *> internal_vectors_real; std::map<ID, InternalField<UInt> *> internal_vectors_uint; std::map<ID, InternalField<bool> *> internal_vectors_bool; protected: /// Link to the fem object in the model FEEngine & fem; /// Finite deformation bool finite_deformation; /// Finite deformation bool inelastic_deformation; /// material name std::string name; /// The model to witch the material belong SolidMechanicsModel & model; /// density : rho Real rho; /// spatial dimension UInt spatial_dimension; /// list of element handled by the material ElementTypeMapArray<UInt> element_filter; /// stresses arrays ordered by element types InternalField<Real> stress; /// eigengrad_u arrays ordered by element types InternalField<Real> eigengradu; /// grad_u arrays ordered by element types InternalField<Real> gradu; /// Green Lagrange strain (Finite deformation) InternalField<Real> green_strain; /// Second Piola-Kirchhoff stress tensor arrays ordered by element types /// (Finite deformation) InternalField<Real> piola_kirchhoff_2; /// potential energy by element InternalField<Real> potential_energy; /// tell if using in non local mode or not bool is_non_local; /// tell if the material need the previous stress state bool use_previous_stress; /// tell if the material need the previous strain state bool use_previous_gradu; /// elemental field interpolation coordinates InternalField<Real> interpolation_inverse_coordinates; /// elemental field interpolation points InternalField<Real> interpolation_points_matrices; /// vector that contains the names of all the internals that need to /// be transferred when material interfaces move std::vector<ID> internals_to_transfer; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Material & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "material_inline_impl.cc" #include "internal_field_tmpl.hh" #include "random_internal_field_tmpl.hh" /* -------------------------------------------------------------------------- */ /* Auto loop */ /* -------------------------------------------------------------------------- */ /// This can be used to automatically write the loop on quadrature points in /// functions such as computeStress. This macro in addition to write the loop /// provides two tensors (matrices) sigma and grad_u #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type) \ Array<Real>::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ Array<Real>::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type) \ .end(this->spatial_dimension, this->spatial_dimension); \ \ this->stress(el_type, ghost_type) \ .resize(this->gradu(el_type, ghost_type).size()); \ \ Array<Real>::iterator<Matrix<Real>> stress_it = \ this->stress(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ \ if (this->isFiniteDeformation()) { \ this->piola_kirchhoff_2(el_type, ghost_type) \ .resize(this->gradu(el_type, ghost_type).size()); \ stress_it = this->piola_kirchhoff_2(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ } \ \ for (; gradu_it != gradu_end; ++gradu_it, ++stress_it) { \ Matrix<Real> & __attribute__((unused)) grad_u = *gradu_it; \ Matrix<Real> & __attribute__((unused)) sigma = *stress_it #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END } /// This can be used to automatically write the loop on quadrature points in /// functions such as computeTangentModuli. This macro in addition to write the /// loop provides two tensors (matrices) sigma_tensor, grad_u, and a matrix /// where the elemental tangent moduli should be stored in Voigt Notation #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_mat) \ Array<Real>::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ Array<Real>::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type) \ .end(this->spatial_dimension, this->spatial_dimension); \ Array<Real>::matrix_iterator sigma_it = \ this->stress(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ \ tangent_mat.resize(this->gradu(el_type, ghost_type).size()); \ \ UInt tangent_size = \ this->getTangentStiffnessVoigtSize(this->spatial_dimension); \ Array<Real>::matrix_iterator tangent_it = \ tangent_mat.begin(tangent_size, tangent_size); \ \ for (; gradu_it != gradu_end; ++gradu_it, ++sigma_it, ++tangent_it) { \ Matrix<Real> & __attribute__((unused)) grad_u = *gradu_it; \ Matrix<Real> & __attribute__((unused)) sigma_tensor = *sigma_it; \ Matrix<Real> & tangent = *tangent_it #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END } /* -------------------------------------------------------------------------- */ namespace akantu { using MaterialFactory = Factory<Material, ID, UInt, const ID &, SolidMechanicsModel &, const ID &>; } // namespace akantu #define INSTANTIATE_MATERIAL_ONLY(mat_name) \ template class mat_name<1>; \ template class mat_name<2>; \ template class mat_name<3> #define MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name) \ [](UInt dim, const ID &, SolidMechanicsModel & model, \ const ID & id) -> std::unique_ptr<Material> { \ switch (dim) { \ case 1: \ return std::make_unique<mat_name<1>>(model, id); \ case 2: \ return std::make_unique<mat_name<2>>(model, id); \ case 3: \ return std::make_unique<mat_name<3>>(model, id); \ default: \ AKANTU_EXCEPTION("The dimension " \ << dim << "is not a valid dimension for the material " \ << #id); \ } \ } #define INSTANTIATE_MATERIAL(id, mat_name) \ INSTANTIATE_MATERIAL_ONLY(mat_name); \ static bool material_is_alocated_##id [[gnu::unused]] = \ MaterialFactory::getInstance().registerAllocator( \ #id, MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name)) #endif /* __AKANTU_MATERIAL_HH__ */ diff --git a/src/model/solid_mechanics/material_inline_impl.cc b/src/model/solid_mechanics/material_inline_impl.cc index f6141480e..1f6d1c0dd 100644 --- a/src/model/solid_mechanics/material_inline_impl.cc +++ b/src/model/solid_mechanics/material_inline_impl.cc @@ -1,463 +1,475 @@ /** * @file material_inline_impl.cc * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of the inline functions of the class material * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const ElementType & type, UInt element, const GhostType & ghost_type) { Array<UInt> & el_filter = this->element_filter(type, ghost_type); el_filter.push_back(element); return el_filter.size() - 1; } /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const Element & element) { return this->addElement(element.type, element.element, element.ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Material::getTangentStiffnessVoigtSize(UInt dim) const { return (dim * (dim - 1) / 2 + dim); } /* -------------------------------------------------------------------------- */ inline UInt Material::getCauchyStressMatrixSize(UInt dim) const { return (dim * dim); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToF(const Matrix<Real> & grad_u, Matrix<Real> & F) { AKANTU_DEBUG_ASSERT(F.size() >= grad_u.size() && grad_u.size() == dim * dim, "The dimension of the tensor F should be greater or " "equal to the dimension of the tensor grad_u."); F.eye(); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) F(i, j) += grad_u(i, j); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::computeCauchyStressOnQuad(const Matrix<Real> & F, const Matrix<Real> & piola, Matrix<Real> & sigma, const Real & C33) const { Real J = F.det() * sqrt(C33); Matrix<Real> F_S(dim, dim); F_S.mul<false, false>(F, piola); Real constant = J ? 1. / J : 0; sigma.mul<false, true>(F_S, F, constant); } /* -------------------------------------------------------------------------- */ inline void Material::rightCauchy(const Matrix<Real> & F, Matrix<Real> & C) { C.mul<true, false>(F, F); } /* -------------------------------------------------------------------------- */ inline void Material::leftCauchy(const Matrix<Real> & F, Matrix<Real> & B) { B.mul<false, true>(F, F); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) { for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) = 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::gradUToGreenStrain(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) { epsilon.mul<true, false>(grad_u, grad_u, .5); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) += 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ inline Real Material::stressToVonMises(const Matrix<Real> & stress) { // compute deviatoric stress UInt dim = stress.cols(); Matrix<Real> deviatoric_stress = Matrix<Real>::eye(dim, -1. * stress.trace() / 3.); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) deviatoric_stress(i, j) += stress(i, j); // return Von Mises stress return std::sqrt(3. * deviatoric_stress.doubleDot(deviatoric_stress) / 2.); } /* ---------------------------------------------------------------------------*/ template <UInt dim> inline void Material::setCauchyStressArray(const Matrix<Real> & S_t, Matrix<Real> & sigma_voight) { AKANTU_DEBUG_IN(); sigma_voight.clear(); // see Finite element formulations for large deformation dynamic analysis, // Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau /* * 1d: [ s11 ]' * 2d: [ s11 s22 s12 ]' * 3d: [ s11 s22 s33 s23 s13 s12 ] */ for (UInt i = 0; i < dim; ++i) // diagonal terms sigma_voight(i, 0) = S_t(i, i); for (UInt i = 1; i < dim; ++i) // term s12 in 2D and terms s23 s13 in 3D sigma_voight(dim + i - 1, 0) = S_t(dim - i - 1, dim - 1); for (UInt i = 2; i < dim; ++i) // term s13 in 3D sigma_voight(dim + i, 0) = S_t(0, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> inline void Material::setCauchyStressMatrix(const Matrix<Real> & S_t, Matrix<Real> & sigma) { AKANTU_DEBUG_IN(); sigma.clear(); /// see Finite ekement formulations for large deformation dynamic analysis, /// Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau for (UInt i = 0; i < dim; ++i) { for (UInt m = 0; m < dim; ++m) { for (UInt n = 0; n < dim; ++n) { sigma(i * dim + m, i * dim + n) = S_t(m, n); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline Element Material::convertToLocalElement(const Element & global_element) const { UInt ge = global_element.element; #ifndef AKANTU_NDEBUG UInt model_mat_index = this->model.getMaterialByElement( global_element.type, global_element.ghost_type)(ge); UInt mat_index = this->model.getMaterialIndex(this->name); AKANTU_DEBUG_ASSERT(model_mat_index == mat_index, "Conversion of a global element in a local element for " "the wrong material " << this->name << std::endl); #endif UInt le = this->model.getMaterialLocalNumbering( global_element.type, global_element.ghost_type)(ge); Element tmp_quad{global_element.type, le, global_element.ghost_type}; return tmp_quad; } /* -------------------------------------------------------------------------- */ inline Element Material::convertToGlobalElement(const Element & local_element) const { UInt le = local_element.element; UInt ge = this->element_filter(local_element.type, local_element.ghost_type)(le); Element tmp_quad{local_element.type, ge, local_element.ghost_type}; return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToLocalPoint(const IntegrationPoint & global_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(global_point.type); Element el = this->convertToLocalElement(static_cast<const Element &>(global_point)); IntegrationPoint tmp_quad(el, global_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToGlobalPoint(const IntegrationPoint & local_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(local_point.type); Element el = this->convertToGlobalElement(static_cast<const Element &>(local_point)); IntegrationPoint tmp_quad(el, local_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline UInt Material::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { return (this->isFiniteDeformation() ? 3 : 1) * spatial_dimension * spatial_dimension * sizeof(Real) * this->getModel().getNbIntegrationPoints(elements); } return 0; } /* -------------------------------------------------------------------------- */ inline void Material::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { packElementDataHelper(piola_kirchhoff_2, buffer, elements); packElementDataHelper(gradu, buffer, elements); } packElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline void Material::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { unpackElementDataHelper(piola_kirchhoff_2, buffer, elements); unpackElementDataHelper(gradu, buffer, elements); } unpackElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline const Parameter & Material::getParam(const ID & param) const { try { return get(param); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::setParam(const ID & param, T value) { try { set<T>(param, value); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } updateInternalParameters(); } +/* -------------------------------------------------------------------------- */ +template <typename T> +inline void Material::setParamNoUpdate(const ID & param, T value) { + try { + set<T>(param, value); + } catch (...) { + AKANTU_EXCEPTION("No parameter " << param << " in the material " + << getID()); + } +} + /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::packElementDataHelper( const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id) const { DataAccessor::packElementalDataHelper<T>(data_to_pack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template <typename T> inline void Material::unpackElementDataHelper( ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements, const ID & fem_id) { DataAccessor::unpackElementalDataHelper<T>(data_to_unpack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template <> inline void Material::registerInternal<Real>(InternalField<Real> & vect) { internal_vectors_real[vect.getID()] = &vect; } template <> inline void Material::registerInternal<UInt>(InternalField<UInt> & vect) { internal_vectors_uint[vect.getID()] = &vect; } template <> inline void Material::registerInternal<bool>(InternalField<bool> & vect) { internal_vectors_bool[vect.getID()] = &vect; } /* -------------------------------------------------------------------------- */ template <> inline void Material::unregisterInternal<Real>(InternalField<Real> & vect) { internal_vectors_real.erase(vect.getID()); } template <> inline void Material::unregisterInternal<UInt>(InternalField<UInt> & vect) { internal_vectors_uint.erase(vect.getID()); } template <> inline void Material::unregisterInternal<bool>(InternalField<bool> & vect) { internal_vectors_bool.erase(vect.getID()); } /* -------------------------------------------------------------------------- */ template <typename T> inline bool Material::isInternal(__attribute__((unused)) const ID & id, - __attribute__((unused)) const ElementKind & element_kind) const { + __attribute__((unused)) + const ElementKind & element_kind) const { AKANTU_DEBUG_TO_IMPLEMENT(); } template <> inline bool Material::isInternal<Real>(const ID & id, const ElementKind & element_kind) const { auto internal_array = internal_vectors_real.find(this->getID() + ":" + id); if (internal_array == internal_vectors_real.end() || internal_array->second->getElementKind() != element_kind) return false; return true; } /* -------------------------------------------------------------------------- */ template <typename T> inline ElementTypeMap<UInt> Material::getInternalDataPerElem(const ID & field_id, const ElementKind & element_kind) const { if (!this->template isInternal<T>(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField<T> & internal_field = this->template getInternal<T>(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); UInt nb_data_per_quad = internal_field.getNbComponent(); ElementTypeMap<UInt> res; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { using type_iterator = typename InternalField<T>::type_iterator; type_iterator tit = internal_field.firstType(*gt); type_iterator tend = internal_field.lastType(*gt); for (; tit != tend; ++tit) { UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(*tit, *gt); res(*tit, *gt) = nb_data_per_quad * nb_quadrature_points; } } return res; } /* -------------------------------------------------------------------------- */ template <typename T> void Material::flattenInternal(const std::string & field_id, ElementTypeMapArray<T> & internal_flat, const GhostType ghost_type, ElementKind element_kind) const { if (!this->template isInternal<T>(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField<T> & internal_field = this->template getInternal<T>(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); const Mesh & mesh = fe_engine.getMesh(); using type_iterator = typename InternalField<T>::filter_type_iterator; type_iterator tit = internal_field.filterFirstType(ghost_type); type_iterator tend = internal_field.filterLastType(ghost_type); for (; tit != tend; ++tit) { ElementType type = *tit; const Array<Real> & src_vect = internal_field(type, ghost_type); const Array<UInt> & filter = internal_field.getFilter(type, ghost_type); // total number of elements in the corresponding mesh UInt nb_element_dst = mesh.getNbElement(type, ghost_type); // number of element in the internal field UInt nb_element_src = filter.size(); // number of quadrature points per elem UInt nb_quad_per_elem = fe_engine.getNbIntegrationPoints(type); // number of data per quadrature point UInt nb_data_per_quad = internal_field.getNbComponent(); if (!internal_flat.exists(type, ghost_type)) { internal_flat.alloc(nb_element_dst * nb_quad_per_elem, nb_data_per_quad, type, ghost_type); } if (nb_element_src == 0) continue; // number of data per element UInt nb_data = nb_quad_per_elem * nb_data_per_quad; Array<Real> & dst_vect = internal_flat(type, ghost_type); dst_vect.resize(nb_element_dst * nb_quad_per_elem); Array<UInt>::const_scalar_iterator it = filter.begin(); Array<UInt>::const_scalar_iterator end = filter.end(); Array<Real>::const_vector_iterator it_src = src_vect.begin_reinterpret(nb_data, nb_element_src); Array<Real>::vector_iterator it_dst = dst_vect.begin_reinterpret(nb_data, nb_element_dst); for (; it != end; ++it, ++it_src) { it_dst[*it] = *it_src; } } } } // akantu #endif /* __AKANTU_MATERIAL_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc index e24a266cd..5f08a8369 100644 --- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc +++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc @@ -1,308 +1,266 @@ /** * @file material_elastic_linear_anisotropic.cc * * @author Till Junge <till.junge@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 25 2013 * @date last modification: Thu Oct 15 2015 * * @brief Anisotropic elastic material * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "material_elastic_linear_anisotropic.hh" #include "solid_mechanics_model.hh" #include <algorithm> #include <sstream> namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt dim> MaterialElasticLinearAnisotropic<dim>::MaterialElasticLinearAnisotropic( SolidMechanicsModel & model, const ID & id, bool symmetric) : Material(model, id), rot_mat(dim, dim), Cprime(dim * dim, dim * dim), C(voigt_h::size, voigt_h::size), eigC(voigt_h::size), symmetric(symmetric), alpha(0), was_stiffness_assembled(false) { AKANTU_DEBUG_IN(); this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim)); (*this->dir_vecs.back())[0] = 1.; this->registerParam("n1", *(this->dir_vecs.back()), _pat_parsmod, "Direction of main material axis"); if (dim > 1) { this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim)); (*this->dir_vecs.back())[1] = 1.; this->registerParam("n2", *(this->dir_vecs.back()), _pat_parsmod, "Direction of secondary material axis"); } if (dim > 2) { this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim)); (*this->dir_vecs.back())[2] = 1.; this->registerParam("n3", *(this->dir_vecs.back()), _pat_parsmod, "Direction of tertiary material axis"); } for (UInt i = 0; i < voigt_h::size; ++i) { UInt start = 0; if (this->symmetric) { start = i; } for (UInt j = start; j < voigt_h::size; ++j) { std::stringstream param("C"); param << "C" << i + 1 << j + 1; this->registerParam(param.str(), this->Cprime(i, j), Real(0.), _pat_parsmod, "Coefficient " + param.str()); } } this->registerParam("alpha", this->alpha, _pat_parsmod, "Proportion of viscous stress"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::updateInternalParameters() { Material::updateInternalParameters(); if (this->symmetric) { for (UInt i = 0; i < voigt_h::size; ++i) { for (UInt j = i + 1; j < voigt_h::size; ++j) { this->Cprime(j, i) = this->Cprime(i, j); } } } this->rotateCprime(); this->C.eig(this->eigC); this->was_stiffness_assembled = false; } /* -------------------------------------------------------------------------- */ template <UInt Dim> void MaterialElasticLinearAnisotropic<Dim>::rotateCprime() { // start by filling the empty parts fo Cprime UInt diff = Dim * Dim - voigt_h::size; for (UInt i = voigt_h::size; i < Dim * Dim; ++i) { for (UInt j = 0; j < Dim * Dim; ++j) { this->Cprime(i, j) = this->Cprime(i - diff, j); } } for (UInt i = 0; i < Dim * Dim; ++i) { for (UInt j = voigt_h::size; j < Dim * Dim; ++j) { this->Cprime(i, j) = this->Cprime(i, j - diff); } } // construction of rotator tensor // normalise rotation matrix for (UInt j = 0; j < Dim; ++j) { Vector<Real> rot_vec = this->rot_mat(j); rot_vec = *this->dir_vecs[j]; rot_vec.normalize(); } // make sure the vectors form a right-handed base Vector<Real> test_axis(3); Vector<Real> v1(3), v2(3), v3(3); if (Dim == 2) { for (UInt i = 0; i < Dim; ++i) { v1[i] = this->rot_mat(0, i); v2[i] = this->rot_mat(1, i); v3[i] = 0.; } v3[2] = 1.; v1[2] = 0.; v2[2] = 0.; } else if (Dim == 3) { v1 = this->rot_mat(0); v2 = this->rot_mat(1); v3 = this->rot_mat(2); } test_axis.crossProduct(v1, v2); test_axis -= v3; if (test_axis.norm() > 8 * std::numeric_limits<Real>::epsilon()) { AKANTU_DEBUG_ERROR("The axis vectors do not form a right-handed coordinate " << "system. I. e., ||n1 x n2 - n3|| should be zero, but " << "it is " << test_axis.norm() << "."); } // create the rotator and the reverse rotator Matrix<Real> rotator(Dim * Dim, Dim * Dim); Matrix<Real> revrotor(Dim * Dim, Dim * Dim); for (UInt i = 0; i < Dim; ++i) { for (UInt j = 0; j < Dim; ++j) { for (UInt k = 0; k < Dim; ++k) { for (UInt l = 0; l < Dim; ++l) { UInt I = voigt_h::mat[i][j]; UInt J = voigt_h::mat[k][l]; rotator(I, J) = this->rot_mat(k, i) * this->rot_mat(l, j); revrotor(I, J) = this->rot_mat(i, k) * this->rot_mat(j, l); } } } } // create the full rotated matrix Matrix<Real> Cfull(Dim * Dim, Dim * Dim); Cfull = rotator * Cprime * revrotor; for (UInt i = 0; i < voigt_h::size; ++i) { for (UInt j = 0; j < voigt_h::size; ++j) { this->C(i, j) = Cfull(i, j); } } } /* -------------------------------------------------------------------------- */ template <UInt dim> -void MaterialElasticLinearAnisotropic<dim>::computeStress( - ElementType el_type, GhostType ghost_type) { +void MaterialElasticLinearAnisotropic<dim>::computeStress(ElementType el_type, + GhostType ghost_type) { // Wikipedia convention: // 2*eps_ij (i!=j) = voigt_eps_I // http://en.wikipedia.org/wiki/Voigt_notation AKANTU_DEBUG_IN(); - Array<Real>::iterator<Matrix<Real>> gradu_it = - this->gradu(el_type, ghost_type).begin(dim, dim); - Array<Real>::iterator<Matrix<Real>> gradu_end = - this->gradu(el_type, ghost_type).end(dim, dim); - - UInt nb_quad_pts = gradu_end - gradu_it; - - // create array for strains and stresses of all dof of all gauss points - // for efficient computation of stress - Matrix<Real> voigt_strains(voigt_h::size, nb_quad_pts); - Matrix<Real> voigt_stresses(voigt_h::size, nb_quad_pts); - - // copy strains Matrix<Real> strain(dim, dim); - for (UInt q = 0; gradu_it != gradu_end; ++gradu_it, ++q) { - Matrix<Real> & grad_u = *gradu_it; - - for (UInt I = 0; I < voigt_h::size; ++I) { - Real voigt_factor = voigt_h::factors[I]; - UInt i = voigt_h::vec[I][0]; - UInt j = voigt_h::vec[I][1]; - - voigt_strains(I, q) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.; - } - } - - // compute the strain rate proportional part if needed - // bool viscous = this->alpha == 0.; // only works if default value - bool viscous = false; - if (viscous) { - Array<Real> strain_rate(0, dim * dim, "strain_rate"); - - Array<Real> & velocity = this->model.getVelocity(); - const Array<UInt> & elem_filter = this->element_filter(el_type, ghost_type); + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); - this->fem.gradientOnIntegrationPoints(velocity, strain_rate, dim, el_type, - ghost_type, elem_filter); + this->computeStressOnQuad(strain,sigma); - Array<Real>::matrix_iterator gradu_dot_it = strain_rate.begin(dim, dim); - Array<Real>::matrix_iterator gradu_dot_end = strain_rate.end(dim, dim); - - Matrix<Real> strain_dot(dim, dim); - for (UInt q = 0; gradu_dot_it != gradu_dot_end; ++gradu_dot_it, ++q) { - Matrix<Real> & grad_u_dot = *gradu_dot_it; - - for (UInt I = 0; I < voigt_h::size; ++I) { - Real voigt_factor = voigt_h::factors[I]; - UInt i = voigt_h::vec[I][0]; - UInt j = voigt_h::vec[I][1]; - - voigt_strains(I, q) = this->alpha * voigt_factor * - (grad_u_dot(i, j) + grad_u_dot(j, i)) / 2.; - } - } - } + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; +} - // compute stresses - voigt_stresses = this->C * voigt_strains; +/* -------------------------------------------------------------------------- */ +template <UInt dim> +void MaterialElasticLinearAnisotropic<dim>::computeTangentModuli( + const ElementType & el_type, Array<Real> & tangent_matrix, + GhostType ghost_type) { + AKANTU_DEBUG_IN(); - // copy stresses back - Array<Real>::iterator<Matrix<Real>> stress_it = - this->stress(el_type, ghost_type).begin(dim, dim); + MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); - Array<Real>::iterator<Matrix<Real>> stress_end = - this->stress(el_type, ghost_type).end(dim, dim); + this->computeTangentModuliOnQuad(tangent); - for (UInt q = 0; stress_it != stress_end; ++stress_it, ++q) { - Matrix<Real> & stress = *stress_it; + MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; - for (UInt I = 0; I < voigt_h::size; ++I) { - UInt i = voigt_h::vec[I][0]; - UInt j = voigt_h::vec[I][1]; - stress(i, j) = stress(j, i) = voigt_stresses(I, q); - } - } + this->was_stiffness_assembled = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> -void MaterialElasticLinearAnisotropic<dim>::computeTangentModuli( - const ElementType & el_type, Array<Real> & tangent_matrix, - GhostType ghost_type) { +void MaterialElasticLinearAnisotropic<dim>::computePotentialEnergy( + ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); - MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); - tangent.copy(this->C); - MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; + Material::computePotentialEnergy(el_type, ghost_type); - this->was_stiffness_assembled = true; + AKANTU_DEBUG_ASSERT(!this->finite_deformation, + "finite deformation not possible in material anisotropic " + "(TO BE IMPLEMENTED)"); + + if (ghost_type != _not_ghost) + return; + Array<Real>::scalar_iterator epot = + this->potential_energy(el_type, ghost_type).begin(); + + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); + + computePotentialEnergyOnQuad(grad_u, sigma, *epot); + ++epot; + + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt dim> Real MaterialElasticLinearAnisotropic<dim>::getCelerity( __attribute__((unused)) const Element & element) const { return std::sqrt(this->eigC(0) / rho); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(elastic_anisotropic, MaterialElasticLinearAnisotropic); } // akantu diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh index dec6765fd..2cfa119bb 100644 --- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh +++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh @@ -1,122 +1,139 @@ /** * @file material_elastic_linear_anisotropic.hh * * @author Till Junge <till.junge@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Aug 18 2015 * * @brief Orthotropic elastic material * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "material_elastic.hh" /* -------------------------------------------------------------------------- */ #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__ #define __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__ namespace akantu { /** * General linear anisotropic elastic material * The only constraint on the elastic tensor is that it can be represented * as a symmetric 6x6 matrix (3D) or 3x3 (2D). * * parameters in the material files : * - rho : density (default: 0) * - C_ij : entry on the stiffness */ template <UInt Dim> class MaterialElasticLinearAnisotropic : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialElasticLinearAnisotropic(SolidMechanicsModel & model, const ID & id = "", bool symmetric = true); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; /// 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, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost) override; + /// compute the elastic potential energy + void computePotentialEnergy(ElementType el_type, + GhostType ghost_type = _not_ghost) override; + void updateInternalParameters() override; bool hasStiffnessMatrixChanged() override { return (!was_stiffness_assembled); } protected: // compute C from Cprime void rotateCprime(); + /// constitutive law for a given quadrature point + inline void computeStressOnQuad(const Matrix<Real> & grad_u, + Matrix<Real> & sigma) const; + + /// tangent matrix for a given quadrature point + inline void computeTangentModuliOnQuad(Matrix<Real> & tangent) const; + + inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u, + const Matrix<Real> & sigma, + Real & epot); + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// compute max wave celerity Real getCelerity(const Element & element) const override; AKANTU_GET_MACRO(VoigtStiffness, C, Matrix<Real>); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: using voigt_h = VoigtHelper<Dim>; /// direction matrix and vectors std::vector<std::unique_ptr<Vector<Real>>> dir_vecs; Matrix<Real> rot_mat; /// Elastic stiffness tensor in material frame and full vectorised notation Matrix<Real> Cprime; /// Elastic stiffness tensor in voigt notation Matrix<Real> C; /// eigenvalues of stiffness tensor Vector<Real> eigC; bool symmetric; /// viscous proportion Real alpha; /// defines if the stiffness was computed bool was_stiffness_assembled; }; } // akantu +#include "material_elastic_linear_anisotropic_inline_impl.cc" + #endif /* __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc new file mode 100644 index 000000000..900b8d5ae --- /dev/null +++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc @@ -0,0 +1,96 @@ +/** + * @file material_elastic_linear_anisotropic_inline_impl.cc + * + * @author Enrico Milanese <enrico.milanese@epfl.ch> + * @author Nicolas Richart <nicolas.richart@epfl.ch> + * + * @date creation: Mon Feb 12 2018 + * @date last modification: Mon Feb 12 2018 + * + * @brief Implementation of the inline functions of the material elastic linear + * anisotropic + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ +#include "material_elastic_linear_anisotropic.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__ +#define __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +template <UInt dim> +inline void MaterialElasticLinearAnisotropic<dim>::computeStressOnQuad(const Matrix<Real> & grad_u, + Matrix<Real> & sigma) const { + // Wikipedia convention: + // 2*eps_ij (i!=j) = voigt_eps_I + // http://en.wikipedia.org/wiki/Voigt_notation + Vector<Real> voigt_strain(voigt_h::size); + Vector<Real> voigt_stress(voigt_h::size); + + for (UInt I = 0; I < voigt_h::size; ++I){ + Real voigt_factor = voigt_h::factors[I]; + UInt i = voigt_h::vec[I][0]; + UInt j = voigt_h::vec[I][1]; + + voigt_strain(I) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.; + + } + + voigt_stress = this->C * voigt_strain; + + for (UInt I = 0; I < voigt_h::size; ++I){ + UInt i = voigt_h::vec[I][0]; + UInt j = voigt_h::vec[I][1]; + + sigma(i, j) = sigma(j, i) = voigt_stress(I); + + } + +} + +/* -------------------------------------------------------------------------- */ +template <UInt dim> +inline void MaterialElasticLinearAnisotropic<dim>::computeTangentModuliOnQuad(Matrix<Real> & tangent) const { + + tangent.copy(this->C); + +} + +/* -------------------------------------------------------------------------- */ +template <UInt dim> +inline void MaterialElasticLinearAnisotropic<dim>::computePotentialEnergyOnQuad( + const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot) { + + AKANTU_DEBUG_ASSERT(this->symmetric, + "The elastic constants matrix is not symmetric," + "energy is not path independent."); + + epot = .5 * sigma.doubleDot(grad_u); +} + +} // akantu + +#endif /* __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc b/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc index 22815792a..331a25fbe 100644 --- a/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc +++ b/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc @@ -1,212 +1,168 @@ /** * @file material_elastic_orthotropic.cc * * @author Till Junge <till.junge@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Oct 15 2015 * * @brief Orthotropic elastic material * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "material_elastic_orthotropic.hh" #include "solid_mechanics_model.hh" #include <algorithm> namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt Dim> MaterialElasticOrthotropic<Dim>::MaterialElasticOrthotropic( SolidMechanicsModel & model, const ID & id) : MaterialElasticLinearAnisotropic<Dim>(model, id) { AKANTU_DEBUG_IN(); this->registerParam("E1", E1, Real(0.), _pat_parsmod, "Young's modulus (n1)"); this->registerParam("E2", E2, Real(0.), _pat_parsmod, "Young's modulus (n2)"); this->registerParam("nu12", nu12, Real(0.), _pat_parsmod, "Poisson's ratio (12)"); this->registerParam("G12", G12, Real(0.), _pat_parsmod, "Shear modulus (12)"); if (Dim > 2) { this->registerParam("E3", E3, Real(0.), _pat_parsmod, "Young's modulus (n3)"); this->registerParam("nu13", nu13, Real(0.), _pat_parsmod, "Poisson's ratio (13)"); this->registerParam("nu23", nu23, Real(0.), _pat_parsmod, "Poisson's ratio (23)"); this->registerParam("G13", G13, Real(0.), _pat_parsmod, "Shear modulus (13)"); this->registerParam("G23", G23, Real(0.), _pat_parsmod, "Shear modulus (23)"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt Dim> void MaterialElasticOrthotropic<Dim>::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); updateInternalParameters(); AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -inline Real vector_norm(Vector<Real> & vec) { - Real norm = 0; - for (UInt i = 0; i < vec.size(); ++i) { - norm += vec(i) * vec(i); - } - return std::sqrt(norm); -} - /* -------------------------------------------------------------------------- */ template <UInt Dim> void MaterialElasticOrthotropic<Dim>::updateInternalParameters() { /* 1) construction of temporary material frame stiffness tensor------------ */ // http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 Real nu21 = nu12 * E2 / E1; Real nu31 = nu13 * E3 / E1; Real nu32 = nu23 * E3 / E2; // Full (i.e. dim^2 by dim^2) stiffness tensor in material frame if (Dim == 1) { AKANTU_DEBUG_ERROR("Dimensions 1 not implemented: makes no sense to have " "orthotropy for 1D"); } Real Gamma; if (Dim == 3) Gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - 2 * nu21 * nu32 * nu13); if (Dim == 2) Gamma = 1 / (1 - nu12 * nu21); // Lamé's first parameters this->Cprime(0, 0) = E1 * (1 - nu23 * nu32) * Gamma; this->Cprime(1, 1) = E2 * (1 - nu13 * nu31) * Gamma; if (Dim == 3) this->Cprime(2, 2) = E3 * (1 - nu12 * nu21) * Gamma; // normalised poisson's ratio's this->Cprime(1, 0) = this->Cprime(0, 1) = E1 * (nu21 + nu31 * nu23) * Gamma; if (Dim == 3) { this->Cprime(2, 0) = this->Cprime(0, 2) = E1 * (nu31 + nu21 * nu32) * Gamma; this->Cprime(2, 1) = this->Cprime(1, 2) = E2 * (nu32 + nu12 * nu31) * Gamma; } // Lamé's second parameters (shear moduli) if (Dim == 3) { this->Cprime(3, 3) = G23; this->Cprime(4, 4) = G13; this->Cprime(5, 5) = G12; } else this->Cprime(2, 2) = G12; /* 1) rotation of C into the global frame */ this->rotateCprime(); this->C.eig(this->eigC); } -/* -------------------------------------------------------------------------- */ - -template <UInt dim> -inline void MaterialElasticOrthotropic<dim>::computePotentialEnergyOnQuad( - const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot) { - epot = .5 * sigma.doubleDot(grad_u); -} - -/* -------------------------------------------------------------------------- */ -template <UInt spatial_dimension> -void MaterialElasticOrthotropic<spatial_dimension>::computePotentialEnergy( - ElementType el_type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Material::computePotentialEnergy(el_type, ghost_type); - - AKANTU_DEBUG_ASSERT(!this->finite_deformation, - "finite deformation not possible in material orthotropic " - "(TO BE IMPLEMENTED)"); - - if (ghost_type != _not_ghost) - return; - Array<Real>::scalar_iterator epot = - this->potential_energy(el_type, ghost_type).begin(); - - MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); - - computePotentialEnergyOnQuad(grad_u, sigma, *epot); - ++epot; - - MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; - - AKANTU_DEBUG_OUT(); -} - /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialElasticOrthotropic<spatial_dimension>:: computePotentialEnergyByElement(ElementType type, UInt index, Vector<Real> & epot_on_quad_points) { AKANTU_DEBUG_ASSERT(!this->finite_deformation, "finite deformation not possible in material orthotropic " "(TO BE IMPLEMENTED)"); Array<Real>::matrix_iterator gradu_it = this->gradu(type).begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator gradu_end = this->gradu(type).begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator stress_it = this->stress(type).begin(spatial_dimension, spatial_dimension); UInt nb_quadrature_points = this->fem.getNbIntegrationPoints(type); gradu_it += index * nb_quadrature_points; gradu_end += (index + 1) * nb_quadrature_points; stress_it += index * nb_quadrature_points; Real * epot_quad = epot_on_quad_points.storage(); Matrix<Real> grad_u(spatial_dimension, spatial_dimension); for (; gradu_it != gradu_end; ++gradu_it, ++stress_it, ++epot_quad) { grad_u.copy(*gradu_it); - computePotentialEnergyOnQuad(grad_u, *stress_it, *epot_quad); + this->computePotentialEnergyOnQuad(grad_u, *stress_it, *epot_quad); } } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(elastic_orthotropic, MaterialElasticOrthotropic); } // akantu diff --git a/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh b/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh index f5bad0fe2..60110342c 100644 --- a/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh +++ b/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh @@ -1,145 +1,136 @@ /** * @file material_elastic_orthotropic.hh * * @author Till Junge <till.junge@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Sun Oct 19 2014 * * @brief Orthotropic elastic material * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_elastic_linear_anisotropic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__ #define __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__ namespace akantu { /** * Orthotropic elastic material * * parameters in the material files : * - n1 : direction of x-axis in material base, normalisation not necessary * (default: {1, 0, 0}) * - n2 : direction of y-axis in material base, normalisation not necessary * (default: {0, 1, 0}) * - n3 : direction of z-axis in material base, normalisation not necessary * (default: {0, 0, 1}) * - rho : density (default: 0) * - E1 : Young's modulus along n1 (default: 0) * - E2 : Young's modulus along n2 (default: 0) * - E3 : Young's modulus along n3 (default: 0) * - nu12 : Poisson's ratio along 12 (default: 0) * - nu13 : Poisson's ratio along 13 (default: 0) * - nu23 : Poisson's ratio along 23 (default: 0) * - G12 : Shear modulus along 12 (default: 0) * - G13 : Shear modulus along 13 (default: 0) * - G23 : Shear modulus along 23 (default: 0) */ template <UInt Dim> class MaterialElasticOrthotropic : public MaterialElasticLinearAnisotropic<Dim> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialElasticOrthotropic(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void initMaterial() override; void updateInternalParameters() override; - /// compute the elastic potential energy - void computePotentialEnergy(ElementType el_type, - GhostType ghost_type = _not_ghost) override; - void computePotentialEnergyByElement(ElementType type, UInt index, Vector<Real> & epot_on_quad_points) override; -protected: - inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u, - const Matrix<Real> & sigma, - Real & epot); - /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(E1, E1, Real); AKANTU_GET_MACRO(E2, E2, Real); AKANTU_GET_MACRO(E3, E3, Real); AKANTU_GET_MACRO(Nu12, nu12, Real); AKANTU_GET_MACRO(Nu13, nu13, Real); AKANTU_GET_MACRO(Nu23, nu23, Real); AKANTU_GET_MACRO(G12, G12, Real); AKANTU_GET_MACRO(G13, G13, Real); AKANTU_GET_MACRO(G23, G23, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the n1 young modulus Real E1; /// the n2 young modulus Real E2; /// the n3 young modulus Real E3; /// 12 Poisson coefficient Real nu12; /// 13 Poisson coefficient Real nu13; /// 23 Poisson coefficient Real nu23; /// 12 shear modulus Real G12; /// 13 shear modulus Real G13; /// 23 shear modulus Real G23; }; } // akantu #endif /* __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh b/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh deleted file mode 100644 index 9c8ad1ea4..000000000 --- a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file embedded_internal_field.hh - * - * @author Lucas Frerot <lucas.frerot@epfl.ch> - * - * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jun 30 2015 - * - * @brief Embedded Material internal properties - * - * @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 <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ -#include "aka_common.hh" -#include "internal_field.hh" -/* -------------------------------------------------------------------------- */ - -#ifndef __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ -#define __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ - -namespace akantu { - -class Material; -class FEEngine; - -/// This class is used for MaterialReinforcement internal fields -template<typename T> -class EmbeddedInternalField : public InternalField<T> { - /* ------------------------------------------------------------------------ */ - /* Constructors/Destructors */ - /* ------------------------------------------------------------------------ */ -public: - /// Constructor - EmbeddedInternalField(const ID & id, Material & material): - InternalField<T>(id, - material, - material.getModel().getFEEngine("EmbeddedInterfaceFEEngine"), - material.getElementFilter()) { - this->spatial_dimension = 1; - } - - /// Copy constructor - EmbeddedInternalField(const ID & id, const EmbeddedInternalField & other): - InternalField<T>(id, other) { - this->spatial_dimension = 1; - } - - void operator=(const EmbeddedInternalField & other) { - InternalField<T>::operator=(other); - this->spatial_dimension = 1; - } -}; - -/// Method used to initialise the embedded internal fields from material file -template <> -inline void ParameterTyped<EmbeddedInternalField<Real>>::setAuto( - const ParserParameter & in_param) { - Parameter::setAuto(in_param); - Real r = in_param; - param.setDefaultValue(r); -} - -} // akantu - -#endif // __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh b/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh index d00d9f035..3c04d7b6b 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh @@ -1,43 +1,41 @@ /** * @file material_embedded_includes.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Jan 04 2013 * @date last modification: Fri May 29 2015 * * @brief List of includes for embedded elements * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_CMAKE_LIST_MATERIALS # include "material_reinforcement.hh" -# include "material_reinforcement_template.hh" #endif #define AKANTU_MATERIAL_REINFORCEMENT_LAW_TMPL_LIST \ ((elastic, (MaterialElastic<1>))) \ ((plastic, (MaterialLinearIsotropicHardening<1>))) #define AKANTU_EMBEDDED_MATERIAL_LIST \ - ((3, (reinforcement, MaterialReinforcementTemplate, \ - AKANTU_MATERIAL_REINFORCEMENT_LAW_TMPL_LIST ))) + ((2, (reinforcement, MaterialReinforcement))) diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc deleted file mode 100644 index def0887e8..000000000 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc +++ /dev/null @@ -1,766 +0,0 @@ -/** - * @file material_reinforcement.cc - * - * @author Lucas Frerot <lucas.frerot@epfl.ch> - * - * @date creation: Wed Mar 25 2015 - * @date last modification: Tue Dec 08 2015 - * - * @brief Reinforcement material - * - * @section LICENSE - * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#include "aka_common.hh" -#include "aka_voigthelper.hh" -#include "material_reinforcement.hh" - -namespace akantu { - -/* -------------------------------------------------------------------------- */ -template <UInt dim> -MaterialReinforcement<dim>::MaterialReinforcement(SolidMechanicsModel & model, - UInt /*spatial_dimension*/, - const Mesh & mesh, - FEEngine & fe_engine, - const ID & id) - : Material(model, dim, mesh, fe_engine, - id), // /!\ dim, not spatial_dimension ! - model(NULL), - stress_embedded("stress_embedded", *this, 1, fe_engine, - this->element_filter), - gradu_embedded("gradu_embedded", *this, 1, fe_engine, - this->element_filter), - directing_cosines("directing_cosines", *this, 1, fe_engine, - this->element_filter), - pre_stress("pre_stress", *this, 1, fe_engine, this->element_filter), - area(1.0), shape_derivatives() { - AKANTU_DEBUG_IN(); - this->initialize(model); - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template <UInt dim> -void MaterialReinforcement<dim>::initialize(SolidMechanicsModel & a_model) { - AKANTU_DEBUG_IN(); - this->model = dynamic_cast<EmbeddedInterfaceModel *>(&a_model); - AKANTU_DEBUG_ASSERT(this->model != NULL, - "MaterialReinforcement needs an EmbeddedInterfaceModel"); - - this->registerParam("area", area, _pat_parsable | _pat_modifiable, - "Reinforcement cross-sectional area"); - this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable, - "Uniform pre-stress"); - - this->unregisterInternal(this->stress); - - // Fool the AvgHomogenizingFunctor - // stress.initialize(dim * dim); - - // Reallocate the element filter - this->element_filter.initialize(this->model->getInterfaceMesh(), - _spatial_dimension = 1); - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> MaterialReinforcement<dim>::~MaterialReinforcement() { - AKANTU_DEBUG_IN(); - - ElementTypeMap<ElementTypeMapArray<Real> *>::type_iterator - it = shape_derivatives.firstType(), - end = shape_derivatives.lastType(); - - for (; it != end; ++it) { - delete shape_derivatives(*it, _not_ghost); - delete shape_derivatives(*it, _ghost); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> void MaterialReinforcement<dim>::initMaterial() { - Material::initMaterial(); - - stress_embedded.initialize(dim * dim); - gradu_embedded.initialize(dim * dim); - pre_stress.initialize(1); - - /// We initialise the stuff that is not going to change during the simulation - this->allocBackgroundShapeDerivatives(); - this->initBackgroundShapeDerivatives(); - this->initDirectingCosines(); -} - -/* -------------------------------------------------------------------------- */ - -/** - * Background shape derivatives need to be stored per background element - * types but also per embedded element type, which is why they are stored - * in an ElementTypeMap<ElementTypeMapArray<Real> *>. The outer ElementTypeMap - * refers to the embedded types, and the inner refers to the background types. - */ -template <UInt dim> -void MaterialReinforcement<dim>::allocBackgroundShapeDerivatives() { - AKANTU_DEBUG_IN(); - - Mesh & interface_mesh = model->getInterfaceMesh(); - Mesh & mesh = model->getMesh(); - - ghost_type_t::iterator int_ghost_it = ghost_type_t::begin(); - - // Loop over interface ghosts - for (; int_ghost_it != ghost_type_t::end(); ++int_ghost_it) { - Mesh::type_iterator interface_type_it = - interface_mesh.firstType(1, *int_ghost_it); - Mesh::type_iterator interface_type_end = - interface_mesh.lastType(1, *int_ghost_it); - - // Loop over interface types - for (; interface_type_it != interface_type_end; ++interface_type_it) { - Mesh::type_iterator background_type_it = - mesh.firstType(dim, *int_ghost_it); - Mesh::type_iterator background_type_end = - mesh.lastType(dim, *int_ghost_it); - - // Loop over background types - for (; background_type_it != background_type_end ; ++background_type_it) { - const ElementType & int_type = *interface_type_it; - const ElementType & back_type = *background_type_it; - const GhostType & int_ghost = *int_ghost_it; - - std::string shaped_id = "embedded_shape_derivatives"; - - if (int_ghost == _ghost) shaped_id += ":ghost"; - - ElementTypeMapArray<Real> * shaped_etma = new ElementTypeMapArray<Real>(shaped_id, this->name); - - UInt nb_points = Mesh::getNbNodesPerElement(back_type); - UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbIntegrationPoints(int_type); - UInt nb_elements = element_filter(int_type, int_ghost).size(); - - // Alloc the background ElementTypeMapArray - shaped_etma->alloc(nb_elements * nb_quad_points, - dim * nb_points, - back_type); - - // Insert the background ElementTypeMapArray in the interface - // ElementTypeMap - shape_derivatives(shaped_etma, int_type, int_ghost); - } - } - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> -void MaterialReinforcement<dim>::initBackgroundShapeDerivatives() { - AKANTU_DEBUG_IN(); - - Mesh & mesh = model->getMesh(); - - Mesh::type_iterator type_it = mesh.firstType(dim, _not_ghost); - Mesh::type_iterator type_end = mesh.lastType(dim, _not_ghost); - - for (; type_it != type_end; ++type_it) { - computeBackgroundShapeDerivatives(*type_it, _not_ghost); - // computeBackgroundShapeDerivatives(*type_it, _ghost); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> void MaterialReinforcement<dim>::initDirectingCosines() { - AKANTU_DEBUG_IN(); - - Mesh & mesh = model->getInterfaceMesh(); - - Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost); - Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost); - - const UInt voigt_size = getTangentStiffnessVoigtSize(dim); - directing_cosines.initialize(voigt_size * voigt_size); - - for (; type_it != type_end; ++type_it) { - computeDirectingCosines(*type_it, _not_ghost); - // computeDirectingCosines(*type_it, _ghost); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> -void MaterialReinforcement<dim>::assembleStiffnessMatrix(GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Mesh & interface_mesh = model->getInterfaceMesh(); - - Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); - Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); - - for (; type_it != type_end; ++type_it) { - assembleStiffnessMatrix(*type_it, ghost_type); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> -void MaterialReinforcement<dim>::assembleInternalForces(GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Mesh & interface_mesh = model->getInterfaceMesh(); - - Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); - Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); - - for (; type_it != type_end; ++type_it) { - this->assembleInternalForces(*type_it, ghost_type); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template <UInt dim> -void MaterialReinforcement<dim>::computeGradU(const ElementType & type, - GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Array<UInt> & elem_filter = element_filter(type, ghost_type); - UInt nb_element = elem_filter.size(); - UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine") - .getNbIntegrationPoints(type); - - Array<Real> & gradu_vec = gradu_embedded(type, ghost_type); - - Mesh::type_iterator back_it = model->getMesh().firstType(dim, ghost_type); - Mesh::type_iterator back_end = model->getMesh().lastType(dim, ghost_type); - - for (; back_it != back_end; ++back_it) { - UInt nodes_per_background_e = Mesh::getNbNodesPerElement(*back_it); - - Array<Real> & shapesd = - shape_derivatives(type, ghost_type)->operator()(*back_it, ghost_type); - - Array<UInt> * background_filter = - new Array<UInt>(nb_element, 1, "background_filter"); - filterInterfaceBackgroundElements(*background_filter, *back_it, type, - ghost_type); - - Array<Real> * disp_per_element = new Array<Real>(0, dim * nodes_per_background_e, "disp_elem"); - FEEngine::extractNodalToElementField(model->getMesh(), - model->getDisplacement(), - *disp_per_element, - *back_it, ghost_type, *background_filter); - - Array<Real>::matrix_iterator disp_it = - disp_per_element->begin(dim, nodes_per_background_e); - Array<Real>::matrix_iterator disp_end = - disp_per_element->end(dim, nodes_per_background_e); - - Array<Real>::matrix_iterator shapes_it = - shapesd.begin(dim, nodes_per_background_e); - Array<Real>::matrix_iterator grad_u_it = gradu_vec.begin(dim, dim); - - for (; disp_it != disp_end; ++disp_it) { - for (UInt i = 0; i < nb_quad_points; i++, ++shapes_it, ++grad_u_it) { - Matrix<Real> & B = *shapes_it; - Matrix<Real> & du = *grad_u_it; - Matrix<Real> & u = *disp_it; - - du.mul<false, true>(u, B); - } - } - - delete background_filter; - delete disp_per_element; - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template <UInt dim> -void MaterialReinforcement<dim>::computeAllStresses(GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Mesh::type_iterator it = model->getInterfaceMesh().firstType(); - Mesh::type_iterator last_type = model->getInterfaceMesh().lastType(); - - for (; it != last_type; ++it) { - computeGradU(*it, ghost_type); - computeStress(*it, ghost_type); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template <UInt dim> -void MaterialReinforcement<dim>::assembleInternalForces( - const ElementType & type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Mesh & mesh = model->getMesh(); - - Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); - Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); - - for (; type_it != type_end; ++type_it) { - assembleInternalForcesInterface(type, *type_it, ghost_type); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -/** - * Computes and assemble the residual. Residual in reinforcement is computed as: - * - * \f[ - * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s} - * \f] - */ -template <UInt dim> -void MaterialReinforcement<dim>::assembleInternalForcesInterface( - const ElementType & interface_type, const ElementType & background_type, - GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - UInt voigt_size = getTangentStiffnessVoigtSize(dim); - - FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); - - Array<UInt> & elem_filter = element_filter(interface_type, ghost_type); - - UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); - UInt nb_quadrature_points = - interface_engine.getNbIntegrationPoints(interface_type, ghost_type); - UInt nb_element = elem_filter.size(); - - UInt back_dof = dim * nodes_per_background_e; - - Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( - background_type, ghost_type); - - Array<Real> integrant(nb_quadrature_points * nb_element, back_dof, - "integrant"); - - Array<Real>::vector_iterator integrant_it = integrant.begin(back_dof); - Array<Real>::vector_iterator integrant_end = integrant.end(back_dof); - - Array<Real>::matrix_iterator B_it = - shapesd.begin(dim, nodes_per_background_e); - Array<Real>::matrix_iterator C_it = - directing_cosines(interface_type, ghost_type) - .begin(voigt_size, voigt_size); - Array<Real>::matrix_iterator sigma_it = - stress_embedded(interface_type, ghost_type).begin(dim, dim); - - Vector<Real> sigma(voigt_size); - Matrix<Real> Bvoigt(voigt_size, back_dof); - Vector<Real> Ct_sigma(voigt_size); - - for (; integrant_it != integrant_end ; ++integrant_it, - ++B_it, - ++C_it, - ++sigma_it) { - VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, nodes_per_background_e); - Matrix<Real> & C = *C_it; - Vector<Real> & BtCt_sigma = *integrant_it; - - stressTensorToVoigtVector(*sigma_it, sigma); - - Ct_sigma.mul<true>(C, sigma); - BtCt_sigma.mul<true>(Bvoigt, Ct_sigma); - BtCt_sigma *= area; - } - - Array<Real> residual_interface(nb_element, back_dof, "residual_interface"); - interface_engine.integrate(integrant, residual_interface, back_dof, - interface_type, ghost_type, elem_filter); - integrant.resize(0); - - Array<UInt> background_filter(nb_element, 1, "background_filter"); - - filterInterfaceBackgroundElements(background_filter, background_type, - interface_type, ghost_type); - - model->getDOFManager().assembleElementalArrayLocalArray( - residual_interface, model->getInternalForce(), background_type, ghost_type, -1., - background_filter); - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template <UInt dim> -void MaterialReinforcement<dim>::filterInterfaceBackgroundElements( - Array<UInt> & filter, const ElementType & type, - const ElementType & interface_type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - filter.resize(0); - filter.clear(); - - Array<Element> & elements = - model->getInterfaceAssociatedElements(interface_type, ghost_type); - Array<UInt> & elem_filter = element_filter(interface_type, ghost_type); - - Array<UInt>::scalar_iterator filter_it = elem_filter.begin(), - filter_end = elem_filter.end(); - - for (; filter_it != filter_end; ++filter_it) { - Element & elem = elements(*filter_it); - if (elem.type == type) - filter.push_back(elem.element); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> -void MaterialReinforcement<dim>::computeDirectingCosines( - const ElementType & type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Mesh & interface_mesh = this->model->getInterfaceMesh(); - - const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); - const UInt steel_dof = dim * nb_nodes_per_element; - const UInt voigt_size = getTangentStiffnessVoigtSize(dim); - const UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine") - .getNbIntegrationPoints(type, ghost_type); - - Array<Real> node_coordinates(this->element_filter(type, ghost_type).size(), - steel_dof); - - this->model->getFEEngine().template extractNodalToElementField<Real>(interface_mesh, - interface_mesh.getNodes(), - node_coordinates, - type, - ghost_type, - this->element_filter(type, ghost_type)); - - Array<Real>::matrix_iterator directing_cosines_it = - directing_cosines(type, ghost_type).begin(voigt_size, voigt_size); - - Array<Real>::matrix_iterator node_coordinates_it = - node_coordinates.begin(dim, nb_nodes_per_element); - Array<Real>::matrix_iterator node_coordinates_end = - node_coordinates.end(dim, nb_nodes_per_element); - - for (; node_coordinates_it != node_coordinates_end; ++node_coordinates_it) { - for (UInt i = 0; i < nb_quad_points; i++, ++directing_cosines_it) { - Matrix<Real> & nodes = *node_coordinates_it; - Matrix<Real> & cosines = *directing_cosines_it; - - computeDirectingCosinesOnQuad(nodes, cosines); - } - } - - // Mauro: the directing_cosines internal is defined on the quadrature points of each element - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim> -void MaterialReinforcement<dim>::assembleStiffnessMatrix( - const ElementType & type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Mesh & mesh = model->getMesh(); - - Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); - Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); - - for (; type_it != type_end; ++type_it) { - assembleStiffnessMatrixInterface(type, *type_it, ghost_type); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -/** - * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001) - * \f[ - * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T - * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}} - * \f] - */ -template <UInt dim> -void MaterialReinforcement<dim>::assembleStiffnessMatrixInterface( - const ElementType & interface_type, const ElementType & background_type, - GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - UInt voigt_size = getTangentStiffnessVoigtSize(dim); - - FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); - - Array<UInt> & elem_filter = element_filter(interface_type, ghost_type); - Array<Real> & grad_u = gradu_embedded(interface_type, ghost_type); - - UInt nb_element = elem_filter.size(); - UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); - UInt nb_quadrature_points = - interface_engine.getNbIntegrationPoints(interface_type, ghost_type); - - UInt back_dof = dim * nodes_per_background_e; - - UInt integrant_size = back_dof; - - grad_u.resize(nb_quadrature_points * nb_element); - - Array<Real> tangent_moduli(nb_element * nb_quadrature_points, 1, - "interface_tangent_moduli"); - computeTangentModuli(interface_type, tangent_moduli, ghost_type); - - Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( - background_type, ghost_type); - - Array<Real> integrant(nb_element * nb_quadrature_points, - integrant_size * integrant_size, "B^t*C^t*D*C*B"); - - /// Temporary matrices for integrant product - Matrix<Real> Bvoigt(voigt_size, back_dof); - Matrix<Real> DC(voigt_size, voigt_size); - Matrix<Real> DCB(voigt_size, back_dof); - Matrix<Real> CtDCB(voigt_size, back_dof); - - Array<Real>::scalar_iterator D_it = tangent_moduli.begin(); - Array<Real>::scalar_iterator D_end = tangent_moduli.end(); - - Array<Real>::matrix_iterator C_it = - directing_cosines(interface_type, ghost_type) - .begin(voigt_size, voigt_size); - Array<Real>::matrix_iterator B_it = - shapesd.begin(dim, nodes_per_background_e); - Array<Real>::matrix_iterator integrant_it = - integrant.begin(integrant_size, integrant_size); - - for (; D_it != D_end; ++D_it, ++C_it, ++B_it, ++integrant_it) { - Real & D = *D_it; - Matrix<Real> & C = *C_it; - Matrix<Real> & B = *B_it; - Matrix<Real> & BtCtDCB = *integrant_it; - - VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt, - nodes_per_background_e); - - DC.clear(); - DC(0, 0) = D * area; - DC *= C; - DCB.mul<false, false>(DC, Bvoigt); - CtDCB.mul<true, false>(C, DCB); - BtCtDCB.mul<true, false>(Bvoigt, CtDCB); - } - - tangent_moduli.resize(0); - - Array<Real> K_interface( - nb_element, integrant_size * integrant_size, "K_interface"); - interface_engine.integrate(integrant, K_interface, - integrant_size * integrant_size, interface_type, - ghost_type, elem_filter); - - integrant.resize(0); - - // Mauro: Here K_interface contains the local stiffness matrices, - // directing_cosines contains the information about the orientation - // of the reinforcements, any rotation of the local stiffness matrix - // can be done here - - Array<UInt> background_filter(nb_element, 1, "background_filter"); - - filterInterfaceBackgroundElements(background_filter, background_type, - interface_type, ghost_type); - - model->getDOFManager().assembleElementalMatricesToMatrix( - "K", "displacement", K_interface, background_type, ghost_type, - _symmetric, background_filter); - - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -/// In this function, type and ghost_type refer to background elements -template <UInt dim> -void MaterialReinforcement<dim>::computeBackgroundShapeDerivatives( - const ElementType & type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - Mesh & interface_mesh = model->getInterfaceMesh(); - - FEEngine & engine = model->getFEEngine(); - FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); - - Mesh::type_iterator interface_type = interface_mesh.firstType(); - Mesh::type_iterator interface_last = interface_mesh.lastType(); - - for (; interface_type != interface_last; ++interface_type) { - Array<UInt> & filter = element_filter(*interface_type, ghost_type); - - const UInt nb_elements = filter.size(); - const UInt nb_nodes = Mesh::getNbNodesPerElement(type); - const UInt nb_quad_per_element = - interface_engine.getNbIntegrationPoints(*interface_type); - - Array<Real> quad_pos(nb_quad_per_element * nb_elements, dim, - "interface_quad_points"); - quad_pos.resize(nb_quad_per_element * nb_elements); - interface_engine.interpolateOnIntegrationPoints( - interface_mesh.getNodes(), quad_pos, dim, *interface_type, ghost_type, - filter); - - Array<Real> & background_shapesd = - shape_derivatives(*interface_type, ghost_type) - -> - operator()(type, ghost_type); - background_shapesd.clear(); - - Array<UInt> * background_elements = new Array<UInt>( - nb_elements, 1, "computeBackgroundShapeDerivatives:background_filter"); - filterInterfaceBackgroundElements(*background_elements, type, - *interface_type, ghost_type); - - Array<UInt>::scalar_iterator back_it = background_elements->begin(), - back_end = background_elements->end(); - - Array<Real>::matrix_iterator shapesd_it = - background_shapesd.begin(dim, nb_nodes); - - Array<Real>::vector_iterator quad_pos_it = quad_pos.begin(dim); - - for (; back_it != back_end; ++back_it) { - for (UInt i = 0; i < nb_quad_per_element; - i++, ++shapesd_it, ++quad_pos_it) - engine.computeShapeDerivatives(*quad_pos_it, *back_it, type, - *shapesd_it, ghost_type); - } - - delete background_elements; - } - - AKANTU_DEBUG_OUT(); -} - -template <UInt dim> -Real MaterialReinforcement<dim>::getEnergy(const std::string & id) { - AKANTU_DEBUG_IN(); - if (id == "potential") { - Real epot = 0.; - - computePotentialEnergyByElements(); - - Mesh::type_iterator it = element_filter.firstType(spatial_dimension), - end = element_filter.lastType(spatial_dimension); - - for (; it != end; ++it) { - FEEngine & interface_engine = - model->getFEEngine("EmbeddedInterfaceFEEngine"); - epot += interface_engine.integrate(potential_energy(*it, _not_ghost), *it, - _not_ghost, - element_filter(*it, _not_ghost)); - epot *= area; - } - - return epot; - } - - AKANTU_DEBUG_OUT(); - return 0; -} - -// /* -------------------------------------------------------------------------- -// */ -// template<UInt dim> -// ElementTypeMap<UInt> MaterialReinforcement<dim>::getInternalDataPerElem(const -// ID & field_name, -// const -// ElementKind -// & -// kind, -// const -// ID & -// fe_engine_id) -// const -// { -// return Material::getInternalDataPerElem(field_name, kind, -// "EmbeddedInterfaceFEEngine"); -// } - -// /* -------------------------------------------------------------------------- -// */ -// // Author is Guillaume Anciaux, see material.cc -// template<UInt dim> -// void MaterialReinforcement<dim>::flattenInternal(const std::string & -// field_id, -// ElementTypeMapArray<Real> & -// internal_flat, -// const GhostType ghost_type, -// ElementKind element_kind) -// const { -// AKANTU_DEBUG_IN(); - -// if (field_id == "stress_embedded" || field_id == "inelastic_strain") { -// Material::flattenInternalIntern(field_id, -// internal_flat, -// 1, -// ghost_type, -// _ek_not_defined, -// &(this->element_filter), -// &(this->model->getInterfaceMesh())); -// } - -// AKANTU_DEBUG_OUT(); -// } - -/* -------------------------------------------------------------------------- */ - -INSTANTIATE_MATERIAL_ONLY(MaterialReinforcement); - -/* -------------------------------------------------------------------------- */ - -} // akantu diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh index 09925013b..fa320e42a 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh @@ -1,192 +1,209 @@ /** * @file material_reinforcement.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Mar 13 2015 * @date last modification: Tue Nov 24 2015 * * @brief Reinforcement material * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_REINFORCEMENT_HH__ #define __AKANTU_MATERIAL_REINFORCEMENT_HH__ #include "aka_common.hh" #include "material.hh" #include "embedded_interface_model.hh" -#include "embedded_internal_field.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /** * @brief Material used to represent embedded reinforcements * * This class is used for computing the reinforcement stiffness matrix * along with the reinforcement residual. Room is made for constitutive law, * but actual use of contitutive laws is made in MaterialReinforcementTemplate. * * Be careful with the dimensions in this class : * - this->spatial_dimension is always 1 * - the template parameter dim is the dimension of the problem */ -template <UInt dim> class MaterialReinforcement : virtual public Material { + +template <class Mat, UInt dim> class MaterialReinforcement : public Mat { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// Constructor - MaterialReinforcement(SolidMechanicsModel & model, UInt spatial_dimension, - const Mesh & mesh, FEEngine & fe_engine, - const ID & id = ""); + MaterialReinforcement(EmbeddedInterfaceModel & model, const ID & id = ""); /// Destructor ~MaterialReinforcement() override; protected: - void initialize(SolidMechanicsModel & a_model); + void initialize(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Init the material void initMaterial() override; + /// Init the filters for background elements + void initFilters(); + /// Init the background shape derivatives void initBackgroundShapeDerivatives(); /// Init the cosine matrices void initDirectingCosines(); /// Assemble stiffness matrix void assembleStiffnessMatrix(GhostType ghost_type) override; /// Compute all the stresses ! void computeAllStresses(GhostType ghost_type) override; /// Compute energy Real getEnergy(const std::string & id) override; /// Assemble the residual of one type of element (typically _segment_2) void assembleInternalForces(GhostType ghost_type) override; - // virtual ElementTypeMap<UInt> getInternalDataPerElem(const ID & field_name, - // const ElementKind & - // kind, - // const ID & - // fe_engine_id) const; - - // /// Reimplementation of Material's function to accomodate for interface - // mesh - // virtual void flattenInternal(const std::string & field_id, - // ElementTypeMapArray<Real> & internal_flat, - // const GhostType ghost_type = _not_ghost, - // ElementKind element_kind = _ek_not_defined) - // const; - /* ------------------------------------------------------------------------ */ /* Protected methods */ /* ------------------------------------------------------------------------ */ protected: /// Allocate the background shape derivatives void allocBackgroundShapeDerivatives(); /// Compute the directing cosines matrix for one element type void computeDirectingCosines(const ElementType & type, GhostType ghost_type); /// Compute the directing cosines matrix on quadrature points. inline void computeDirectingCosinesOnQuad(const Matrix<Real> & nodes, Matrix<Real> & cosines); + /// Add the prestress to the computed stress + void addPrestress(const ElementType & type, GhostType ghost_type); + + /// Compute displacement gradient in reinforcement + void computeGradU(const ElementType & interface_type, GhostType ghost_type); + /// Assemble the stiffness matrix for an element type (typically _segment_2) void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// Assemble the stiffness matrix for background & interface types void assembleStiffnessMatrixInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type); /// Compute the background shape derivatives for a type void computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type); + /// Compute the background shape derivatives for a type pair + void computeBackgroundShapeDerivatives(const ElementType & interface_type, + const ElementType & bg_type, + GhostType ghost_type, + const Array<UInt> & filter); + /// Filter elements crossed by interface of a type - void filterInterfaceBackgroundElements(Array<UInt> & filter, + void filterInterfaceBackgroundElements(Array<UInt> & foreground, + Array<UInt> & background, const ElementType & type, const ElementType & interface_type, GhostType ghost_type); /// Assemble the residual of one type of element (typically _segment_2) void assembleInternalForces(const ElementType & type, GhostType ghost_type); /// Assemble the residual for a pair of elements void assembleInternalForcesInterface(const ElementType & interface_type, const ElementType & background_type, GhostType ghost_type); // TODO figure out why voigt size is 4 in 2D inline void stressTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); inline void strainTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); - /// Compute gradu on the interface quadrature points - virtual void computeGradU(const ElementType & type, GhostType ghost_type); + /// Get background filter + Array<UInt> & getBackgroundFilter(const ElementType & fg_type, + const ElementType & bg_type, + GhostType ghost_type) { + return (*background_filter(fg_type, ghost_type))(bg_type, ghost_type); + } + + /// Get foreground filter + Array<UInt> & getForegroundFilter(const ElementType & fg_type, + const ElementType & bg_type, + GhostType ghost_type) { + return (*foreground_filter(fg_type, ghost_type))(bg_type, ghost_type); + } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Embedded model - EmbeddedInterfaceModel * model; - - /// Stress in the reinforcement - InternalField<Real> stress_embedded; + EmbeddedInterfaceModel & emodel; /// Gradu of concrete on reinforcement InternalField<Real> gradu_embedded; /// C matrix on quad InternalField<Real> directing_cosines; /// Prestress on quad InternalField<Real> pre_stress; /// Cross-sectional area Real area; + template <typename T> + using CrossMap = ElementTypeMap<std::unique_ptr<ElementTypeMapArray<T>>>; + /// Background mesh shape derivatives - ElementTypeMap<ElementTypeMapArray<Real> *> shape_derivatives; -}; + CrossMap<Real> shape_derivatives; -#include "material_reinforcement_inline_impl.cc" + /// Foreground mesh filter (contains segment ids) + CrossMap<UInt> foreground_filter; + + /// Background element filter (contains bg ids) + CrossMap<UInt> background_filter; +}; } // akantu +#include "material_reinforcement_tmpl.hh" + #endif // __AKANTU_MATERIAL_REINFORCEMENT_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc deleted file mode 100644 index cf23faf42..000000000 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @file material_reinforcement_inline_impl.cc - * - * @author Lucas Frerot <lucas.frerot@epfl.ch> - * - * @date creation: Fri Jun 18 2010 - * @date last modification: Tue Jul 14 2015 - * - * @brief Reinforcement material - * - * @section LICENSE - * - * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de - * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des - * Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -/** - * The structure of the directing cosines matrix is : - * \f{eqnarray*}{ - * C_{1,\cdot} & = & (l^2, m^2, n^2, mn, ln, lm) \\ - * C_{i,j} & = & 0 - * \f} - * - * with : - * \f[ - * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s} - * \f] - */ -template<UInt dim> -inline void MaterialReinforcement<dim>::computeDirectingCosinesOnQuad(const Matrix<Real> & nodes, - Matrix<Real> & cosines) { - AKANTU_DEBUG_IN(); - - AKANTU_DEBUG_ASSERT(nodes.cols() == 2, "Higher order reinforcement elements not implemented"); - - const Vector<Real> & a = nodes(0), b = nodes(1); - Vector<Real> delta = b - a; - - cosines.clear(); - - Real sq_length = 0.; - for (UInt i = 0 ; i < dim ; i++) { - sq_length += Math::pow<2, Real>(delta(i)); - } - - if (dim == 2) { - cosines(0, 0) = Math::pow<2, Real>(delta(0)); // l^2 - cosines(0, 1) = Math::pow<2, Real>(delta(1)); // m^2 - cosines(0, 2) = delta(0) * delta(1); // lm - } else if (dim == 3) { - cosines(0, 0) = Math::pow<2, Real>(delta(0)); // l^2 - cosines(0, 1) = Math::pow<2, Real>(delta(1)); // m^2 - cosines(0, 2) = Math::pow<2, Real>(delta(2)); // n^2 - - cosines(0, 3) = delta(1) * delta(2); // mn - cosines(0, 4) = delta(0) * delta(2); // ln - cosines(0, 5) = delta(0) * delta(1); // lm - } - - cosines /= sq_length; - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template<UInt dim> -inline void MaterialReinforcement<dim>::stressTensorToVoigtVector(const Matrix<Real> & tensor, - Vector<Real> & vector) { - AKANTU_DEBUG_IN(); - - for (UInt i = 0; i < dim; i++) { - vector(i) = tensor(i, i); - } - - if (dim == 2) { - vector(2) = tensor(0, 1); - } else if (dim == 3) { - vector(3) = tensor(1, 2); - vector(4) = tensor(0, 2); - vector(5) = tensor(0, 1); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template<UInt dim> -inline void MaterialReinforcement<dim>::strainTensorToVoigtVector(const Matrix<Real> & tensor, - Vector<Real> & vector) { - AKANTU_DEBUG_IN(); - - for (UInt i = 0; i < dim; i++) { - vector(i) = tensor(i, i); - } - - if (dim == 2) { - vector(2) = 2 * tensor(0, 1); - } else if (dim == 3) { - vector(3) = 2 * tensor(1, 2); - vector(4) = 2 * tensor(0, 2); - vector(5) = 2 * tensor(0, 1); - } - - AKANTU_DEBUG_OUT(); -} diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh deleted file mode 100644 index 881d5f0df..000000000 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file material_reinforcement_template.hh - * - * @author Lucas Frerot <lucas.frerot@epfl.ch> - * - * @date creation: Wed Mar 25 2015 - * @date last modification: Mon Jun 01 2015 - * - * @brief Reinforcement material templated with constitutive law - * - * @section LICENSE - * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#ifndef __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__ -#define __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__ - -/* -------------------------------------------------------------------------- */ - -#include "aka_common.hh" -#include "material_elastic.hh" -#include "material_linear_isotropic_hardening.hh" -#include "material_reinforcement.hh" - -namespace akantu { - -/** - * @brief Implementation of MaterialReinforcement with 1D constitutive law - * @see MaterialReinforcement, MaterialElastic - * - * This class is a reinforcement featuring a constitutive law. - * <strong>Be careful !</strong> Because of multiple inheritance, this class - * forms a diamond. - */ -template <UInt dim, class ConstLaw = MaterialElastic<1>> -class MaterialReinforcementTemplate : virtual public MaterialReinforcement<dim>, - public ConstLaw { - - /* ------------------------------------------------------------------------ */ - /* Constructors/Destructors */ - /* ------------------------------------------------------------------------ */ -public: - /// Constructor - MaterialReinforcementTemplate(SolidMechanicsModel & a_model, - const ID & id = ""); - - /// Destructor - ~MaterialReinforcementTemplate() override; - - /* ------------------------------------------------------------------------ */ - /* Methods */ - /* ------------------------------------------------------------------------ */ -public: - /// Initialises the material - void initMaterial(); - - /// Compute the stiffness parameter for elements of a type - void computeTangentModuli(const ElementType & type, Array<Real> & tangent, - GhostType ghost_type) override; - - /// Computes stress used by constitutive law - void computeStress(ElementType type, GhostType ghost_type) override; - - /// Computes gradu to be used by the constitutive law - void computeGradU(const ElementType & type, GhostType ghost_type) override; - - /// Compute the potential energy of the reinforcement - void computePotentialEnergy(ElementType type, - GhostType ghost_type = _not_ghost) override; - - /// Get energy in reinforcement (currently limited to potential) - Real getEnergy(const std::string & id) override; - -protected: - /** - * @brief Compute interface gradu from bulk gradu - * \f[ - * \varepsilon_s = C \varepsilon_c - * \f] - */ - inline void computeInterfaceGradUOnQuad(const Matrix<Real> & full_gradu, - Real & gradu, const Matrix<Real> & C); -}; - -#include "material_reinforcement_template_tmpl.hh" - -} // akantu - -#endif // __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh deleted file mode 100644 index 0dcb83d01..000000000 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh +++ /dev/null @@ -1,190 +0,0 @@ -/** - * @file material_reinforcement_template_tmpl.hh - * - * @author Lucas Frerot <lucas.frerot@epfl.ch> - * - * @date creation: Wed Mar 25 2015 - * @date last modification: Thu Oct 15 2015 - * - * @brief Reinforcement material templated with constitutive law - * - * @section LICENSE - * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory - * (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -// /!\ no namespace here ! - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -MaterialReinforcementTemplate<dim, ConstLaw>::MaterialReinforcementTemplate( - SolidMechanicsModel & a_model, const ID & id) - : Material( - a_model, 1, - dynamic_cast<EmbeddedInterfaceModel &>(a_model).getInterfaceMesh(), - a_model.getFEEngine("EmbeddedInterfaceFEEngine"), id), - MaterialReinforcement<dim>( - a_model, 1, - dynamic_cast<EmbeddedInterfaceModel &>(a_model).getInterfaceMesh(), - a_model.getFEEngine("EmbeddedInterfaceFEEngine"), id), - ConstLaw( - a_model, 1, - dynamic_cast<EmbeddedInterfaceModel &>(a_model).getInterfaceMesh(), - a_model.getFEEngine("EmbeddedInterfaceFEEngine"), id + "const_law") {} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -MaterialReinforcementTemplate<dim, ConstLaw>::~MaterialReinforcementTemplate() { -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -void MaterialReinforcementTemplate<dim, ConstLaw>::initMaterial() { - MaterialReinforcement<dim>::initMaterial(); - ConstLaw::initMaterial(); - - // Needed for plasticity law - this->ConstLaw::nu = 0.5; - this->ConstLaw::updateInternalParameters(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -void MaterialReinforcementTemplate<dim, ConstLaw>::computeGradU( - const ElementType & el_type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - MaterialReinforcement<dim>::computeGradU(el_type, ghost_type); - - const UInt voigt_size = ConstLaw::getTangentStiffnessVoigtSize(dim); - - Array<Real>::matrix_iterator full_gradu_it = - this->MaterialReinforcement<dim>::gradu_embedded(el_type, ghost_type) - .begin(dim, dim); - Array<Real>::matrix_iterator full_gradu_end = - this->MaterialReinforcement<dim>::gradu_embedded(el_type, ghost_type) - .end(dim, dim); - - Array<Real>::scalar_iterator gradu_it = - this->ConstLaw::gradu(el_type, ghost_type).begin(); - - Array<Real>::matrix_iterator cosines_it = - this->directing_cosines(el_type, ghost_type) - .begin(voigt_size, voigt_size); - - for (; full_gradu_it != full_gradu_end; - ++full_gradu_it, ++gradu_it, ++cosines_it) { - Matrix<Real> & full_gradu = *full_gradu_it; - Real & gradu = *gradu_it; - Matrix<Real> & C = *cosines_it; - - computeInterfaceGradUOnQuad(full_gradu, gradu, C); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -void MaterialReinforcementTemplate<dim, ConstLaw>::computeInterfaceGradUOnQuad( - const Matrix<Real> & full_gradu, Real & gradu, const Matrix<Real> & C) { - const UInt voigt_size = ConstLaw::getTangentStiffnessVoigtSize(dim); - - Matrix<Real> epsilon(dim, dim); - Vector<Real> e_voigt(voigt_size); - Vector<Real> e_interface_voigt(voigt_size); - - epsilon = 0.5 * (full_gradu + full_gradu.transpose()); - MaterialReinforcement<dim>::strainTensorToVoigtVector(epsilon, e_voigt); - e_interface_voigt.mul<false>(C, e_voigt); - - gradu = e_interface_voigt(0); -} -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -void MaterialReinforcementTemplate<dim, ConstLaw>::computeTangentModuli( - const ElementType & el_type, Array<Real> & tangent, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - AKANTU_DEBUG_ASSERT(tangent.getNbComponent() == 1, - "Reinforcements only work in 1D"); - - ConstLaw::computeTangentModuli(el_type, tangent, ghost_type); - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -void MaterialReinforcementTemplate<dim, ConstLaw>::computeStress( - ElementType type, GhostType ghost_type) { - AKANTU_DEBUG_IN(); - - ConstLaw::computeStress(type, ghost_type); - - Array<Real>::matrix_iterator full_sigma_it = - this->MaterialReinforcement<dim>::stress_embedded(type, ghost_type) - .begin(dim, dim); - Array<Real>::matrix_iterator full_sigma_end = - this->MaterialReinforcement<dim>::stress_embedded(type, ghost_type) - .end(dim, dim); - Array<Real>::scalar_iterator sigma_it = - this->ConstLaw::stress(type, ghost_type).begin(); - Array<Real>::scalar_iterator pre_stress_it = - this->MaterialReinforcement<dim>::pre_stress(type, ghost_type).begin(); - - for (; full_sigma_it != full_sigma_end; - ++full_sigma_it, ++sigma_it, ++pre_stress_it) { - Matrix<Real> & sigma = *full_sigma_it; - - sigma(0, 0) = *sigma_it + *pre_stress_it; - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -Real MaterialReinforcementTemplate<dim, ConstLaw>::getEnergy( - const std::string & id) { - return MaterialReinforcement<dim>::getEnergy(id); -} - -/* -------------------------------------------------------------------------- */ - -template <UInt dim, class ConstLaw> -void MaterialReinforcementTemplate<dim, ConstLaw>::computePotentialEnergy( - ElementType type, GhostType ghost_type) { - const UInt nb_elements = - this->MaterialReinforcement<dim>::element_filter(type, ghost_type).size(); - const UInt nb_quad = this->MaterialReinforcement<dim>::model - ->getFEEngine("EmbeddedInterfaceFEEngine") - .getNbIntegrationPoints(type); - this->ConstLaw::potential_energy.alloc(nb_quad * nb_elements, 1, type, - ghost_type, 0.); - - ConstLaw::computePotentialEnergy(type, ghost_type); -} diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh new file mode 100644 index 000000000..4dc96d2e7 --- /dev/null +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh @@ -0,0 +1,803 @@ +/** + * @file material_reinforcement_tmpl.hh + * + * @author Lucas Frerot <lucas.frerot@epfl.ch> + * + * @date creation: Thu Feb 1 2018 + * + * @brief Reinforcement material + * + * @section LICENSE + * + * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory + * (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +#include "aka_common.hh" +#include "aka_voigthelper.hh" +#include "material_reinforcement.hh" + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +template <class Mat, UInt dim> +MaterialReinforcement<Mat, dim>::MaterialReinforcement( + EmbeddedInterfaceModel & model, const ID & id) + : Mat(model, 1, + model.getInterfaceMesh(), + model.getFEEngine("EmbeddedInterfaceFEEngine"), id), + emodel(model), + gradu_embedded("gradu_embedded", *this, 1, + model.getFEEngine("EmbeddedInterfaceFEEngine"), + this->element_filter), + directing_cosines("directing_cosines", *this, 1, + model.getFEEngine("EmbeddedInterfaceFEEngine"), + this->element_filter), + pre_stress("pre_stress", *this, 1, + model.getFEEngine("EmbeddedInterfaceFEEngine"), + this->element_filter), + area(1.0), shape_derivatives() { + AKANTU_DEBUG_IN(); + this->initialize(); + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::initialize() { + AKANTU_DEBUG_IN(); + + this->registerParam("area", area, _pat_parsable | _pat_modifiable, + "Reinforcement cross-sectional area"); + this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable, + "Uniform pre-stress"); + + // this->unregisterInternal(this->stress); + + // Fool the AvgHomogenizingFunctor + // stress.initialize(dim * dim); + + // Reallocate the element filter + this->element_filter.initialize(this->emodel.getInterfaceMesh(), + _spatial_dimension = 1); + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +MaterialReinforcement<Mat, dim>::~MaterialReinforcement() { + AKANTU_DEBUG_IN(); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::initMaterial() { + Mat::initMaterial(); + + gradu_embedded.initialize(dim * dim); + pre_stress.initialize(1); + + /// We initialise the stuff that is not going to change during the simulation + this->initFilters(); + this->allocBackgroundShapeDerivatives(); + this->initBackgroundShapeDerivatives(); + this->initDirectingCosines(); +} + +/* -------------------------------------------------------------------------- */ +/// Initialize the filter for background elements +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::initFilters() { + for (auto gt : ghost_types) { + for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) { + std::string shaped_id = "filter"; + if (gt == _ghost) + shaped_id += ":ghost"; + + auto & background = + background_filter(std::make_unique<ElementTypeMapArray<UInt>>( + "bg_" + shaped_id, this->name), + type, gt); + auto & foreground = foreground_filter( + std::make_unique<ElementTypeMapArray<UInt>>(shaped_id, this->name), + type, gt); + foreground->initialize(emodel.getMesh(), _nb_component = 1, + _ghost_type = gt); + background->initialize(emodel.getMesh(), _nb_component = 1, + _ghost_type = gt); + + // Computing filters + for (auto && bg_type : background->elementTypes(dim, gt)) { + filterInterfaceBackgroundElements( + (*foreground)(bg_type), (*background)(bg_type), bg_type, type, gt); + } + } + } +} + +/* -------------------------------------------------------------------------- */ +/// Construct a filter for a (interface_type, background_type) pair +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::filterInterfaceBackgroundElements( + Array<UInt> & foreground, Array<UInt> & background, + const ElementType & type, const ElementType & interface_type, + GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + foreground.resize(0); + background.resize(0); + + Array<Element> & elements = + emodel.getInterfaceAssociatedElements(interface_type, ghost_type); + Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); + + for (auto & elem_id : elem_filter) { + Element & elem = elements(elem_id); + if (elem.type == type) { + background.push_back(elem.element); + foreground.push_back(elem_id); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +namespace detail { + class BackgroundShapeDInitializer : public ElementTypeMapArrayInitializer { + public: + BackgroundShapeDInitializer(UInt spatial_dimension, FEEngine & engine, + const ElementType & foreground_type, + const ElementTypeMapArray<UInt> & filter, + const GhostType & ghost_type) + : ElementTypeMapArrayInitializer( + [](const ElementType & bgtype, const GhostType &) { + return ShapeFunctions::getShapeDerivativesSize(bgtype); + }, + spatial_dimension, ghost_type, _ek_regular) { + auto nb_quad = engine.getNbIntegrationPoints(foreground_type); + // Counting how many background elements are affected by elements of + // interface_type + for (auto type : filter.elementTypes(this->spatial_dimension)) { + // Inserting size + array_size_per_bg_type(filter(type).size() * nb_quad, type, + this->ghost_type); + } + } + + auto elementTypes() const -> decltype(auto) { + return array_size_per_bg_type.elementTypes(); + } + + UInt size(const ElementType & bgtype) const { + return array_size_per_bg_type(bgtype, this->ghost_type); + } + + protected: + ElementTypeMap<UInt> array_size_per_bg_type; + }; +} + +/** + * Background shape derivatives need to be stored per background element + * types but also per embedded element type, which is why they are stored + * in an ElementTypeMap<ElementTypeMapArray<Real> *>. The outer ElementTypeMap + * refers to the embedded types, and the inner refers to the background types. + */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::allocBackgroundShapeDerivatives() { + AKANTU_DEBUG_IN(); + + for (auto gt : ghost_types) { + for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) { + std::string shaped_id = "embedded_shape_derivatives"; + if (gt == _ghost) + shaped_id += ":ghost"; + + auto & shaped_etma = shape_derivatives( + std::make_unique<ElementTypeMapArray<Real>>(shaped_id, this->name), + type, gt); + shaped_etma->initialize( + detail::BackgroundShapeDInitializer( + emodel.getSpatialDimension(), + emodel.getFEEngine("EmbeddedInterfaceFEEngine"), type, + *background_filter(type, gt), gt), + 0, true); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::initBackgroundShapeDerivatives() { + AKANTU_DEBUG_IN(); + + for (auto interface_type : + this->element_filter.elementTypes(this->spatial_dimension)) { + for (auto type : background_filter(interface_type)->elementTypes(dim)) { + computeBackgroundShapeDerivatives(interface_type, type, _not_ghost, + this->element_filter(interface_type)); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::computeBackgroundShapeDerivatives( + const ElementType & interface_type, const ElementType & bg_type, + GhostType ghost_type, const Array<UInt> & filter) { + auto & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); + auto & engine = emodel.getFEEngine(); + auto & interface_mesh = emodel.getInterfaceMesh(); + + const auto nb_nodes_elem_bg = Mesh::getNbNodesPerElement(bg_type); + // const auto nb_strss = VoigtHelper<dim>::size; + const auto nb_quads_per_elem = + interface_engine.getNbIntegrationPoints(interface_type); + + Array<Real> quad_pos(0, dim, "interface_quad_pos"); + interface_engine.interpolateOnIntegrationPoints(interface_mesh.getNodes(), + quad_pos, dim, interface_type, + ghost_type, filter); + auto & background_shapesd = + (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type); + auto & background_elements = + (*background_filter(interface_type, ghost_type))(bg_type, ghost_type); + auto & foreground_elements = + (*foreground_filter(interface_type, ghost_type))(bg_type, ghost_type); + + auto shapesd_begin = + background_shapesd.begin(dim, nb_nodes_elem_bg, nb_quads_per_elem); + auto quad_begin = quad_pos.begin(dim, nb_quads_per_elem); + + for (auto && tuple : zip(background_elements, foreground_elements)) { + UInt bg = std::get<0>(tuple), fg = std::get<1>(tuple); + for (UInt i = 0; i < nb_quads_per_elem; ++i) { + Matrix<Real> shapesd = Tensor3<Real>(shapesd_begin[fg])(i); + Vector<Real> quads = Matrix<Real>(quad_begin[fg])(i); + + engine.computeShapeDerivatives(quads, bg, bg_type, shapesd, + ghost_type); + } + } +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::initDirectingCosines() { + AKANTU_DEBUG_IN(); + + Mesh & mesh = emodel.getInterfaceMesh(); + + Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost); + Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost); + + const UInt voigt_size = VoigtHelper<dim>::size; + directing_cosines.initialize(voigt_size); + + for (; type_it != type_end; ++type_it) { + computeDirectingCosines(*type_it, _not_ghost); + // computeDirectingCosines(*type_it, _ghost); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix( + GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + Mesh & interface_mesh = emodel.getInterfaceMesh(); + + Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); + Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); + + for (; type_it != type_end; ++type_it) { + assembleStiffnessMatrix(*type_it, ghost_type); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::assembleInternalForces( + GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + Mesh & interface_mesh = emodel.getInterfaceMesh(); + + Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost); + Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost); + + for (; type_it != type_end; ++type_it) { + this->assembleInternalForces(*type_it, ghost_type); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::computeAllStresses(GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + Mesh::type_iterator it = emodel.getInterfaceMesh().firstType(); + Mesh::type_iterator last_type = emodel.getInterfaceMesh().lastType(); + + for (; it != last_type; ++it) { + computeGradU(*it, ghost_type); + this->computeStress(*it, ghost_type); + addPrestress(*it, ghost_type); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::addPrestress(const ElementType & type, + GhostType ghost_type) { + auto & stress = this->stress(type, ghost_type); + auto & sigma_p = this->pre_stress(type, ghost_type); + + for (auto && tuple : zip(stress, sigma_p)) { + std::get<0>(tuple) += std::get<1>(tuple); + } +} + +/* -------------------------------------------------------------------------- */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::assembleInternalForces( + const ElementType & type, GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + Mesh & mesh = emodel.getMesh(); + + Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); + Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); + + for (; type_it != type_end; ++type_it) { + assembleInternalForcesInterface(type, *type_it, ghost_type); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +/** + * Computes and assemble the residual. Residual in reinforcement is computed as: + * + * \f[ + * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s} + * \f] + */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::assembleInternalForcesInterface( + const ElementType & interface_type, const ElementType & background_type, + GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + UInt voigt_size = VoigtHelper<dim>::size; + + FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); + + Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); + + UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); + UInt nb_quadrature_points = + interface_engine.getNbIntegrationPoints(interface_type, ghost_type); + UInt nb_element = elem_filter.size(); + + UInt back_dof = dim * nodes_per_background_e; + + Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( + background_type, ghost_type); + + Array<Real> integrant(nb_quadrature_points * nb_element, back_dof, + "integrant"); + + Array<Real>::vector_iterator integrant_it = integrant.begin(back_dof); + Array<Real>::vector_iterator integrant_end = integrant.end(back_dof); + + Array<Real>::matrix_iterator B_it = + shapesd.begin(dim, nodes_per_background_e); + Array<Real>::vector_iterator C_it = + directing_cosines(interface_type, ghost_type).begin(voigt_size); + + auto sigma_it = this->stress(interface_type, ghost_type).begin(); + + Matrix<Real> Bvoigt(voigt_size, back_dof); + + for (; integrant_it != integrant_end; + ++integrant_it, ++B_it, ++C_it, ++sigma_it) { + VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, + nodes_per_background_e); + Vector<Real> & C = *C_it; + Vector<Real> & BtCt_sigma = *integrant_it; + + BtCt_sigma.mul<true>(Bvoigt, C); + BtCt_sigma *= *sigma_it * area; + } + + Array<Real> residual_interface(nb_element, back_dof, "residual_interface"); + interface_engine.integrate(integrant, residual_interface, back_dof, + interface_type, ghost_type, elem_filter); + integrant.resize(0); + + Array<UInt> background_filter(nb_element, 1, "background_filter"); + + auto & filter = + getBackgroundFilter(interface_type, background_type, ghost_type); + + emodel.getDOFManager().assembleElementalArrayLocalArray( + residual_interface, emodel.getInternalForce(), background_type, + ghost_type, -1., filter); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::computeDirectingCosines( + const ElementType & type, GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + Mesh & interface_mesh = emodel.getInterfaceMesh(); + + const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + const UInt steel_dof = dim * nb_nodes_per_element; + const UInt voigt_size = VoigtHelper<dim>::size; + const UInt nb_quad_points = emodel.getFEEngine("EmbeddedInterfaceFEEngine") + .getNbIntegrationPoints(type, ghost_type); + + Array<Real> node_coordinates(this->element_filter(type, ghost_type).size(), + steel_dof); + + this->emodel.getFEEngine().template extractNodalToElementField<Real>( + interface_mesh, interface_mesh.getNodes(), node_coordinates, type, + ghost_type, this->element_filter(type, ghost_type)); + + Array<Real>::matrix_iterator directing_cosines_it = + directing_cosines(type, ghost_type).begin(1, voigt_size); + + Array<Real>::matrix_iterator node_coordinates_it = + node_coordinates.begin(dim, nb_nodes_per_element); + Array<Real>::matrix_iterator node_coordinates_end = + node_coordinates.end(dim, nb_nodes_per_element); + + for (; node_coordinates_it != node_coordinates_end; ++node_coordinates_it) { + for (UInt i = 0; i < nb_quad_points; i++, ++directing_cosines_it) { + Matrix<Real> & nodes = *node_coordinates_it; + Matrix<Real> & cosines = *directing_cosines_it; + + computeDirectingCosinesOnQuad(nodes, cosines); + } + } + + // Mauro: the directing_cosines internal is defined on the quadrature points + // of each element + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix( + const ElementType & type, GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + Mesh & mesh = emodel.getMesh(); + + Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); + Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); + + for (; type_it != type_end; ++type_it) { + assembleStiffnessMatrixInterface(type, *type_it, ghost_type); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +/** + * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001) + * \f[ + * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T + * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}} + * \f] + */ +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrixInterface( + const ElementType & interface_type, const ElementType & background_type, + GhostType ghost_type) { + AKANTU_DEBUG_IN(); + + UInt voigt_size = VoigtHelper<dim>::size; + + FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine"); + + Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type); + Array<Real> & grad_u = gradu_embedded(interface_type, ghost_type); + + UInt nb_element = elem_filter.size(); + UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); + UInt nb_quadrature_points = + interface_engine.getNbIntegrationPoints(interface_type, ghost_type); + + UInt back_dof = dim * nodes_per_background_e; + + UInt integrant_size = back_dof; + + grad_u.resize(nb_quadrature_points * nb_element); + + Array<Real> tangent_moduli(nb_element * nb_quadrature_points, 1, + "interface_tangent_moduli"); + this->computeTangentModuli(interface_type, tangent_moduli, ghost_type); + + Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))( + background_type, ghost_type); + + Array<Real> integrant(nb_element * nb_quadrature_points, + integrant_size * integrant_size, "B^t*C^t*D*C*B"); + + /// Temporary matrices for integrant product + Matrix<Real> Bvoigt(voigt_size, back_dof); + Matrix<Real> DCB(1, back_dof); + Matrix<Real> CtDCB(voigt_size, back_dof); + + Array<Real>::scalar_iterator D_it = tangent_moduli.begin(); + Array<Real>::scalar_iterator D_end = tangent_moduli.end(); + + Array<Real>::matrix_iterator C_it = + directing_cosines(interface_type, ghost_type).begin(1, voigt_size); + Array<Real>::matrix_iterator B_it = + shapesd.begin(dim, nodes_per_background_e); + Array<Real>::matrix_iterator integrant_it = + integrant.begin(integrant_size, integrant_size); + + for (; D_it != D_end; ++D_it, ++C_it, ++B_it, ++integrant_it) { + Real & D = *D_it; + Matrix<Real> & C = *C_it; + Matrix<Real> & B = *B_it; + Matrix<Real> & BtCtDCB = *integrant_it; + + VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt, + nodes_per_background_e); + + DCB.mul<false, false>(C, Bvoigt); + DCB *= D * area; + CtDCB.mul<true, false>(C, DCB); + BtCtDCB.mul<true, false>(Bvoigt, CtDCB); + } + + tangent_moduli.resize(0); + + Array<Real> K_interface(nb_element, integrant_size * integrant_size, + "K_interface"); + interface_engine.integrate(integrant, K_interface, + integrant_size * integrant_size, interface_type, + ghost_type, elem_filter); + + integrant.resize(0); + + // Mauro: Here K_interface contains the local stiffness matrices, + // directing_cosines contains the information about the orientation + // of the reinforcements, any rotation of the local stiffness matrix + // can be done here + + auto & filter = + getBackgroundFilter(interface_type, background_type, ghost_type); + + emodel.getDOFManager().assembleElementalMatricesToMatrix( + "K", "displacement", K_interface, background_type, ghost_type, _symmetric, + filter); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class Mat, UInt dim> +Real MaterialReinforcement<Mat, dim>::getEnergy(const std::string & id) { + AKANTU_DEBUG_IN(); + if (id == "potential") { + Real epot = 0.; + + this->computePotentialEnergyByElements(); + + Mesh::type_iterator it = this->element_filter.firstType( + this->spatial_dimension), + end = this->element_filter.lastType( + this->spatial_dimension); + + for (; it != end; ++it) { + FEEngine & interface_engine = + emodel.getFEEngine("EmbeddedInterfaceFEEngine"); + epot += interface_engine.integrate( + this->potential_energy(*it, _not_ghost), *it, _not_ghost, + this->element_filter(*it, _not_ghost)); + epot *= area; + } + + return epot; + } + + AKANTU_DEBUG_OUT(); + return 0; +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +void MaterialReinforcement<Mat, dim>::computeGradU( + const ElementType & interface_type, GhostType ghost_type) { + // Looping over background types + for (auto && bg_type : + background_filter(interface_type, ghost_type)->elementTypes(dim)) { + + const UInt nodes_per_background_e = Mesh::getNbNodesPerElement(bg_type); + const UInt voigt_size = VoigtHelper<dim>::size; + + auto & bg_shapesd = + (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type); + + auto & filter = getBackgroundFilter(interface_type, bg_type, ghost_type); + + Array<Real> disp_per_element(0, dim * nodes_per_background_e, "disp_elem"); + + FEEngine::extractNodalToElementField( + emodel.getMesh(), emodel.getDisplacement(), disp_per_element, bg_type, + ghost_type, filter); + + Matrix<Real> concrete_du(dim, dim); + Matrix<Real> epsilon(dim, dim); + Vector<Real> evoigt(voigt_size); + + for (auto && tuple : + zip(make_view(disp_per_element, dim, nodes_per_background_e), + make_view(bg_shapesd, dim, nodes_per_background_e), + this->gradu(interface_type, ghost_type), + make_view(this->directing_cosines(interface_type, ghost_type), + voigt_size))) { + auto & u = std::get<0>(tuple); + auto & B = std::get<1>(tuple); + auto & du = std::get<2>(tuple); + auto & C = std::get<3>(tuple); + + concrete_du.mul<false, true>(u, B); + auto epsilon = 0.5 * (concrete_du + concrete_du.transpose()); + strainTensorToVoigtVector(epsilon, evoigt); + du = C.dot(evoigt); + } + } +} + +/* -------------------------------------------------------------------------- */ + +/** + * The structure of the directing cosines matrix is : + * \f{eqnarray*}{ + * C_{1,\cdot} & = & (l^2, m^2, n^2, mn, ln, lm) \\ + * C_{i,j} & = & 0 + * \f} + * + * with : + * \f[ + * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot + * \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s} + * \f] + */ +template <class Mat, UInt dim> +inline void MaterialReinforcement<Mat, dim>::computeDirectingCosinesOnQuad( + const Matrix<Real> & nodes, Matrix<Real> & cosines) { + AKANTU_DEBUG_IN(); + + AKANTU_DEBUG_ASSERT(nodes.cols() == 2, + "Higher order reinforcement elements not implemented"); + + const Vector<Real> a = nodes(0), b = nodes(1); + Vector<Real> delta = b - a; + + Real sq_length = 0.; + for (UInt i = 0; i < dim; i++) { + sq_length += delta(i) * delta(i); + } + + if (dim == 2) { + cosines(0, 0) = delta(0) * delta(0); // l^2 + cosines(0, 1) = delta(1) * delta(1); // m^2 + cosines(0, 2) = delta(0) * delta(1); // lm + } else if (dim == 3) { + cosines(0, 0) = delta(0) * delta(0); // l^2 + cosines(0, 1) = delta(1) * delta(1); // m^2 + cosines(0, 2) = delta(2) * delta(2); // n^2 + + cosines(0, 3) = delta(1) * delta(2); // mn + cosines(0, 4) = delta(0) * delta(2); // ln + cosines(0, 5) = delta(0) * delta(1); // lm + } + + cosines /= sq_length; + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +inline void MaterialReinforcement<Mat, dim>::stressTensorToVoigtVector( + const Matrix<Real> & tensor, Vector<Real> & vector) { + AKANTU_DEBUG_IN(); + + for (UInt i = 0; i < dim; i++) { + vector(i) = tensor(i, i); + } + + if (dim == 2) { + vector(2) = tensor(0, 1); + } else if (dim == 3) { + vector(3) = tensor(1, 2); + vector(4) = tensor(0, 2); + vector(5) = tensor(0, 1); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +template <class Mat, UInt dim> +inline void MaterialReinforcement<Mat, dim>::strainTensorToVoigtVector( + const Matrix<Real> & tensor, Vector<Real> & vector) { + AKANTU_DEBUG_IN(); + + for (UInt i = 0; i < dim; i++) { + vector(i) = tensor(i, i); + } + + if (dim == 2) { + vector(2) = 2 * tensor(0, 1); + } else if (dim == 3) { + vector(3) = 2 * tensor(1, 2); + vector(4) = 2 * tensor(0, 2); + vector(5) = 2 * tensor(0, 1); + } + + AKANTU_DEBUG_OUT(); +} + +} // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc index 61d01bcbd..5780ec6e0 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc @@ -1,653 +1,651 @@ /** * @file material_cohesive_linear.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Feb 22 2012 * @date last modification: Thu Jan 14 2016 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <algorithm> #include <numeric> /* -------------------------------------------------------------------------- */ #include "dof_synchronizer.hh" #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> MaterialCohesiveLinear<spatial_dimension>::MaterialCohesiveLinear( SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model, id), sigma_c_eff("sigma_c_eff", *this), delta_c_eff("delta_c_eff", *this), insertion_stress("insertion_stress", *this), opening_prec("opening_prec", *this), reduction_penalty("reduction_penalty", *this) { AKANTU_DEBUG_IN(); this->registerParam("beta", beta, Real(0.), _pat_parsable | _pat_readable, "Beta parameter"); this->registerParam("G_c", G_c, Real(0.), _pat_parsable | _pat_readable, "Mode I fracture energy"); this->registerParam("penalty", penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty coefficient"); this->registerParam("volume_s", volume_s, Real(0.), _pat_parsable | _pat_readable, "Reference volume for sigma_c scaling"); this->registerParam("m_s", m_s, Real(1.), _pat_parsable | _pat_readable, "Weibull exponent for sigma_c scaling"); this->registerParam("kappa", kappa, Real(1.), _pat_parsable | _pat_readable, "Kappa parameter"); this->registerParam( "contact_after_breaking", contact_after_breaking, false, _pat_parsable | _pat_readable, "Activation of contact when the elements are fully damaged"); this->registerParam("max_quad_stress_insertion", max_quad_stress_insertion, false, _pat_parsable | _pat_readable, "Insertion of cohesive element when stress is high " "enough just on one quadrature point"); this->registerParam("recompute", recompute, false, _pat_parsable | _pat_modifiable, "recompute solution"); this->use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); /// compute scalars beta2_kappa2 = beta * beta / kappa / kappa; beta2_kappa = beta * beta / kappa; if (Math::are_float_equal(beta, 0)) beta2_inv = 0; else beta2_inv = 1. / beta / beta; sigma_c_eff.initialize(1); delta_c_eff.initialize(1); insertion_stress.initialize(spatial_dimension); opening_prec.initialize(spatial_dimension); reduction_penalty.initialize(1); if (!Math::are_float_equal(delta_c, 0.)) delta_c_eff.setDefaultValue(delta_c); else delta_c_eff.setDefaultValue(2 * G_c / sigma_c); if (model->getIsExtrinsic()) scaleInsertionTraction(); opening_prec.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::scaleInsertionTraction() { AKANTU_DEBUG_IN(); // do nothing if volume_s hasn't been specified by the user if (Math::are_float_equal(volume_s, 0.)) return; const Mesh & mesh_facets = model->getMeshFacets(); const FEEngine & fe_engine = model->getFEEngine(); const FEEngine & fe_engine_facet = model->getFEEngine("FacetsFEEngine"); // loop over facet type Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1); Real base_sigma_c = sigma_c; for (; first != last; ++first) { ElementType type_facet = *first; const Array<std::vector<Element>> & facet_to_element = mesh_facets.getElementToSubelement(type_facet); UInt nb_facet = facet_to_element.size(); UInt nb_quad_per_facet = fe_engine_facet.getNbIntegrationPoints(type_facet); // iterator to modify sigma_c for all the quadrature points of a facet Array<Real>::vector_iterator sigma_c_iterator = sigma_c(type_facet).begin_reinterpret(nb_quad_per_facet, nb_facet); for (UInt f = 0; f < nb_facet; ++f, ++sigma_c_iterator) { const std::vector<Element> & element_list = facet_to_element(f); // compute bounding volume Real volume = 0; auto elem = element_list.begin(); auto elem_end = element_list.end(); for (; elem != elem_end; ++elem) { if (*elem == ElementNull) continue; // unit vector for integration in order to obtain the volume UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(elem->type); Vector<Real> unit_vector(nb_quadrature_points, 1); volume += fe_engine.integrate(unit_vector, elem->type, elem->element, elem->ghost_type); } // scale sigma_c *sigma_c_iterator -= base_sigma_c; *sigma_c_iterator *= std::pow(volume_s / volume, 1. / m_s); *sigma_c_iterator += base_sigma_c; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkInsertion( bool check_only) { AKANTU_DEBUG_IN(); const Mesh & mesh_facets = model->getMeshFacets(); CohesiveElementInserter & inserter = model->getElementInserter(); - Real tolerance = Math::getTolerance(); - for (auto && type_facet : mesh_facets.elementTypes(spatial_dimension - 1)) { ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); const Array<bool> & facets_check = inserter.getCheckFacets(type_facet); auto & f_insertion = inserter.getInsertionFacets(type_facet); auto & f_filter = facet_filter(type_facet); auto & sig_c_eff = sigma_c_eff(type_cohesive); auto & del_c = delta_c_eff(type_cohesive); auto & ins_stress = insertion_stress(type_cohesive); - auto & trac_old = tractions_old(type_cohesive); + auto & trac_old = tractions.previous(type_cohesive); auto & open_prec = opening_prec(type_cohesive); auto & red_penalty = reduction_penalty(type_cohesive); const auto & f_stress = model->getStressOnFacets(type_facet); const auto & sigma_lim = sigma_c(type_facet); Real max_ratio = 0.; UInt index_f = 0; UInt index_filter = 0; UInt nn = 0; UInt nb_quad_facet = model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); UInt nb_quad_cohesive = model->getFEEngine("CohesiveFEEngine") .getNbIntegrationPoints(type_cohesive); AKANTU_DEBUG_ASSERT(nb_quad_cohesive == nb_quad_facet, "The cohesive element and the corresponding facet do " "not have the same numbers of integration points"); UInt nb_facet = f_filter.size(); // if (nb_facet == 0) continue; auto sigma_lim_it = sigma_lim.begin(); Matrix<Real> stress_tmp(spatial_dimension, spatial_dimension); Matrix<Real> normal_traction(spatial_dimension, nb_quad_facet); Vector<Real> stress_check(nb_quad_facet); UInt sp2 = spatial_dimension * spatial_dimension; const auto & tangents = model->getTangents(type_facet); const auto & normals = model->getFEEngine("FacetsFEEngine") .getNormalsOnIntegrationPoints(type_facet); auto normal_begin = normals.begin(spatial_dimension); auto tangent_begin = tangents.begin(tangents.getNbComponent()); auto facet_stress_begin = f_stress.begin(spatial_dimension, spatial_dimension * 2); std::vector<Real> new_sigmas; std::vector<Vector<Real>> new_normal_traction; std::vector<Real> new_delta_c; // loop over each facet belonging to this material for (UInt f = 0; f < nb_facet; ++f, ++sigma_lim_it) { UInt facet = f_filter(f); // skip facets where check shouldn't be realized if (!facets_check(facet)) continue; // compute the effective norm on each quadrature point of the facet for (UInt q = 0; q < nb_quad_facet; ++q) { UInt current_quad = facet * nb_quad_facet + q; const Vector<Real> & normal = normal_begin[current_quad]; const Vector<Real> & tangent = tangent_begin[current_quad]; const Matrix<Real> & facet_stress_it = facet_stress_begin[current_quad]; // compute average stress on the current quadrature point Matrix<Real> stress_1(facet_stress_it.storage(), spatial_dimension, spatial_dimension); Matrix<Real> stress_2(facet_stress_it.storage() + sp2, spatial_dimension, spatial_dimension); stress_tmp.copy(stress_1); stress_tmp += stress_2; stress_tmp /= 2.; Vector<Real> normal_traction_vec(normal_traction(q)); // compute normal and effective stress stress_check(q) = computeEffectiveNorm(stress_tmp, normal, tangent, normal_traction_vec); } // verify if the effective stress overcomes the threshold Real final_stress = stress_check.mean(); if (max_quad_stress_insertion) final_stress = *std::max_element( stress_check.storage(), stress_check.storage() + nb_quad_facet); - if (final_stress > (*sigma_lim_it - tolerance)) { + if (final_stress > *sigma_lim_it) { if (model->isDefaultSolverExplicit()) { f_insertion(facet) = true; if (check_only) continue; // store the new cohesive material parameters for each quadrature // point for (UInt q = 0; q < nb_quad_facet; ++q) { Real new_sigma = stress_check(q); Vector<Real> normal_traction_vec(normal_traction(q)); if (spatial_dimension != 3) normal_traction_vec *= -1.; new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; // set delta_c in function of G_c or a given delta_c value if (Math::are_float_equal(delta_c, 0.)) new_delta = 2 * G_c / new_sigma; else new_delta = (*sigma_lim_it) / new_sigma * delta_c; new_delta_c.push_back(new_delta); } } else { Real ratio = final_stress / (*sigma_lim_it); if (ratio > max_ratio) { ++nn; max_ratio = ratio; index_f = f; index_filter = f_filter(f); } } } } /// Insertion of only 1 cohesive element in case of implicit approach. The /// one subjected to the highest stress. if (!model->isDefaultSolverExplicit()) { const Communicator & comm = model->getMesh().getCommunicator(); Array<Real> abs_max(comm.getNbProc()); abs_max(comm.whoAmI()) = max_ratio; comm.allGather(abs_max); auto it = std::max_element(abs_max.begin(), abs_max.end()); Int pos = it - abs_max.begin(); if (pos != comm.whoAmI()) { AKANTU_DEBUG_OUT(); return; } if (nn) { f_insertion(index_filter) = true; if (!check_only) { // Array<Real>::iterator<Matrix<Real> > normal_traction_it = // normal_traction.begin_reinterpret(nb_quad_facet, // spatial_dimension, nb_facet); Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin(); for (UInt q = 0; q < nb_quad_cohesive; ++q) { Real new_sigma = (sigma_lim_it[index_f]); Vector<Real> normal_traction_vec(spatial_dimension, 0.0); new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; // set delta_c in function of G_c or a given delta_c value if (!Math::are_float_equal(delta_c, 0.)) new_delta = delta_c; else new_delta = 2 * G_c / (new_sigma); new_delta_c.push_back(new_delta); } } } } // update material data for the new elements UInt old_nb_quad_points = sig_c_eff.size(); UInt new_nb_quad_points = new_sigmas.size(); sig_c_eff.resize(old_nb_quad_points + new_nb_quad_points); ins_stress.resize(old_nb_quad_points + new_nb_quad_points); trac_old.resize(old_nb_quad_points + new_nb_quad_points); del_c.resize(old_nb_quad_points + new_nb_quad_points); open_prec.resize(old_nb_quad_points + new_nb_quad_points); red_penalty.resize(old_nb_quad_points + new_nb_quad_points); for (UInt q = 0; q < new_nb_quad_points; ++q) { sig_c_eff(old_nb_quad_points + q) = new_sigmas[q]; del_c(old_nb_quad_points + q) = new_delta_c[q]; red_penalty(old_nb_quad_points + q) = false; for (UInt dim = 0; dim < spatial_dimension; ++dim) { ins_stress(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); trac_old(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); open_prec(old_nb_quad_points + q, dim) = 0.; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTraction( const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators auto traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension); /// opening_prec is the opening of the previous step in the /// Newton-Raphson loop auto opening_prec_it = opening_prec(el_type, ghost_type).begin(spatial_dimension); auto contact_traction_it = contact_tractions(el_type, ghost_type).begin(spatial_dimension); auto contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); auto normal_it = normal.begin(spatial_dimension); auto traction_end = tractions(el_type, ghost_type).end(spatial_dimension); auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); auto delta_max_it = delta_max(el_type, ghost_type).begin(); auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto damage_it = damage(el_type, ghost_type).begin(); auto insertion_stress_it = insertion_stress(el_type, ghost_type).begin(spatial_dimension); auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); if (!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, ++opening_prec_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, ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; this->computeTractionOnQuad( *traction_it, *delta_max_it, *delta_max_prev_it, *delta_c_it, *insertion_stress_it, *sigma_c_it, *opening_it, *opening_prec_it, *normal_it, normal_opening, tangential_opening, normal_opening_norm, tangential_opening_norm, *damage_it, penetration, *reduction_penalty_it, current_penalty, *contact_traction_it, *contact_opening_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkDeltaMax( GhostType ghost_type) { AKANTU_DEBUG_IN(); /** * This function set a predefined value to the parameter * delta_max_prev of the elements that have been inserted in the * last loading step for which convergence has not been * reached. This is done before reducing the loading and re-doing * the step. Otherwise, the updating of delta_max_prev would be * done with reference to the non-convergent solution. In this * function also other variables related to the contact and * friction behavior are correctly set. */ Mesh & mesh = fem_cohesive.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); /** * the variable "recompute" is set to true to activate the * procedure that reduce the penalty parameter for * compression. This procedure is set true only during the phase of * load_reduction, that has to be set in the maiin file. The * penalty parameter will be reduced only for the elements having * reduction_penalty = true. */ recompute = true; for (; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; ElementType el_type = *it; /// define iterators auto delta_max_it = delta_max(el_type, ghost_type).begin(); auto delta_max_end = delta_max(el_type, ghost_type).end(); auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto opening_prec_it = opening_prec(el_type, ghost_type).begin(spatial_dimension); auto opening_prec_prev_it = opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); /// loop on each quadrature point for (; delta_max_it != delta_max_end; ++delta_max_it, ++delta_max_prev_it, ++delta_c_it, ++opening_prec_it, ++opening_prec_prev_it) { if (*delta_max_prev_it == 0) /// elements inserted in the last incremental step, that did /// not converge *delta_max_it = *delta_c_it / 1000; else /// elements introduced in previous incremental steps, for /// which a correct value of delta_max_prev already exists *delta_max_it = *delta_max_prev_it; /// in case convergence is not reached, set opening_prec to the /// value referred to the previous incremental step *opening_prec_it = *opening_prec_prev_it; } } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::resetVariables( GhostType ghost_type) { AKANTU_DEBUG_IN(); /** * This function set the variables "recompute" and * "reduction_penalty" to false. It is called by solveStepCohesive * when convergence is reached. Such variables, in fact, have to be * false at the beginning of a new incremental step. */ Mesh & mesh = fem_cohesive.getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); recompute = false; for (; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; ElementType el_type = *it; auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); auto reduction_penalty_end = reduction_penalty(el_type, ghost_type).end(); /// loop on each quadrature point for (; reduction_penalty_it != reduction_penalty_end; ++reduction_penalty_it) { *reduction_penalty_it = false; } } } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTangentTraction( const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & 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 = normal.begin(spatial_dimension); auto opening_it = opening(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 = delta_max.previous(el_type, ghost_type).begin(); auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); auto delta_c_it = delta_c_eff(el_type, ghost_type).begin(); auto damage_it = damage(el_type, ghost_type).begin(); auto contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it, ++reduction_penalty_it) { Real normal_opening_norm, tangential_opening_norm; bool penetration; Real current_penalty = 0.; 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, *reduction_penalty_it, current_penalty, *contact_opening_it); // 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, MaterialCohesiveLinear); } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc index de473fdf3..130bf7a92 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc @@ -1,581 +1,572 @@ /** * @file material_cohesive.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Feb 22 2012 * @date last modification: Tue Jan 12 2016 * * @brief Specialization of the material class for cohesive elements * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" #include "aka_random_generator.hh" #include "dof_synchronizer.hh" #include "fe_engine_template.hh" #include "integrator_gauss.hh" #include "shape_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MaterialCohesive::MaterialCohesive(SolidMechanicsModel & model, const ID & id) : Material(model, id), facet_filter("facet_filter", id, this->getMemoryID()), fem_cohesive( model.getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine")), reversible_energy("reversible_energy", *this), total_energy("total_energy", *this), opening("opening", *this), - opening_old("opening (old)", *this), tractions("tractions", *this), - tractions_old("tractions (old)", *this), + tractions("tractions", *this), contact_tractions("contact_tractions", *this), contact_opening("contact_opening", *this), delta_max("delta max", *this), use_previous_delta_max(false), use_previous_opening(false), damage("damage", *this), sigma_c("sigma_c", *this), normal(0, spatial_dimension, "normal") { AKANTU_DEBUG_IN(); this->model = dynamic_cast<SolidMechanicsModelCohesive *>(&model); this->registerParam("sigma_c", sigma_c, _pat_parsable | _pat_readable, "Critical stress"); this->registerParam("delta_c", delta_c, Real(0.), _pat_parsable | _pat_readable, "Critical displacement"); this->element_filter.initialize(this->model->getMesh(), _spatial_dimension = spatial_dimension, _element_kind = _ek_cohesive); // this->model->getMesh().initElementTypeMapArray( // this->element_filter, 1, spatial_dimension, false, _ek_cohesive); if (this->model->getIsExtrinsic()) this->facet_filter.initialize(this->model->getMeshFacets(), _spatial_dimension = spatial_dimension - 1, _element_kind = _ek_regular); // this->model->getMeshFacets().initElementTypeMapArray(facet_filter, 1, // spatial_dimension - // 1); this->reversible_energy.initialize(1); this->total_energy.initialize(1); - this->tractions_old.initialize(spatial_dimension); + this->tractions.initialize(spatial_dimension); - this->opening_old.initialize(spatial_dimension); + this->tractions.initializeHistory(); + this->contact_tractions.initialize(spatial_dimension); this->contact_opening.initialize(spatial_dimension); + this->opening.initialize(spatial_dimension); + this->opening.initializeHistory(); + this->delta_max.initialize(1); this->damage.initialize(1); if (this->model->getIsExtrinsic()) this->sigma_c.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MaterialCohesive::~MaterialCohesive() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); if (this->use_previous_delta_max) this->delta_max.initializeHistory(); if (this->use_previous_opening) this->opening.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Tractions", tractions); #endif auto & internal_force = const_cast<Array<Real> &>(model->getInternalForce()); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { auto & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; const auto & shapes = fem_cohesive.getShapes(type, ghost_type); auto & traction = tractions(type, ghost_type); auto & contact_traction = contact_tractions(type, ghost_type); UInt size_of_shapes = shapes.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem_cohesive.getNbIntegrationPoints(type, ghost_type); /// compute @f$t_i N_a@f$ Array<Real> * traction_cpy = new Array<Real>( nb_element * nb_quadrature_points, spatial_dimension * size_of_shapes); auto traction_it = traction.begin(spatial_dimension, 1); auto contact_traction_it = contact_traction.begin(spatial_dimension, 1); auto shapes_filtered_begin = shapes.begin(1, size_of_shapes); auto traction_cpy_it = traction_cpy->begin(spatial_dimension, size_of_shapes); Matrix<Real> traction_tmp(spatial_dimension, 1); for (UInt el = 0; el < nb_element; ++el) { UInt current_quad = elem_filter(el) * nb_quadrature_points; for (UInt q = 0; q < nb_quadrature_points; ++q, ++traction_it, ++contact_traction_it, ++current_quad, ++traction_cpy_it) { const Matrix<Real> & shapes_filtered = shapes_filtered_begin[current_quad]; traction_tmp.copy(*traction_it); traction_tmp += *contact_traction_it; traction_cpy_it->mul<false, false>(traction_tmp, shapes_filtered); } } /** * compute @f$\int t \cdot N\, dS@f$ by @f$ \sum_q \mathbf{N}^t * \mathbf{t}_q \overline w_q J_q@f$ */ Array<Real> * int_t_N = new Array<Real>( nb_element, spatial_dimension * size_of_shapes, "int_t_N"); fem_cohesive.integrate(*traction_cpy, *int_t_N, spatial_dimension * size_of_shapes, type, ghost_type, elem_filter); delete traction_cpy; int_t_N->extendComponentsInterlaced(2, int_t_N->getNbComponent()); Real * int_t_N_val = int_t_N->storage(); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < size_of_shapes * spatial_dimension; ++n) int_t_N_val[n] *= -1.; int_t_N_val += nb_nodes_per_element * spatial_dimension; } /// assemble model->getDOFManager().assembleElementalArrayLocalArray( *int_t_N, internal_force, type, ghost_type, -1, elem_filter); delete int_t_N; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { UInt nb_quadrature_points = fem_cohesive.getNbIntegrationPoints(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<Real> & shapes = fem_cohesive.getShapes(type, ghost_type); Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (!nb_element) continue; UInt size_of_shapes = shapes.getNbComponent(); Array<Real> * shapes_filtered = new Array<Real>( nb_element * nb_quadrature_points, size_of_shapes, "filtered shapes"); Real * shapes_filtered_val = shapes_filtered->storage(); UInt * elem_filter_val = elem_filter.storage(); for (UInt el = 0; el < nb_element; ++el) { - auto shapes_val = shapes.storage() + - elem_filter_val[el] * size_of_shapes * nb_quadrature_points; + auto shapes_val = + shapes.storage() + + elem_filter_val[el] * size_of_shapes * nb_quadrature_points; memcpy(shapes_filtered_val, shapes_val, size_of_shapes * nb_quadrature_points * sizeof(Real)); shapes_filtered_val += size_of_shapes * nb_quadrature_points; } /** * compute A matrix @f$ \mathbf{A} = \left[\begin{array}{c c c c c c c c c c *c c} * 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 \\ * 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 \\ * 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 \\ * 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 \\ * 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 \\ * 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 * \end{array} \right]@f$ **/ // UInt size_of_A = // spatial_dimension*size_of_shapes*spatial_dimension*nb_nodes_per_element; // Real * A = new Real[size_of_A]; // memset(A, 0, size_of_A*sizeof(Real)); Matrix<Real> A(spatial_dimension * size_of_shapes, spatial_dimension * nb_nodes_per_element); for (UInt i = 0; i < spatial_dimension * size_of_shapes; ++i) { A(i, i) = 1; A(i, i + spatial_dimension * size_of_shapes) = -1; } // compute traction. This call is not necessary for the linear // cohesive law that, currently, is the only one used for the // extrinsic approach. // if (!model->getIsExtrinsic()){ // computeTraction(ghost_type); //} /// get the tangent matrix @f$\frac{\partial{(t/\delta)}}{\partial{\delta}} /// @f$ Array<Real> * tangent_stiffness_matrix = new Array<Real>( nb_element * nb_quadrature_points, spatial_dimension * spatial_dimension, "tangent_stiffness_matrix"); // Array<Real> * normal = new Array<Real>(nb_element * // nb_quadrature_points, spatial_dimension, "normal"); normal.resize(nb_quadrature_points); computeNormal(model->getCurrentPosition(), normal, type, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ // computeOpening(model->getDisplacement(), opening(type, ghost_type), type, // ghost_type); tangent_stiffness_matrix->clear(); computeTangentTraction(type, *tangent_stiffness_matrix, normal, ghost_type); // delete normal; UInt size_at_nt_d_n_a = spatial_dimension * nb_nodes_per_element * spatial_dimension * nb_nodes_per_element; Array<Real> * at_nt_d_n_a = new Array<Real>( nb_element * nb_quadrature_points, size_at_nt_d_n_a, "A^t*N^t*D*N*A"); Array<Real>::iterator<Vector<Real>> shapes_filt_it = shapes_filtered->begin(size_of_shapes); Array<Real>::matrix_iterator D_it = tangent_stiffness_matrix->begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator At_Nt_D_N_A_it = at_nt_d_n_a->begin(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Array<Real>::matrix_iterator At_Nt_D_N_A_end = at_nt_d_n_a->end(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Matrix<Real> N(spatial_dimension, spatial_dimension * size_of_shapes); Matrix<Real> N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); Matrix<Real> D_N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); for (; At_Nt_D_N_A_it != At_Nt_D_N_A_end; ++At_Nt_D_N_A_it, ++D_it, ++shapes_filt_it) { N.clear(); /** * store the shapes in voigt notations matrix @f$\mathbf{N} = * \begin{array}{cccccc} N_0(\xi) & 0 & N_1(\xi) &0 & N_2(\xi) & 0 \\ * 0 & * N_0(\xi)& 0 &N_1(\xi)& 0 & N_2(\xi) \end{array} @f$ **/ for (UInt i = 0; i < spatial_dimension; ++i) for (UInt n = 0; n < size_of_shapes; ++n) N(i, i + spatial_dimension * n) = (*shapes_filt_it)(n); /** * compute stiffness matrix @f$ \mathbf{K} = \delta \mathbf{U}^T * \int_{\Gamma_c} {\mathbf{P}^t \frac{\partial{\mathbf{t}}} *{\partial{\delta}} * \mathbf{P} d\Gamma \Delta \mathbf{U}} @f$ **/ N_A.mul<false, false>(N, A); D_N_A.mul<false, false>(*D_it, N_A); (*At_Nt_D_N_A_it).mul<true, false>(D_N_A, N_A); } delete tangent_stiffness_matrix; delete shapes_filtered; Array<Real> * K_e = new Array<Real>(nb_element, size_at_nt_d_n_a, "K_e"); fem_cohesive.integrate(*at_nt_d_n_a, *K_e, size_at_nt_d_n_a, type, ghost_type, elem_filter); delete at_nt_d_n_a; model->getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _unsymmetric, elem_filter); delete K_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- * * Compute traction from displacements * * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void MaterialCohesive::computeTraction(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Openings", opening); #endif for (auto & type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) continue; UInt nb_quadrature_points = nb_element * fem_cohesive.getNbIntegrationPoints(type, ghost_type); normal.resize(nb_quadrature_points); /// compute normals @f$\mathbf{n}@f$ computeNormal(model->getCurrentPosition(), normal, type, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ computeOpening(model->getDisplacement(), opening(type, ghost_type), type, ghost_type); /// compute traction @f$\mathbf{t}@f$ computeTraction(normal, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeNormal(const Array<Real> & position, Array<Real> & normal, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem_cohesive = this->model->getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine"); - if (type == _cohesive_1d_2) - fem_cohesive.computeNormalsOnIntegrationPoints(position, normal, type, - ghost_type); - else { #define COMPUTE_NORMAL(type) \ fem_cohesive.getShapeFunctions() \ .computeNormalsOnIntegrationPoints<type, CohesiveReduceFunctionMean>( \ position, normal, ghost_type, element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_NORMAL); #undef COMPUTE_NORMAL - } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeOpening(const Array<Real> & displacement, Array<Real> & opening, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem_cohesive = this->model->getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine"); #define COMPUTE_OPENING(type) \ fem_cohesive.getShapeFunctions() \ .interpolateOnIntegrationPoints<type, CohesiveReduceFunctionOpening>( \ displacement, opening, spatial_dimension, ghost_type, \ element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_OPENING); #undef COMPUTE_OPENING AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -void MaterialCohesive::computeEnergies() { +void MaterialCohesive::updateEnergies(ElementType type, + GhostType ghost_type) { AKANTU_DEBUG_IN(); + if(Mesh::getKind(type) != _ek_cohesive) return; + Vector<Real> b(spatial_dimension); Vector<Real> h(spatial_dimension); - - for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, - _ek_cohesive)) { - auto erev = reversible_energy(type, _not_ghost).begin(); - auto etot = total_energy(type, _not_ghost).begin(); - auto traction_it = tractions(type, _not_ghost).begin(spatial_dimension); - auto traction_old_it = - tractions_old(type, _not_ghost).begin(spatial_dimension); - auto opening_it = opening(type, _not_ghost).begin(spatial_dimension); - auto opening_old_it = - opening_old(type, _not_ghost).begin(spatial_dimension); - - auto traction_end = tractions(type, _not_ghost).end(spatial_dimension); - - /// loop on each quadrature point - for (; traction_it != traction_end; ++traction_it, ++traction_old_it, - ++opening_it, ++opening_old_it, ++erev, - ++etot) { - /// trapezoidal integration - b = *opening_it; - b -= *opening_old_it; - - h = *traction_old_it; - h += *traction_it; - - *etot += .5 * b.dot(h); - *erev = .5 * traction_it->dot(*opening_it); - } + auto erev = reversible_energy(type, ghost_type).begin(); + auto etot = total_energy(type, ghost_type).begin(); + auto traction_it = tractions(type, ghost_type).begin(spatial_dimension); + auto traction_old_it = + tractions.previous(type, ghost_type).begin(spatial_dimension); + auto opening_it = opening(type, ghost_type).begin(spatial_dimension); + auto opening_old_it = opening.previous(type, ghost_type).begin(spatial_dimension); + + auto traction_end = tractions(type, ghost_type).end(spatial_dimension); + + /// loop on each quadrature point + for (; traction_it != traction_end; ++traction_it, ++traction_old_it, + ++opening_it, ++opening_old_it, ++erev, + ++etot) { + /// trapezoidal integration + b = *opening_it; + b -= *opening_old_it; + + h = *traction_old_it; + h += *traction_it; + + *etot += .5 * b.dot(h); + *erev = .5 * traction_it->dot(*opening_it); } /// update old values - GhostType ghost_type = _not_ghost; - for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, - _ek_cohesive)) { - tractions_old(type, ghost_type).copy(tractions(type, ghost_type)); - opening_old(type, ghost_type).copy(opening(type, ghost_type)); - } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getReversibleEnergy() { AKANTU_DEBUG_IN(); Real erev = 0.; /// integrate reversible energy for each type of elements for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, _ek_cohesive)) { erev += fem_cohesive.integrate(reversible_energy(type, _not_ghost), type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return erev; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getDissipatedEnergy() { AKANTU_DEBUG_IN(); Real edis = 0.; /// integrate dissipated energy for each type of elements for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, _ek_cohesive)) { Array<Real> dissipated_energy(total_energy(type, _not_ghost)); dissipated_energy -= reversible_energy(type, _not_ghost); edis += fem_cohesive.integrate(dissipated_energy, type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return edis; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getContactEnergy() { AKANTU_DEBUG_IN(); Real econ = 0.; /// integrate contact energy for each type of elements for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost, _ek_cohesive)) { auto & el_filter = element_filter(type, _not_ghost); UInt nb_quad_per_el = fem_cohesive.getNbIntegrationPoints(type, _not_ghost); UInt nb_quad_points = el_filter.size() * nb_quad_per_el; Array<Real> contact_energy(nb_quad_points); auto contact_traction_it = contact_tractions(type, _not_ghost).begin(spatial_dimension); auto contact_opening_it = contact_opening(type, _not_ghost).begin(spatial_dimension); /// loop on each quadrature point for (UInt q = 0; q < nb_quad_points; ++contact_traction_it, ++contact_opening_it, ++q) { contact_energy(q) = .5 * contact_traction_it->dot(*contact_opening_it); } econ += fem_cohesive.integrate(contact_energy, type, _not_ghost, el_filter); } AKANTU_DEBUG_OUT(); return econ; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getEnergy(const std::string & type) { AKANTU_DEBUG_IN(); if (type == "reversible") return getReversibleEnergy(); else if (type == "dissipated") return getDissipatedEnergy(); else if (type == "cohesive contact") return getContactEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh index 4643f98ac..596297cc9 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh @@ -1,256 +1,251 @@ /** * @file material_cohesive.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Jan 12 2016 * * @brief Specialization of the material class for cohesive elements * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "material.hh" /* -------------------------------------------------------------------------- */ #include "cohesive_internal_field.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_HH__ #define __AKANTU_MATERIAL_COHESIVE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class SolidMechanicsModelCohesive; } namespace akantu { class MaterialCohesive : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using MyFEEngineCohesiveType = FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>; public: MaterialCohesive(SolidMechanicsModel & model, const ID & id = ""); ~MaterialCohesive() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter void initMaterial() override; /// compute tractions (including normals and openings) void computeTraction(GhostType ghost_type = _not_ghost); /// assemble residual void assembleInternalForces(GhostType ghost_type = _not_ghost) override; - /// compute reversible and total energies by element - void computeEnergies(); - - /// check stress for cohesive elements' insertion, by default it + /// check stress for cohesive elements' insertion, by default it /// also updates the cohesive elements' data virtual void checkInsertion(bool /*check_only*/ = false) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// check delta_max for cohesive elements in case of no convergence /// in the solveStep (only for extrinsic-implicit) virtual void checkDeltaMax(GhostType /*ghost_type*/ = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// reset variables when convergence is reached (only for /// extrinsic-implicit) virtual void resetVariables(GhostType /*ghost_type*/ = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// interpolate stress on given positions for each element (empty /// implemantation to avoid the generic call to be done on cohesive elements) virtual void interpolateStress(const ElementType /*type*/, Array<Real> & /*result*/){}; /// compute the stresses void computeAllStresses(GhostType /*ghost_type*/ = _not_ghost) override{}; // add the facet to be handled by the material UInt addFacet(const Element & element); protected: virtual void computeTangentTraction(const ElementType & /*el_type*/, Array<Real> & /*tangent_matrix*/, const Array<Real> & /*normal*/, GhostType /*ghost_type*/ = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the normal void computeNormal(const Array<Real> & position, Array<Real> & normal, ElementType type, GhostType ghost_type); /// compute the opening void computeOpening(const Array<Real> & displacement, Array<Real> & opening, ElementType type, GhostType ghost_type); template <ElementType type> void computeNormal(const Array<Real> & position, Array<Real> & normal, GhostType ghost_type); /// assemble stiffness void assembleStiffnessMatrix(GhostType ghost_type) override; /// constitutive law virtual void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost) = 0; /// parallelism functions inline UInt getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const; inline void packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const; inline void unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag); +protected: + void updateEnergies(ElementType el_type, GhostType ghost_type) override; + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the opening AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Opening, opening, Real); /// get the traction AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Traction, tractions, Real); /// get damage AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real); /// get facet filter AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO(FacetFilter, facet_filter, const ElementTypeMapArray<UInt> &); // AKANTU_GET_MACRO(ElementFilter, element_filter, const // ElementTypeMapArray<UInt> &); /// compute reversible energy Real getReversibleEnergy(); /// compute dissipated energy Real getDissipatedEnergy(); /// compute contact energy Real getContactEnergy(); /// get energy - Real getEnergy(const std::string &type) override; + Real getEnergy(const std::string & type) override; /// return the energy (identified by id) for the provided element - Real getEnergy(const std::string &energy_id, ElementType type, UInt index) override { + Real getEnergy(const std::string & energy_id, ElementType type, + UInt index) override { return Material::getEnergy(energy_id, type, index); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of facets assigned to this material ElementTypeMapArray<UInt> facet_filter; /// Link to the cohesive fem object in the model FEEngine & fem_cohesive; private: /// reversible energy by quadrature point CohesiveInternalField<Real> reversible_energy; /// total energy by quadrature point CohesiveInternalField<Real> total_energy; protected: /// opening in all elements and quadrature points CohesiveInternalField<Real> opening; - /// opening in all elements and quadrature points (previous time step) - CohesiveInternalField<Real> opening_old; - /// traction in all elements and quadrature points CohesiveInternalField<Real> tractions; - /// traction in all elements and quadrature points (previous time step) - CohesiveInternalField<Real> tractions_old; - /// traction due to contact CohesiveInternalField<Real> contact_tractions; /// normal openings for contact tractions CohesiveInternalField<Real> contact_opening; /// maximum displacement CohesiveInternalField<Real> delta_max; /// tell if the previous delta_max state is needed (in iterative schemes) bool use_previous_delta_max; /// tell if the previous opening state is needed (in iterative schemes) bool use_previous_opening; /// damage CohesiveInternalField<Real> damage; /// pointer to the solid mechanics model for cohesive elements SolidMechanicsModelCohesive * model; /// critical stress RandomInternalField<Real, FacetInternalField> sigma_c; /// critical displacement Real delta_c; /// array to temporarily store the normals Array<Real> normal; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_inline_impl.cc" } // namespace akantu #include "cohesive_internal_field_tmpl.hh" #endif /* __AKANTU_MATERIAL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc index 3a03852bf..5e6a2cf69 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc @@ -1,95 +1,102 @@ /** * @file material_cohesive_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Aug 04 2010 * @date last modification: Thu Oct 15 2015 * * @brief MaterialCohesive inline implementation * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline UInt MaterialCohesive::addFacet(const Element & element) { Array<UInt> & f_filter = facet_filter(element.type, element.ghost_type); f_filter.push_back(element.element); - return f_filter.size()-1; + return f_filter.size() - 1; } - /* -------------------------------------------------------------------------- */ -template<ElementType type> +template <ElementType type> void MaterialCohesive::computeNormal(const Array<Real> & /*position*/, - Array<Real> & /*normal*/, - GhostType /*ghost_type*/) { -} + Array<Real> & /*normal*/, + GhostType /*ghost_type*/) {} /* -------------------------------------------------------------------------- */ -inline UInt MaterialCohesive::getNbDataForElements(const Array<Element> & elements, - SynchronizationTag tag) const { +inline UInt +MaterialCohesive::getNbDataForElements(const Array<Element> & elements, + SynchronizationTag tag) const { switch (tag) { case _gst_smm_stress: { - return 2 * spatial_dimension * sizeof(Real) * this->getModel().getNbIntegrationPoints(elements, "CohesiveFEEngine"); + return 2 * spatial_dimension * sizeof(Real) * + this->getModel().getNbIntegrationPoints(elements, + "CohesiveFEEngine"); } case _gst_smmc_damage: { - return sizeof(Real) * this->getModel().getNbIntegrationPoints(elements, "CohesiveFEEngine"); + return sizeof(Real) * + this->getModel().getNbIntegrationPoints(elements, + "CohesiveFEEngine"); } default: {} } return 0; } /* -------------------------------------------------------------------------- */ inline void MaterialCohesive::packElementData(CommunicationBuffer & buffer, - const Array<Element> & elements, - SynchronizationTag tag) const { + const Array<Element> & elements, + SynchronizationTag tag) const { switch (tag) { case _gst_smm_stress: { packElementDataHelper(tractions, buffer, elements, "CohesiveFEEngine"); - packElementDataHelper(contact_tractions, buffer, elements, "CohesiveFEEngine"); + packElementDataHelper(contact_tractions, buffer, elements, + "CohesiveFEEngine"); break; } case _gst_smmc_damage: - packElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); break; + packElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); + break; default: {} } } /* -------------------------------------------------------------------------- */ inline void MaterialCohesive::unpackElementData(CommunicationBuffer & buffer, - const Array<Element> & elements, - SynchronizationTag tag) { + const Array<Element> & elements, + SynchronizationTag tag) { switch (tag) { case _gst_smm_stress: { unpackElementDataHelper(tractions, buffer, elements, "CohesiveFEEngine"); - unpackElementDataHelper(contact_tractions, buffer, elements, "CohesiveFEEngine"); + unpackElementDataHelper(contact_tractions, buffer, elements, + "CohesiveFEEngine"); break; } case _gst_smmc_damage: - unpackElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); break; + unpackElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); + break; default: {} } } diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc index 4af001104..ab54a0dc6 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc @@ -1,752 +1,713 @@ /** * @file solid_mechanics_model_cohesive.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Wed Jan 13 2016 * * @brief Solid mechanics model for cohesive elements * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "aka_iterators.hh" #include "cohesive_element_inserter.hh" #include "element_synchronizer.hh" #include "facet_synchronizer.hh" #include "fe_engine_template.hh" #include "integrator_gauss.hh" #include "material_cohesive.hh" #include "parser.hh" #include "shape_cohesive.hh" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ namespace akantu { -const SolidMechanicsModelCohesiveOptions - default_solid_mechanics_model_cohesive_options(_explicit_lumped_mass, - false); - /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::SolidMechanicsModelCohesive( Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, dim, id, memory_id, ModelType::_solid_mechanics_model_cohesive), tangents("tangents", id), facet_stress("facet_stress", id), facet_material("facet_material", id) { AKANTU_DEBUG_IN(); auto && tmp_material_selector = std::make_shared<DefaultMaterialCohesiveSelector>(*this); tmp_material_selector->setFallback(this->material_selector); this->material_selector = tmp_material_selector; #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("cohesive elements", id); this->mesh.addDumpMeshToDumper("cohesive elements", mesh, Model::spatial_dimension, _not_ghost, _ek_cohesive); #endif if (this->mesh.isDistributed()) { /// create the distributed synchronizer for cohesive elements this->cohesive_synchronizer = std::make_unique<ElementSynchronizer>( mesh, "cohesive_distributed_synchronizer"); auto & synchronizer = mesh.getElementSynchronizer(); this->cohesive_synchronizer->split(synchronizer, [](auto && el) { return Mesh::getKind(el.type) == _ek_cohesive; }); this->registerSynchronizer(*cohesive_synchronizer, _gst_material_id); this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_stress); this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_boundary); } this->inserter = std::make_unique<CohesiveElementInserter>( this->mesh, id + ":cohesive_element_inserter"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::~SolidMechanicsModelCohesive() = default; /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::setTimeStep(Real time_step, const ID & solver_id) { SolidMechanicsModel::setTimeStep(time_step, solver_id); #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper("cohesive elements").setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initFullImpl(const ModelOptions & options) { AKANTU_DEBUG_IN(); const auto & smmc_options = dynamic_cast<const SolidMechanicsModelCohesiveOptions &>(options); this->is_extrinsic = smmc_options.extrinsic; inserter->setIsExtrinsic(is_extrinsic); if (mesh.isDistributed()) { auto & mesh_facets = inserter->getMeshFacets(); auto & synchronizer = dynamic_cast<FacetSynchronizer &>(mesh_facets.getElementSynchronizer()); this->registerSynchronizer(synchronizer, _gst_smmc_facets); this->registerSynchronizer(synchronizer, _gst_smmc_facets_conn); synchronizeGhostFacetsConnectivity(); /// create the facet synchronizer for extrinsic simulations if (is_extrinsic) { - facet_stress_synchronizer = - std::make_unique<ElementSynchronizer>(mesh_facets); - - facet_stress_synchronizer->updateSchemes( - [&](auto & scheme, auto & proc, auto & direction) { - scheme.copy(const_cast<const FacetSynchronizer &>(synchronizer) - .getCommunications() - .getScheme(proc, direction)); - }); + facet_stress_synchronizer = std::make_unique<ElementSynchronizer>( + synchronizer, id + ":facet_stress_synchronizer"); + this->registerSynchronizer(*facet_stress_synchronizer, _gst_smmc_facets_stress); } inserter->initParallel(*cohesive_synchronizer); } ParserSection section; bool is_empty; std::tie(section, is_empty) = this->getParserSection(); if (not is_empty) { auto inserter_section = section.getSubSections(ParserType::_cohesive_inserter); if (inserter_section.begin() != inserter_section.end()) { inserter->parseSection(*inserter_section.begin()); } } SolidMechanicsModel::initFullImpl(options); AKANTU_DEBUG_OUT(); } // namespace akantu /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initMaterials() { AKANTU_DEBUG_IN(); // make sure the material are instantiated if (!are_materials_instantiated) instantiateMaterials(); /// find the first cohesive material UInt cohesive_index = UInt(-1); for (auto && material : enumerate(materials)) { if (dynamic_cast<MaterialCohesive *>(std::get<1>(material).get())) { cohesive_index = std::get<0>(material); break; } } if (cohesive_index == UInt(-1)) AKANTU_EXCEPTION("No cohesive materials in the material input file"); material_selector->setFallback(cohesive_index); // set the facet information in the material in case of dynamic insertion // to know what material to call for stress checks if (is_extrinsic) { this->initExtrinsicMaterials(); } else { this->initIntrinsicMaterials(); } AKANTU_DEBUG_OUT(); } // namespace akantu /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initExtrinsicMaterials() { const Mesh & mesh_facets = inserter->getMeshFacets(); facet_material.initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = material_selector->getFallbackValue()); - for_each_element(mesh_facets, - [&](auto && element) { - auto mat_index = (*material_selector)(element); - auto & mat = dynamic_cast<MaterialCohesive &>( - *materials[mat_index]); - facet_material(element) = mat_index; - mat.addFacet(element); - }, - _spatial_dimension = spatial_dimension - 1); + for_each_element( + mesh_facets, + [&](auto && element) { + auto mat_index = (*material_selector)(element); + auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]); + facet_material(element) = mat_index; + mat.addFacet(element); + }, + _spatial_dimension = spatial_dimension - 1, _ghost_type = _not_ghost); SolidMechanicsModel::initMaterials(); this->initAutomaticInsertion(); } /* -------------------------------------------------------------------------- */ #if 0 void SolidMechanicsModelCohesive::initIntrinsicCohesiveMaterials( const std::string & cohesive_surfaces) { AKANTU_DEBUG_IN(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) if (facet_synchronizer != nullptr) inserter->initParallel(facet_synchronizer, cohesive_element_synchronizer); // inserter->initParallel(facet_synchronizer, synch_parallel); #endif std::istringstream split(cohesive_surfaces); std::string physname; while (std::getline(split, physname, ',')) { AKANTU_DEBUG_INFO( "Pre-inserting cohesive elements along facets from physical surface: " << physname); insertElementsFromMeshData(physname); } synchronizeInsertionData(); SolidMechanicsModel::initMaterials(); auto && tmp = std::make_shared<MeshDataMaterialCohesiveSelector>(*this); tmp->setFallback(material_selector->getFallbackValue()); tmp->setFallback(material_selector->getFallbackSelector()); material_selector = tmp; // UInt nb_new_elements = inserter->insertElements(); // if (nb_new_elements > 0) { // this->reinitializeSolver(); // } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::synchronizeInsertionData() { if (inserter->getMeshFacets().isDistributed()) { inserter->getMeshFacets().getElementSynchronizer().synchronizeOnce( *inserter, _gst_ce_groups); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initIntrinsicMaterials() { AKANTU_DEBUG_IN(); SolidMechanicsModel::initMaterials(); this->insertIntrinsicElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian */ void SolidMechanicsModelCohesive::initModel() { AKANTU_DEBUG_IN(); SolidMechanicsModel::initModel(); registerFEEngineObject<MyFEEngineCohesiveType>("CohesiveFEEngine", mesh, Model::spatial_dimension); /// add cohesive type connectivity ElementType type = _not_defined; for (auto && type_ghost : ghost_types) { for (const auto & tmp_type : mesh.elementTypes(spatial_dimension, type_ghost)) { const auto & connectivity = mesh.getConnectivity(tmp_type, type_ghost); if (connectivity.size() == 0) continue; type = tmp_type; auto type_facet = Mesh::getFacetType(type); auto type_cohesive = FEEngine::getCohesiveElementType(type_facet); mesh.addConnectivityType(type_cohesive, type_ghost); } } AKANTU_DEBUG_ASSERT(type != _not_defined, "No elements in the mesh"); getFEEngine("CohesiveFEEngine").initShapeFunctions(_not_ghost); getFEEngine("CohesiveFEEngine").initShapeFunctions(_ghost); registerFEEngineObject<MyFEEngineFacetType>( "FacetsFEEngine", mesh.getMeshFacets(), Model::spatial_dimension - 1); if (is_extrinsic) { getFEEngine("FacetsFEEngine").initShapeFunctions(_not_ghost); getFEEngine("FacetsFEEngine").initShapeFunctions(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::insertIntrinsicElements() { AKANTU_DEBUG_IN(); inserter->insertIntrinsicElements(); AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::updateFacetStressSynchronizer() { - if (facet_stress_synchronizer != nullptr) { - const auto & rank_to_element = - mesh.getElementSynchronizer().getElementToRank(); - const auto & facet_checks = inserter->getCheckFacets(); - const auto & element_to_facet = mesh.getElementToSubelement(); - UInt rank = mesh.getCommunicator().whoAmI(); - - facet_stress_synchronizer->updateSchemes( - [&](auto & scheme, auto & proc, auto & /*direction*/) { - UInt el = 0; - for (auto && element : scheme) { - if (not facet_checks(element)) - continue; - - const auto & next_el = element_to_facet(element); - UInt rank_left = rank_to_element(next_el[0]); - UInt rank_right = rank_to_element(next_el[1]); - - if ((rank_left == rank and rank_right == proc) or - (rank_left == proc and rank_right == rank)) { - scheme[el] = element; - ++el; - } - } - scheme.resize(el); - }); - } -} - /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initAutomaticInsertion() { AKANTU_DEBUG_IN(); this->inserter->limitCheckFacets(); - this->updateFacetStressSynchronizer(); - this->resizeFacetStress(); /// compute normals on facets this->computeNormals(); this->initStressInterpolation(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateAutomaticInsertion() { AKANTU_DEBUG_IN(); this->inserter->limitCheckFacets(); this->updateFacetStressSynchronizer(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initStressInterpolation() { Mesh & mesh_facets = inserter->getMeshFacets(); /// compute quadrature points coordinates on facets Array<Real> & position = mesh.getNodes(); ElementTypeMapArray<Real> quad_facets("quad_facets", id); quad_facets.initialize(mesh_facets, _nb_component = Model::spatial_dimension, _spatial_dimension = Model::spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(quad_facets, Model::spatial_dimension, // Model::spatial_dimension - 1); getFEEngine("FacetsFEEngine") .interpolateOnIntegrationPoints(position, quad_facets); /// compute elements quadrature point positions and build /// element-facet quadrature points data structure ElementTypeMapArray<Real> elements_quad_facets("elements_quad_facets", id); elements_quad_facets.initialize( mesh, _nb_component = Model::spatial_dimension, _spatial_dimension = Model::spatial_dimension); // mesh.initElementTypeMapArray(elements_quad_facets, // Model::spatial_dimension, // Model::spatial_dimension); for (auto elem_gt : ghost_types) { for (auto & type : mesh.elementTypes(Model::spatial_dimension, elem_gt)) { UInt nb_element = mesh.getNbElement(type, elem_gt); if (nb_element == 0) continue; /// compute elements' quadrature points and list of facet /// quadrature points positions by element - Array<Element> & facet_to_element = + const auto & facet_to_element = mesh_facets.getSubelementToElement(type, elem_gt); - UInt nb_facet_per_elem = facet_to_element.getNbComponent(); - Array<Real> & el_q_facet = elements_quad_facets(type, elem_gt); - ElementType facet_type = Mesh::getFacetType(type); - UInt nb_quad_per_facet = - getFEEngine("FacetsFEEngine").getNbIntegrationPoints(facet_type); + auto & el_q_facet = elements_quad_facets(type, elem_gt); - el_q_facet.resize(nb_element * nb_facet_per_elem * nb_quad_per_facet); - - for (UInt el = 0; el < nb_element; ++el) { - for (UInt f = 0; f < nb_facet_per_elem; ++f) { - Element global_facet_elem = facet_to_element(el, f); - UInt global_facet = global_facet_elem.element; - GhostType facet_gt = global_facet_elem.ghost_type; - const Array<Real> & quad_f = quad_facets(facet_type, facet_gt); - - for (UInt q = 0; q < nb_quad_per_facet; ++q) { - for (UInt s = 0; s < Model::spatial_dimension; ++s) { - el_q_facet(el * nb_facet_per_elem * nb_quad_per_facet + - f * nb_quad_per_facet + q, - s) = quad_f(global_facet * nb_quad_per_facet + q, s); - } - } - } + auto facet_type = Mesh::getFacetType(type); + auto nb_quad_per_facet = + getFEEngine("FacetsFEEngine").getNbIntegrationPoints(facet_type); + auto nb_facet_per_elem = facet_to_element.getNbComponent(); + + // small hack in the loop to skip boundary elements, they are silently + // initialized to NaN to see if this causes problems + el_q_facet.resize(nb_element * nb_facet_per_elem * nb_quad_per_facet, + std::numeric_limits<Real>::quiet_NaN()); + + for (auto && data : + zip(make_view(facet_to_element), + make_view(el_q_facet, spatial_dimension, nb_quad_per_facet))) { + const auto & global_facet = std::get<0>(data); + auto & el_q = std::get<1>(data); + + if (global_facet == ElementNull) + continue; + + Matrix<Real> quad_f = + make_view(quad_facets(global_facet.type, global_facet.ghost_type), + spatial_dimension, nb_quad_per_facet) + .begin()[global_facet.element]; + + el_q = quad_f; + + // for (UInt q = 0; q < nb_quad_per_facet; ++q) { + // for (UInt s = 0; s < Model::spatial_dimension; ++s) { + // el_q_facet(el * nb_facet_per_elem * nb_quad_per_facet + + // f * nb_quad_per_facet + q, + // s) = quad_f(global_facet * nb_quad_per_facet + q, + // s); + // } + // } + //} } } } /// loop over non cohesive materials for (auto && material : materials) { if (dynamic_cast<MaterialCohesive *>(material.get())) continue; /// initialize the interpolation function material->initElementalFieldInterpolation(elements_quad_facets); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::assembleInternalForces() { AKANTU_DEBUG_IN(); // f_int += f_int_cohe for (auto & material : this->materials) { try { auto & mat = dynamic_cast<MaterialCohesive &>(*material); mat.computeTraction(_not_ghost); } catch (std::bad_cast & bce) { } } SolidMechanicsModel::assembleInternalForces(); - if (isDefaultSolverExplicit()) { - for (auto & material : materials) { - try { - auto & mat = dynamic_cast<MaterialCohesive &>(*material); - mat.computeEnergies(); - } catch (std::bad_cast & bce) { - } - } - } - AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeNormals() { AKANTU_DEBUG_IN(); Mesh & mesh_facets = this->inserter->getMeshFacets(); this->getFEEngine("FacetsFEEngine") .computeNormalsOnIntegrationPoints(_not_ghost); /** * @todo store tangents while computing normals instead of * recomputing them as follows: */ /* ------------------------------------------------------------------------ */ UInt tangent_components = Model::spatial_dimension * (Model::spatial_dimension - 1); tangents.initialize(mesh_facets, _nb_component = tangent_components, _spatial_dimension = Model::spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(tangents, tangent_components, // Model::spatial_dimension - 1); for (auto facet_type : mesh_facets.elementTypes(Model::spatial_dimension - 1)) { const Array<Real> & normals = this->getFEEngine("FacetsFEEngine") .getNormalsOnIntegrationPoints(facet_type); Array<Real> & tangents = this->tangents(facet_type); Math::compute_tangents(normals, tangents); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::interpolateStress() { ElementTypeMapArray<Real> by_elem_result("temporary_stress_by_facets", id); for (auto & material : materials) { - try { - auto & mat __attribute__((unused)) = - dynamic_cast<MaterialCohesive &>(*material); - } catch (std::bad_cast &) { + auto * mat = dynamic_cast<MaterialCohesive *>(material.get()); + if (mat == nullptr) /// interpolate stress on facet quadrature points positions material->interpolateStressOnFacets(facet_stress, by_elem_result); - } } #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData( debug::_dm_model_cohesive, "Interpolated stresses before", facet_stress); #endif this->synchronize(_gst_smmc_facets_stress); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_model_cohesive, "Interpolated stresses", facet_stress); #endif } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::checkCohesiveStress() { + AKANTU_DEBUG_IN(); + interpolateStress(); for (auto & mat : materials) { - try { - auto & mat_cohesive = dynamic_cast<MaterialCohesive &>(*mat); + auto * mat_cohesive = dynamic_cast<MaterialCohesive *>(mat.get()); + if(mat_cohesive) { /// check which not ghost cohesive elements are to be created - mat_cohesive.checkInsertion(); - } catch (std::bad_cast &) { + mat_cohesive->checkInsertion(); } } /// communicate data among processors this->synchronize(_gst_smmc_facets); /// insert cohesive elements UInt nb_new_elements = inserter->insertElements(); // if (nb_new_elements > 0) { // this->reinitializeSolver(); // } + AKANTU_DEBUG_OUT(); + return nb_new_elements; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onElementsAdded( const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); updateCohesiveSynchronizers(); SolidMechanicsModel::onElementsAdded(element_list, event); if (cohesive_synchronizer != nullptr) cohesive_synchronizer->computeAllBufferSizes(*this); if (is_extrinsic) resizeFacetStress(); /// if (method != _explicit_lumped_mass) { /// this->initSolver(); /// } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onNodesAdded(const Array<UInt> & new_nodes, const NewNodesEvent & event) { AKANTU_DEBUG_IN(); // Array<UInt> nodes_list(nb_new_nodes); // for (UInt n = 0; n < nb_new_nodes; ++n) // nodes_list(n) = doubled_nodes(n, 1); SolidMechanicsModel::onNodesAdded(new_nodes, event); UInt new_node, old_node; try { const auto & cohesive_event = dynamic_cast<const CohesiveNewNodesEvent &>(event); const auto & old_nodes = cohesive_event.getOldNodesList(); auto copy = [this, &new_node, &old_node](auto & arr) { for (UInt s = 0; s < spatial_dimension; ++s) { arr(new_node, s) = arr(old_node, s); } }; for (auto && pair : zip(new_nodes, old_nodes)) { std::tie(new_node, old_node) = pair; copy(*displacement); copy(*blocked_dofs); if (velocity) copy(*velocity); if (acceleration) copy(*acceleration); if (current_position) copy(*current_position); if (previous_displacement) copy(*previous_displacement); } // if (this->getDOFManager().hasMatrix("M")) { // this->assembleMass(old_nodes); // } // if (this->getDOFManager().hasLumpedMatrix("M")) { // this->assembleMassLumped(old_nodes); // } } catch (std::bad_cast &) { } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onEndSolveStep(const AnalysisMethod &) { AKANTU_DEBUG_IN(); /* * This is required because the Cauchy stress is the stress measure that * is used to check the insertion of cohesive elements */ for (auto & mat : materials) { if (mat->isFiniteDeformation()) mat->computeAllCauchyStresses(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "SolidMechanicsModelCohesive [" << std::endl; SolidMechanicsModel::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::resizeFacetStress() { AKANTU_DEBUG_IN(); this->facet_stress.initialize(getFEEngine("FacetsFEEngine"), _nb_component = 2 * spatial_dimension * spatial_dimension, _spatial_dimension = spatial_dimension - 1); // for (auto && ghost_type : ghost_types) { // for (const auto & type : // mesh_facets.elementTypes(spatial_dimension - 1, ghost_type)) { // UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); // UInt nb_quadrature_points = getFEEngine("FacetsFEEngine") // .getNbIntegrationPoints(type, // ghost_type); // UInt new_size = nb_facet * nb_quadrature_points; // facet_stress(type, ghost_type).resize(new_size); // } // } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::addDumpGroupFieldToDumper( const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { AKANTU_DEBUG_IN(); UInt spatial_dimension = Model::spatial_dimension; ElementKind _element_kind = element_kind; if (dumper_name == "cohesive elements") { _element_kind = _ek_cohesive; } else if (dumper_name == "facets") { spatial_dimension = Model::spatial_dimension - 1; } SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, spatial_dimension, _element_kind, padding_flag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onDump() { this->flattenAllRegisteredInternals(_ek_cohesive); SolidMechanicsModel::onDump(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc index c9deec2a9..ba6037031 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc @@ -1,399 +1,484 @@ /** * @file solid_mechanics_model_cohesive_parallel.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * * @brief Functions for parallel cohesive elements * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * */ /* -------------------------------------------------------------------------- */ +#include "communicator.hh" #include "element_synchronizer.hh" +#include "material_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "solid_mechanics_model_tmpl.hh" -#include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <type_traits> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::synchronizeGhostFacetsConnectivity() { AKANTU_DEBUG_IN(); const Communicator & comm = mesh.getCommunicator(); Int psize = comm.getNbProc(); if (psize > 1) { /// get global connectivity for not ghost facets global_connectivity = new ElementTypeMapArray<UInt>("global_connectivity", id); auto & mesh_facets = inserter->getMeshFacets(); global_connectivity->initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _with_nb_nodes_per_element = true, - _element_kind = _ek_regular, - _ghost_type = _not_ghost); + _element_kind = _ek_regular); mesh_facets.getGlobalConnectivity(*global_connectivity); /// communicate synchronize(_gst_smmc_facets_conn); /// flip facets MeshUtils::flipFacets(mesh_facets, *global_connectivity, _ghost); delete global_connectivity; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateCohesiveSynchronizers() { /// update synchronizers if needed if (not mesh.isDistributed()) return; auto & mesh_facets = inserter->getMeshFacets(); auto & facet_synchronizer = mesh_facets.getElementSynchronizer(); const auto & cfacet_synchronizer = facet_synchronizer; // update the cohesive element synchronizer - cohesive_synchronizer->updateSchemes( - [&](auto && scheme, auto && proc, auto && direction) { - auto & facet_scheme = - cfacet_synchronizer.getCommunications().getScheme(proc, direction); - - for (auto && facet : facet_scheme) { - const auto & connected_elements = mesh_facets.getElementToSubelement( - facet.type, - facet.ghost_type)(facet.element); // slow access here - const auto & cohesive_element = connected_elements[1]; - - auto && cohesive_type = FEEngine::getCohesiveElementType(facet.type); - auto old_nb_cohesive_elements = - mesh.getNbElement(cohesive_type, facet.ghost_type); - old_nb_cohesive_elements -= - mesh.getData<UInt>("facet_to_double", facet.type, - facet.ghost_type).size(); - - if (cohesive_element.kind() == _ek_cohesive and - cohesive_element.element >= old_nb_cohesive_elements) { - scheme.push_back(cohesive_element); - } - } - }); + cohesive_synchronizer->updateSchemes([&](auto && scheme, auto && proc, + auto && direction) { + auto & facet_scheme = + cfacet_synchronizer.getCommunications().getScheme(proc, direction); + + for (auto && facet : facet_scheme) { + const auto & connected_elements = mesh_facets.getElementToSubelement( + facet.type, + facet.ghost_type)(facet.element); // slow access here + const auto & cohesive_element = connected_elements[1]; + + auto && cohesive_type = FEEngine::getCohesiveElementType(facet.type); + auto old_nb_cohesive_elements = + mesh.getNbElement(cohesive_type, facet.ghost_type); + old_nb_cohesive_elements -= + mesh.getData<UInt>("facet_to_double", facet.type, facet.ghost_type) + .size(); + + if (cohesive_element.kind() == _ek_cohesive and + cohesive_element.element >= old_nb_cohesive_elements) { + scheme.push_back(cohesive_element); + } + } + }); const auto & comm = mesh.getCommunicator(); auto && my_rank = comm.whoAmI(); // update the facet stress synchronizer - facet_stress_synchronizer->updateSchemes([&](auto && scheme, auto && proc, - auto && /*direction*/) { - auto it_element = scheme.begin(); - for (auto && element : scheme) { - auto && facet_check = inserter->getCheckFacets( - element.type, element.ghost_type)(element.element); // slow access - // here - - if (facet_check) { - auto && connected_elements = mesh_facets.getElementToSubelement( + if (facet_stress_synchronizer) + facet_stress_synchronizer->updateSchemes([&](auto && scheme, auto && proc, + auto && /*direction*/) { + auto it_element = scheme.begin(); + for (auto && element : scheme) { + auto && facet_check = inserter->getCheckFacets( element.type, element.ghost_type)(element.element); // slow access // here - auto && rank_left = facet_synchronizer.getRank(connected_elements[0]); - auto && rank_right = facet_synchronizer.getRank(connected_elements[1]); - - // keep element if the element is still a boundary element between two - // processors - if ((rank_left == Int(proc) and rank_right == my_rank) or - (rank_left == my_rank and rank_right == Int(proc))) { - *it_element = element; - ++it_element; + + if (facet_check) { + auto && connected_elements = mesh_facets.getElementToSubelement( + element.type, element.ghost_type)(element.element); // slow access + // here + auto && rank_left = facet_synchronizer.getRank(connected_elements[0]); + auto && rank_right = + facet_synchronizer.getRank(connected_elements[1]); + + // keep element if the element is still a boundary element between two + // processors + if ((rank_left == Int(proc) and rank_right == my_rank) or + (rank_left == my_rank and rank_right == Int(proc))) { + *it_element = element; + ++it_element; + } } } - } - scheme.resize(it_element - scheme.begin()); - }); + scheme.resize(it_element - scheme.begin()); + }); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesive::updateFacetStressSynchronizer() { + if (facet_stress_synchronizer != nullptr) { + const auto & rank_to_element = + mesh.getElementSynchronizer().getElementToRank(); + const auto & facet_checks = inserter->getCheckFacets(); + const auto & mesh_facets = inserter->getMeshFacets(); + const auto & element_to_facet = mesh_facets.getElementToSubelement(); + UInt rank = mesh.getCommunicator().whoAmI(); + + facet_stress_synchronizer->updateSchemes( + [&](auto & scheme, auto & proc, auto & /*direction*/) { + UInt el = 0; + for (auto && element : scheme) { + if (not facet_checks(element)) + continue; + + const auto & next_el = element_to_facet(element); + UInt rank_left = rank_to_element(next_el[0]); + UInt rank_right = rank_to_element(next_el[1]); + + if ((rank_left == rank and rank_right == proc) or + (rank_left == proc and rank_right == rank)) { + scheme[el] = element; + ++el; + } + } + scheme.resize(el); + }); + } } /* -------------------------------------------------------------------------- */ template <typename T> void SolidMechanicsModelCohesive::packFacetStressDataHelper( const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const { packUnpackFacetStressDataHelper<T, true>( const_cast<ElementTypeMapArray<T> &>(data_to_pack), buffer, elements); } /* -------------------------------------------------------------------------- */ template <typename T> void SolidMechanicsModelCohesive::unpackFacetStressDataHelper( ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements) const { packUnpackFacetStressDataHelper<T, false>(data_to_unpack, buffer, elements); } /* -------------------------------------------------------------------------- */ template <typename T, bool pack_helper> void SolidMechanicsModelCohesive::packUnpackFacetStressDataHelper( ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt nb_quad_per_elem = 0; UInt sp2 = spatial_dimension * spatial_dimension; UInt nb_component = sp2 * 2; bool element_rank = false; Mesh & mesh_facets = inserter->getMeshFacets(); Array<T> * vect = nullptr; Array<std::vector<Element>> * element_to_facet = nullptr; auto & fe_engine = this->getFEEngine("FacetsFEEngine"); for (auto && el : elements) { if (el.type == _not_defined) - AKANTU_EXCEPTION("packUnpackFacetStressDataHelper called with wrong inputs"); + AKANTU_EXCEPTION( + "packUnpackFacetStressDataHelper called with wrong inputs"); if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; vect = &data_to_pack(el.type, el.ghost_type); element_to_facet = &(mesh_facets.getElementToSubelement(el.type, el.ghost_type)); nb_quad_per_elem = fe_engine.getNbIntegrationPoints(el.type, el.ghost_type); } if (pack_helper) element_rank = (*element_to_facet)(el.element)[0].ghost_type != _not_ghost; else element_rank = (*element_to_facet)(el.element)[0].ghost_type == _not_ghost; for (UInt q = 0; q < nb_quad_per_elem; ++q) { Vector<T> data(vect->storage() + (el.element * nb_quad_per_elem + q) * nb_component + element_rank * sp2, sp2); if (pack_helper) buffer << data; else buffer >> data; } } } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::getNbQuadsForFacetCheck( const Array<Element> & elements) const { UInt nb_quads = 0; UInt nb_quad_per_facet = 0; ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; auto & fe_engine = this->getFEEngine("FacetsFEEngine"); - for(auto & el : elements) { + for (auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; - nb_quad_per_facet = fe_engine - .getNbIntegrationPoints(el.type, el.ghost_type); + nb_quad_per_facet = + fe_engine.getNbIntegrationPoints(el.type, el.ghost_type); } nb_quads += nb_quad_per_facet; } return nb_quads; } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::getNbData( const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if (elements.size() == 0) return 0; /// regular element case if (elements(0).kind() == _ek_regular) { switch (tag) { case _gst_smmc_facets: { size += elements.size() * sizeof(bool); break; } case _gst_smmc_facets_conn: { UInt nb_nodes = Mesh::getNbNodesPerElementList(elements); size += nb_nodes * sizeof(UInt); break; } case _gst_smmc_facets_stress: { UInt nb_quads = getNbQuadsForFacetCheck(elements); size += nb_quads * spatial_dimension * spatial_dimension * sizeof(Real); break; } + case _gst_material_id: { + for (auto && element : elements) { + if (Mesh::getSpatialDimension(element.type) == (spatial_dimension - 1)) + size += sizeof(UInt); + } + + size += SolidMechanicsModel::getNbData(elements, tag); + break; + } + default: { size += SolidMechanicsModel::getNbData(elements, tag); } } } /// cohesive element case else if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { size += elements.size() * sizeof(UInt); break; } case _gst_smm_boundary: { UInt nb_nodes_per_element = 0; for (auto && el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } default: break; } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { size += mat.getNbData(elements, tag); }); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::packData( CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); if (elements.size() == 0) return; if (elements(0).kind() == _ek_regular) { switch (tag) { case _gst_smmc_facets: { packElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_conn: { packElementalDataHelper(*global_connectivity, buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_stress: { packFacetStressDataHelper(facet_stress, buffer, elements); break; } + case _gst_material_id: { + for (auto && element : elements) { + if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1)) + continue; + buffer << material_index(element); + } + + SolidMechanicsModel::packData(buffer, elements, tag); + break; + } default: { SolidMechanicsModel::packData(buffer, elements, tag); } } - } else if (elements(0).kind() == _ek_cohesive) { + + AKANTU_DEBUG_OUT(); + return; + } + + if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { packElementalDataHelper(material_index, buffer, elements, false, getFEEngine("CohesiveFEEngine")); break; } case _gst_smm_boundary: { packNodalDataHelper(*internal_force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.packData(buffer, elements, tag); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (elements.size() == 0) return; if (elements(0).kind() == _ek_regular) { switch (tag) { case _gst_smmc_facets: { unpackElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_conn: { unpackElementalDataHelper(*global_connectivity, buffer, elements, false, getFEEngine()); break; } case _gst_smmc_facets_stress: { unpackFacetStressDataHelper(facet_stress, buffer, elements); break; } + case _gst_material_id: { + for (auto && element : elements) { + if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1)) + continue; + + UInt recv_mat_index; + buffer >> recv_mat_index; + UInt & mat_index = material_index(element); + if (mat_index != UInt(-1)) + continue; + + // add ghosts element to the correct material + mat_index = recv_mat_index; + auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]); + mat.addFacet(element); + facet_material(element) = recv_mat_index; + } + SolidMechanicsModel::unpackData(buffer, elements, tag); + break; + } default: { SolidMechanicsModel::unpackData(buffer, elements, tag); } } - } else if (elements(0).kind() == _ek_cohesive) { + + AKANTU_DEBUG_OUT(); + return; + } + + if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { unpackElementalDataHelper(material_index, buffer, elements, false, getFEEngine("CohesiveFEEngine")); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*internal_force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.unpackData(buffer, elements, tag); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc index f3418e008..39e0c4939 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc @@ -1,174 +1,176 @@ /** * @file embedded_interface_model.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Fri Mar 13 2015 * @date last modification: Mon Dec 14 2015 * * @brief Model of Solid Mechanics with embedded interfaces * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "embedded_interface_model.hh" -#include "material_reinforcement_template.hh" +#include "material_reinforcement.hh" +#include "material_elastic.hh" #include "mesh_iterators.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #ifdef AKANTU_USE_IOHELPER # include "dumper_iohelper_paraview.hh" # include "dumpable_inline_impl.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ EmbeddedInterfaceModel::EmbeddedInterfaceModel(Mesh & mesh, Mesh & primitive_mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, spatial_dimension, id, memory_id), intersector(mesh, primitive_mesh), interface_mesh(nullptr), primitive_mesh(primitive_mesh), interface_material_selector(nullptr) { this->model_type = ModelType::_embedded_model; // This pointer should be deleted by ~SolidMechanicsModel() auto mat_sel_pointer = std::make_shared<MeshDataMaterialSelector<std::string>>("physical_names", *this); this->setMaterialSelector(mat_sel_pointer); interface_mesh = &(intersector.getInterfaceMesh()); // Create 1D FEEngine on the interface mesh registerFEEngineObject<MyFEEngineType>("EmbeddedInterfaceFEEngine", *interface_mesh, 1); // Registering allocator for material reinforcement MaterialFactory::getInstance().registerAllocator( "reinforcement", [&](UInt dim, const ID & constitutive, SolidMechanicsModel &, const ID & id) -> std::unique_ptr<Material> { if (constitutive == "elastic") { using mat = MaterialElastic<1>; switch (dim) { case 2: - return std::unique_ptr<MaterialReinforcement<2>>{ - new MaterialReinforcementTemplate<2, mat>(*this, id)}; + return std::make_unique<MaterialReinforcement<mat, 2>>(*this, id); case 3: - return std::unique_ptr<MaterialReinforcement<3>>{ - new MaterialReinforcementTemplate<3, mat>(*this, id)}; + return std::make_unique<MaterialReinforcement<mat, 3>>(*this, id); default: AKANTU_EXCEPTION("Dimension 1 is invalid for reinforcements"); } } else { AKANTU_EXCEPTION("Reinforcement type" << constitutive << " is not recognized"); } }); } /* -------------------------------------------------------------------------- */ EmbeddedInterfaceModel::~EmbeddedInterfaceModel() { delete interface_material_selector; } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::initFullImpl(const ModelOptions & options) { const auto & eim_options = dynamic_cast<const EmbeddedInterfaceModelOptions &>(options); // Do no initialize interface_mesh if told so if (eim_options.has_intersections) intersector.constructData(); SolidMechanicsModel::initFullImpl(options); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("reinforcement", id); this->mesh.addDumpMeshToDumper("reinforcement", *interface_mesh, 1, _not_ghost, _ek_regular); #endif } void EmbeddedInterfaceModel::initModel() { // Initialize interface FEEngine + SolidMechanicsModel::initModel(); FEEngine & engine = getFEEngine("EmbeddedInterfaceFEEngine"); engine.initShapeFunctions(_not_ghost); engine.initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::assignMaterialToElements( const ElementTypeMapArray<UInt> * filter) { delete interface_material_selector; interface_material_selector = new InterfaceMeshDataMaterialSelector<std::string>("physical_names", *this); - for_each_element(mesh, + for_each_element(getInterfaceMesh(), [&](auto && element) { auto mat_index = (*interface_material_selector)(element); - material_index(element) = mat_index; + // material_index(element) = mat_index; materials[mat_index]->addElement(element); + // this->material_local_numbering(element) = index; }, - _element_filter = filter); + _element_filter = filter, + _spatial_dimension = 1); SolidMechanicsModel::assignMaterialToElements(filter); } /* -------------------------------------------------------------------------- */ void EmbeddedInterfaceModel::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { #ifdef AKANTU_USE_IOHELPER dumper::Field * field = NULL; // If dumper is reinforcement, create a 1D elemental field if (dumper_name == "reinforcement") field = this->createElementalField(field_id, group_name, padding_flag, 1, element_kind); else { try { SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, element_kind, padding_flag); } catch (...) {} } if (field) { DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name,group_name); Model::addDumpGroupFieldToDumper(field_id,field,dumper); } #endif } } // akantu diff --git a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh index 116c8d9fc..68a85eac0 100644 --- a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh +++ b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh @@ -1,107 +1,76 @@ /** * @file structural_element_bernoulli_kirchhoff_shell.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation Tue Sep 19 2017 * * @brief Specific functions for bernoulli kirchhoff shell * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__ #define __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__ +#include "structural_mechanics_model.hh" + namespace akantu { /* -------------------------------------------------------------------------- */ template <> -inline void StructuralMechanicsModel::assembleMass<_discrete_kirchhoff_triangle_18>() { - +inline void +StructuralMechanicsModel::assembleMass<_discrete_kirchhoff_triangle_18>() { AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ template <> -void StructuralMechanicsModel::computeRotationMatrix<_discrete_kirchhoff_triangle_18>( - Array<Real> & rotations) { - ElementType type = _discrete_kirchhoff_triangle_18; - Mesh & mesh = getFEEngine().getMesh(); - UInt nb_element = mesh.getNbElement(type); - - Array<UInt>::iterator<Vector<UInt> > connec_it = - mesh.getConnectivity(type).begin(3); - Array<Real>::vector_iterator nodes_it = - mesh.getNodes().begin(spatial_dimension); - - Matrix<Real> Pe(spatial_dimension, spatial_dimension); - Matrix<Real> Pg(spatial_dimension, spatial_dimension); - Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension); - - Array<Real>::matrix_iterator R_it = - rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); - - for (UInt e = 0; e < nb_element; ++e, ++connec_it, ++R_it) { - - Pe.eye(); - - Matrix<Real> & R = *R_it; - Vector<UInt> & connec = *connec_it; - - Vector<Real> x2; - x2 = nodes_it[connec(1)]; // X2 - Vector<Real> x1; - x1 = nodes_it[connec(0)]; // X1 - Vector<Real> x3; - x3 = nodes_it[connec(2)]; // X3 - - Vector<Real> Pg_col_1 = x2 - x1; - - Vector<Real> Pg_col_2 = x3 - x1; - - Vector<Real> Pg_col_3(spatial_dimension); - Pg_col_3.crossProduct(Pg_col_1, Pg_col_2); - - for (UInt i = 0; i < spatial_dimension; ++i) { - Pg(i, 0) = Pg_col_1(i); - Pg(i, 1) = Pg_col_2(i); - Pg(i, 2) = Pg_col_3(i); - } - - inv_Pg.inverse(Pg); - // Pe *= inv_Pg; - Pe.eye(); - - for (UInt i = 0; i < spatial_dimension; ++i) { - for (UInt j = 0; j < spatial_dimension; ++j) { - R(i, j) = Pe(i, j); - R(i + spatial_dimension, j + spatial_dimension) = Pe(i, j); - } +void StructuralMechanicsModel::computeTangentModuli< + _discrete_kirchhoff_triangle_18>(Array<Real> & tangent_moduli) { + + auto tangent_size = + ElementClass<_discrete_kirchhoff_triangle_18>::getNbStressComponents(); + auto nb_quad = + getFEEngine().getNbIntegrationPoints(_discrete_kirchhoff_triangle_18); + + auto H_it = tangent_moduli.begin(tangent_size, tangent_size); + + for (UInt mat : + element_material(_discrete_kirchhoff_triangle_18, _not_ghost)) { + auto & m = materials[mat]; + + for (UInt q = 0; q < nb_quad; ++q, ++H_it) { + auto & H = *H_it; + H.clear(); + Matrix<Real> D = {{1, m.nu, 0}, {m.nu, 1, 0}, {0, 0, (1 - m.nu) / 2}}; + D *= m.E / (1 - m.nu * m.nu); + H.block(D, 0, 0); // in plane membrane behavior + H.block(D * Math::pow<3>(m.t) / 12., 3, 3); // bending behavior } } } } // akantu #endif /* __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_DISCRETE_KIRCHHOFF_TRIANGLE_18_HH__ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc index 4ff13730b..8ed981deb 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.cc +++ b/src/model/structural_mechanics/structural_mechanics_model.cc @@ -1,441 +1,490 @@ /** * @file structural_mechanics_model.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Thu Oct 15 2015 * * @brief Model implementation for StucturalMechanics elements * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model.hh" #include "dof_manager.hh" -#include "sparse_matrix.hh" #include "integrator_gauss.hh" -#include "shape_structural.hh" #include "mesh.hh" +#include "shape_structural.hh" +#include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER +#include "dumpable_inline_impl.hh" #include "dumper_elemental_field.hh" #include "dumper_iohelper_paraview.hh" -#include "dumpable_inline_impl.hh" #include "group_manager_inline_impl.cc" #endif /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model_inline_impl.cc" /* -------------------------------------------------------------------------- */ - namespace akantu { /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::StructuralMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) - : Model(mesh, ModelType::_structural_mechanics_model, dim, id, memory_id), time_step(NAN), f_m2a(1.0), - stress("stress", id, memory_id), + : Model(mesh, ModelType::_structural_mechanics_model, dim, id, memory_id), + time_step(NAN), f_m2a(1.0), stress("stress", id, memory_id), element_material("element_material", id, memory_id), set_ID("beam sets", id, memory_id), rotation_matrix("rotation_matices", id, memory_id) { AKANTU_DEBUG_IN(); registerFEEngineObject<MyFEEngineType>("StructuralMechanicsFEEngine", mesh, spatial_dimension); if (spatial_dimension == 2) nb_degree_of_freedom = 3; else if (spatial_dimension == 3) nb_degree_of_freedom = 6; else { AKANTU_DEBUG_TO_IMPLEMENT(); } #ifdef AKANTU_USE_IOHELPER this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); #endif this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_structural); this->initDOFManager(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::~StructuralMechanicsModel() = default; /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initFullImpl(const ModelOptions & options) { // <<<< This is the SolidMechanicsModel implementation for future ref >>>> // material_index.initialize(mesh, _element_kind = _ek_not_defined, - // _default_value = UInt(-1), _with_nb_element = true); + // _default_value = UInt(-1), _with_nb_element = + // true); // material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined, // _with_nb_element = true); // Model::initFullImpl(options); // // initialize pbc // if (this->pbc_pair.size() != 0) // this->initPBC(); // // initialize the materials // if (this->parser.getLastParsedFile() != "") { // this->instantiateMaterials(); // } // this->initMaterials(); - // this->initBC(*this, *displacement, *displacement_increment, *external_force); + // this->initBC(*this, *displacement, *displacement_increment, + // *external_force); // <<<< END >>>> Model::initFullImpl(options); + + // Initializing stresses + ElementTypeMap<UInt> stress_components; + + /// TODO this is ugly af, maybe add a function to FEEngine + for (auto & type : mesh.elementTypes(_spatial_dimension = _all_dimensions, + _element_kind = _ek_structural)) { + UInt nb_components = 0; + + // Getting number of components for each element type +#define GET_(type) nb_components = ElementClass<type>::getNbStressComponents() + AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(GET_); +#undef GET_ + + stress_components(nb_components, type); + } + + stress.initialize(getFEEngine(), _spatial_dimension = _all_dimensions, + _element_kind = _ek_structural, + _all_ghost_types = true, + _nb_component = [&stress_components]( + const ElementType & type, const GhostType &) -> UInt { + return stress_components(type); + }); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initFEEngineBoundary() { /// TODO: this function should not be reimplemented /// we're just avoiding a call to Model::initFEEngineBoundary() } /* -------------------------------------------------------------------------- */ // void StructuralMechanicsModel::setTimeStep(Real time_step) { // this->time_step = time_step; // #if defined(AKANTU_USE_IOHELPER) // this->mesh.getDumper().setTimeStep(time_step); // #endif // } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initSolver( TimeStepSolverType time_step_solver_type, NonLinearSolverType) { AKANTU_DEBUG_IN(); this->allocNodalField(displacement_rotation, nb_degree_of_freedom, "displacement"); - this->allocNodalField(external_force_momentum, nb_degree_of_freedom, + this->allocNodalField(external_force, nb_degree_of_freedom, "external_force"); - this->allocNodalField(internal_force_momentum, nb_degree_of_freedom, + this->allocNodalField(internal_force, nb_degree_of_freedom, "internal_force"); this->allocNodalField(blocked_dofs, nb_degree_of_freedom, "blocked_dofs"); auto & dof_manager = this->getDOFManager(); if (!dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *displacement_rotation, _dst_nodal); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); } if (time_step_solver_type == _tsst_dynamic || time_step_solver_type == _tsst_dynamic_lumped) { this->allocNodalField(velocity, spatial_dimension, "velocity"); this->allocNodalField(acceleration, spatial_dimension, "acceleration"); if (!dof_manager.hasDOFsDerivatives("displacement", 1)) { dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity); dof_manager.registerDOFsDerivative("displacement", 2, *this->acceleration); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initModel() { - for (auto && type : - mesh.elementTypes(_element_kind = _ek_structural)) { + for (auto && type : mesh.elementTypes(_element_kind = _ek_structural)) { // computeRotationMatrix(type); element_material.alloc(mesh.getNbElement(type), 1, type); } getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); getDOFManager().getMatrix("K").clear(); - for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { + for (auto & type : + mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { #define ASSEMBLE_STIFFNESS_MATRIX(type) assembleStiffnessMatrix<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(ASSEMBLE_STIFFNESS_MATRIX); #undef ASSEMBLE_STIFFNESS_MATRIX } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeStresses() { AKANTU_DEBUG_IN(); - for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { + for (auto & type : + mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) { #define COMPUTE_STRESS_ON_QUAD(type) computeStressOnQuad<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_STRESS_ON_QUAD); #undef COMPUTE_STRESS_ON_QUAD } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -void StructuralMechanicsModel::updateResidual() { - AKANTU_DEBUG_IN(); - - auto & K = getDOFManager().getMatrix("K"); - - internal_force_momentum->clear(); - K.matVecMul(*displacement_rotation, *internal_force_momentum); - *internal_force_momentum *= -1.; - - getDOFManager().assembleToResidual("displacement", *external_force_momentum, - 1.); - - getDOFManager().assembleToResidual("displacement", *internal_force_momentum, - 1.); - - AKANTU_DEBUG_OUT(); -} - /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeRotationMatrix(const ElementType & type) { Mesh & mesh = getFEEngine().getMesh(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); if (!rotation_matrix.exists(type)) { rotation_matrix.alloc(nb_element, nb_degree_of_freedom * nb_nodes_per_element * - nb_degree_of_freedom * nb_nodes_per_element, + nb_degree_of_freedom * nb_nodes_per_element, type); } else { rotation_matrix(type).resize(nb_element); } rotation_matrix(type).clear(); Array<Real> rotations(nb_element, nb_degree_of_freedom * nb_degree_of_freedom); rotations.clear(); #define COMPUTE_ROTATION_MATRIX(type) computeRotationMatrix<type>(rotations); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_ROTATION_MATRIX); #undef COMPUTE_ROTATION_MATRIX auto R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); auto T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++R_it, ++T_it) { auto & T = *T_it; auto & R = *R_it; for (UInt k = 0; k < nb_nodes_per_element; ++k) { for (UInt i = 0; i < nb_degree_of_freedom; ++i) for (UInt j = 0; j < nb_degree_of_freedom; ++j) T(k * nb_degree_of_freedom + i, k * nb_degree_of_freedom + j) = R(i, j); } } } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel::createNodalFieldBool( const std::string & field_name, const std::string & group_name, __attribute__((unused)) bool padding_flag) { std::map<std::string, Array<bool> *> uint_nodal_fields; uint_nodal_fields["blocked_dofs"] = blocked_dofs; dumper::Field * field = NULL; field = mesh.createNodalField(uint_nodal_fields[field_name], group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { UInt n; if (spatial_dimension == 2) { n = 2; } else { n = 3; } if (field_name == "displacement") { return mesh.createStridedNodalField(displacement_rotation, group_name, n, 0, padding_flag); } if (field_name == "rotation") { return mesh.createStridedNodalField(displacement_rotation, group_name, nb_degree_of_freedom - n, n, padding_flag); } if (field_name == "force") { - return mesh.createStridedNodalField(external_force_momentum, group_name, n, + return mesh.createStridedNodalField(external_force, group_name, n, 0, padding_flag); } if (field_name == "momentum") { - return mesh.createStridedNodalField(external_force_momentum, group_name, + return mesh.createStridedNodalField(external_force, group_name, nb_degree_of_freedom - n, n, padding_flag); } if (field_name == "internal_force") { - return mesh.createStridedNodalField(internal_force_momentum, group_name, n, + return mesh.createStridedNodalField(internal_force, group_name, n, 0, padding_flag); } if (field_name == "internal_momentum") { - return mesh.createStridedNodalField(internal_force_momentum, group_name, + return mesh.createStridedNodalField(internal_force, group_name, nb_degree_of_freedom - n, n, padding_flag); } return nullptr; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel::createElementalField( const std::string & field_name, const std::string & group_name, bool, const ElementKind & kind, const std::string &) { dumper::Field * field = NULL; if (field_name == "element_index_by_material") field = mesh.createElementalField<UInt, Vector, dumper::ElementalField>( field_name, group_name, this->spatial_dimension, kind); return field; } /* -------------------------------------------------------------------------- */ /* Virtual methods from SolverCallback */ /* -------------------------------------------------------------------------- */ /// get the type of matrix needed MatrixType StructuralMechanicsModel::getMatrixType(const ID & /*id*/) { return _symmetric; } /// callback to assemble a Matrix void StructuralMechanicsModel::assembleMatrix(const ID & id) { if (id == "K") assembleStiffnessMatrix(); } /// callback to assemble a lumped Matrix void StructuralMechanicsModel::assembleLumpedMatrix(const ID & /*id*/) {} /// callback to assemble the residual StructuralMechanicsModel::(rhs) void StructuralMechanicsModel::assembleResidual() { - this->getDOFManager().assembleToResidual("displacement", - *this->external_force_momentum, 1); + AKANTU_DEBUG_IN(); + + internal_force->clear(); + computeStresses(); + assembleInternalForce(); + + getDOFManager().assembleToResidual("displacement", *external_force, + 1.); + + getDOFManager().assembleToResidual("displacement", *internal_force, + -1); + + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Virtual methods from MeshEventHandler */ /* -------------------------------------------------------------------------- */ /// function to implement to react on akantu::NewNodesEvent void StructuralMechanicsModel::onNodesAdded(const Array<UInt> & /*nodes_list*/, const NewNodesEvent & /*event*/) {} /// function to implement to react on akantu::RemovedNodesEvent void StructuralMechanicsModel::onNodesRemoved( const Array<UInt> & /*nodes_list*/, const Array<UInt> & /*new_numbering*/, const RemovedNodesEvent & /*event*/) {} /// function to implement to react on akantu::NewElementsEvent void StructuralMechanicsModel::onElementsAdded( const Array<Element> & /*elements_list*/, const NewElementsEvent & /*event*/) {} /// function to implement to react on akantu::RemovedElementsEvent void StructuralMechanicsModel::onElementsRemoved( const Array<Element> & /*elements_list*/, const ElementTypeMapArray<UInt> & /*new_numbering*/, const RemovedElementsEvent & /*event*/) {} /// function to implement to react on akantu::ChangedElementsEvent void StructuralMechanicsModel::onElementsChanged( const Array<Element> & /*old_elements_list*/, const Array<Element> & /*new_elements_list*/, const ElementTypeMapArray<UInt> & /*new_numbering*/, const ChangedElementsEvent & /*event*/) {} /* -------------------------------------------------------------------------- */ /* Virtual methods from Model */ /* -------------------------------------------------------------------------- */ /// get some default values for derived classes -std::tuple<ID, TimeStepSolverType> StructuralMechanicsModel::getDefaultSolverID( - const AnalysisMethod & method) { +std::tuple<ID, TimeStepSolverType> +StructuralMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _static: { return std::make_tuple("static", _tsst_static); } case _implicit_dynamic: { return std::make_tuple("implicit", _tsst_dynamic); } default: return std::make_tuple("unknown", _tsst_not_defined); } } /* ------------------------------------------------------------------------ */ ModelSolverOptions StructuralMechanicsModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_static: { options.non_linear_solver_type = _nls_linear; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } + /* -------------------------------------------------------------------------- */ +void StructuralMechanicsModel::assembleInternalForce() { + for (auto type : mesh.elementTypes(_spatial_dimension = _all_dimensions, + _element_kind = _ek_structural)) { + assembleInternalForce(type, _not_ghost); + // assembleInternalForce(type, _ghost); + } +} +/* -------------------------------------------------------------------------- */ +void StructuralMechanicsModel::assembleInternalForce(const ElementType & type, + GhostType gt) { + auto & fem = getFEEngine(); + auto & sigma = stress(type, gt); + auto ndof = getNbDegreeOfFreedom(type); + auto nb_nodes = mesh.getNbNodesPerElement(type); + auto ndof_per_elem = ndof * nb_nodes; + + Array<Real> BtSigma(fem.getNbIntegrationPoints(type) * + mesh.getNbElement(type), + ndof_per_elem, "BtSigma"); + fem.computeBtD(sigma, BtSigma, type, gt); + + Array<Real> intBtSigma(0, ndof_per_elem, + "intBtSigma"); + fem.integrate(BtSigma, intBtSigma, ndof_per_elem, type, gt); + BtSigma.resize(0); + + getDOFManager().assembleElementalArrayLocalArray(intBtSigma, *internal_force, + type, gt, 1); +} +/* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/structural_mechanics/structural_mechanics_model.hh b/src/model/structural_mechanics/structural_mechanics_model.hh index fcb036768..b06e1ea41 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.hh +++ b/src/model/structural_mechanics/structural_mechanics_model.hh @@ -1,327 +1,333 @@ /** * @file structural_mechanics_model.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Thu Jan 21 2016 * * @brief Particular implementation of the structural elements in the * StructuralMechanicsModel * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_named_argument.hh" #include "boundary_condition.hh" #include "model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Material; class MaterialSelector; class DumperIOHelper; class NonLocalManager; template <ElementKind kind, class IntegrationOrderFunctor> class IntegratorGauss; template <ElementKind kind> class ShapeStructural; } // namespace akantu namespace akantu { struct StructuralMaterial { Real E{0}; Real A{1}; Real I{0}; Real Iz{0}; Real Iy{0}; Real GJ{0}; Real rho{0}; Real t{0}; Real nu{0}; }; class StructuralMechanicsModel : public Model { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using MyFEEngineType = FEEngineTemplate<IntegratorGauss, ShapeStructural, _ek_structural>; StructuralMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "structural_mechanics_model", const MemoryID & memory_id = 0); virtual ~StructuralMechanicsModel(); /// Init full model void initFullImpl(const ModelOptions & options) override; /// Init boundary FEEngine void initFEEngineBoundary() override; /* ------------------------------------------------------------------------ */ /* Virtual methods from SolverCallback */ /* ------------------------------------------------------------------------ */ /// get the type of matrix needed MatrixType getMatrixType(const ID &) override; /// callback to assemble a Matrix void assembleMatrix(const ID &) override; /// callback to assemble a lumped Matrix void assembleLumpedMatrix(const ID &) override; /// callback to assemble the residual (rhs) void assembleResidual() override; /* ------------------------------------------------------------------------ */ /* Virtual methods from MeshEventHandler */ /* ------------------------------------------------------------------------ */ /// function to implement to react on akantu::NewNodesEvent void onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) override; /// function to implement to react on akantu::RemovedNodesEvent void onNodesRemoved(const Array<UInt> & nodes_list, const Array<UInt> & new_numbering, const RemovedNodesEvent & event) override; /// function to implement to react on akantu::NewElementsEvent void onElementsAdded(const Array<Element> & elements_list, const NewElementsEvent & event) override; /// function to implement to react on akantu::RemovedElementsEvent void onElementsRemoved(const Array<Element> & elements_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; /// function to implement to react on akantu::ChangedElementsEvent void onElementsChanged(const Array<Element> & old_elements_list, const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> & new_numbering, const ChangedElementsEvent & event) override; /* ------------------------------------------------------------------------ */ /* Virtual methods from Model */ /* ------------------------------------------------------------------------ */ protected: /// get some default values for derived classes std::tuple<ID, TimeStepSolverType> getDefaultSolverID(const AnalysisMethod & method) override; ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const override; + UInt getNbDegreeOfFreedom(const ElementType & type) const; + /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ void initSolver(TimeStepSolverType, NonLinearSolverType) override; /// initialize the model void initModel() override; /// compute the stresses per elements void computeStresses(); + /// compute the nodal forces + void assembleInternalForce(); + + /// compute the nodal forces for an element type + void assembleInternalForce(const ElementType & type, GhostType gt); + /// assemble the stiffness matrix void assembleStiffnessMatrix(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); - /// update the residual vector - void updateResidual(); - + /// TODO remove void computeRotationMatrix(const ElementType & type); protected: /// compute Rotation Matrices template <const ElementType type> void computeRotationMatrix(__attribute__((unused)) Array<Real> & rotations) {} /* ------------------------------------------------------------------------ */ /* Mass (structural_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); /// computes rho void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type); /// finish the computation of residual to solve in increment void updateResidualInternal(); /* ------------------------------------------------------------------------ */ private: template <ElementType type> void assembleStiffnessMatrix(); template <ElementType type> void assembleMass(); template <ElementType type> void computeStressOnQuad(); template <ElementType type> void computeTangentModuli(Array<Real> & tangent_moduli); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: virtual dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind, const std::string & fe_engine_id = ""); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// set the value of the time step // void setTimeStep(Real time_step, const ID & solver_id = "") override; /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the StructuralMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement_rotation, Array<Real> &); /// get the StructuralMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array<Real> &); /// get the StructuralMechanicsModel::acceleration vector, updated /// by /// StructuralMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array<Real> &); /// get the StructuralMechanicsModel::external_force vector - AKANTU_GET_MACRO(ExternalForce, *external_force_momentum, Array<Real> &); + AKANTU_GET_MACRO(ExternalForce, *external_force, Array<Real> &); /// get the StructuralMechanicsModel::internal_force vector (boundary forces) - AKANTU_GET_MACRO(InternalForce, *internal_force_momentum, Array<Real> &); + AKANTU_GET_MACRO(InternalForce, *internal_force, Array<Real> &); /// get the StructuralMechanicsModel::boundary vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(RotationMatrix, rotation_matrix, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementMaterial, element_material, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Set_ID, set_ID, UInt); void addMaterial(StructuralMaterial & material) { materials.push_back(material); } const StructuralMaterial & getMaterial(const Element & element) const { return materials[element_material(element)]; } /* ------------------------------------------------------------------------ */ /* Boundaries (structural_mechanics_model_boundary.cc) */ /* ------------------------------------------------------------------------ */ public: /// Compute Linear load function set in global axis template <ElementType type> void computeForcesByGlobalTractionArray(const Array<Real> & tractions); /// Compute Linear load function set in local axis template <ElementType type> void computeForcesByLocalTractionArray(const Array<Real> & tractions); /// compute force vector from a function(x,y,momentum) that describe stresses // template <ElementType type> // void computeForcesFromFunction(BoundaryFunction in_function, // BoundaryFunctionType function_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array<Real> * displacement_rotation{nullptr}; /// velocities array Array<Real> * velocity{nullptr}; /// accelerations array Array<Real> * acceleration{nullptr}; /// forces array - Array<Real> * internal_force_momentum{nullptr}; + Array<Real> * internal_force{nullptr}; /// forces array - Array<Real> * external_force_momentum{nullptr}; + Array<Real> * external_force{nullptr}; /// lumped mass array Array<Real> * mass{nullptr}; /// boundaries array Array<bool> * blocked_dofs{nullptr}; /// stress array ElementTypeMapArray<Real> stress; ElementTypeMapArray<UInt> element_material; // Define sets of beams ElementTypeMapArray<UInt> set_ID; /// number of degre of freedom UInt nb_degree_of_freedom; // Rotation matrix ElementTypeMapArray<Real> rotation_matrix; // /// analysis method check the list in akantu::AnalysisMethod // AnalysisMethod method; /// flag defining if the increment must be computed or not bool increment_flag; /* ------------------------------------------------------------------------ */ std::vector<StructuralMaterial> materials; }; } // namespace akantu #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc index ec27c7ede..7ef7ed0cc 100644 --- a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc +++ b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc @@ -1,361 +1,370 @@ /** * @file structural_mechanics_model_inline_impl.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Thu Oct 15 2015 * * @brief Implementation of inline functions of StructuralMechanicsModel * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ namespace akantu { +/* -------------------------------------------------------------------------- */ +inline UInt +StructuralMechanicsModel::getNbDegreeOfFreedom(const ElementType & type) const { + UInt ndof = 0; +#define GET_(type) ndof = ElementClass<type>::getNbDegreeOfFreedom() + AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_, _ek_structural); +#undef GET_ + + return ndof; +} + /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeTangentModuli( Array<Real> & /*tangent_moduli*/) { AKANTU_DEBUG_TO_IMPLEMENT(); } } // namespace akantu #include "structural_element_bernoulli_beam_2.hh" #include "structural_element_bernoulli_beam_3.hh" #include "structural_element_kirchhoff_shell.hh" namespace akantu { /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); auto nb_element = getFEEngine().getMesh().getNbElement(type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); auto tangent_size = ElementClass<type>::getNbStressComponents(); auto tangent_moduli = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); computeTangentModuli<type>(*tangent_moduli); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = nb_degree_of_freedom * nb_nodes_per_element; auto bt_d_b = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); const auto & b = getFEEngine().getShapesDerivatives(type); Matrix<Real> BtD(bt_d_b_size, tangent_size); for (auto && tuple : zip(make_view(b, tangent_size, bt_d_b_size), make_view(*tangent_moduli, tangent_size, tangent_size), make_view(*bt_d_b, bt_d_b_size, bt_d_b_size))) { auto & B = std::get<0>(tuple); auto & D = std::get<1>(tuple); auto & BtDB = std::get<2>(tuple); BtD.mul<true, false>(B, D); BtDB.template mul<false, false>(BtD, B); } /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto int_bt_d_b = std::make_unique<Array<Real>>( nb_element, bt_d_b_size * bt_d_b_size, "int_B^t*D*B"); getFEEngine().integrate(*bt_d_b, *int_bt_d_b, bt_d_b_size * bt_d_b_size, type); getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *int_bt_d_b, type, _not_ghost, _symmetric); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeStressOnQuad() { AKANTU_DEBUG_IN(); Array<Real> & sigma = stress(type, _not_ghost); auto nb_element = mesh.getNbElement(type); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); auto tangent_size = ElementClass<type>::getNbStressComponents(); auto tangent_moduli = std::make_unique<Array<Real>>( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); computeTangentModuli<type>(*tangent_moduli); /// compute DB auto d_b_size = nb_degree_of_freedom * nb_nodes_per_element; auto d_b = std::make_unique<Array<Real>>(nb_element * nb_quadrature_points, d_b_size * tangent_size, "D*B"); const auto & b = getFEEngine().getShapesDerivatives(type); auto B = b.begin(tangent_size, d_b_size); auto D = tangent_moduli->begin(tangent_size, tangent_size); auto D_B = d_b->begin(tangent_size, d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++B, ++D, ++D_B) { D_B->template mul<false, false>(*D, *B); } } /// compute DBu D_B = d_b->begin(tangent_size, d_b_size); auto DBu = sigma.begin(tangent_size); - Vector<Real> ul(d_b_size); Array<Real> u_el(0, d_b_size); FEEngine::extractNodalToElementField(mesh, *displacement_rotation, u_el, type); auto ug = u_el.begin(d_b_size); - auto T = rotation_matrix(type).begin(d_b_size, d_b_size); - for (UInt e = 0; e < nb_element; ++e, ++T, ++ug) { - ul.mul<false>(*T, *ug); + // No need to rotate because B is post-multiplied + for (UInt e = 0; e < nb_element; ++e, ++ug) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_B, ++DBu) { - DBu->template mul<false>(*D_B, ul); + DBu->template mul<false>(*D_B, *ug); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeForcesByLocalTractionArray( const Array<Real> & tractions) { AKANTU_DEBUG_IN(); #if 0 UInt nb_element = getFEEngine().getMesh().getNbElement(type); UInt nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(type); UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); // check dimension match AKANTU_DEBUG_ASSERT( Mesh::getSpatialDimension(type) == getFEEngine().getElementDimension(), "element type dimension does not match the dimension of boundaries : " << getFEEngine().getElementDimension() << " != " << Mesh::getSpatialDimension(type)); // check size of the vector AKANTU_DEBUG_ASSERT( tractions.size() == nb_quad * nb_element, "the size of the vector should be the total number of quadrature points"); // check number of components AKANTU_DEBUG_ASSERT(tractions.getNbComponent() == nb_degree_of_freedom, "the number of components should be the spatial " "dimension of the problem"); Array<Real> Nvoigt(nb_element * nb_quad, nb_degree_of_freedom * nb_degree_of_freedom * nb_nodes_per_element); transferNMatrixToSymVoigtNMatrix<type>(Nvoigt); Array<Real>::const_matrix_iterator N_it = Nvoigt.begin( nb_degree_of_freedom, nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_vector_iterator te_it = tractions.begin(nb_degree_of_freedom); Array<Real> funct(nb_element * nb_quad, nb_degree_of_freedom * nb_nodes_per_element, 0.); Array<Real>::iterator<Vector<Real>> Fe_it = funct.begin(nb_degree_of_freedom * nb_nodes_per_element); Vector<Real> fe(nb_degree_of_freedom * nb_nodes_per_element); for (UInt e = 0; e < nb_element; ++e, ++T_it) { const Matrix<Real> & T = *T_it; for (UInt q = 0; q < nb_quad; ++q, ++N_it, ++te_it, ++Fe_it) { const Matrix<Real> & N = *N_it; const Vector<Real> & te = *te_it; Vector<Real> & Fe = *Fe_it; // compute N^t tl fe.mul<true>(N, te); // turn N^t tl back in the global referential Fe.mul<true>(T, fe); } } // allocate the vector that will contain the integrated values std::stringstream name; name << id << type << ":integral_boundary"; Array<Real> int_funct(nb_element, nb_degree_of_freedom * nb_nodes_per_element, name.str()); // do the integration getFEEngine().integrate(funct, int_funct, nb_degree_of_freedom * nb_nodes_per_element, type); // assemble the result into force vector getFEEngine().assembleArray(int_funct, *force_momentum, dof_synchronizer->getLocalDOFEquationNumbers(), nb_degree_of_freedom, type); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void StructuralMechanicsModel::computeForcesByGlobalTractionArray( const Array<Real> & traction_global) { AKANTU_DEBUG_IN(); #if 0 UInt nb_element = mesh.getNbElement(type); UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); UInt nb_nodes_per_element = getFEEngine().getMesh().getNbNodesPerElement(type); std::stringstream name; name << id << ":structuralmechanics:imposed_linear_load"; Array<Real> traction_local(nb_element * nb_quad, nb_degree_of_freedom, name.str()); Array<Real>::const_matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element, nb_degree_of_freedom * nb_nodes_per_element); Array<Real>::const_iterator<Vector<Real>> Te_it = traction_global.begin(nb_degree_of_freedom); Array<Real>::iterator<Vector<Real>> te_it = traction_local.begin(nb_degree_of_freedom); Matrix<Real> R(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e = 0; e < nb_element; ++e, ++T_it) { const Matrix<Real> & T = *T_it; for (UInt i = 0; i < nb_degree_of_freedom; ++i) for (UInt j = 0; j < nb_degree_of_freedom; ++j) R(i, j) = T(i, j); for (UInt q = 0; q < nb_quad; ++q, ++Te_it, ++te_it) { const Vector<Real> & Te = *Te_it; Vector<Real> & te = *te_it; // turn the traction in the local referential te.mul<false>(R, Te); } } computeForcesByLocalTractionArray<type>(traction_local); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * @param myf pointer to a function that fills a vector/tensor with respect to * passed coordinates */ #if 0 template <ElementType type> inline void StructuralMechanicsModel::computeForcesFromFunction( BoundaryFunction myf, BoundaryFunctionType function_type) { /** function type is ** _bft_forces : linear load is given ** _bft_stress : stress function is given -> Not already done for this kind *of model */ std::stringstream name; name << id << ":structuralmechanics:imposed_linear_load"; Array<Real> lin_load(0, nb_degree_of_freedom, name.str()); name.clear(); UInt offset = nb_degree_of_freedom; // prepare the loop over element types UInt nb_quad = getFEEngine().getNbIntegrationPoints(type); UInt nb_element = getFEEngine().getMesh().getNbElement(type); name.clear(); name << id << ":structuralmechanics:quad_coords"; Array<Real> quad_coords(nb_element * nb_quad, spatial_dimension, "quad_coords"); getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>(getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension); getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>( getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension, _not_ghost, empty_filter, true, 0, 1, 1); if (spatial_dimension == 3) getFEEngineClass<MyFEEngineType>() .getShapeFunctions() .interpolateOnIntegrationPoints<type>( getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension, _not_ghost, empty_filter, true, 0, 2, 2); lin_load.resize(nb_element * nb_quad); Real * imposed_val = lin_load.storage(); /// sigma/load on each quadrature points Real * qcoord = quad_coords.storage(); for (UInt el = 0; el < nb_element; ++el) { for (UInt q = 0; q < nb_quad; ++q) { myf(qcoord, imposed_val, NULL, 0); imposed_val += offset; qcoord += spatial_dimension; } } switch (function_type) { case _bft_traction_local: computeForcesByLocalTractionArray<type>(lin_load); break; case _bft_traction: computeForcesByGlobalTractionArray<type>(lin_load); break; default: break; } } #endif } // namespace akantu #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ */ diff --git a/src/synchronizer/communications.hh b/src/synchronizer/communications.hh index 528a8274f..58f56ca01 100644 --- a/src/synchronizer/communications.hh +++ b/src/synchronizer/communications.hh @@ -1,272 +1,273 @@ /** * @file communications.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Aug 24 13:56:14 2016 * * @brief * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communication_descriptor.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_HH__ #define __AKANTU_COMMUNICATIONS_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class Entity> class Communications { public: using Scheme = Array<Entity>; protected: using CommunicationPerProcs = std::map<UInt, Communication>; using CommunicationsPerTags = std::map<SynchronizationTag, CommunicationPerProcs>; using CommunicationSchemes = std::map<UInt, Scheme>; using Request = std::map<UInt, std::vector<CommunicationRequest>>; friend class CommunicationDescriptor<Entity>; public: using scheme_iterator = typename CommunicationSchemes::iterator; using const_scheme_iterator = typename CommunicationSchemes::const_iterator; /* ------------------------------------------------------------------------ */ class iterator; class tag_iterator; /* ------------------------------------------------------------------------ */ public: CommunicationPerProcs & getCommunications(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ bool hasPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; UInt getPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ iterator begin(const SynchronizationTag & tag, const CommunicationSendRecv & sr); iterator end(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ iterator waitAny(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void waitAll(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void incrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void decrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void freeRequests(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ Scheme & createScheme(UInt proc, const CommunicationSendRecv & sr); void resetSchemes(const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void setCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size, const CommunicationSendRecv & sr); public: explicit Communications(const Communicator & communicator); + explicit Communications(const Communications & communications); /* ------------------------------------------------------------------------ */ class IterableCommunicationDesc { public: IterableCommunicationDesc(Communications & communications, SynchronizationTag tag, CommunicationSendRecv sr) : communications(communications), tag(std::move(tag)), sr(std::move(sr)) {} auto begin() { return communications.begin(tag, sr); } auto end() { return communications.end(tag, sr); } private: Communications & communications; SynchronizationTag tag; CommunicationSendRecv sr; }; auto iterateRecv(const SynchronizationTag & tag) { return IterableCommunicationDesc(*this, tag, _recv); } auto iterateSend(const SynchronizationTag & tag) { return IterableCommunicationDesc(*this, tag, _send); } /* ------------------------------------------------------------------------ */ // iterator begin_send(const SynchronizationTag & tag); // iterator end_send(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ // iterator begin_recv(const SynchronizationTag & tag); // iterator end_recv(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ class IterableTags { public: explicit IterableTags(Communications & communications) : communications(communications) {} decltype(auto) begin() { return communications.begin_tag(); } decltype(auto) end() { return communications.end_tag(); } private: Communications & communications; }; decltype(auto) iterateTags() { return IterableTags(*this); } tag_iterator begin_tag(); tag_iterator end_tag(); /* ------------------------------------------------------------------------ */ bool hasCommunication(const SynchronizationTag & tag) const; void incrementCounter(const SynchronizationTag & tag); UInt getCounter(const SynchronizationTag & tag) const; bool hasCommunicationSize(const SynchronizationTag & tag) const; void invalidateSizes(); /* ------------------------------------------------------------------------ */ bool hasPendingRecv(const SynchronizationTag & tag) const; bool hasPendingSend(const SynchronizationTag & tag) const; const auto & getCommunicator() const; /* ------------------------------------------------------------------------ */ iterator waitAnyRecv(const SynchronizationTag & tag); iterator waitAnySend(const SynchronizationTag & tag); void waitAllRecv(const SynchronizationTag & tag); void waitAllSend(const SynchronizationTag & tag); void freeSendRequests(const SynchronizationTag & tag); void freeRecvRequests(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ class IterableSchemes { public: IterableSchemes(Communications & communications, CommunicationSendRecv sr) : communications(communications), sr(std::move(sr)) {} decltype(auto) begin() { return communications.begin_scheme(sr); } decltype(auto) end() { return communications.end_scheme(sr); } private: Communications & communications; CommunicationSendRecv sr; }; class ConstIterableSchemes { public: ConstIterableSchemes(const Communications & communications, CommunicationSendRecv sr) : communications(communications), sr(std::move(sr)) {} decltype(auto) begin() const { return communications.begin_scheme(sr); } decltype(auto) end() const { return communications.end_scheme(sr); } private: const Communications & communications; CommunicationSendRecv sr; }; decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) { return IterableSchemes(*this, sr); } decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) const { return ConstIterableSchemes(*this, sr); } decltype(auto) iterateSendSchemes() { return IterableSchemes(*this, _send); } decltype(auto) iterateSendSchemes() const { return ConstIterableSchemes(*this, _send); } decltype(auto) iterateRecvSchemes() { return IterableSchemes(*this, _recv); } decltype(auto) iterateRecvSchemes() const { return ConstIterableSchemes(*this, _recv); } scheme_iterator begin_scheme(const CommunicationSendRecv & sr); scheme_iterator end_scheme(const CommunicationSendRecv & sr); const_scheme_iterator begin_scheme(const CommunicationSendRecv & sr) const; const_scheme_iterator end_scheme(const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_send_scheme(); scheme_iterator end_send_scheme(); const_scheme_iterator begin_send_scheme() const; const_scheme_iterator end_send_scheme() const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_recv_scheme(); scheme_iterator end_recv_scheme(); const_scheme_iterator begin_recv_scheme() const; const_scheme_iterator end_recv_scheme() const; /* ------------------------------------------------------------------------ */ Scheme & createSendScheme(UInt proc); Scheme & createRecvScheme(UInt proc); /* ------------------------------------------------------------------------ */ Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr); const Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ void resetSchemes(); /* ------------------------------------------------------------------------ */ void setSendCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void setRecvCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void initializeCommunications(const SynchronizationTag & tag); protected: CommunicationSchemes schemes[2]; CommunicationsPerTags communications[2]; std::map<SynchronizationTag, UInt> comm_counter; std::map<SynchronizationTag, UInt> pending_communications[2]; std::map<SynchronizationTag, bool> comm_size_computed; const Communicator & communicator; }; } // namespace akantu #include "communications_tmpl.hh" #endif /* __AKANTU_COMMUNICATIONS_HH__ */ diff --git a/src/synchronizer/communications_tmpl.hh b/src/synchronizer/communications_tmpl.hh index 5bef47632..f87ced61a 100644 --- a/src/synchronizer/communications_tmpl.hh +++ b/src/synchronizer/communications_tmpl.hh @@ -1,534 +1,550 @@ /** * @file communications_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Tue Sep 6 17:14:06 2016 * * @brief Implementation of Communications * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communications.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_TMPL_HH__ #define __AKANTU_COMMUNICATIONS_TMPL_HH__ namespace akantu { +/* -------------------------------------------------------------------------- */ +template <class Entity> +Communications<Entity>::Communications(const Communicator & communicator) + : communicator(communicator) {} + +/* -------------------------------------------------------------------------- */ +template <class Entity> +Communications<Entity>::Communications(const Communications & other) + : communicator(other.communicator) { + for(auto && sr : iterate_send_recv) { + for (const auto & scheme_pair : other.iterateSchemes(sr)) { + auto proc = scheme_pair.first; + auto & other_scheme = scheme_pair.second; + auto & scheme = this->createScheme(proc, sr); + scheme.copy(other_scheme); + } + } + + this->invalidateSizes(); +} + /* -------------------------------------------------------------------------- */ template <class Entity> class Communications<Entity>::iterator { using communication_iterator = typename std::map<UInt, Communication>::iterator; public: iterator() : communications(nullptr) {} iterator(scheme_iterator scheme_it, communication_iterator comm_it, Communications<Entity> & communications, const SynchronizationTag & tag) : scheme_it(scheme_it), comm_it(comm_it), communications(&communications), tag(tag) {} iterator & operator=(const iterator & other) { if (this != &other) { this->scheme_it = other.scheme_it; this->comm_it = other.comm_it; this->communications = other.communications; this->tag = other.tag; } return *this; } iterator & operator++() { ++scheme_it; ++comm_it; return *this; } CommunicationDescriptor<Entity> operator*() { AKANTU_DEBUG_ASSERT( scheme_it->first == comm_it->first, "The two iterators are not in phase, something wrong" << " happened, time to take out your favorite debugger (" << scheme_it->first << " != " << comm_it->first << ")"); return CommunicationDescriptor<Entity>(comm_it->second, scheme_it->second, *communications, tag, scheme_it->first); } bool operator==(const iterator & other) const { return scheme_it == other.scheme_it && comm_it == other.comm_it; } bool operator!=(const iterator & other) const { return scheme_it != other.scheme_it || comm_it != other.comm_it; } private: scheme_iterator scheme_it; communication_iterator comm_it; Communications<Entity> * communications; SynchronizationTag tag; }; /* -------------------------------------------------------------------------- */ template <class Entity> class Communications<Entity>::tag_iterator { using internal_iterator = std::map<SynchronizationTag, UInt>::const_iterator; public: tag_iterator(const internal_iterator & it) : it(it) {} tag_iterator & operator++() { ++it; return *this; } SynchronizationTag operator*() { return it->first; } bool operator==(const tag_iterator & other) const { return it == other.it; } bool operator!=(const tag_iterator & other) const { return it != other.it; } private: internal_iterator it; }; /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::CommunicationPerProcs & Communications<Entity>::getCommunications(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto comm_it = this->communications[sr].find(tag); if (comm_it == this->communications[sr].end()) AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No known communications for the tag: " << tag); return comm_it->second; } /* ---------------------------------------------------------------------- */ template <class Entity> UInt Communications<Entity>::getPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) const { const std::map<SynchronizationTag, UInt> & pending = pending_communications[sr]; auto it = pending.find(tag); if (it == pending.end()) return 0; return it->second; } /* -------------------------------------------------------------------------- */ template <class Entity> bool Communications<Entity>::hasPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) const { return this->hasCommunication(tag) && (this->getPending(tag, sr) != 0); } /* ---------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::begin(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); return iterator(this->schemes[sr].begin(), comms.begin(), *this, tag); } template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::end(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); return iterator(this->schemes[sr].end(), comms.end(), *this, tag); } /* ---------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::waitAny(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); auto it = comms.begin(); auto end = comms.end(); std::vector<CommunicationRequest> requests; for (; it != end; ++it) { auto & request = it->second.request(); if (!request.isFreed()) requests.push_back(request); } UInt req_id = communicator.waitAny(requests); if (req_id != UInt(-1)) { auto & request = requests[req_id]; UInt proc = sr == _recv ? request.getSource() : request.getDestination(); return iterator(this->schemes[sr].find(proc), comms.find(proc), *this, tag); } else { return this->end(tag, sr); } } /* ---------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::waitAll(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); auto it = comms.begin(); auto end = comms.end(); std::vector<CommunicationRequest> requests; for (; it != end; ++it) { requests.push_back(it->second.request()); } communicator.waitAll(requests); } template <class Entity> void Communications<Entity>::incrementPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) { ++(pending_communications[sr][tag]); } template <class Entity> void Communications<Entity>::decrementPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) { --(pending_communications[sr][tag]); } template <class Entity> void Communications<Entity>::freeRequests(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { iterator it = this->begin(tag, sr); iterator end = this->end(tag, sr); for (; it != end; ++it) { (*it).freeRequest(); } } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::createScheme(UInt proc, const CommunicationSendRecv & sr) { // scheme_iterator it = schemes[sr].find(proc); // if (it != schemes[sr].end()) { // AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), // "Communication scheme(" // << sr // << ") already created for proc: " << // proc); // } return schemes[sr][proc]; } template <class Entity> void Communications<Entity>::resetSchemes(const CommunicationSendRecv & sr) { auto it = this->schemes[sr].begin(); auto end = this->schemes[sr].end(); for (; it != end; ++it) { it->second.resize(0); } } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::setCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size, const CommunicationSendRecv & sr) { // accessor that fails if it does not exists comm_size_computed[tag] = true; // TODO: need perhaps to be split based on sr auto & comms = this->communications[sr]; auto & comms_per_tag = comms.at(tag); comms_per_tag.at(proc).resize(size); } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::initializeCommunications( const SynchronizationTag & tag) { for (auto t = send_recv_t::begin(); t != send_recv_t::end(); ++t) { pending_communications[*t].insert(std::make_pair(tag, 0)); auto & comms = this->communications[*t]; auto & comms_per_tag = comms.insert(std::make_pair(tag, CommunicationPerProcs())) .first->second; for (auto pair : this->schemes[*t]) { comms_per_tag.emplace(std::piecewise_construct, std::forward_as_tuple(pair.first), std::forward_as_tuple(*t)); } } comm_counter.insert(std::make_pair(tag, 0)); } -/* -------------------------------------------------------------------------- */ -template <class Entity> -Communications<Entity>::Communications(const Communicator & communicator) - : communicator(communicator) {} - /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::tag_iterator Communications<Entity>::begin_tag() { return tag_iterator(comm_counter.begin()); } template <class Entity> typename Communications<Entity>::tag_iterator Communications<Entity>::end_tag() { return tag_iterator(comm_counter.end()); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::begin_scheme(const CommunicationSendRecv & sr) { return this->schemes[sr].begin(); } template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::end_scheme(const CommunicationSendRecv & sr) { return this->schemes[sr].end(); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::begin_scheme(const CommunicationSendRecv & sr) const { return this->schemes[sr].begin(); } template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::end_scheme(const CommunicationSendRecv & sr) const { return this->schemes[sr].end(); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::begin_send_scheme() { return this->begin_scheme(_send); } template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::end_send_scheme() { return this->end_scheme(_send); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::begin_send_scheme() const { return this->begin_scheme(_send); } template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::end_send_scheme() const { return this->end_scheme(_send); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::begin_recv_scheme() { return this->begin_scheme(_recv); } template <class Entity> typename Communications<Entity>::scheme_iterator Communications<Entity>::end_recv_scheme() { return this->end_scheme(_recv); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::begin_recv_scheme() const { return this->begin_scheme(_recv); } template <class Entity> typename Communications<Entity>::const_scheme_iterator Communications<Entity>::end_recv_scheme() const { return this->end_scheme(_recv); } /* ------------------------------------------------------------------------ */ template <class Entity> bool Communications<Entity>::hasCommunication( const SynchronizationTag & tag) const { return (communications[_send].find(tag) != communications[_send].end()); } template <class Entity> void Communications<Entity>::incrementCounter(const SynchronizationTag & tag) { auto it = comm_counter.find(tag); if (it == comm_counter.end()) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No counter initialized in communications for the tags: " << tag); } ++(it->second); } template <class Entity> UInt Communications<Entity>::getCounter(const SynchronizationTag & tag) const { auto it = comm_counter.find(tag); if (it == comm_counter.end()) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No counter initialized in communications for the tags: " << tag); } return it->second; } template <class Entity> bool Communications<Entity>::hasCommunicationSize( const SynchronizationTag & tag) const { auto it = comm_size_computed.find(tag); if (it == comm_size_computed.end()) { return false; } return it->second; } template <class Entity> void Communications<Entity>::invalidateSizes() { for (auto && pair : comm_size_computed) { pair.second = true; } } template <class Entity> bool Communications<Entity>::hasPendingRecv( const SynchronizationTag & tag) const { return this->hasPending(tag, _recv); } template <class Entity> bool Communications<Entity>::hasPendingSend( const SynchronizationTag & tag) const { return this->hasPending(tag, _send); } template <class Entity> const auto & Communications<Entity>::getCommunicator() const { return communicator; } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::waitAnyRecv(const SynchronizationTag & tag) { return this->waitAny(tag, _recv); } template <class Entity> typename Communications<Entity>::iterator Communications<Entity>::waitAnySend(const SynchronizationTag & tag) { return this->waitAny(tag, _send); } template <class Entity> void Communications<Entity>::waitAllRecv(const SynchronizationTag & tag) { this->waitAll(tag, _recv); } template <class Entity> void Communications<Entity>::waitAllSend(const SynchronizationTag & tag) { this->waitAll(tag, _send); } template <class Entity> void Communications<Entity>::freeSendRequests(const SynchronizationTag & tag) { this->freeRequests(tag, _send); } template <class Entity> void Communications<Entity>::freeRecvRequests(const SynchronizationTag & tag) { this->freeRequests(tag, _recv); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::createSendScheme(UInt proc) { return createScheme(proc, _send); } template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::createRecvScheme(UInt proc) { return createScheme(proc, _recv); } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::resetSchemes() { resetSchemes(_send); resetSchemes(_recv); } /* -------------------------------------------------------------------------- */ template <class Entity> typename Communications<Entity>::Scheme & Communications<Entity>::getScheme(UInt proc, const CommunicationSendRecv & sr) { return this->schemes[sr].find(proc)->second; } /* -------------------------------------------------------------------------- */ template <class Entity> const typename Communications<Entity>::Scheme & Communications<Entity>::getScheme(UInt proc, const CommunicationSendRecv & sr) const { return this->schemes[sr].find(proc)->second; } /* -------------------------------------------------------------------------- */ template <class Entity> void Communications<Entity>::setSendCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size) { this->setCommunicationSize(tag, proc, size, _send); } template <class Entity> void Communications<Entity>::setRecvCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size) { this->setCommunicationSize(tag, proc, size, _recv); } } // namespace akantu #endif /* __AKANTU_COMMUNICATIONS_TMPL_HH__ */ diff --git a/src/synchronizer/data_accessor.cc b/src/synchronizer/data_accessor.cc index c4855e9ab..3a51a7016 100644 --- a/src/synchronizer/data_accessor.cc +++ b/src/synchronizer/data_accessor.cc @@ -1,163 +1,155 @@ /** * @file data_accessor.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Sun Oct 19 2014 * * @brief data accessors constructor functions * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "fe_engine.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template <typename T, bool pack_helper> void DataAccessor<Element>::packUnpackNodalDataHelper( Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh) { UInt nb_component = data.getNbComponent(); UInt nb_nodes_per_element = 0; ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt * conn = nullptr; - Array<Element>::const_iterator<Element> it = elements.begin(); - Array<Element>::const_iterator<Element> end = elements.end(); - for (; it != end; ++it) { - const Element & el = *it; + for (auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; conn = mesh.getConnectivity(el.type, el.ghost_type).storage(); nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type); } UInt el_offset = el.element * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt offset_conn = conn[el_offset + n]; Vector<T> data_vect(data.storage() + offset_conn * nb_component, nb_component); if (pack_helper) buffer << data_vect; else buffer >> data_vect; } } } /* ------------------------------------------------------------------------ */ template <typename T, bool pack_helper> void DataAccessor<Element>::packUnpackElementalDataHelper( ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & element, bool per_quadrature_point_data, const FEEngine & fem) { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt nb_quad_per_elem = 0; UInt nb_component = 0; Array<T> * vect = nullptr; - Array<Element>::const_iterator<Element> it = element.begin(); - Array<Element>::const_iterator<Element> end = element.end(); - for (; it != end; ++it) { - const Element & el = *it; + for (auto & el : element) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; vect = &data_to_pack(el.type, el.ghost_type); - if (per_quadrature_point_data) - nb_quad_per_elem = fem.getNbIntegrationPoints(el.type, el.ghost_type); - else - nb_quad_per_elem = 1; + + nb_quad_per_elem = + per_quadrature_point_data + ? fem.getNbIntegrationPoints(el.type, el.ghost_type) + : 1; nb_component = vect->getNbComponent(); } Vector<T> data(vect->storage() + el.element * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem); if (pack_helper) buffer << data; else buffer >> data; } } /* -------------------------------------------------------------------------- */ template <typename T, bool pack_helper> void DataAccessor<UInt>::packUnpackDOFDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<UInt> & dofs) { - Array<UInt>::const_scalar_iterator it_dof = dofs.begin(); - Array<UInt>::const_scalar_iterator end_dof = dofs.end(); T * data_ptr = data.storage(); - - for (; it_dof != end_dof; ++it_dof) { + for (const auto & dof : dofs) { if (pack_helper) - buffer << data_ptr[*it_dof]; + buffer << data_ptr[dof]; else - buffer >> data_ptr[*it_dof]; + buffer >> data_ptr[dof]; } } /* -------------------------------------------------------------------------- */ #define DECLARE_HELPERS(T) \ template void DataAccessor<Element>::packUnpackNodalDataHelper<T, false>( \ Array<T> & data, CommunicationBuffer & buffer, \ const Array<Element> & elements, const Mesh & mesh); \ template void DataAccessor<Element>::packUnpackNodalDataHelper<T, true>( \ Array<T> & data, CommunicationBuffer & buffer, \ const Array<Element> & elements, const Mesh & mesh); \ template void \ DataAccessor<Element>::packUnpackElementalDataHelper<T, false>( \ ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, \ const Array<Element> & element, bool per_quadrature_point_data, \ const FEEngine & fem); \ template void DataAccessor<Element>::packUnpackElementalDataHelper<T, true>( \ ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, \ const Array<Element> & element, bool per_quadrature_point_data, \ const FEEngine & fem); \ template void DataAccessor<UInt>::packUnpackDOFDataHelper<T, true>( \ Array<T> & data, CommunicationBuffer & buffer, \ const Array<UInt> & dofs); \ template void DataAccessor<UInt>::packUnpackDOFDataHelper<T, false>( \ Array<T> & data, CommunicationBuffer & buffer, const Array<UInt> & dofs) /* -------------------------------------------------------------------------- */ DECLARE_HELPERS(Real); DECLARE_HELPERS(UInt); DECLARE_HELPERS(bool); /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/synchronizer/element_synchronizer.cc b/src/synchronizer/element_synchronizer.cc index 9ffc5f5f8..32698e302 100644 --- a/src/synchronizer/element_synchronizer.cc +++ b/src/synchronizer/element_synchronizer.cc @@ -1,353 +1,369 @@ /** * @file element_synchronizer.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Sep 01 2010 * @date last modification: Fri Jan 22 2016 * * @brief implementation of a communicator using a static_communicator for * real * send/receive * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "aka_common.hh" #include "mesh.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <iostream> #include <map> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ElementSynchronizer::ElementSynchronizer(Mesh & mesh, const ID & id, MemoryID memory_id, bool register_to_event_manager, EventHandlerPriority event_priority) : SynchronizerImpl<Element>(mesh.getCommunicator(), id, memory_id), mesh(mesh), element_to_prank("element_to_prank", id, memory_id) { + AKANTU_DEBUG_IN(); + + if (register_to_event_manager) + this->mesh.registerEventHandler(*this, event_priority); + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +ElementSynchronizer::ElementSynchronizer(const ElementSynchronizer & other, + const ID & id, + bool register_to_event_manager, + EventHandlerPriority event_priority) + : SynchronizerImpl<Element>(other, id), mesh(other.mesh), + element_to_prank("element_to_prank", id, other.memory_id) { AKANTU_DEBUG_IN(); + element_to_prank.copy(other.element_to_prank); + if (register_to_event_manager) this->mesh.registerEventHandler(*this, event_priority); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementSynchronizer::~ElementSynchronizer() = default; /* -------------------------------------------------------------------------- */ void ElementSynchronizer::substituteElements( const std::map<Element, Element> & old_to_new_elements) { auto found_element_end = old_to_new_elements.end(); // substitute old elements with new ones for (auto && sr : iterate_send_recv) { for (auto && scheme_pair : communications.iterateSchemes(sr)) { auto & list = scheme_pair.second; for (auto & el : list) { auto found_element_it = old_to_new_elements.find(el); if (found_element_it != found_element_end) el = found_element_it->second; } } } } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::onElementsChanged( const Array<Element> & old_elements_list, const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> &, const ChangedElementsEvent &) { // create a map to link old elements to new ones std::map<Element, Element> old_to_new_elements; for (UInt el = 0; el < old_elements_list.size(); ++el) { AKANTU_DEBUG_ASSERT(old_to_new_elements.find(old_elements_list(el)) == old_to_new_elements.end(), "The same element cannot appear twice in the list"); old_to_new_elements[old_elements_list(el)] = new_elements_list(el); } substituteElements(old_to_new_elements); communications.invalidateSizes(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::onElementsRemoved( const Array<Element> & element_to_remove, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent &) { AKANTU_DEBUG_IN(); this->removeElements(element_to_remove); this->renumberElements(new_numbering); communications.invalidateSizes(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::buildElementToPrank() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); element_to_prank.initialize(mesh, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined, _with_nb_element = true, _default_value = rank); /// assign prank to all ghost elements for (auto && scheme : communications.iterateSchemes(_recv)) { auto & recv = scheme.second; auto proc = scheme.first; for (auto & element : recv) { element_to_prank(element) = proc; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Int ElementSynchronizer::getRank(const Element & element) const { if (not element_to_prank.exists(element.type, element.ghost_type)) { // Nicolas: Ok This is nasty I know.... const_cast<ElementSynchronizer *>(this)->buildElementToPrank(); } return element_to_prank(element); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::reset() { AKANTU_DEBUG_IN(); communications.resetSchemes(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::removeElements( const Array<Element> & element_to_remove) { AKANTU_DEBUG_IN(); std::vector<CommunicationRequest> send_requests; std::map<UInt, Array<UInt>> list_of_elements_per_proc; auto filter_list = [](const Array<UInt> & keep, Array<Element> & list) { Array<Element> new_list; for (UInt e = 0; e < keep.size() - 1; ++e) { Element & el = list(keep(e)); new_list.push_back(el); } list.copy(new_list); }; // Handling ghost elements for (auto && scheme_pair : communications.iterateSchemes(_recv)) { auto proc = scheme_pair.first; auto & recv = scheme_pair.second; Array<UInt> & keep_list = list_of_elements_per_proc[proc]; auto rem_it = element_to_remove.begin(); auto rem_end = element_to_remove.end(); for (auto && pair : enumerate(recv)) { const auto & el = std::get<1>(pair); auto pos = std::find(rem_it, rem_end, el); if (pos == rem_end) { keep_list.push_back(std::get<0>(pair)); } } keep_list.push_back(UInt(-1)); // To no send empty arrays auto && tag = Tag::genTag(proc, 0, Tag::_MODIFY_SCHEME, this->hash_id); AKANTU_DEBUG_INFO("Sending a message of size " << keep_list.size() << " to proc " << proc << " TAG(" << tag << ")"); send_requests.push_back(this->communicator.asyncSend(keep_list, proc, tag)); #ifndef AKANTU_NDEBUG auto old_size = recv.size(); #endif filter_list(keep_list, recv); AKANTU_DEBUG_INFO("I had " << old_size << " elements to recv from proc " << proc << " and " << keep_list.size() << " elements to keep. I have " << recv.size() << " elements left."); } for (auto && scheme_pair : communications.iterateSchemes(_send)) { auto proc = scheme_pair.first; auto & send = scheme_pair.second; CommunicationStatus status; auto && tag = Tag::genTag(rank, 0, Tag::_MODIFY_SCHEME, this->hash_id); AKANTU_DEBUG_INFO("Getting number of elements of proc " << proc << " to keep - TAG(" << tag << ")"); this->communicator.probe<UInt>(proc, tag, status); Array<UInt> keep_list(status.size()); AKANTU_DEBUG_INFO("Receiving list of elements (" << keep_list.size() << " elements) to keep for proc " << proc << " TAG(" << tag << ")"); this->communicator.receive(keep_list, proc, tag); #ifndef AKANTU_NDEBUG auto old_size = send.size(); #endif filter_list(keep_list, send); AKANTU_DEBUG_INFO("I had " << old_size << " elements to send to proc " << proc << " and " << keep_list.size() << " elements to keep. I have " << send.size() << " elements left."); } this->communicator.waitAll(send_requests); this->communicator.freeCommunicationRequest(send_requests); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::renumberElements( const ElementTypeMapArray<UInt> & new_numbering) { for (auto && sr : iterate_send_recv) { for (auto && scheme_pair : communications.iterateSchemes(sr)) { auto & list = scheme_pair.second; for (auto && el : list) { if (new_numbering.exists(el.type, el.ghost_type)) el.element = new_numbering(el); } } } } /* -------------------------------------------------------------------------- */ UInt ElementSynchronizer::sanityCheckDataSize( const Array<Element> & elements, const SynchronizationTag &) const { UInt size = 0; size += sizeof(SynchronizationTag); // tag size += sizeof(UInt); // comm_desc.getNbData(); size += sizeof(UInt); // comm_desc.getProc(); size += sizeof(UInt); // mesh.getCommunicator().whoAmI(); // barycenters size += (elements.size() * mesh.getSpatialDimension() * sizeof(Real)); return size; } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::packSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const { auto & buffer = comm_desc.getBuffer(); buffer << comm_desc.getTag(); buffer << comm_desc.getNbData(); buffer << comm_desc.getProc(); buffer << mesh.getCommunicator().whoAmI(); auto & send_element = comm_desc.getScheme(); /// pack barycenters in debug mode for (auto && element : send_element) { Vector<Real> barycenter(mesh.getSpatialDimension()); mesh.getBarycenter(element, barycenter); buffer << barycenter; } } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::unpackSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const { auto & buffer = comm_desc.getBuffer(); const auto & tag = comm_desc.getTag(); auto nb_data = comm_desc.getNbData(); auto proc = comm_desc.getProc(); auto rank = mesh.getCommunicator().whoAmI(); decltype(nb_data) recv_nb_data; decltype(proc) recv_proc; decltype(rank) recv_rank; SynchronizationTag t; buffer >> t; buffer >> recv_nb_data; buffer >> recv_proc; buffer >> recv_rank; AKANTU_DEBUG_ASSERT( t == tag, "The tag received does not correspond to the tag expected"); AKANTU_DEBUG_ASSERT( nb_data == recv_nb_data, "The nb_data received does not correspond to the nb_data expected"); AKANTU_DEBUG_ASSERT(UInt(recv_rank) == proc, "The rank received does not correspond to the proc"); AKANTU_DEBUG_ASSERT(recv_proc == UInt(rank), "The proc received does not correspond to the rank"); auto & recv_element = comm_desc.getScheme(); auto spatial_dimension = mesh.getSpatialDimension(); for (auto && element : recv_element) { Vector<Real> barycenter_loc(spatial_dimension); mesh.getBarycenter(element, barycenter_loc); Vector<Real> barycenter(spatial_dimension); buffer >> barycenter; auto dist = barycenter_loc.distance(barycenter); if (not Math::are_float_equal(dist, 0.)) AKANTU_EXCEPTION("Unpacking an unknown value for the element " << element << "(barycenter " << barycenter_loc << " != buffer " << barycenter << ") [" << dist << "] - tag: " << tag << " comm from " << proc << " to " << rank); } } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/element_synchronizer.hh b/src/synchronizer/element_synchronizer.hh index 53fbc6e76..8764beb79 100644 --- a/src/synchronizer/element_synchronizer.hh +++ b/src/synchronizer/element_synchronizer.hh @@ -1,211 +1,216 @@ /** * @file element_synchronizer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Dec 08 2015 * * @brief Main element synchronizer * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_SYNCHRONIZER_HH__ #define __AKANTU_ELEMENT_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "mesh_partition.hh" #include "synchronizer_impl.hh" namespace akantu { class Mesh; } /* -------------------------------------------------------------------------- */ namespace akantu { class ElementSynchronizer : public SynchronizerImpl<Element>, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ElementSynchronizer(Mesh & mesh, const ID & id = "element_synchronizer", MemoryID memory_id = 0, bool register_to_event_manager = true, EventHandlerPriority event_priority = _ehp_synchronizer); + ElementSynchronizer(const ElementSynchronizer & other, + const ID & id = "element_synchronizer_copy", + bool register_to_event_manager = true, + EventHandlerPriority event_priority = _ehp_synchronizer); + public: ~ElementSynchronizer() override; friend class ElementInfoPerProc; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /// mesh event handler onElementsChanged void onElementsChanged(const Array<Element> & old_elements_list, const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> & new_numbering, const ChangedElementsEvent & event) override; /// mesh event handler onRemovedElement void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) override; /// mesh event handler onNodesAdded void onNodesAdded(const Array<UInt> & /* nodes_list*/, const NewNodesEvent & /*event*/) override{}; /// mesh event handler onRemovedNodes void onNodesRemoved(const Array<UInt> & /*nodes_list*/, const Array<UInt> & /*new_numbering*/, const RemovedNodesEvent & /*event*/) override{}; /// mesh event handler onElementsAdded void onElementsAdded(const Array<Element> & /*elements_list*/, const NewElementsEvent & /*event*/) override{}; protected: /// reset send and recv element lists void reset(); /// remove elements from the synchronizer without renumbering them void removeElements(const Array<Element> & element_to_remove); /// renumber the elements in the synchronizer void renumberElements(const ElementTypeMapArray<UInt> & new_numbering); /// build processor to element correspondence void buildElementToPrank(); protected: /// fill the nodes type vector void fillNodesType(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num); template <typename T> void fillTagBufferTemplated(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition); void fillTagBuffer(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition); /// function that handels the MeshData to be split (root side) static void synchronizeTagsSend(ElementSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_local_element, UInt nb_ghost_element); /// function that handles the MeshData to be split (other nodes) static void synchronizeTagsRecv(ElementSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, UInt nb_local_element, UInt nb_ghost_element); /// function that handles the preexisting groups in the mesh static void synchronizeElementGroups(ElementSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_element); /// function that handles the preexisting groups in the mesh static void synchronizeElementGroups(ElementSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsMaster(ElementSynchronizer & communicator, UInt root, Mesh & mesh); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsSlaves(ElementSynchronizer & communicator, UInt root, Mesh & mesh); template <class CommunicationBuffer> static void fillNodeGroupsFromBuffer(ElementSynchronizer & communicator, Mesh & mesh, CommunicationBuffer & buffer); /// substitute elements in the send and recv arrays void substituteElements(const std::map<Element, Element> & old_to_new_elements); /* ------------------------------------------------------------------------ */ /* Sanity checks */ /* ------------------------------------------------------------------------ */ UInt sanityCheckDataSize(const Array<Element> & elements, const SynchronizationTag & tag) const override; /* ------------------------------------------------------------------------ */ void packSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const override; /* ------------------------------------------------------------------------ */ void unpackSanityCheckData( CommunicationDescriptor<Element> & comm_desc) const override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Mesh, mesh, Mesh &); AKANTU_GET_MACRO(ElementToRank, element_to_prank, const ElementTypeMapArray<Int> &); Int getRank(const Element & element) const final; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// reference to the underlying mesh Mesh & mesh; friend class FacetSynchronizer; ElementTypeMapArray<Int> element_to_prank; }; /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_ELEMENT_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/synchronizer.hh b/src/synchronizer/synchronizer.hh index 0f809526e..8f3501158 100644 --- a/src/synchronizer/synchronizer.hh +++ b/src/synchronizer/synchronizer.hh @@ -1,123 +1,125 @@ /** * @file synchronizer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Dec 10 2015 * * @brief Common interface for synchronizers * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_HH__ #define __AKANTU_SYNCHRONIZER_HH__ namespace akantu { class Communicator; } namespace akantu { /* -------------------------------------------------------------------------- */ /* Base class for synchronizers */ /* -------------------------------------------------------------------------- */ class Synchronizer : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Synchronizer(const Communicator & comm, const ID & id = "synchronizer", MemoryID memory_id = 0); + Synchronizer(const Synchronizer & other) = default; + ~Synchronizer() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronize ghosts without state template <class DataAccessor> void synchronizeOnce(DataAccessor & data_accessor, const SynchronizationTag & tag) const; /// synchronize ghosts template <class DataAccessor> void synchronize(DataAccessor & data_accessor, const SynchronizationTag & tag); /// asynchronous synchronization of ghosts template <class DataAccessor> void asynchronousSynchronize(const DataAccessor & data_accessor, const SynchronizationTag & tag); /// wait end of asynchronous synchronization of ghosts template <class DataAccessor> void waitEndSynchronize(DataAccessor & data_accessor, const SynchronizationTag & tag); /// compute buffer size for a given tag and data accessor template <class DataAccessor> void computeBufferSize(const DataAccessor & data_accessor, const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Communicator, communicator, const Communicator &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the synchronizer ID id; /// hashed version of the id int hash_id; /// message counter per tag std::map<SynchronizationTag, UInt> tag_counter; /// the static memory instance const Communicator & communicator; /// nb processors in the communicator UInt nb_proc; /// rank in the communicator UInt rank; }; } // namespace akantu #include "synchronizer_tmpl.hh" #endif /* __AKANTU_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/synchronizer_impl.hh b/src/synchronizer/synchronizer_impl.hh index b4b87c96d..fcfedb3e8 100644 --- a/src/synchronizer/synchronizer_impl.hh +++ b/src/synchronizer/synchronizer_impl.hh @@ -1,121 +1,123 @@ /** * @file synchronizer_impl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Aug 24 13:26:47 2016 * * @brief Implementation of the generic part of synchronizers * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communications.hh" #include "synchronizer.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_IMPL_HH__ #define __AKANTU_SYNCHRONIZER_IMPL_HH__ namespace akantu { template <class Entity> class SynchronizerImpl : public Synchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SynchronizerImpl(const Communicator & communicator, const ID & id = "synchronizer", MemoryID memory_id = 0); + SynchronizerImpl(const SynchronizerImpl & other, const ID & id); + ~SynchronizerImpl() override = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronous synchronization without state virtual void synchronizeOnceImpl(DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) const; /// asynchronous synchronization of ghosts virtual void asynchronousSynchronizeImpl(const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag); /// wait end of asynchronous synchronization of ghosts virtual void waitEndSynchronizeImpl(DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag); /// compute all buffer sizes virtual void computeAllBufferSizes(const DataAccessor<Entity> & data_accessor); /// compute buffer size for a given tag and data accessor virtual void computeBufferSizeImpl(const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ virtual void synchronizeImpl(DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { this->asynchronousSynchronizeImpl(data_accessor, tag); this->waitEndSynchronizeImpl(data_accessor, tag); } /* ------------------------------------------------------------------------ */ /// extract the elements that have a true predicate from in_synchronizer and /// store them in the current synchronizer template <typename Pred> void split(SynchronizerImpl & in_synchronizer, Pred && pred); /// update schemes in a synchronizer template <typename Updater> void updateSchemes(Updater && scheme_updater); /* ------------------------------------------------------------------------ */ virtual UInt sanityCheckDataSize(const Array<Entity> & elements, const SynchronizationTag & tag) const; virtual void packSanityCheckData(CommunicationDescriptor<Entity> & comm_desc) const; virtual void unpackSanityCheckData(CommunicationDescriptor<Entity> & comm_desc) const; public: AKANTU_GET_MACRO(Communications, communications, const Communications<Entity> &); protected: AKANTU_GET_MACRO_NOT_CONST(Communications, communications, Communications<Entity> &); virtual Int getRank(const Entity & entity) const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// information on the communications Communications<Entity> communications; }; } // namespace akantu #include "synchronizer_impl_tmpl.hh" #endif /* __AKANTU_SYNCHRONIZER_IMPL_HH__ */ diff --git a/src/synchronizer/synchronizer_impl_tmpl.hh b/src/synchronizer/synchronizer_impl_tmpl.hh index 8cd7a2cdf..b8129ce99 100644 --- a/src/synchronizer/synchronizer_impl_tmpl.hh +++ b/src/synchronizer/synchronizer_impl_tmpl.hh @@ -1,305 +1,314 @@ /** * @file synchronizer_impl_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Aug 24 13:29:47 2016 * * @brief Implementation of the SynchronizerImpl * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "synchronizer_impl.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ #define __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template <class Entity> -SynchronizerImpl<Entity>::SynchronizerImpl(const Communicator & comm, const ID & id, MemoryID memory_id) +SynchronizerImpl<Entity>::SynchronizerImpl(const Communicator & comm, + const ID & id, MemoryID memory_id) : Synchronizer(comm, id, memory_id), communications(comm) {} +/* -------------------------------------------------------------------------- */ +template <class Entity> +SynchronizerImpl<Entity>::SynchronizerImpl(const SynchronizerImpl & other, + const ID & id) + : Synchronizer(other), communications(other.communications) { + this->id = id; +} + /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::synchronizeOnceImpl( DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) const { // no need to synchronize if (this->nb_proc == 1) return; using CommunicationRequests = std::vector<CommunicationRequest>; using CommunicationBuffers = std::map<UInt, CommunicationBuffer>; CommunicationRequests send_requests, recv_requests; CommunicationBuffers send_buffers, recv_buffers; auto postComm = [&](const CommunicationSendRecv & sr, CommunicationBuffers & buffers, CommunicationRequests & requests) -> void { for (auto && pair : communications.iterateSchemes(sr)) { auto & proc = pair.first; const auto & scheme = pair.second; auto & buffer = buffers[proc]; UInt buffer_size = data_accessor.getNbData(scheme, tag); buffer.resize(buffer_size); if (sr == _recv) { requests.push_back(communicator.asyncReceive( buffer, proc, Tag::genTag(this->rank, 0, Tag::_SYNCHRONIZE, this->hash_id))); } else { data_accessor.packData(buffer, scheme, tag); send_requests.push_back(communicator.asyncSend( buffer, proc, Tag::genTag(proc, 0, Tag::_SYNCHRONIZE, this->hash_id))); } } }; // post the receive requests postComm(_recv, recv_buffers, recv_requests); // post the send data requests postComm(_send, send_buffers, send_requests); // treat the receive requests UInt request_ready; while ((request_ready = communicator.waitAny(recv_requests)) != UInt(-1)) { CommunicationRequest & req = recv_requests[request_ready]; UInt proc = req.getSource(); CommunicationBuffer & buffer = recv_buffers[proc]; const auto & scheme = this->communications.getScheme(proc, _recv); data_accessor.unpackData(buffer, scheme, tag); req.free(); recv_requests.erase(recv_requests.begin() + request_ready); } communicator.waitAll(send_requests); communicator.freeCommunicationRequest(send_requests); } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::asynchronousSynchronizeImpl( const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (not this->communications.hasCommunicationSize(tag)) this->computeBufferSize(data_accessor, tag); this->communications.incrementCounter(tag); // Posting the receive ------------------------------------------------------- if (this->communications.hasPendingRecv(tag)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "There must still be some pending receive communications." << " Tag is " << tag << " Cannot start new ones"); } for (auto && comm_desc : this->communications.iterateRecv(tag)) { comm_desc.postRecv(this->hash_id); } // Posting the sends ------------------------------------------------------- if (communications.hasPendingSend(tag)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "There must be some pending sending communications." << " Tag is " << tag); } for (auto && comm_desc : this->communications.iterateSend(tag)) { comm_desc.resetBuffer(); #ifndef AKANTU_NDEBUG this->packSanityCheckData(comm_desc); #endif comm_desc.packData(data_accessor); comm_desc.postSend(this->hash_id); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::waitEndSynchronizeImpl( DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); #ifndef AKANTU_NDEBUG if (this->communications.begin(tag, _recv) != - this->communications.end(tag, _recv) && + this->communications.end(tag, _recv) && !this->communications.hasPendingRecv(tag)) AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), "No pending communication with the tag \"" << tag); #endif auto recv_end = this->communications.end(tag, _recv); decltype(recv_end) recv_it; while ((recv_it = this->communications.waitAnyRecv(tag)) != recv_end) { auto && comm_desc = *recv_it; #ifndef AKANTU_NDEBUG this->unpackSanityCheckData(comm_desc); #endif comm_desc.unpackData(data_accessor); comm_desc.resetBuffer(); comm_desc.freeRequest(); } this->communications.waitAllSend(tag); this->communications.freeSendRequests(tag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::computeAllBufferSizes( const DataAccessor<Entity> & data_accessor) { for (auto && tag : this->communications.iterateTags()) { this->computeBufferSize(data_accessor, tag); } } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::computeBufferSizeImpl( const DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (not this->communications.hasCommunication(tag)) { this->communications.initializeCommunications(tag); AKANTU_DEBUG_ASSERT(communications.hasCommunication(tag) == true, "Communications where not properly initialized"); } for (auto sr : iterate_send_recv) { for (auto && pair : this->communications.iterateSchemes(sr)) { auto proc = pair.first; const auto & scheme = pair.second; UInt size = 0; #ifndef AKANTU_NDEBUG size += this->sanityCheckDataSize(scheme, tag); #endif size += data_accessor.getNbData(scheme, tag); AKANTU_DEBUG_INFO("I have " << size << "(" << printMemorySize<char>(size) << " - " << scheme.size() << " element(s)) data to " << std::string(sr == _recv ? "receive from" : "send to") << proc << " for tag " << tag); this->communications.setCommunicationSize(tag, proc, size, sr); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Entity> template <typename Pred> void SynchronizerImpl<Entity>::split(SynchronizerImpl<Entity> & in_synchronizer, Pred && pred) { AKANTU_DEBUG_IN(); auto filter_list = [&](auto & list, auto & new_list) { auto copy = list; list.resize(0); new_list.resize(0); for (auto && entity : copy) { if (std::forward<Pred>(pred)(entity)) { new_list.push_back(entity); } else { list.push_back(entity); } } }; for (auto sr : iterate_send_recv) { for (auto & scheme_pair : in_synchronizer.communications.iterateSchemes(sr)) { auto proc = scheme_pair.first; auto & scheme = scheme_pair.second; auto & new_scheme = communications.createScheme(proc, sr); - filter_list(new_scheme, scheme); + filter_list(scheme, new_scheme); } } in_synchronizer.communications.invalidateSizes(); communications.invalidateSizes(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename Entity> template <typename Updater> void SynchronizerImpl<Entity>::updateSchemes(Updater && scheme_updater) { for (auto sr : iterate_send_recv) { for (auto & scheme_pair : communications.iterateSchemes(sr)) { auto proc = scheme_pair.first; auto & scheme = scheme_pair.second; std::forward<Updater>(scheme_updater)(scheme, proc, sr); } } communications.invalidateSizes(); } /* -------------------------------------------------------------------------- */ template <class Entity> UInt SynchronizerImpl<Entity>::sanityCheckDataSize( const Array<Entity> &, const SynchronizationTag &) const { return 0; } /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::packSanityCheckData( CommunicationDescriptor<Entity> &) const {} /* -------------------------------------------------------------------------- */ template <class Entity> void SynchronizerImpl<Entity>::unpackSanityCheckData( CommunicationDescriptor<Entity> &) const {} /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ */ diff --git a/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh b/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh index 741047074..7422ecdb9 100644 --- a/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh +++ b/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh @@ -1,50 +1,271 @@ $MeshFormat 2.2 0 8 $EndMeshFormat $Nodes -13 +100 1 0 0 0 2 1 0 0 3 1 1 0 4 0 1 0 -5 0.4999999999990217 0 0 -6 1 0.4999999999990217 0 -7 0.5000000000013878 1 0 -8 0 0.5000000000013878 0 -9 0.5000000000000262 0.5000000000000762 0 -10 0.2500000000004626 0.7500000000004626 0 -11 0.7500000000004626 0.7499999999996739 0 -12 0.7499999999996739 0.2499999999996739 0 -13 0.24999999999961 0.2500000000004752 0 +5 0.1111111111109082 0 0 +6 0.2222222222217143 0 0 +7 0.333333333332501 0 0 +8 0.4444444444432878 0 0 +9 0.5555555555543833 0 0 +10 0.6666666666657874 0 0 +11 0.7777777777771916 0 0 +12 0.8888888888885959 0 0 +13 1 0.1111111111109082 0 +14 1 0.2222222222217143 0 +15 1 0.333333333332501 0 +16 1 0.4444444444432878 0 +17 1 0.5555555555543833 0 +18 1 0.6666666666657874 0 +19 1 0.7777777777771916 0 +20 1 0.8888888888885959 0 +21 0.8888888888884262 1 0 +22 0.777777777777932 1 0 +23 0.6666666666675918 1 0 +24 0.5555555555572513 1 0 +25 0.4444444444462943 1 0 +26 0.3333333333347207 1 0 +27 0.2222222222231471 1 0 +28 0.1111111111115736 1 0 +29 0 0.8888888888884262 0 +30 0 0.777777777777932 0 +31 0 0.6666666666675918 0 +32 0 0.5555555555572513 0 +33 0 0.4444444444462943 0 +34 0 0.3333333333347207 0 +35 0 0.2222222222231471 0 +36 0 0.1111111111115736 0 +37 0.1111111111109822 0.1111111111114996 0 +38 0.1111111111110561 0.2222222222229879 0 +39 0.11111111111113 0.3333333333344741 0 +40 0.1111111111112039 0.4444444444459603 0 +41 0.1111111111112778 0.5555555555569326 0 +42 0.1111111111113518 0.6666666666673913 0 +43 0.1111111111114257 0.7777777777778498 0 +44 0.1111111111114996 0.8888888888884451 0 +45 0.2222222222218735 0.1111111111114257 0 +46 0.2222222222220326 0.2222222222228287 0 +47 0.2222222222221919 0.3333333333342274 0 +48 0.2222222222223511 0.4444444444456261 0 +49 0.2222222222225103 0.5555555555566142 0 +50 0.2222222222226695 0.6666666666671908 0 +51 0.2222222222228287 0.7777777777777674 0 +52 0.2222222222229879 0.888888888888464 0 +53 0.3333333333327477 0.1111111111113518 0 +54 0.3333333333329943 0.2222222222226695 0 +55 0.3333333333332409 0.3333333333339809 0 +56 0.3333333333334876 0.4444444444452921 0 +57 0.3333333333337343 0.5555555555562953 0 +58 0.3333333333339809 0.6666666666669903 0 +59 0.3333333333342274 0.7777777777776852 0 +60 0.3333333333344741 0.8888888888884829 0 +61 0.4444444444436218 0.1111111111112778 0 +62 0.444444444443956 0.2222222222225103 0 +63 0.44444444444429 0.3333333333337343 0 +64 0.4444444444446239 0.4444444444449581 0 +65 0.4444444444449581 0.5555555555559767 0 +66 0.4444444444452921 0.66666666666679 0 +67 0.4444444444456261 0.7777777777776029 0 +68 0.4444444444459603 0.8888888888885014 0 +69 0.5555555555547019 0.1111111111112039 0 +70 0.5555555555550206 0.2222222222223511 0 +71 0.5555555555553394 0.3333333333334876 0 +72 0.5555555555556581 0.444444444444624 0 +73 0.5555555555559767 0.5555555555556581 0 +74 0.5555555555562953 0.6666666666665895 0 +75 0.555555555556614 0.7777777777775207 0 +76 0.5555555555569326 0.8888888888885206 0 +77 0.6666666666659877 0.11111111111113 0 +78 0.6666666666661885 0.2222222222221919 0 +79 0.6666666666663887 0.3333333333332409 0 +80 0.6666666666665892 0.44444444444429 0 +81 0.66666666666679 0.5555555555553392 0 +82 0.6666666666669905 0.6666666666663887 0 +83 0.6666666666671908 0.7777777777774383 0 +84 0.6666666666673913 0.8888888888885393 0 +85 0.7777777777772739 0.1111111111110561 0 +86 0.7777777777773561 0.2222222222220327 0 +87 0.7777777777774385 0.3333333333329943 0 +88 0.7777777777775208 0.4444444444439559 0 +89 0.7777777777776028 0.5555555555550208 0 +90 0.7777777777776852 0.6666666666661885 0 +91 0.7777777777777674 0.7777777777773561 0 +92 0.7777777777778497 0.8888888888885581 0 +93 0.888888888888577 0.1111111111109821 0 +94 0.8888888888885583 0.2222222222218735 0 +95 0.8888888888885393 0.3333333333327477 0 +96 0.8888888888885205 0.4444444444436219 0 +97 0.8888888888885017 0.5555555555547019 0 +98 0.8888888888884829 0.666666666665988 0 +99 0.888888888888464 0.777777777777274 0 +100 0.8888888888884451 0.888888888888577 0 $EndNodes $Elements -28 -1 15 2 0 101 1 -2 15 2 0 102 2 -3 15 2 0 103 3 -4 15 2 0 104 4 -5 1 2 0 101 1 5 -6 1 2 0 101 5 2 -7 1 2 0 102 2 6 -8 1 2 0 102 6 3 -9 1 2 0 103 3 7 -10 1 2 0 103 7 4 -11 1 2 0 104 4 8 -12 1 2 0 104 8 1 -13 2 2 0 101 4 10 7 -14 2 2 0 101 1 13 8 -15 2 2 0 101 3 11 6 -16 2 2 0 101 2 12 5 -17 2 2 0 101 8 9 10 -18 2 2 0 101 7 10 9 -19 2 2 0 101 7 9 11 -20 2 2 0 101 8 13 9 -21 2 2 0 101 6 11 9 -22 2 2 0 101 5 9 13 -23 2 2 0 101 5 12 9 -24 2 2 0 101 6 9 12 -25 2 2 0 101 1 5 13 -26 2 2 0 101 4 8 10 -27 2 2 0 101 2 6 12 -28 2 2 0 101 3 7 11 +162 +1 2 2 1 101 1 5 36 +2 2 2 1 101 36 5 37 +3 2 2 1 101 36 37 35 +4 2 2 1 101 35 37 38 +5 2 2 1 101 35 38 34 +6 2 2 1 101 34 38 39 +7 2 2 1 101 34 39 33 +8 2 2 1 101 33 39 40 +9 2 2 1 101 33 40 32 +10 2 2 1 101 32 40 41 +11 2 2 1 101 32 41 31 +12 2 2 1 101 31 41 42 +13 2 2 1 101 31 42 30 +14 2 2 1 101 30 42 43 +15 2 2 1 101 30 43 29 +16 2 2 1 101 29 43 44 +17 2 2 1 101 29 44 4 +18 2 2 1 101 4 44 28 +19 2 2 1 101 5 6 37 +20 2 2 1 101 37 6 45 +21 2 2 1 101 37 45 38 +22 2 2 1 101 38 45 46 +23 2 2 1 101 38 46 39 +24 2 2 1 101 39 46 47 +25 2 2 1 101 39 47 40 +26 2 2 1 101 40 47 48 +27 2 2 1 101 40 48 41 +28 2 2 1 101 41 48 49 +29 2 2 1 101 41 49 42 +30 2 2 1 101 42 49 50 +31 2 2 1 101 42 50 43 +32 2 2 1 101 43 50 51 +33 2 2 1 101 43 51 44 +34 2 2 1 101 44 51 52 +35 2 2 1 101 44 52 28 +36 2 2 1 101 28 52 27 +37 2 2 1 101 6 7 45 +38 2 2 1 101 45 7 53 +39 2 2 1 101 45 53 46 +40 2 2 1 101 46 53 54 +41 2 2 1 101 46 54 47 +42 2 2 1 101 47 54 55 +43 2 2 1 101 47 55 48 +44 2 2 1 101 48 55 56 +45 2 2 1 101 48 56 49 +46 2 2 1 101 49 56 57 +47 2 2 1 101 49 57 50 +48 2 2 1 101 50 57 58 +49 2 2 1 101 50 58 51 +50 2 2 1 101 51 58 59 +51 2 2 1 101 51 59 52 +52 2 2 1 101 52 59 60 +53 2 2 1 101 52 60 27 +54 2 2 1 101 27 60 26 +55 2 2 1 101 7 8 53 +56 2 2 1 101 53 8 61 +57 2 2 1 101 53 61 54 +58 2 2 1 101 54 61 62 +59 2 2 1 101 54 62 55 +60 2 2 1 101 55 62 63 +61 2 2 1 101 55 63 56 +62 2 2 1 101 56 63 64 +63 2 2 1 101 56 64 57 +64 2 2 1 101 57 64 65 +65 2 2 1 101 57 65 58 +66 2 2 1 101 58 65 66 +67 2 2 1 101 58 66 59 +68 2 2 1 101 59 66 67 +69 2 2 1 101 59 67 60 +70 2 2 1 101 60 67 68 +71 2 2 1 101 60 68 26 +72 2 2 1 101 26 68 25 +73 2 2 1 101 8 9 61 +74 2 2 1 101 61 9 69 +75 2 2 1 101 61 69 62 +76 2 2 1 101 62 69 70 +77 2 2 1 101 62 70 63 +78 2 2 1 101 63 70 71 +79 2 2 1 101 63 71 64 +80 2 2 1 101 64 71 72 +81 2 2 1 101 64 72 65 +82 2 2 1 101 65 72 73 +83 2 2 1 101 65 73 66 +84 2 2 1 101 66 73 74 +85 2 2 1 101 66 74 67 +86 2 2 1 101 67 74 75 +87 2 2 1 101 67 75 68 +88 2 2 1 101 68 75 76 +89 2 2 1 101 68 76 25 +90 2 2 1 101 25 76 24 +91 2 2 1 101 9 10 69 +92 2 2 1 101 69 10 77 +93 2 2 1 101 69 77 70 +94 2 2 1 101 70 77 78 +95 2 2 1 101 70 78 71 +96 2 2 1 101 71 78 79 +97 2 2 1 101 71 79 72 +98 2 2 1 101 72 79 80 +99 2 2 1 101 72 80 73 +100 2 2 1 101 73 80 81 +101 2 2 1 101 73 81 74 +102 2 2 1 101 74 81 82 +103 2 2 1 101 74 82 75 +104 2 2 1 101 75 82 83 +105 2 2 1 101 75 83 76 +106 2 2 1 101 76 83 84 +107 2 2 1 101 76 84 24 +108 2 2 1 101 24 84 23 +109 2 2 1 101 10 11 77 +110 2 2 1 101 77 11 85 +111 2 2 1 101 77 85 78 +112 2 2 1 101 78 85 86 +113 2 2 1 101 78 86 79 +114 2 2 1 101 79 86 87 +115 2 2 1 101 79 87 80 +116 2 2 1 101 80 87 88 +117 2 2 1 101 80 88 81 +118 2 2 1 101 81 88 89 +119 2 2 1 101 81 89 82 +120 2 2 1 101 82 89 90 +121 2 2 1 101 82 90 83 +122 2 2 1 101 83 90 91 +123 2 2 1 101 83 91 84 +124 2 2 1 101 84 91 92 +125 2 2 1 101 84 92 23 +126 2 2 1 101 23 92 22 +127 2 2 1 101 11 12 85 +128 2 2 1 101 85 12 93 +129 2 2 1 101 85 93 86 +130 2 2 1 101 86 93 94 +131 2 2 1 101 86 94 87 +132 2 2 1 101 87 94 95 +133 2 2 1 101 87 95 88 +134 2 2 1 101 88 95 96 +135 2 2 1 101 88 96 89 +136 2 2 1 101 89 96 97 +137 2 2 1 101 89 97 90 +138 2 2 1 101 90 97 98 +139 2 2 1 101 90 98 91 +140 2 2 1 101 91 98 99 +141 2 2 1 101 91 99 92 +142 2 2 1 101 92 99 100 +143 2 2 1 101 92 100 22 +144 2 2 1 101 22 100 21 +145 2 2 1 101 12 2 93 +146 2 2 1 101 93 2 13 +147 2 2 1 101 93 13 94 +148 2 2 1 101 94 13 14 +149 2 2 1 101 94 14 95 +150 2 2 1 101 95 14 15 +151 2 2 1 101 95 15 96 +152 2 2 1 101 96 15 16 +153 2 2 1 101 96 16 97 +154 2 2 1 101 97 16 17 +155 2 2 1 101 97 17 98 +156 2 2 1 101 98 17 18 +157 2 2 1 101 98 18 99 +158 2 2 1 101 99 18 19 +159 2 2 1 101 99 19 100 +160 2 2 1 101 100 19 20 +161 2 2 1 101 100 20 21 +162 2 2 1 101 21 20 3 $EndElements diff --git a/test/test_fe_engine/test_fe_engine_fixture.hh b/test/test_fe_engine/test_fe_engine_fixture.hh index 822bf968c..8e2ba7b74 100644 --- a/test/test_fe_engine/test_fe_engine_fixture.hh +++ b/test/test_fe_engine/test_fe_engine_fixture.hh @@ -1,84 +1,83 @@ /* -------------------------------------------------------------------------- */ #include "element_class.hh" #include "fe_engine.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "test_gtest_utils.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TEST_FE_ENGINE_FIXTURE_HH__ #define __AKANTU_TEST_FE_ENGINE_FIXTURE_HH__ using namespace akantu; /// Generic class for FEEngine tests template <typename type_, template <ElementKind> class shape_t, ElementKind kind = _ek_regular> class TestFEMBaseFixture : public ::testing::Test { public: static constexpr const ElementType type = type_::value; static constexpr const size_t dim = ElementClass<type>::getSpatialDimension(); using FEM = FEEngineTemplate<IntegratorGauss, shape_t, kind>; /// Setup reads mesh corresponding to element type and initializes an FEEngine void SetUp() override { const auto dim = this->dim; const auto type = this->type; mesh = std::make_unique<Mesh>(dim); std::stringstream meshfilename; meshfilename << type << ".msh"; this->readMesh(meshfilename.str()); lower = mesh->getLowerBounds(); upper = mesh->getUpperBounds(); nb_element = this->mesh->getNbElement(type); fem = std::make_unique<FEM>(*mesh, dim, "my_fem"); - fem->initShapeFunctions(); - - nb_quadrature_points_total = fem->getNbIntegrationPoints(type) * nb_element; + nb_quadrature_points_total = + GaussIntegrationElement<type>::getNbQuadraturePoints() * nb_element; SCOPED_TRACE(aka::to_string(type)); } void TearDown() override { fem.reset(nullptr); mesh.reset(nullptr); } /// Should be reimplemented if further treatment of the mesh is needed virtual void readMesh(std::string file_name) { mesh->read(file_name); } protected: std::unique_ptr<FEM> fem; std::unique_ptr<Mesh> mesh; UInt nb_element; UInt nb_quadrature_points_total; Vector<Real> lower; Vector<Real> upper; }; template <typename type_, template <ElementKind> class shape_t, ElementKind kind> constexpr const ElementType TestFEMBaseFixture<type_, shape_t, kind>::type; template <typename type_, template <ElementKind> class shape_t, ElementKind kind> constexpr const size_t TestFEMBaseFixture<type_, shape_t, kind>::dim; /* -------------------------------------------------------------------------- */ /// Base class for test with Lagrange FEEngine and regular elements template <typename type_> using TestFEMFixture = TestFEMBaseFixture<type_, ShapeLagrange>; /* -------------------------------------------------------------------------- */ using types = gtest_list_t<TestElementTypes>; TYPED_TEST_CASE(TestFEMFixture, types); #endif /* __AKANTU_TEST_FE_ENGINE_FIXTURE_HH__ */ diff --git a/test/test_fe_engine/test_fe_engine_gauss_integration.cc b/test/test_fe_engine/test_fe_engine_gauss_integration.cc index 9e44bc23e..48fee7c9f 100644 --- a/test/test_fe_engine/test_fe_engine_gauss_integration.cc +++ b/test/test_fe_engine/test_fe_engine_gauss_integration.cc @@ -1,153 +1,155 @@ /** * @file test_fe_engine_precomputation.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 * @date last modification: Mon Jul 13 2015 * * @brief test integration on elements, this test consider that mesh is a cube * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "test_fe_engine_fixture.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> #include <iostream> /* -------------------------------------------------------------------------- */ using namespace akantu; namespace { /* -------------------------------------------------------------------------- */ template <size_t t> using degree_t = std::integral_constant<size_t, t>; /* -------------------------------------------------------------------------- */ using TestDegreeTypes = std::tuple<degree_t<0>, degree_t<1>, degree_t<2>, degree_t<3>, degree_t<4>, degree_t<5>>; std::array<Polynomial<5>, 3> global_polys{ {{0.40062394, 0.13703225, 0.51731446, 0.87830084, 0.5410543, 0.71842292}, {0.41861835, 0.11080576, 0.49874043, 0.49077504, 0.85073835, 0.66259755}, {0.92620845, 0.7503478, 0.62962232, 0.31662719, 0.64069644, 0.30878135}}}; template <typename T> class TestGaussIntegrationFixture : public TestFEMFixture<std::tuple_element_t<0, T>> { protected: using parent = TestFEMFixture<std::tuple_element_t<0, T>>; static constexpr size_t degree{std::tuple_element_t<1, T>::value}; public: TestGaussIntegrationFixture() : integration_points_pos(0, parent::dim) {} void SetUp() override { parent::SetUp(); + this->fem->initShapeFunctions(); + auto integration_points = this->fem->getIntegrator().template getIntegrationPoints < parent::type, degree == 0 ? 1 : degree > (); nb_integration_points = integration_points.cols(); auto shapes_size = ElementClass<parent::type>::getShapeSize(); Array<Real> shapes(0, shapes_size); this->fem->getShapeFunctions() .template computeShapesOnIntegrationPoints<parent::type>( this->mesh->getNodes(), integration_points, shapes, _not_ghost); auto vect_size = this->nb_integration_points * this->nb_element; integration_points_pos.resize(vect_size); this->fem->getShapeFunctions() .template interpolateOnIntegrationPoints<parent::type>( this->mesh->getNodes(), integration_points_pos, this->dim, shapes); for (size_t d = 0; d < this->dim; ++d) { polys[d] = global_polys[d].extract(degree); } } void testIntegrate() { std::stringstream sstr; sstr << this->type << ":" << this->degree; SCOPED_TRACE(sstr.str().c_str()); auto vect_size = this->nb_integration_points * this->nb_element; Array<Real> polynomial(vect_size); size_t dim = parent::dim; for (size_t d = 0; d < dim; ++d) { auto poly = this->polys[d]; for (auto && pair : zip(polynomial, make_view(this->integration_points_pos, dim))) { auto && p = std::get<0>(pair); auto & x = std::get<1>(pair); p = poly(x(d)); } auto res = this->fem->getIntegrator() .template integrate<parent::type, (degree == 0 ? 1 : degree)>(polynomial); auto expect = poly.integrate(this->lower(d), this->upper(d)); for (size_t o = 0; o < dim; ++o) { if (o == d) continue; expect *= this->upper(d) - this->lower(d); } EXPECT_NEAR(expect, res, 5e-14); } } protected: UInt nb_integration_points; std::array<Array<Real>, parent::dim> polynomial; Array<Real> integration_points_pos; std::array<Polynomial<5>, 3> polys; }; template <typename T> constexpr size_t TestGaussIntegrationFixture<T>::degree; /* -------------------------------------------------------------------------- */ /* Tests */ /* -------------------------------------------------------------------------- */ TYPED_TEST_CASE_P(TestGaussIntegrationFixture); TYPED_TEST_P(TestGaussIntegrationFixture, ArbitraryOrder) { this->testIntegrate(); } REGISTER_TYPED_TEST_CASE_P(TestGaussIntegrationFixture, ArbitraryOrder); using TestTypes = gtest_list_t<tuple_split_t<50, cross_product_t<TestElementTypes, TestDegreeTypes>>>; INSTANTIATE_TYPED_TEST_CASE_P(Split1, TestGaussIntegrationFixture, TestTypes); using TestTypesTail = gtest_list_t<tuple_split_tail_t<50, cross_product_t<TestElementTypes, TestDegreeTypes>>>; INSTANTIATE_TYPED_TEST_CASE_P(Split2, TestGaussIntegrationFixture, TestTypesTail); } diff --git a/test/test_fe_engine/test_fe_engine_precomputation.cc b/test/test_fe_engine/test_fe_engine_precomputation.cc index c66054cc6..149785f5b 100644 --- a/test/test_fe_engine/test_fe_engine_precomputation.cc +++ b/test/test_fe_engine/test_fe_engine_precomputation.cc @@ -1,112 +1,113 @@ /** * @file test_fe_engine_precomputation.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 * @date last modification: Mon Jul 13 2015 * * @brief test of the fem class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "pybind11_akantu.hh" #include "test_fe_engine_fixture.hh" /* -------------------------------------------------------------------------- */ #include <pybind11/embed.h> #include <pybind11/numpy.h> /* -------------------------------------------------------------------------- */ using namespace akantu; namespace py = pybind11; using namespace py::literals; template <typename type_> class TestFEMPyFixture : public TestFEMFixture<type_> { using parent = TestFEMFixture<type_>; public: void SetUp() override { parent::SetUp(); const auto & connectivities = this->mesh->getConnectivity(this->type); const auto & nodes = this->mesh->getNodes().begin(this->dim); coordinates = std::make_unique<Array<Real>>( connectivities.size(), connectivities.getNbComponent() * this->dim); for (auto && tuple : zip(make_view(connectivities, connectivities.getNbComponent()), make_view(*coordinates, this->dim, connectivities.getNbComponent()))) { const auto & conn = std::get<0>(tuple); const auto & X = std::get<1>(tuple); for (auto s : arange(conn.size())) { Vector<Real>(X(s)) = Vector<Real>(nodes[conn(s)]); } } } void TearDown() override { parent::TearDown(); coordinates.reset(nullptr); } protected: std::unique_ptr<Array<Real>> coordinates; }; TYPED_TEST_CASE(TestFEMPyFixture, types); TYPED_TEST(TestFEMPyFixture, Precompute) { SCOPED_TRACE(aka::to_string(this->type)); + this->fem->initShapeFunctions(); const auto & N = this->fem->getShapeFunctions().getShapes(this->type); const auto & B = this->fem->getShapeFunctions().getShapesDerivatives(this->type); const auto & j = this->fem->getIntegrator().getJacobians(this->type); // Array<Real> ref_N(this->nb_quadrature_points_total, N.getNbComponent()); // Array<Real> ref_B(this->nb_quadrature_points_total, B.getNbComponent()); Array<Real> ref_j(this->nb_quadrature_points_total, j.getNbComponent()); auto ref_N(N); auto ref_B(B); py::module py_engine = py::module::import("py_engine"); auto py_shape = py_engine.attr("Shapes")(py::str(aka::to_string(this->type))); auto kwargs = py::dict( "N"_a = make_proxy(ref_N), "B"_a = make_proxy(ref_B), "j"_a = make_proxy(ref_j), "X"_a = make_proxy(*this->coordinates), "Q"_a = make_proxy( this->fem->getIntegrationPoints(this->type))); auto ret = py_shape.attr("precompute")(**kwargs); auto check = [&](auto & ref_A, auto & A, const auto & id) { SCOPED_TRACE(aka::to_string(this->type) + " " + id); for (auto && n : zip(make_view(ref_A, ref_A.getNbComponent()), make_view(A, A.getNbComponent()))) { auto diff = (std::get<0>(n) - std::get<1>(n)).template norm<L_inf>(); EXPECT_NEAR(0., diff, 1e-10); } }; check(ref_N, N, "N"); check(ref_B, B, "B"); check(ref_j, j, "j"); } diff --git a/test/test_fe_engine/test_fe_engine_precomputation_structural.cc b/test/test_fe_engine/test_fe_engine_precomputation_structural.cc index fc69aaa56..fc7e3b8e5 100644 --- a/test/test_fe_engine/test_fe_engine_precomputation_structural.cc +++ b/test/test_fe_engine/test_fe_engine_precomputation_structural.cc @@ -1,109 +1,126 @@ /** * @file test_fe_engine_precomputation_structural.cc * * @author Lucas Frérot * * @date creation: Fri Feb 26 2018 * * @brief test of the structural precomputations * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fe_engine.hh" #include "integrator_gauss.hh" #include "shape_structural.hh" #include "test_fe_engine_structural_fixture.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ // Need a special fixture for the extra normal class TestBernoulliB3 : public TestFEMStructuralFixture<element_type_t<_bernoulli_beam_3>> { using parent = TestFEMStructuralFixture<element_type_t<_bernoulli_beam_3>>; public: /// Load the mesh and provide extra normal direction void readMesh(std::string filename) override { parent::readMesh(filename); auto & normals = this->mesh->registerData<Real>("extra_normal") .alloc(0, dim, type, _not_ghost); Vector<Real> normal = {-36. / 65, -48. / 65, 5. / 13}; normals.push_back(normal); } }; /* -------------------------------------------------------------------------- */ /// Type alias using TestBernoulliB2 = TestFEMStructuralFixture<element_type_t<_bernoulli_beam_2>>; + using TestDKT18 = + TestFEMStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>>; /* -------------------------------------------------------------------------- */ /// Solution for 2D rotation matrices Matrix<Real> globalToLocalRotation(Real theta) { auto c = std::cos(theta); auto s = std::sin(theta); return {{c, s, 0}, {-s, c, 0}, {0, 0, 1}}; } /* -------------------------------------------------------------------------- */ TEST_F(TestBernoulliB2, PrecomputeRotations) { + this->fem->initShapeFunctions(); using ShapeStruct = ShapeStructural<_ek_structural>; auto & shape = dynamic_cast<const ShapeStruct &>(fem->getShapeFunctions()); auto & rot = shape.getRotations(type); Real a = std::atan(4. / 3); std::vector<Real> angles = {a, -a, 0}; Math::setTolerance(1e-15); for (auto && tuple : zip(make_view(rot, ndof, ndof), angles)) { auto rotation = std::get<0>(tuple); auto angle = std::get<1>(tuple); auto rotation_error = (rotation - globalToLocalRotation(angle)).norm<L_2>(); EXPECT_NEAR(rotation_error, 0., Math::getTolerance()); } } /* -------------------------------------------------------------------------- */ TEST_F(TestBernoulliB3, PrecomputeRotations) { + this->fem->initShapeFunctions(); using ShapeStruct = ShapeStructural<_ek_structural>; auto & shape = dynamic_cast<const ShapeStruct &>(fem->getShapeFunctions()); auto & rot = shape.getRotations(type); Matrix<Real> ref = {{3. / 13, 4. / 13, 12. / 13}, {-4. / 5, 3. / 5, 0}, {-36. / 65, -48. / 65, 5. / 13}}; Matrix<Real> solution{ndof, ndof}; solution.block(ref, 0, 0); solution.block(ref, dim, dim); // The default tolerance is too much, really Math::setTolerance(1e-15); for (auto & rotation : make_view(rot, ndof, ndof)) { auto rotation_error = (rotation - solution).norm<L_2>(); EXPECT_NEAR(rotation_error, 0., Math::getTolerance()); } } + +/* -------------------------------------------------------------------------- */ +TEST_F(TestDKT18, PrecomputeRotations) { + this->fem->initShapeFunctions(); + using ShapeStruct = ShapeStructural<_ek_structural>; + auto & shape = dynamic_cast<const ShapeStruct &>(fem->getShapeFunctions()); + auto & rot = shape.getRotations(type); + + for (auto & rotation : make_view(rot, ndof, ndof)) { + std::cout << rotation << "\n"; + } + std::cout.flush(); +} diff --git a/test/test_fe_engine/test_gradient.cc b/test/test_fe_engine/test_gradient.cc index edd30e6a9..4afb40172 100644 --- a/test/test_fe_engine/test_gradient.cc +++ b/test/test_fe_engine/test_gradient.cc @@ -1,103 +1,105 @@ /** * @file test_gradient.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Peter Spijker <peter.spijker@epfl.ch> * * @date creation: Fri Sep 03 2010 * @date last modification: Thu Oct 15 2015 * * @brief test of the fem class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * * @section DESCRIPTION * * This code is computing the gradient of a linear field and check that it gives * a constant result. It also compute the gradient the coordinates of the mesh * and check that it gives the identity * */ /* -------------------------------------------------------------------------- */ #include "test_fe_engine_fixture.hh" /* -------------------------------------------------------------------------- */ #include <cstdlib> #include <iostream> /* -------------------------------------------------------------------------- */ using namespace akantu; namespace { TYPED_TEST(TestFEMFixture, GradientPoly) { + this->fem->initShapeFunctions(); Real alpha[2][3] = {{13, 23, 31}, {11, 7, 5}}; const auto dim = this->dim; const auto type = this->type; const auto & position = this->fem->getMesh().getNodes(); Array<Real> const_val(this->fem->getMesh().getNbNodes(), 2, "const_val"); for(auto && pair : zip(make_view(position, dim), make_view(const_val, 2))) { auto & pos = std::get<0>(pair); auto & const_ = std::get<1>(pair); const_.set(0.); for (UInt d = 0; d < dim; ++d) { const_(0) += alpha[0][d] * pos(d); const_(1) += alpha[1][d] * pos(d); } } /// compute the gradient Array<Real> grad_on_quad(this->nb_quadrature_points_total, 2 * dim, "grad_on_quad"); this->fem->gradientOnIntegrationPoints(const_val, grad_on_quad, 2, type); /// check the results for(auto && grad : make_view(grad_on_quad, 2, dim)) { for (UInt d = 0; d < dim; ++d) { EXPECT_NEAR(grad(0, d), alpha[0][d], 5e-13); EXPECT_NEAR(grad(1, d), alpha[1][d], 5e-13); } } } TYPED_TEST(TestFEMFixture, GradientPositions) { + this->fem->initShapeFunctions(); const auto dim = this->dim; const auto type = this->type; UInt nb_quadrature_points = this->fem->getNbIntegrationPoints(type) * this->nb_element; Array<Real> grad_coord_on_quad(nb_quadrature_points, dim * dim, "grad_coord_on_quad"); const auto & position = this->mesh->getNodes(); this->fem->gradientOnIntegrationPoints(position, grad_coord_on_quad, dim, type); auto I = Matrix<Real>::eye(UInt(dim)); for(auto && grad : make_view(grad_coord_on_quad, dim, dim)) { auto diff = (I - grad).template norm<L_inf>(); EXPECT_NEAR(0., diff, 2e-14); } } } diff --git a/test/test_fe_engine/test_integrate.cc b/test/test_fe_engine/test_integrate.cc index 40200579e..74ad310ad 100644 --- a/test/test_fe_engine/test_integrate.cc +++ b/test/test_fe_engine/test_integrate.cc @@ -1,75 +1,77 @@ /** * @file test_integrate.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Peter Spijker <peter.spijker@epfl.ch> * * @date creation: Fri Sep 03 2010 * @date last modification: Thu Oct 15 2015 * * @brief test of the fem class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "test_fe_engine_fixture.hh" /* -------------------------------------------------------------------------- */ #include <cstdlib> #include <iostream> /* -------------------------------------------------------------------------- */ using namespace akantu; namespace { TYPED_TEST(TestFEMFixture, IntegrateConstant) { + this->fem->initShapeFunctions(); + const auto type = this->type; const auto & position = this->fem->getMesh().getNodes(); Array<Real> const_val(position.size(), 2, "const_val"); Array<Real> val_on_quad(this->nb_quadrature_points_total, 2, "val_on_quad"); Vector<Real> value{1, 2}; for (auto && const_ : make_view(const_val, 2)) { const_ = value; } // interpolate function on quadrature points this->fem->interpolateOnIntegrationPoints(const_val, val_on_quad, 2, type); // integrate function on elements Array<Real> int_val_on_elem(this->nb_element, 2, "int_val_on_elem"); this->fem->integrate(val_on_quad, int_val_on_elem, 2, type); // get global integration value Vector<Real> sum{0., 0.}; for (auto && int_ : make_view(int_val_on_elem, 2)) { sum += int_; } auto diff = (value - sum).template norm<L_inf>(); EXPECT_NEAR(0, diff, 1e-14); } } // namespace diff --git a/test/test_fe_engine/test_inverse_map.cc b/test/test_fe_engine/test_inverse_map.cc index b4a0e9518..6da60b1df 100644 --- a/test/test_fe_engine/test_inverse_map.cc +++ b/test/test_fe_engine/test_inverse_map.cc @@ -1,69 +1,71 @@ /** * @file test_inverse_map.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Fri Sep 03 2010 * @date last modification: Thu Oct 15 2015 * * @brief test of the fem class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "test_fe_engine_fixture.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; namespace { TYPED_TEST(TestFEMFixture, InverseMap) { + this->fem->initShapeFunctions(); + Matrix<Real> quad = GaussIntegrationElement<TestFixture::type>::getQuadraturePoints(); const auto & position = this->fem->getMesh().getNodes(); /// get the quadrature points coordinates Array<Real> coord_on_quad(quad.cols() * this->nb_element, this->dim, "coord_on_quad"); this->fem->interpolateOnIntegrationPoints(position, coord_on_quad, this->dim, this->type); Vector<Real> natural_coords(this->dim); auto length = (this->upper - this->lower).template norm<L_inf>(); for(auto && enum_ : enumerate(make_view(coord_on_quad, this->dim, quad.cols()))) { auto el = std::get<0>(enum_); const auto & quads_coords = std::get<1>(enum_); for (auto q : arange(quad.cols())) { Vector<Real> quad_coord = quads_coords(q); Vector<Real> ref_quad_coord = quad(q); this->fem->inverseMap(quad_coord, el, this->type, natural_coords); auto dis_normalized = ref_quad_coord.distance(natural_coords) / length; EXPECT_NEAR(0., dis_normalized, 5e-12); } } } } // namespace diff --git a/test/test_model/patch_tests/CMakeLists.txt b/test/test_model/patch_tests/CMakeLists.txt index aebad9be4..d845ec350 100644 --- a/test/test_model/patch_tests/CMakeLists.txt +++ b/test/test_model/patch_tests/CMakeLists.txt @@ -1,112 +1,117 @@ #=============================================================================== # @file CMakeLists.txt # # @author David Simon Kammer <david.kammer@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Fri Oct 22 2010 # @date last modification: Mon Dec 07 2015 # # @brief configuration for patch tests # # @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 <http://www.gnu.org/licenses/>. # # @section DESCRIPTION # #=============================================================================== add_subdirectory(data) register_gtest_sources(SOURCES patch_test_linear_elastic_explicit.cc PACKAGE solid_mechanics FILES_TO_COPY data/material_check_stress_plane_strain.dat data/material_check_stress_plane_stress.dat) register_gtest_sources(SOURCES patch_test_linear_elastic_implicit.cc PACKAGE solid_mechanics implicit FILES_TO_COPY data/material_check_stress_plane_strain.dat data/material_check_stress_plane_stress.dat) + register_gtest_sources(SOURCES patch_test_linear_anisotropic_explicit.cc - PACKAGE solid_mechanics - FILES_TO_COPY data/material_anisotropic.dat - UNSTABLE) + PACKAGE solid_mechanics lapack + FILES_TO_COPY data/material_anisotropic.dat) register_gtest_sources(SOURCES test_lumped_mass.cc PACKAGE solid_mechanics FILES_TO_COPY data/material_lumped.dat) register_gtest_sources( SOURCES patch_test_linear_heat_transfer_explicit.cc FILES_TO_COPY data/heat_transfer_input.dat PACKAGE heat_transfer) register_gtest_sources( SOURCES patch_test_linear_heat_transfer_static.cc FILES_TO_COPY data/heat_transfer_input.dat PACKAGE heat_transfer implicit) +register_gtest_sources( + SOURCES patch_test_linear_heat_transfer_implicit.cc + FILES_TO_COPY data/heat_transfer_input.dat + PACKAGE heat_transfer implicit) + register_gtest_test(patch_test_linear FILES_TO_COPY ${PATCH_TEST_MESHES}) register_test(test_linear_elastic_explicit_python SCRIPT patch_test_linear_elastic_explicit.py PYTHON PACKAGE python_interface FILES_TO_COPY patch_test_linear_fixture.py FILES_TO_COPY patch_test_linear_solid_mechanics_fixture.py FILES_TO_COPY ${PATCH_TEST_MESHES}) register_test(test_linear_elastic_static_python SCRIPT patch_test_linear_elastic_static.py PYTHON PACKAGE python_interface implicit FILES_TO_COPY patch_test_linear_fixture.py FILES_TO_COPY patch_test_linear_solid_mechanics_fixture.py) register_test(test_linear_anisotropic_explicit_python SCRIPT patch_test_linear_anisotropic_explicit.py PYTHON - PACKAGE python_interface + PACKAGE python_interface lapack FILES_TO_COPY patch_test_linear_fixture.py FILES_TO_COPY patch_test_linear_solid_mechanics_fixture.py FILES_TO_COPY data/material_anisotropic.dat) register_test(patch_test_linear_heat_transfer_explicit_python SCRIPT patch_test_linear_heat_transfer_explicit.py PYTHON PACKAGE python_interface heat_transfer FILES_TO_COPY patch_test_linear_fixture.py FILES_TO_COPY patch_test_linear_heat_transfer_fixture.py FILES_TO_COPY data/heat_transfer_input.dat) register_test(patch_test_linear_heat_transfer_static_python SCRIPT patch_test_linear_heat_transfer_static.py PYTHON PACKAGE python_interface heat_transfer implicit FILES_TO_COPY patch_test_linear_fixture.py FILES_TO_COPY patch_test_linear_heat_transfer_fixture.py FILES_TO_COPY data/heat_transfer_input.dat) register_test(patch_test_linear_heat_transfer_implicit_python SCRIPT patch_test_linear_heat_transfer_implicit.py PYTHON PACKAGE python_interface heat_transfer implicit FILES_TO_COPY patch_test_linear_fixture.py FILES_TO_COPY patch_test_linear_heat_transfer_fixture.py FILES_TO_COPY data/heat_transfer_input.dat) diff --git a/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc b/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc index d85e51e86..f34a42414 100644 --- a/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc +++ b/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc @@ -1,109 +1,114 @@ /** * @file patch_test_explicit_anisotropic.cc * * @author Till Junge <till.junge@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Sat Apr 16 2011 * @date last modification: Thu Oct 15 2015 * * @brief patch test for elastic material in solid mechanics model * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ -#include "patch_test_linear_fixture.hh" +#include "patch_test_linear_solid_mechanics_fixture.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; // Stiffness tensor, rotated by hand Real C[3][3][3] [3] = {{{{112.93753505, 1.85842452538e-10, -4.47654358027e-10}, {1.85847317471e-10, 54.2334345331, -3.69840984824}, {-4.4764768395e-10, -3.69840984824, 56.848605217}}, {{1.85847781609e-10, 25.429294233, -3.69840984816}, {25.429294233, 3.31613847493e-10, -8.38797920011e-11}, {-3.69840984816, -8.38804581349e-11, -1.97875715813e-10}}, {{-4.47654358027e-10, -3.69840984816, 28.044464917}, {-3.69840984816, 2.09374961813e-10, 9.4857455224e-12}, {28.044464917, 9.48308098714e-12, -2.1367885239e-10}}}, {{{1.85847781609e-10, 25.429294233, -3.69840984816}, {25.429294233, 3.31613847493e-10, -8.38793479119e-11}, {-3.69840984816, -8.38795699565e-11, -1.97876381947e-10}}, {{54.2334345331, 3.31617400207e-10, 2.09372075233e-10}, {3.3161562385e-10, 115.552705733, -3.15093728886e-10}, {2.09372075233e-10, -3.15090176173e-10, 54.2334345333}}, {{-3.69840984824, -8.38795699565e-11, 9.48219280872e-12}, {-8.38795699565e-11, -3.1509195253e-10, 25.4292942335}, {9.48441325477e-12, 25.4292942335, 3.69840984851}}}, {{{-4.47653469848e-10, -3.69840984816, 28.044464917}, {-3.69840984816, 2.09374073634e-10, 9.48752187924e-12}, {28.044464917, 9.48552347779e-12, -2.1367885239e-10}}, {{-3.69840984824, -8.3884899027e-11, 9.48219280872e-12}, {-8.3884899027e-11, -3.150972816e-10, 25.4292942335}, {9.48041645188e-12, 25.4292942335, 3.69840984851}}, {{56.848605217, -1.97875493768e-10, -2.13681516925e-10}, {-1.97877270125e-10, 54.2334345333, 3.69840984851}, {-2.13683293282e-10, 3.69840984851, 112.93753505}}}}; /* -------------------------------------------------------------------------- */ -TYPED_TEST(TestPatchTestLinear, AnisotropicExplicit) { +TYPED_TEST(TestPatchTestSMMLinear, AnisotropicExplicit) { this->initModel(_explicit_lumped_mass, "material_anisotropic.dat"); const auto & coordinates = this->mesh->getNodes(); auto & displacement = this->model->getDisplacement(); // set the position of all nodes to the static solution for (auto && tuple : zip(make_view(coordinates, this->dim), make_view(displacement, this->dim))) { - this->setDisplacement(std::get<1>(tuple), std::get<0>(tuple)); + this->setLinearDOF(std::get<1>(tuple), std::get<0>(tuple)); } for (UInt s = 0; s < 100; ++s) { this->model->solveStep(); } auto ekin = this->model->getEnergy("kinetic"); EXPECT_NEAR(0, ekin, 1e-16); - this->checkDisplacements(); - this->checkStrains(); - this->checkStresses([&](const Matrix<Real> & pstrain) { + auto & mat = this->model->getMaterial(0); + + this->checkDOFs(displacement); + this->checkGradient(mat.getGradU(this->type), displacement); + + + this->checkResults([&](const Matrix<Real> & pstrain) { auto strain = (pstrain + pstrain.transpose()) / 2.; decltype(strain) stress(this->dim, this->dim); for (UInt i = 0; i < this->dim; ++i) { for (UInt j = 0; j < this->dim; ++j) { stress(i, j) = 0; for (UInt k = 0; k < this->dim; ++k) { for (UInt l = 0; l < this->dim; ++l) { stress(i, j) += C[i][j][k][l] * strain(k, l); } } } } return stress; - }); + }, + mat.getStress(this->type), displacement); } diff --git a/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc index 08e3ddd1f..c14e0207b 100644 --- a/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc +++ b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc @@ -1,21 +1,21 @@ /* -------------------------------------------------------------------------- */ #include "patch_test_linear_heat_transfer_fixture.hh" /* -------------------------------------------------------------------------- */ -TYPED_TEST(TestPatchTestHTMLinear, Explicit) { +TYPED_TEST(TestPatchTestHTMLinear, Implicit) { this->initModel(_implicit_dynamic, "heat_transfer_input.dat"); const auto & coordinates = this->mesh->getNodes(); auto & temperature = this->model->getTemperature(); // set the position of all nodes to the static solution for (auto && tuple : zip(make_view(coordinates, this->dim), make_view(temperature, 1))) { this->setLinearDOF(std::get<1>(tuple), std::get<0>(tuple)); } for (UInt s = 0; s < 100; ++s) { this->model->solveStep(); } this->checkAll(); } diff --git a/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.py b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.py new file mode 100644 index 000000000..c78ad8bfa --- /dev/null +++ b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +from patch_test_linear_heat_transfer_fixture import TestPatchTestHTMLinear +import akantu + + +def foo(self): + self.initModel(akantu.HeatTransferModelOptions(akantu._implicit_dynamic), + "heat_transfer_input.dat") + + coordinates = self.mesh.getNodes() + temperature = self.model.getTemperature() + # set the position of all nodes to the static solution + self.setLinearDOF(temperature, coordinates) + + for s in range(0, 100): + self.model.solveStep() + + self.checkAll() + + +TestPatchTestHTMLinear.TYPED_TEST(foo, "Explicit") diff --git a/test/test_model/patch_tests/patch_test_linear_heat_transfer_static.py b/test/test_model/patch_tests/patch_test_linear_heat_transfer_static.py new file mode 100644 index 000000000..5d1749b10 --- /dev/null +++ b/test/test_model/patch_tests/patch_test_linear_heat_transfer_static.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +from patch_test_linear_heat_transfer_fixture import TestPatchTestHTMLinear +import akantu + + +def foo(self): + self.initModel(akantu.HeatTransferModelOptions(akantu._static), + "heat_transfer_input.dat") + + solver = self.model.getNonLinearSolver() + solver.set("max_iterations", 2) + solver.set("threshold", 2e-4) + solver.set("convergence_type", akantu._scc_residual) + + self.model.solveStep() + + self.checkAll() + + +TestPatchTestHTMLinear.TYPED_TEST(foo, "Implicit") diff --git a/test/test_model/test_model_solver/test_model_solver_dynamic.cc b/test/test_model/test_model_solver/test_model_solver_dynamic.cc index 1373d2946..7956e1e98 100644 --- a/test/test_model/test_model_solver/test_model_solver_dynamic.cc +++ b/test/test_model/test_model_solver/test_model_solver_dynamic.cc @@ -1,171 +1,171 @@ /** * @file test_dof_manager_default.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date Wed Feb 24 12:28:44 2016 * * @brief Test default dof manager * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "dof_manager.hh" #include "dof_manager_default.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_accessor.hh" #include "model_solver.hh" #include "non_linear_solver.hh" #include "sparse_matrix.hh" #include "communicator.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ #include "test_model_solver_my_model.hh" /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ #ifndef EXPLICIT #define EXPLICIT true #endif using namespace akantu; static void genMesh(Mesh & mesh, UInt nb_nodes); /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { initialize(argc, argv); UInt prank = Communicator::getStaticCommunicator().whoAmI(); UInt global_nb_nodes = 201; UInt max_steps = 200; Real time_step = 0.001; Mesh mesh(1); Real F = -9.81; bool _explicit = EXPLICIT; if (prank == 0) genMesh(mesh, global_nb_nodes); mesh.distribute(); MyModel model(F, mesh, _explicit); if (!_explicit) { model.getNewSolver("dynamic", _tsst_dynamic, _nls_newton_raphson); model.setIntegrationScheme("dynamic", "disp", _ist_trapezoidal_rule_2, IntegrationScheme::_displacement); } else { model.getNewSolver("dynamic", _tsst_dynamic_lumped, _nls_lumped); model.setIntegrationScheme("dynamic", "disp", _ist_central_difference, IntegrationScheme::_acceleration); } model.setTimeStep(time_step); // #if EXPLICIT == true // std::ofstream output("output_dynamic_explicit.csv"); // #else // std::ofstream output("output_dynamic_implicit.csv"); // #endif if (prank == 0) { std::cout << std::scientific; std::cout << std::setw(14) << "time" << "," << std::setw(14) << "wext" << "," << std::setw(14) << "epot" << "," << std::setw(14) << "ekin" << "," << std::setw(14) << "total" << std::endl; } Real wext = 0.; model.getDOFManager().clearResidual(); model.assembleResidual(); Real epot = 0;//model.getPotentialEnergy(); Real ekin = 0;//model.getKineticEnergy(); Real einit = ekin + epot; Real etot = ekin + epot - wext - einit; if (prank == 0) { std::cout << std::setw(14) << 0. << "," << std::setw(14) << wext << "," << std::setw(14) << epot << "," << std::setw(14) << ekin << "," << std::setw(14) << etot << std::endl; } #if EXPLICIT == false NonLinearSolver & solver = model.getDOFManager().getNonLinearSolver("dynamic"); solver.set("max_iterations", 20); #endif for (UInt i = 1; i < max_steps + 1; ++i) { - model.solveStep(); + model.solveStep("dynamic"); #if EXPLICIT == false //int nb_iter = solver.get("nb_iterations"); //Real error = solver.get("error"); //bool converged = solver.get("converged"); //if (prank == 0) // std::cerr << error << " " << nb_iter << " -> " << converged << std::endl; #endif epot = model.getPotentialEnergy(); ekin = model.getKineticEnergy(); wext += model.getExternalWorkIncrement(); etot = ekin + epot - wext - einit; if (prank == 0) { std::cout << std::setw(14) << time_step * i << "," << std::setw(14) << wext << "," << std::setw(14) << epot << "," << std::setw(14) << ekin << "," << std::setw(14) << etot << std::endl; } if (std::abs(etot) > 1e-1) { AKANTU_DEBUG_ERROR("The total energy of the system is not conserved!"); } } // output.close(); finalize(); return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ void genMesh(Mesh & mesh, UInt nb_nodes) { MeshAccessor mesh_accessor(mesh); Array<Real> & nodes = mesh_accessor.getNodes(); Array<UInt> & conn = mesh_accessor.getConnectivity(_segment_2); nodes.resize(nb_nodes); for (UInt n = 0; n < nb_nodes; ++n) { nodes(n, _x) = n * (1. / (nb_nodes - 1)); } conn.resize(nb_nodes - 1); for (UInt n = 0; n < nb_nodes - 1; ++n) { conn(n, 0) = n; conn(n, 1) = n + 1; } } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt b/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt index bce3d66b5..816e1ed21 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt @@ -1,55 +1,110 @@ #=============================================================================== # @file CMakeLists.txt # # @author Marco Vocialta <marco.vocialta@epfl.ch> # # @date creation: Fri Oct 22 2010 # @date last modification: Thu Jan 14 2016 # # @brief configuration for cohesive elements tests # # @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 <http://www.gnu.org/licenses/>. # # @section DESCRIPTION # #=============================================================================== #add_akantu_test(test_cohesive_intrinsic "test_cohesive_intrinsic") #add_akantu_test(test_cohesive_extrinsic "test_cohesive_extrinsic") #add_akantu_test(test_cohesive_intrinsic_impl "test_cohesive_intrinsic_impl") #add_akantu_test(test_cohesive_1d_element "test_cohesive_1d_element") #add_akantu_test(test_cohesive_extrinsic_implicit "test_cohesive_extrinsic_implicit") add_akantu_test(test_cohesive_buildfragments "test_cohesive_buildfragments") add_akantu_test(test_cohesive_insertion "test_cohesive_insertion") add_akantu_test(test_cohesive_linear_friction "test_cohesive_linear_friction") #add_akantu_test(test_parallel_cohesive "parallel_cohesive_test") -add_mesh(cohesive_2d_4 data/cohesive_strait_2D.geo 2 1 OUTPUT _cohesive_2d_4.msh) -add_mesh(cohesive_2d_6 data/cohesive_strait_2D.geo 2 2 OUTPUT _cohesive_2d_6.msh) +set(_meshes) + +add_mesh(cohesive_1d_2_seg data/cohesive_1D.geo + DIM 2 ORDER 1 + OUTPUT _cohesive_1d_2_segment_2.msh) +list(APPEND _meshes cohesive_1d_2_seg) + +add_mesh(cohesive_2d_4_tri data/cohesive_strait_2D.geo + DIM 2 ORDER 1 + OUTPUT _cohesive_2d_4_triangle_3.msh) +list(APPEND _meshes cohesive_2d_4_tri) + +add_mesh(cohesive_2d_6_tri data/cohesive_strait_2D.geo + DIM 2 ORDER 2 + OUTPUT _cohesive_2d_6_triangle_6.msh) +list(APPEND _meshes cohesive_2d_6_tri) + +add_mesh(cohesive_2d_4_quad data/cohesive_strait_2D_structured.geo + DIM 2 ORDER 1 + OUTPUT _cohesive_2d_4_quadrangle_4.msh) +list(APPEND _meshes cohesive_2d_4_quad) + +add_mesh(cohesive_2d_6_quad data/cohesive_strait_2D_structured.geo + DIM 2 ORDER 2 + OUTPUT _cohesive_2d_6_quadrangle_8.msh) +list(APPEND _meshes cohesive_2d_6_quad) + +add_mesh(cohesive_2d_4_tri_quad data/cohesive_strait_2D_mixte.geo + DIM 2 ORDER 1 + OUTPUT _cohesive_2d_4_triangle_3_quadrangle_4.msh) +list(APPEND _meshes cohesive_2d_4_tri_quad) + +add_mesh(cohesive_2d_6_tri_quad data/cohesive_strait_2D_mixte.geo + DIM 2 ORDER 2 + OUTPUT _cohesive_2d_6_triangle_6_quadrangle_8.msh) +list(APPEND _meshes cohesive_2d_6_tri_quad) + +add_mesh(cohesive_3d_6_tet data/cohesive_strait_3D.geo + DIM 3 ORDER 1 + OUTPUT _cohesive_3d_6_tetrahedron_4.msh) +list(APPEND _meshes cohesive_3d_6_tet) + +add_mesh(cohesive_3d_12_tet data/cohesive_strait_3D.geo + DIM 3 ORDER 2 + OUTPUT _cohesive_3d_12_tetrahedron_10.msh) +list(APPEND _meshes cohesive_3d_12_tet) + +add_mesh(cohesive_3d_8_hex data/cohesive_strait_3D_structured.geo + DIM 3 ORDER 1 + OUTPUT _cohesive_3d_8_hexahedron_8.msh) +list(APPEND _meshes cohesive_3d_8_hex) + +add_mesh(cohesive_3d_16_hex data/cohesive_strait_3D_structured.geo + DIM 3 ORDER 2 + OUTPUT _cohesive_3d_16_hexahedron_20.msh) +list(APPEND _meshes cohesive_3d_16_hex) register_gtest_sources( SOURCES test_cohesive.cc PACKAGE cohesive_element - DEPENDS cohesive_2d_4 cohesive_2d_6 + DEPENDS ${_meshes} + FILES_TO_COPY material_0.dat material_1.dat ) register_gtest_test(test_solid_mechanics_model_cohesive) #=============================================================================== diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_1D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_1D.geo new file mode 100644 index 000000000..f52f56ea0 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_1D.geo @@ -0,0 +1,15 @@ +h = 0.5; + +Point(1) = { 1., 0., 0., h}; +Point(3) = { 0., 0., 0., h}; +Point(2) = {-1., 0., 0., h}; + +Line(1) = {2, 3}; +Line(2) = {3, 1}; + +Physical Point ("loading") = {1}; +Physical Point ("fixed") = {2}; + +Physical Point ("insertion") = {3}; + +Physical Line ("body") = {1, 2}; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo index be9cd3a9b..65c7a7dd0 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo @@ -1,29 +1,30 @@ -h = 1.; +h = 0.5; Point(1) = { 1, 1, 0, h}; Point(2) = {-1, 1, 0, h}; Point(3) = {-1,-1, 0, h}; Point(4) = { 1,-1, 0, h}; Point(5) = {-1, 0, 0, h}; Point(6) = { 1, 0, 0, h}; Line(1) = {1, 2}; Line(2) = {2, 5}; Line(3) = {5, 6}; Line(4) = {6, 1}; Line(5) = {5, 3}; Line(6) = {3, 4}; Line(7) = {4, 6}; Line Loop(1) = {1, 2, 3, 4}; Line Loop(2) = {-3, 5, 6, 7}; Plane Surface(1) = {1}; Plane Surface(2) = {2}; Physical Line("fixed") = {6}; Physical Line("loading") = {1}; Physical Line("insertion") = {3}; +Physical Line("sides") = {2, 5, 7, 4}; Physical Surface("body") = {1, 2}; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo similarity index 80% copy from test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo copy to test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo index be9cd3a9b..5550c66de 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo @@ -1,29 +1,34 @@ -h = 1.; +h = 0.4; Point(1) = { 1, 1, 0, h}; Point(2) = {-1, 1, 0, h}; Point(3) = {-1,-1, 0, h}; Point(4) = { 1,-1, 0, h}; Point(5) = {-1, 0, 0, h}; Point(6) = { 1, 0, 0, h}; Line(1) = {1, 2}; Line(2) = {2, 5}; Line(3) = {5, 6}; Line(4) = {6, 1}; Line(5) = {5, 3}; Line(6) = {3, 4}; Line(7) = {4, 6}; Line Loop(1) = {1, 2, 3, 4}; Line Loop(2) = {-3, 5, 6, 7}; Plane Surface(1) = {1}; Plane Surface(2) = {2}; Physical Line("fixed") = {6}; Physical Line("loading") = {1}; Physical Line("insertion") = {3}; +Physical Line("sides") = {2, 5, 7, 4}; Physical Surface("body") = {1, 2}; + +Recombine Surface {2}; +Transfinite Surface {2}; +Mesh.SecondOrderIncomplete = 1; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo similarity index 80% copy from test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo copy to test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo index be9cd3a9b..c571a062e 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo @@ -1,29 +1,34 @@ -h = 1.; +h = 0.2; Point(1) = { 1, 1, 0, h}; Point(2) = {-1, 1, 0, h}; Point(3) = {-1,-1, 0, h}; Point(4) = { 1,-1, 0, h}; Point(5) = {-1, 0, 0, h}; Point(6) = { 1, 0, 0, h}; Line(1) = {1, 2}; Line(2) = {2, 5}; Line(3) = {5, 6}; Line(4) = {6, 1}; Line(5) = {5, 3}; Line(6) = {3, 4}; Line(7) = {4, 6}; Line Loop(1) = {1, 2, 3, 4}; Line Loop(2) = {-3, 5, 6, 7}; Plane Surface(1) = {1}; Plane Surface(2) = {2}; Physical Line("fixed") = {6}; Physical Line("loading") = {1}; Physical Line("insertion") = {3}; +Physical Line("sides") = {2, 5, 7, 4}; Physical Surface("body") = {1, 2}; + +Recombine Surface "*"; +Transfinite Surface "*"; +Mesh.SecondOrderIncomplete = 1; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo new file mode 100644 index 000000000..ad9490148 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo @@ -0,0 +1,33 @@ +h = 0.5; + +Point(1) = { 1, 1, -.5, h}; +Point(2) = {-1, 1, -.5, h}; +Point(3) = {-1,-1, -.5, h}; +Point(4) = { 1,-1, -.5, h}; + +Point(5) = {-1, 0, -.5, h}; +Point(6) = { 1, 0, -.5, h}; + +Line(1) = {1, 2}; +Line(2) = {2, 5}; +Line(3) = {5, 6}; +Line(4) = {6, 1}; + +Line(5) = {5, 3}; +Line(6) = {3, 4}; +Line(7) = {4, 6}; + +Line Loop(1) = {1, 2, 3, 4}; +Line Loop(2) = {-3, 5, 6, 7}; +Plane Surface(1) = {1}; +Plane Surface(2) = {2}; +Extrude {0, 0, 1} { + Surface{1}; Surface{2}; +} + +Physical Surface("fixed") = {46}; +Physical Surface("insertion") = {24}; +Physical Surface("loading") = {16}; +Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42}; + +Physical Volume("body") = {1, 2}; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo new file mode 100644 index 000000000..c54ed8705 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo @@ -0,0 +1,40 @@ +h = 0.5; + +Point(1) = { 1, 1, -.5, h}; +Point(2) = {-1, 1, -.5, h}; +Point(3) = {-1,-1, -.5, h}; +Point(4) = { 1,-1, -.5, h}; + +Point(5) = {-1, 0, -.5, h}; +Point(6) = { 1, 0, -.5, h}; + +Line(1) = {1, 2}; +Line(2) = {2, 5}; +Line(3) = {5, 6}; +Line(4) = {6, 1}; + +Line(5) = {5, 3}; +Line(6) = {3, 4}; +Line(7) = {4, 6}; + +Line Loop(1) = {1, 2, 3, 4}; +Line Loop(2) = {-3, 5, 6, 7}; +Plane Surface(1) = {1}; +Plane Surface(2) = {2}; +Extrude {0, 0, 1} { + Surface{1}; Surface{2}; +} + +Physical Surface("fixed") = {46}; +Physical Surface("insertion") = {24}; +Physical Surface("loading") = {16}; +Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42}; + +Physical Volume("body") = {1, 2}; + +Transfinite Surface "*"; +Transfinite Volume "*"; + +Recombine Surface "*"; + +Mesh.SecondOrderIncomplete = 1; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat b/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat index ad4749045..5e89a3873 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat @@ -1,19 +1,19 @@ model solid_mechanics_model_cohesive [ cohesive_inserter [ cohesive_surfaces = [insertion] ] material elastic [ - name = steel + name = body rho = 1e3 # density - E = 1e3 # young's modulus - nu = 0.001 # poisson's ratio + E = 1e9 # young's modulus + nu = 0.2 # poisson's ratio ] material cohesive_linear [ name = insertion beta = 1 - G_c = 100 - sigma_c = 100 + G_c = 10 + sigma_c = 1e6 ] ] diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat b/test/test_model/test_solid_mechanics_model/test_cohesive/material_0.dat similarity index 65% copy from test/test_model/test_solid_mechanics_model/test_cohesive/material.dat copy to test/test_model/test_solid_mechanics_model/test_cohesive/material_0.dat index ad4749045..5e89a3873 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/material_0.dat @@ -1,19 +1,19 @@ model solid_mechanics_model_cohesive [ cohesive_inserter [ cohesive_surfaces = [insertion] ] material elastic [ - name = steel + name = body rho = 1e3 # density - E = 1e3 # young's modulus - nu = 0.001 # poisson's ratio + E = 1e9 # young's modulus + nu = 0.2 # poisson's ratio ] material cohesive_linear [ name = insertion beta = 1 - G_c = 100 - sigma_c = 100 + G_c = 10 + sigma_c = 1e6 ] ] diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat b/test/test_model/test_solid_mechanics_model/test_cohesive/material_1.dat similarity index 54% copy from test/test_model/test_solid_mechanics_model/test_cohesive/material.dat copy to test/test_model/test_solid_mechanics_model/test_cohesive/material_1.dat index ad4749045..1d5cc574d 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/material_1.dat @@ -1,19 +1,20 @@ model solid_mechanics_model_cohesive [ cohesive_inserter [ cohesive_surfaces = [insertion] ] material elastic [ - name = steel + name = body rho = 1e3 # density - E = 1e3 # young's modulus - nu = 0.001 # poisson's ratio + E = 1e9 # young's modulus + nu = 0.2 # poisson's ratio ] - material cohesive_linear [ + material cohesive_bilinear [ name = insertion beta = 1 - G_c = 100 - sigma_c = 100 + G_c = 10 + sigma_c = 1e6 + delta_0 = 1e-7 ] ] diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc index 593c99e1d..043b77e70 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc @@ -1,50 +1,64 @@ /* -------------------------------------------------------------------------- */ -#include "test_cohesive_fixture.hh" #include "aka_iterators.hh" +#include "test_cohesive_fixture.hh" /* -------------------------------------------------------------------------- */ -TYPED_TEST(TestSMMCFixture, ModeI) { - auto max_steps = 100; - auto disp_inc = 0.1; - for(auto _ [[gnu::unused]] : arange(max_steps)) { - this->model->applyBC(BC::Dirichlet::IncrementValue(disp_inc, _x), "loading"); - if(this->is_extrinsic) - this->model->checkCohesiveStress(); +TYPED_TEST(TestSMMCFixture, ExtrinsicModeI) { + getStaticParser().parse("material_0.dat"); + this->is_extrinsic = true; + this->analysis_method = _explicit_lumped_mass; + + this->testModeI(); + + this->checkInsertion(); + + auto & mat_co = this->model->getMaterial("insertion"); + Real G_c = mat_co.get("G_c"); + + this->checkDissipated(G_c); +} + +TYPED_TEST(TestSMMCFixture, ExtrinsicModeII) { + getStaticParser().parse("material_0.dat"); + this->is_extrinsic = true; + this->analysis_method = _explicit_lumped_mass; + + this->testModeII(); + + this->checkInsertion(); + + auto & mat_co = this->model->getMaterial("insertion"); + Real G_c = mat_co.get("G_c"); + + this->checkDissipated(G_c); +} + +TYPED_TEST(TestSMMCFixture, IntrinsicModeI) { + getStaticParser().parse("material_1.dat"); + this->is_extrinsic = false; + this->analysis_method = _explicit_lumped_mass; - this->model->solveStep(); - } + this->testModeI(); - auto nb_cohesive_element = this->mesh->getNbElement(TestFixture::cohesive_type); - auto & mesh_facets = this->mesh->getMeshFacets(); - auto facet_type = mesh_facets.getFacetType(this->cohesive_type); - const auto & group = mesh_facets.getElementGroup("insertion").getElements(facet_type); + this->checkInsertion(); - std::cout << nb_cohesive_element << " " << group.size() << std::endl; + auto & mat_co = this->model->getMaterial("insertion"); + Real G_c = mat_co.get("G_c"); - Real sigma = this->model->getMaterial("insertion").get("sigma_c"); - Real edis = this->model->getEnergy("dissipated"); - EXPECT_NEAR(this->surface * sigma, edis, 1e-8); + this->checkDissipated(G_c); } -TYPED_TEST(TestSMMCFixture, ModeII) { - auto max_steps = 100; - auto disp_inc = 0.1; - for(auto _ [[gnu::unused]] : arange(max_steps)) { - this->model->applyBC(BC::Dirichlet::IncrementValue(disp_inc, _y ), "loading"); - if(this->is_extrinsic) - this->model->checkCohesiveStress(); +TYPED_TEST(TestSMMCFixture, IntrinsicModeII) { + getStaticParser().parse("material_1.dat"); + this->is_extrinsic = false; + this->analysis_method = _explicit_lumped_mass; - this->model->solveStep(); - } + this->testModeII(); - auto nb_cohesive_element = this->mesh->getNbElement(TestFixture::cohesive_type); - auto & mesh_facets = this->mesh->getMeshFacets(); - auto facet_type = mesh_facets.getFacetType(this->cohesive_type); - const auto & group = mesh_facets.getElementGroup("insertion").getElements(facet_type); + this->checkInsertion(); - std::cout << nb_cohesive_element << " " << group.size() << std::endl; + auto & mat_co = this->model->getMaterial("insertion"); + Real G_c = mat_co.get("G_c"); - Real sigma = this->model->getMaterial("insertion").get("sigma_c"); - Real edis = this->model->getEnergy("dissipated"); - EXPECT_NEAR(this->surface * sigma, edis, 1e-8); + this->checkDissipated(G_c); } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh index 7888df67b..9d97a7293 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh @@ -1,78 +1,274 @@ /* -------------------------------------------------------------------------- */ +#include "communicator.hh" #include "solid_mechanics_model_cohesive.hh" #include "test_gtest_utils.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TEST_COHESIVE_FIXTURE_HH__ #define __AKANTU_TEST_COHESIVE_FIXTURE_HH__ using namespace akantu; +template <::akantu::AnalysisMethod t> +using analysis_method_t = std::integral_constant<::akantu::AnalysisMethod, t>; + template <typename param_> class TestSMMCFixture : public ::testing::Test { public: static constexpr ElementType cohesive_type = std::tuple_element_t<0, param_>::value; + static constexpr ElementType type_1 = std::tuple_element_t<1, param_>::value; + static constexpr ElementType type_2 = std::tuple_element_t<2, param_>::value; + static constexpr size_t dim = ElementClass<cohesive_type>::getSpatialDimension(); - static constexpr bool is_extrinsic = std::tuple_element_t<1, param_>::value; void SetUp() override { - getStaticParser().parse(this->input_file); + normal = Vector<Real>(this->dim, 0.); + if (dim == 1) + normal(_x) = 1.; + else + normal(_y) = 1.; mesh = std::make_unique<Mesh>(this->dim); - EXPECT_NO_THROW({ mesh->read(this->mesh_name); }); + if (Communicator::getStaticCommunicator().whoAmI() == 0) { + EXPECT_NO_THROW({ mesh->read(this->mesh_name); }); + } + mesh->distribute(); + } + + void TearDown() override { + model.reset(nullptr); + mesh.reset(nullptr); + } + void createModel() { model = std::make_unique<SolidMechanicsModelCohesive>(*mesh); model->initFull(_analysis_method = this->analysis_method, _is_extrinsic = this->is_extrinsic); - model->applyBC(BC::Dirichlet::FlagOnly(_x), "fixed"); - if (this->dim > 1) - model->applyBC(BC::Dirichlet::FlagOnly(_y), "fixed"); - if (this->dim > 2) - model->applyBC(BC::Dirichlet::FlagOnly(_z), "fixed"); + // auto stable_time_step = this->model->getStableTimeStep(); + this->model->setTimeStep(4e-6); + + // std::cout << stable_time_step *0.0 << std::endl; + if (dim == 1) { + surface = 1; + return; + } + + auto facet_type = mesh->getFacetType(this->cohesive_type); - auto & fe_engine = model->getFEEngine("FacetsFEEngine"); - auto & mesh_facets = fe_engine.getMesh(); - auto facet_type = mesh_facets.getFacetType(this->cohesive_type); - auto & group = - mesh_facets.getElementGroup("insertion").getElements(facet_type); + auto & fe_engine = model->getFEEngineBoundary(); + auto & group = mesh->getElementGroup("insertion").getElements(facet_type); Array<Real> ones(fe_engine.getNbIntegrationPoints(facet_type) * group.size()); ones.set(1.); surface = fe_engine.integrate(ones, facet_type, _not_ghost, group); + mesh->getCommunicator().allReduce(surface, SynchronizerOperation::_sum); } - void TearDown() override { - model.reset(nullptr); - mesh.reset(nullptr); + void setInitialCondition(const Vector<Real> & direction, Real strain) { + auto lower = this->mesh->getLowerBounds().dot(normal); + auto upper = this->mesh->getUpperBounds().dot(normal); + + Real L = upper - lower; + + for (auto && data : + zip(make_view(this->mesh->getNodes(), this->dim), + make_view(this->model->getDisplacement(), this->dim))) { + const auto & pos = std::get<0>(data); + auto & disp = std::get<1>(data); + + auto x = pos.dot(normal) - (upper + lower) / 2.; + disp = direction * (x * 2. * strain / L); + } + } + +#define debug 1 + + void steps(const Vector<Real> & displacement_max) { +#if debug + this->model->addDumpFieldVector("displacement"); + this->model->addDumpFieldVector("velocity"); + this->model->addDumpField("stress"); + this->model->addDumpField("strain"); + this->model->assembleInternalForces(); + this->model->setBaseNameToDumper("cohesive elements", "cohesive_elements"); + this->model->addDumpFieldVectorToDumper("cohesive elements", + "displacement"); + this->model->addDumpFieldToDumper("cohesive elements", "damage"); + this->model->addDumpFieldToDumper("cohesive elements", "tractions"); + this->model->addDumpFieldToDumper("cohesive elements", "opening"); + this->model->dump(); + this->model->dump("cohesive elements"); +#endif + auto inc_load = BC::Dirichlet::Increment(displacement_max / Real(nb_steps)); + auto inc_fix = + BC::Dirichlet::Increment(-1. / Real(nb_steps) * displacement_max); + + for (auto _[[gnu::unused]] : arange(nb_steps)) { + this->model->applyBC(inc_load, "loading"); + this->model->applyBC(inc_fix, "fixed"); + if (this->is_extrinsic) + this->model->checkCohesiveStress(); + + this->model->solveStep(); +#if debug + this->model->dump(); + this->model->dump("cohesive elements"); +#endif + } + } + void checkInsertion() { + auto nb_cohesive_element = this->mesh->getNbElement(cohesive_type); + mesh->getCommunicator().allReduce(nb_cohesive_element, + SynchronizerOperation::_sum); + + auto facet_type = this->mesh->getFacetType(this->cohesive_type); + const auto & group = + this->mesh->getElementGroup("insertion").getElements(facet_type); + auto group_size = group.size(); + mesh->getCommunicator().allReduce(group_size, SynchronizerOperation::_sum); + + EXPECT_EQ(nb_cohesive_element, group_size); + } + + void checkDissipated(Real expected_density) { + Real edis = this->model->getEnergy("dissipated"); + + EXPECT_NEAR(this->surface * expected_density, edis, 4e-1); + } + + void testModeI() { + Vector<Real> direction(this->dim, 0.); + if (dim == 1) + direction(_x) = 1.; + else + direction(_y) = 1.; + + // EXPECT_NO_THROW(this->createModel()); + this->createModel(); + + if (this->dim > 1) + this->model->applyBC(BC::Dirichlet::FlagOnly(_x), "sides"); + if (this->dim > 2) + this->model->applyBC(BC::Dirichlet::FlagOnly(_z), "sides"); + + auto & mat_co = this->model->getMaterial("insertion"); + Real sigma_c = mat_co.get("sigma_c"); + Real G_c = mat_co.get("G_c"); + + auto & mat_el = this->model->getMaterial("body"); + Real E = mat_el.get("E"); + Real nu = mat_el.get("nu"); + + auto delta_c = 2. * G_c / sigma_c; + Real strain = sigma_c / E; + + if (dim == 1) + strain *= .9999; + else + strain *= .935; // there must be an error in my computations + + if (this->dim == 2) + strain *= (1. - nu) * (1. + nu); + + auto max_travel = .5 * delta_c; + this->setInitialCondition(direction, strain); + this->steps(direction * max_travel); + } + + void testModeII() { + Vector<Real> direction(this->dim, 0.); + direction(_x) = 1.; + + EXPECT_NO_THROW(this->createModel()); + + if (this->dim > 1) + this->model->applyBC(BC::Dirichlet::FlagOnly(_y), "sides"); + if (this->dim > 2) + this->model->applyBC(BC::Dirichlet::FlagOnly(_z), "sides"); + + auto & mat_co = this->model->getMaterial("insertion"); + Real sigma_c = mat_co.get("sigma_c"); + Real G_c = mat_co.get("G_c"); + Real beta = mat_co.get("beta"); + + auto & mat_el = this->model->getMaterial("body"); + Real E = mat_el.get("E"); + Real nu = mat_el.get("nu"); + + auto L = this->mesh->getUpperBounds().dot(direction) - + this->mesh->getLowerBounds().dot(direction); + + auto delta_c = 2. * G_c / sigma_c; + Real strain = .99999 * L * beta * beta * sigma_c / E; + if (this->dim > 1) { + strain *= (1. + nu); + } + auto max_travel = 1.2 * delta_c; + this->setInitialCondition(direction, strain); + this->steps(direction * max_travel); } protected: std::unique_ptr<Mesh> mesh; std::unique_ptr<SolidMechanicsModelCohesive> model; - AnalysisMethod analysis_method{_explicit_lumped_mass}; - std::string mesh_name{aka::to_string(cohesive_type) + ".msh"}; - std::string input_file{"material.dat"}; + std::string mesh_name{aka::to_string(cohesive_type) + aka::to_string(type_1) + + (type_1 == type_2 ? "" : aka::to_string(type_2)) + + ".msh"}; + + bool is_extrinsic; + AnalysisMethod analysis_method; + + Vector<Real> normal; Real surface{0}; + UInt nb_steps{300}; }; /* -------------------------------------------------------------------------- */ template <typename param_> constexpr ElementType TestSMMCFixture<param_>::cohesive_type; +template <typename param_> +constexpr ElementType TestSMMCFixture<param_>::type_1; +template <typename param_> +constexpr ElementType TestSMMCFixture<param_>::type_2; + template <typename param_> constexpr size_t TestSMMCFixture<param_>::dim; -template <typename param_> constexpr bool TestSMMCFixture<param_>::is_extrinsic; /* -------------------------------------------------------------------------- */ using IsExtrinsicTypes = std::tuple<std::true_type, std::false_type>; -using types = - gtest_list_t<cross_product_t<TestCohesiveElementTypes, IsExtrinsicTypes>>; +using AnalysisMethodTypes = + std::tuple<analysis_method_t<_explicit_lumped_mass>>; + +using types = gtest_list_t<std::tuple< + std::tuple<element_type_t<_cohesive_1d_2>, element_type_t<_segment_2>, + element_type_t<_segment_2>>, + std::tuple<element_type_t<_cohesive_2d_4>, element_type_t<_triangle_3>, + element_type_t<_triangle_3>>, + std::tuple<element_type_t<_cohesive_2d_4>, element_type_t<_quadrangle_4>, + element_type_t<_quadrangle_4>>, + std::tuple<element_type_t<_cohesive_2d_4>, element_type_t<_triangle_3>, + element_type_t<_quadrangle_4>>, + std::tuple<element_type_t<_cohesive_2d_6>, element_type_t<_triangle_6>, + element_type_t<_triangle_6>>, + std::tuple<element_type_t<_cohesive_2d_6>, element_type_t<_quadrangle_8>, + element_type_t<_quadrangle_8>>, + std::tuple<element_type_t<_cohesive_2d_6>, element_type_t<_triangle_6>, + element_type_t<_quadrangle_8>>, + std::tuple<element_type_t<_cohesive_3d_6>, element_type_t<_tetrahedron_4>, + element_type_t<_tetrahedron_4>>, + std::tuple<element_type_t<_cohesive_3d_12>, element_type_t<_tetrahedron_10>, + element_type_t<_tetrahedron_10>>, + std::tuple<element_type_t<_cohesive_3d_8>, element_type_t<_hexahedron_8>, + element_type_t<_hexahedron_8>>, + std::tuple<element_type_t<_cohesive_3d_16>, element_type_t<_hexahedron_20>, + element_type_t<_hexahedron_20>>>>; TYPED_TEST_CASE(TestSMMCFixture, types); #endif /* __AKANTU_TEST_COHESIVE_FIXTURE_HH__ */ diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc index 6ad371486..be0eeabd1 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc @@ -1,87 +1,96 @@ /** * @file test_embedded_element_matrix.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Wed Mar 25 2015 * @date last modification: Wed May 13 2015 * * @brief test of the class EmbeddedInterfaceModel * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "embedded_interface_model.hh" +#include "sparse_solver.hh" #include "sparse_matrix_aij.hh" using namespace akantu; int main(int argc, char * argv[]) { debug::setDebugLevel(dblWarning); initialize("embedded_element.dat", argc, argv); constexpr UInt dim = 2; constexpr ElementType type = _segment_2; - const Real height = 0.5; + const Real height = 0.4; Mesh mesh(dim); mesh.read("triangle.msh"); Mesh reinforcement_mesh(dim, "reinforcement_mesh"); auto & nodes = reinforcement_mesh.getNodes(); nodes.push_back(Vector<Real>({0, height})); nodes.push_back(Vector<Real>({1, height})); reinforcement_mesh.addConnectivityType(type); auto & connectivity = reinforcement_mesh.getConnectivity(type); connectivity.push_back(Vector<UInt>({0, 1})); Array<std::string> names_vec(1, 1, "reinforcement", "reinforcement_names"); reinforcement_mesh.registerData<std::string>("physical_names").alloc(1, 1, type); reinforcement_mesh.getData<std::string>("physical_names")(type).copy(names_vec); EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim); model.initFull(_analysis_method = _static); if (model.getInterfaceMesh().getNbElement(type) != 1) return EXIT_FAILURE; if (model.getInterfaceMesh().getSpatialDimension() != 2) return EXIT_FAILURE; - model.assembleStiffnessMatrix(); + try { // matrix should be singular + model.solveStep(); + } catch (debug::SingularMatrixException & e) { + std::cerr << "Matrix is singular, relax, everything is fine :)" << std::endl; + } catch (debug::Exception & e) { + std::cerr << "Unexpceted error: " << e.what() << std::endl; + throw e; + } SparseMatrixAIJ & K = dynamic_cast<SparseMatrixAIJ &>(model.getDOFManager().getMatrix("K")); + K.saveMatrix("stiffness.mtx"); Math::setTolerance(1e-8); // Testing the assembled stiffness matrix if (!Math::are_float_equal(K(0, 0), 1. - height) || !Math::are_float_equal(K(0, 2), height - 1.) || !Math::are_float_equal(K(2, 0), height - 1.) || !Math::are_float_equal(K(2, 2), 1. - height)) return EXIT_FAILURE; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc index 76a80f295..116108dc1 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc @@ -1,222 +1,224 @@ /** * @file test_embedded_interface_model_prestress.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Tue Apr 28 2015 * @date last modification: Thu Oct 15 2015 * * @brief Embedded model test for prestressing (bases on stress norm) * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ #include "aka_common.hh" #include "embedded_interface_model.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; #define YG 0.483644859 #define I_eq 0.012488874 #define A_eq (1e-2 + 1. / 7. * 1.) /* -------------------------------------------------------------------------- */ struct StressSolution : public BC::Neumann::FromHigherDim { Real M; Real I; Real yg; Real pre_stress; StressSolution(UInt dim, Real M, Real I, Real yg = 0, Real pre_stress = 0) : BC::Neumann::FromHigherDim(Matrix<Real>(dim, dim)), M(M), I(I), yg(yg), pre_stress(pre_stress) {} virtual ~StressSolution() {} void operator()(const IntegrationPoint & /*quad_point*/, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const { UInt dim = coord.size(); if (dim < 2) AKANTU_DEBUG_ERROR("Solution not valid for 1D"); Matrix<Real> stress(dim, dim); stress.clear(); stress(0, 0) = this->stress(coord(1)); dual.mul<false>(stress, normals); } inline Real stress(Real height) const { return -M / I * (height - yg) + pre_stress; } inline Real neutral_axis() const { return -I * pre_stress / M + yg; } }; /* -------------------------------------------------------------------------- */ int main (int argc, char * argv[]) { initialize("prestress.dat", argc, argv); debug::setDebugLevel(dblError); Math::setTolerance(1e-6); const UInt dim = 2; /* -------------------------------------------------------------------------- */ Mesh mesh(dim); mesh.read("embedded_mesh_prestress.msh"); - mesh.createGroupsFromMeshData<std::string>("physical_names"); + // mesh.createGroupsFromMeshData<std::string>("physical_names"); Mesh reinforcement_mesh(dim, "reinforcement_mesh"); try { reinforcement_mesh.read("embedded_mesh_prestress_reinforcement.msh"); } catch(debug::Exception & e) {} - reinforcement_mesh.createGroupsFromMeshData<std::string>("physical_names"); + // reinforcement_mesh.createGroupsFromMeshData<std::string>("physical_names"); EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim); model.initFull(EmbeddedInterfaceModelOptions(_static)); /* -------------------------------------------------------------------------- */ /* Computation of analytical residual */ /* -------------------------------------------------------------------------- */ /* * q = 1000 N/m * L = 20 m * a = 1 m */ - Real steel_area = - model.getMaterial("reinforcement").get("area"); - Real pre_stress = 1e6; + Real steel_area = model.getMaterial("reinforcement").get("area"); + Real pre_stress = model.getMaterial("reinforcement").get("pre_stress"); Real stress_norm = 0.; - StressSolution * concrete_stress = NULL, * steel_stress = NULL; + StressSolution * concrete_stress = nullptr, * steel_stress = nullptr; Real pre_force = pre_stress * steel_area; Real pre_moment = -pre_force * (YG - 0.25); Real neutral_axis = YG - I_eq / A_eq * pre_force / pre_moment; concrete_stress = new StressSolution(dim, pre_moment, 7. * I_eq, YG, -pre_force / (7. * A_eq)); steel_stress = new StressSolution(dim, pre_moment, I_eq, YG, pre_stress - pre_force / A_eq); stress_norm = std::abs(concrete_stress->stress(1)) * (1 - neutral_axis) * 0.5 + std::abs(concrete_stress->stress(0)) * neutral_axis * 0.5 + std::abs(steel_stress->stress(0.25)) * steel_area; model.applyBC(*concrete_stress, "XBlocked"); - ElementGroup & end_node = mesh.getElementGroup("EndNode"); - NodeGroup & end_node_group = end_node.getNodeGroup(); - NodeGroup::const_node_iterator end_node_it = end_node_group.begin(); + auto end_node = *mesh.getElementGroup("EndNode").getNodeGroup().begin(); - Vector<Real> end_node_force = model.getForce().begin(dim)[*end_node_it]; + Vector<Real> end_node_force = model.getForce().begin(dim)[end_node]; end_node_force(0) += steel_stress->stress(0.25) * steel_area; Array<Real> analytical_residual(mesh.getNbNodes(), dim, "analytical_residual"); analytical_residual.copy(model.getForce()); model.getForce().clear(); delete concrete_stress; delete steel_stress; /* -------------------------------------------------------------------------- */ model.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "XBlocked"); model.applyBC(BC::Dirichlet::FixedValue(0.0, _y), "YBlocked"); try { model.solveStep(); } catch (debug::Exception e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } /* -------------------------------------------------------------------------- */ /* Computation of FEM residual norm */ /* -------------------------------------------------------------------------- */ ElementGroup & xblocked = mesh.getElementGroup("XBlocked"); NodeGroup & boundary_nodes = xblocked.getNodeGroup(); NodeGroup::const_node_iterator nodes_it = boundary_nodes.begin(), nodes_end = boundary_nodes.end(); - Array<Real>::vector_iterator com_res = model.getInternalForce().begin(dim); - Array<Real>::vector_iterator ana_res = analytical_residual.begin(dim); + model.assembleInternalForces(); + Array<Real> residual(mesh.getNbNodes(), dim, "my_residual"); + residual.copy(model.getInternalForce()); + residual -= model.getForce(); + + Array<Real>::vector_iterator com_res = residual.begin(dim); Array<Real>::vector_iterator position = mesh.getNodes().begin(dim); Real res_sum = 0.; UInt lower_node = -1; UInt upper_node = -1; Real lower_dist = 1; Real upper_dist = 1; for (; nodes_it != nodes_end ; ++nodes_it) { UInt node_number = *nodes_it; const Vector<Real> res = com_res[node_number]; - const Vector<Real> ana = ana_res[node_number]; const Vector<Real> pos = position[node_number]; if (!Math::are_float_equal(pos(1), 0.25)) { if ((std::abs(pos(1) - 0.25) < lower_dist) && (pos(1) < 0.25)) { lower_dist = std::abs(pos(1) - 0.25); lower_node = node_number; } if ((std::abs(pos(1) - 0.25) < upper_dist) && (pos(1) > 0.25)) { upper_dist = std::abs(pos(1) - 0.25); upper_node = node_number; } } for (UInt i = 0 ; i < dim ; i++) { if (!Math::are_float_equal(pos(1), 0.25)) { res_sum += std::abs(res(i)); } } } const Vector<Real> upper_res = com_res[upper_node], lower_res = com_res[lower_node]; - const Vector<Real> end_node_res = com_res[*end_node_it]; + const Vector<Real> end_node_res = com_res[end_node]; Vector<Real> delta = upper_res - lower_res; delta *= lower_dist / (upper_dist + lower_dist); Vector<Real> concrete_residual = lower_res + delta; Vector<Real> steel_residual = end_node_res - concrete_residual; for (UInt i = 0 ; i < dim ; i++) { res_sum += std::abs(concrete_residual(i)); res_sum += std::abs(steel_residual(i)); } Real relative_error = std::abs(res_sum - stress_norm) / stress_norm; - if (relative_error > 1e-3) + if (relative_error > 1e-3) { + std::cerr << "Relative error = " << relative_error << std::endl; return EXIT_FAILURE; + } finalize(); return 0; } diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc index ed8a61267..24445e0f4 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc @@ -1,48 +1,43 @@ /* -------------------------------------------------------------------------- */ #include "material_marigo.hh" #include "material_mazars.hh" #include "solid_mechanics_model.hh" #include "test_material_fixtures.hh" #include <gtest/gtest.h> #include <type_traits> /* -------------------------------------------------------------------------- */ using namespace akantu; using types = ::testing::Types< Traits<MaterialMarigo, 1>, Traits<MaterialMarigo, 2>, Traits<MaterialMarigo, 3>, Traits<MaterialMazars, 1>, Traits<MaterialMazars, 2>, Traits<MaterialMazars, 3>>; - /*****************************************************************/ namespace { template <typename T> class TestDamageMaterialFixture : public ::TestMaterialFixture<T> {}; TYPED_TEST_CASE(TestDamageMaterialFixture, types); TYPED_TEST(TestDamageMaterialFixture, DamageComputeStress) { this->material->testComputeStress(); } TYPED_TEST(TestDamageMaterialFixture, DamageEnergyDensity) { this->material->testEnergyDensity(); } TYPED_TEST(TestDamageMaterialFixture, DamageComputeTangentModuli) { this->material->testComputeTangentModuli(); } -TYPED_TEST(TestDamageMaterialFixture, DamageComputePushWaveSpeed) { - this->material->testPushWaveSpeed(); -} - -TYPED_TEST(TestDamageMaterialFixture, DamageComputeShearWaveSpeed) { - this->material->testShearWaveSpeed(); +TYPED_TEST(TestDamageMaterialFixture, DamageComputeCelerity) { + this->material->testCelerity(); } } /*****************************************************************/ diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc index 98b0cb329..f89fcb12d 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc @@ -1,313 +1,1074 @@ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" #include "material_elastic_orthotropic.hh" #include "solid_mechanics_model.hh" #include "test_material_fixtures.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> #include <type_traits> /* -------------------------------------------------------------------------- */ using namespace akantu; using types = ::testing::Types<Traits<MaterialElastic, 1>, Traits<MaterialElastic, 2>, Traits<MaterialElastic, 3>, - Traits<MaterialElasticOrthotropic, 1>, Traits<MaterialElasticOrthotropic, 2>, Traits<MaterialElasticOrthotropic, 3>, - Traits<MaterialElasticLinearAnisotropic, 1>, Traits<MaterialElasticLinearAnisotropic, 2>, Traits<MaterialElasticLinearAnisotropic, 3>>; /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<3>>::testPushWaveSpeed() { +template <> void FriendMaterial<MaterialElastic<1>>::testComputeStress() { + Real E = 3.; + setParam("E", E); + + Matrix<Real> eps = {{2}}; + Matrix<Real> sigma(1, 1); + Real sigma_th = 2; + this->computeStressOnQuad(eps, sigma, sigma_th); + + auto solution = E * eps(0, 0) + sigma_th; + ASSERT_NEAR(sigma(0, 0), solution, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial<MaterialElastic<1>>::testEnergyDensity() { + Real eps = 2, sigma = 2; + Real epot = 0; + this->computePotentialEnergyOnQuad({{eps}}, {{sigma}}, epot); + Real solution = 2; + ASSERT_NEAR(epot, solution, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial<MaterialElastic<1>>::testComputeTangentModuli() { + Real E = 2; + setParam("E", E); + Matrix<Real> tangent(1, 1); + this->computeTangentModuliOnQuad(tangent); + ASSERT_NEAR(tangent(0, 0), E, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial<MaterialElastic<1>>::testCelerity() { + Real E = 3., rho = 2.; + setParam("E", E); + setParam("rho", rho); + + auto wave_speed = this->getCelerity(Element()); + auto solution = std::sqrt(E / rho); + ASSERT_NEAR(wave_speed, solution, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial<MaterialElastic<2>>::testComputeStress() { Real E = 1.; Real nu = .3; - Real rho = 2; + Real sigma_th = 0.3; // thermal stress setParam("E", E); setParam("nu", nu); - setParam("rho", rho); - auto wave_speed = this->getPushWaveSpeed(Element()); - Real K = E / (3 * (1 - 2 * nu)); - Real mu = E / (2 * (1 + nu)); - Real sol = std::sqrt((K + 4. / 3 * mu) / rho); + Real bulk_modulus_K = E / 3. / (1 - 2. * nu); + Real shear_modulus_mu = 0.5 * E / (1 + nu); + + Matrix<Real> rotation_matrix = getRandomRotation2d(); + + auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2); + + auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix); + + Matrix<Real> sigma_rot(2, 2); + this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th); + + auto sigma = this->reverseRotation(sigma_rot, rotation_matrix); + + Matrix<Real> identity(2, 2); + identity.eye(); + + Matrix<Real> strain = 0.5 * (grad_u + grad_u.transpose()); + Matrix<Real> deviatoric_strain = strain - 1. / 3. * strain.trace() * identity; + + Matrix<Real> sigma_expected = 2 * shear_modulus_mu * deviatoric_strain + + (sigma_th + 2. * bulk_modulus_K) * identity; + + auto diff = sigma - sigma_expected; + Real stress_error = diff.norm<L_inf>(); + ASSERT_NEAR(stress_error, 0., 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial<MaterialElastic<2>>::testEnergyDensity() { + Matrix<Real> sigma = {{1, 2}, {2, 4}}; + Matrix<Real> eps = {{1, 0}, {0, 1}}; + Real epot = 0; + Real solution = 2.5; + this->computePotentialEnergyOnQuad(eps, sigma, epot); + ASSERT_NEAR(epot, solution, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial<MaterialElastic<2>>::testComputeTangentModuli() { + Real E = 1.; + Real nu = .3; + setParam("E", E); + setParam("nu", nu); + Matrix<Real> tangent(3, 3); + + /* Plane Strain */ + // clang-format off + Matrix<Real> solution = { + {1 - nu, nu, 0}, + {nu, 1 - nu, 0}, + {0, 0, (1 - 2 * nu) / 2}, + }; + // clang-format on + solution *= E / ((1 + nu) * (1 - 2 * nu)); + + this->computeTangentModuliOnQuad(tangent); + Real tangent_error = (tangent - solution).norm<L_2>(); + ASSERT_NEAR(tangent_error, 0, 1e-14); + + /* Plane Stress */ + this->plane_stress = true; + this->updateInternalParameters(); + // clang-format off + solution = { + {1, nu, 0}, + {nu, 1, 0}, + {0, 0, (1 - nu) / 2}, + }; + // clang-format on + solution *= E / (1 - nu * nu); - ASSERT_NEAR(wave_speed, sol, 1e-14); + this->computeTangentModuliOnQuad(tangent); + tangent_error = (tangent - solution).norm<L_2>(); + ASSERT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<3>>::testShearWaveSpeed() { +template <> void FriendMaterial<MaterialElastic<2>>::testCelerity() { Real E = 1.; Real nu = .3; Real rho = 2; setParam("E", E); setParam("nu", nu); setParam("rho", rho); - auto wave_speed = this->getShearWaveSpeed(Element()); + auto push_wave_speed = this->getPushWaveSpeed(Element()); + auto celerity = this->getCelerity(Element()); + Real K = E / (3 * (1 - 2 * nu)); Real mu = E / (2 * (1 + nu)); - Real sol = std::sqrt(mu / rho); + Real sol = std::sqrt((K + 4. / 3 * mu) / rho); + + ASSERT_NEAR(push_wave_speed, sol, 1e-14); + ASSERT_NEAR(celerity, sol, 1e-14); + + auto shear_wave_speed = this->getShearWaveSpeed(Element()); - ASSERT_NEAR(wave_speed, sol, 1e-14); + sol = std::sqrt(mu / rho); + + ASSERT_NEAR(shear_wave_speed, sol, 1e-14); } /* -------------------------------------------------------------------------- */ + template <> void FriendMaterial<MaterialElastic<3>>::testComputeStress() { Real E = 1.; Real nu = .3; Real sigma_th = 0.3; // thermal stress setParam("E", E); setParam("nu", nu); + Real bulk_modulus_K = E / 3. / (1 - 2. * nu); + Real shear_modulus_mu = 0.5 * E / (1 + nu); + Matrix<Real> rotation_matrix = getRandomRotation3d(); - auto grad_u = this->getDeviatoricStrain(1.); + auto grad_u = this->getComposedStrain(1.); auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix); Matrix<Real> sigma_rot(3, 3); this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th); auto sigma = this->reverseRotation(sigma_rot, rotation_matrix); Matrix<Real> identity(3, 3); identity.eye(); - Matrix<Real> sigma_expected = - 0.5 * E / (1 + nu) * (grad_u + grad_u.transpose()) + sigma_th * identity; + Matrix<Real> strain = 0.5 * (grad_u + grad_u.transpose()); + Matrix<Real> deviatoric_strain = strain - 1. / 3. * strain.trace() * identity; + + Matrix<Real> sigma_expected = 2 * shear_modulus_mu * deviatoric_strain + + (sigma_th + 3. * bulk_modulus_K) * identity; auto diff = sigma - sigma_expected; Real stress_error = diff.norm<L_inf>(); ASSERT_NEAR(stress_error, 0., 1e-14); } +/* -------------------------------------------------------------------------- */ +template <> void FriendMaterial<MaterialElastic<3>>::testEnergyDensity() { + Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; + Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; + Real epot = 0; + Real solution = 5.5; + this->computePotentialEnergyOnQuad(eps, sigma, epot); + ASSERT_NEAR(epot, solution, 1e-14); +} + /* -------------------------------------------------------------------------- */ template <> void FriendMaterial<MaterialElastic<3>>::testComputeTangentModuli() { Real E = 1.; Real nu = .3; setParam("E", E); setParam("nu", nu); Matrix<Real> tangent(6, 6); // clang-format off Matrix<Real> solution = { {1 - nu, nu, nu, 0, 0, 0}, {nu, 1 - nu, nu, 0, 0, 0}, {nu, nu, 1 - nu, 0, 0, 0}, {0, 0, 0, (1 - 2 * nu) / 2, 0, 0}, {0, 0, 0, 0, (1 - 2 * nu) / 2, 0}, {0, 0, 0, 0, 0, (1 - 2 * nu) / 2}, }; // clang-format on solution *= E / ((1 + nu) * (1 - 2 * nu)); this->computeTangentModuliOnQuad(tangent); Real tangent_error = (tangent - solution).norm<L_2>(); ASSERT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<3>>::testEnergyDensity() { - Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; - Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; - Real epot = 0; - Real solution = 5.5; - this->computePotentialEnergyOnQuad(eps, sigma, epot); - ASSERT_NEAR(epot, solution, 1e-14); +template <> void FriendMaterial<MaterialElastic<3>>::testCelerity() { + Real E = 1.; + Real nu = .3; + Real rho = 2; + setParam("E", E); + setParam("nu", nu); + setParam("rho", rho); + + auto push_wave_speed = this->getPushWaveSpeed(Element()); + auto celerity = this->getCelerity(Element()); + + Real K = E / (3 * (1 - 2 * nu)); + Real mu = E / (2 * (1 + nu)); + Real sol = std::sqrt((K + 4. / 3 * mu) / rho); + + ASSERT_NEAR(push_wave_speed, sol, 1e-14); + ASSERT_NEAR(celerity, sol, 1e-14); + + auto shear_wave_speed = this->getShearWaveSpeed(Element()); + + sol = std::sqrt(mu / rho); + + ASSERT_NEAR(shear_wave_speed, sol, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<1>>::testComputeStress() { - Real E = 3.; - setParam("E", E); +template <> +void FriendMaterial<MaterialElasticOrthotropic<2>>::testComputeStress() { + UInt Dim = 2; + Real E1 = 1.; + Real E2 = 2.; + Real nu12 = 0.1; + Real G12 = 2.; - Matrix<Real> eps = {{2}}; - Matrix<Real> sigma(1, 1); - Real sigma_th = 2; - this->computeStressOnQuad(eps, sigma, sigma_th); + setParamNoUpdate("E1", E1); + setParamNoUpdate("E2", E2); + setParamNoUpdate("nu12", nu12); + setParamNoUpdate("G12", G12); - auto solution = E * eps(0, 0) + sigma_th; - ASSERT_NEAR(sigma(0, 0), solution, 1e-14); + // material frame of reference is rotate by rotation_matrix starting from + // canonical basis + Matrix<Real> rotation_matrix = getRandomRotation2d(); + + // canonical basis as expressed in the material frame of reference, as + // required by MaterialElasticOrthotropic class (it is simply given by the + // columns of the rotation_matrix; the lines give the material basis expressed + // in the canonical frame of reference) + Vector<Real> v1(Dim); + Vector<Real> v2(Dim); + for (UInt i = 0; i < Dim; ++i) { + v1[i] = rotation_matrix(i, 0); + v2[i] = rotation_matrix(i, 1); + } + + setParamNoUpdate("n1", v1.normalize()); + setParamNoUpdate("n2", v2.normalize()); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // gradient in material frame of reference + auto grad_u = this->getComposedStrain(2.).block(0, 0, 2, 2); + + // gradient in canonical basis (we need to rotate *back* to the canonical + // basis) + auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); + + // stress in the canonical basis + Matrix<Real> sigma_rot(2, 2); + this->computeStressOnQuad(grad_u_rot, sigma_rot); + + // stress in the material reference (we need to apply the rotation) + auto sigma = this->applyRotation(sigma_rot, rotation_matrix); + + // construction of Cijkl engineering tensor in the *material* frame of + // reference + // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 + Real nu21 = nu12 * E2 / E1; + Real gamma = 1 / (1 - nu12 * nu21); + + Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0); + C_expected(0, 0) = gamma * E1; + C_expected(1, 1) = gamma * E2; + C_expected(2, 2) = G12; + + C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21; + + // epsilon is computed directly in the *material* frame of reference + Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose()); + + // sigma_expected is computed directly in the *material* frame of reference + Matrix<Real> sigma_expected(Dim, Dim); + for (UInt i = 0; i < Dim; ++i) { + for (UInt j = 0; j < Dim; ++j) { + sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j); + } + } + + sigma_expected(0, 1) = sigma_expected(1, 0) = + C_expected(2, 2) * 2 * epsilon(0, 1); + + // sigmas are checked in the *material* frame of reference + auto diff = sigma - sigma_expected; + Real stress_error = diff.norm<L_inf>(); + ASSERT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<1>>::testEnergyDensity() { - Real eps = 2, sigma = 2; +template <> +void FriendMaterial<MaterialElasticOrthotropic<2>>::testEnergyDensity() { + Matrix<Real> sigma = {{1, 2}, {2, 4}}; + Matrix<Real> eps = {{1, 0}, {0, 1}}; Real epot = 0; - this->computePotentialEnergyOnQuad({{eps}}, {{sigma}}, epot); - Real solution = 2; + Real solution = 2.5; + this->computePotentialEnergyOnQuad(eps, sigma, epot); ASSERT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ template <> -void FriendMaterial<MaterialElastic<1>>::testComputeTangentModuli() { - Real E = 2; - setParam("E", E); - Matrix<Real> tangent(1, 1); +void FriendMaterial<MaterialElasticOrthotropic<2>>::testComputeTangentModuli() { + + // Note: for this test material and canonical basis coincide + Vector<Real> n1 = {1, 0}; + Vector<Real> n2 = {0, 1}; + Real E1 = 1.; + Real E2 = 2.; + Real nu12 = 0.1; + Real G12 = 2.; + + setParamNoUpdate("n1", n1); + setParamNoUpdate("n2", n2); + setParamNoUpdate("E1", E1); + setParamNoUpdate("E2", E2); + setParamNoUpdate("nu12", nu12); + setParamNoUpdate("G12", G12); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // construction of Cijkl engineering tensor in the *material* frame of + // reference + // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 + Real nu21 = nu12 * E2 / E1; + Real gamma = 1 / (1 - nu12 * nu21); + + Matrix<Real> C_expected(3, 3); + C_expected(0, 0) = gamma * E1; + C_expected(1, 1) = gamma * E2; + C_expected(2, 2) = G12; + + C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21; + + Matrix<Real> tangent(3, 3); this->computeTangentModuliOnQuad(tangent); - ASSERT_NEAR(tangent(0, 0), E, 1e-14); + + Real tangent_error = (tangent - C_expected).norm<L_2>(); + ASSERT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<1>>::testPushWaveSpeed() { - Real E = 3., rho = 2.; - setParam("E", E); - setParam("rho", rho); - auto wave_speed = this->getPushWaveSpeed(Element()); - auto solution = std::sqrt(E / rho); - ASSERT_NEAR(wave_speed, solution, 1e-14); +template <> void FriendMaterial<MaterialElasticOrthotropic<2>>::testCelerity() { + + // Note: for this test material and canonical basis coincide + Vector<Real> n1 = {1, 0}; + Vector<Real> n2 = {0, 1}; + Real E1 = 1.; + Real E2 = 2.; + Real nu12 = 0.1; + Real G12 = 2.; + Real rho = 2.5; + + setParamNoUpdate("n1", n1); + setParamNoUpdate("n2", n2); + setParamNoUpdate("E1", E1); + setParamNoUpdate("E2", E2); + setParamNoUpdate("nu12", nu12); + setParamNoUpdate("G12", G12); + setParamNoUpdate("rho", rho); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // construction of Cijkl engineering tensor in the *material* frame of + // reference + // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 + Real nu21 = nu12 * E2 / E1; + Real gamma = 1 / (1 - nu12 * nu21); + + Matrix<Real> C_expected(3, 3); + C_expected(0, 0) = gamma * E1; + C_expected(1, 1) = gamma * E2; + C_expected(2, 2) = G12; + + C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21; + + Vector<Real> eig_expected(3); + C_expected.eig(eig_expected); + + auto celerity_expected = std::sqrt(eig_expected(0) / rho); + + auto celerity = this->getCelerity(Element()); + + ASSERT_NEAR(celerity_expected, celerity, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<1>>::testShearWaveSpeed() { - ASSERT_THROW(this->getShearWaveSpeed(Element()), debug::Exception); +template <> +void FriendMaterial<MaterialElasticOrthotropic<3>>::testComputeStress() { + UInt Dim = 3; + Real E1 = 1.; + Real E2 = 2.; + Real E3 = 3.; + Real nu12 = 0.1; + Real nu13 = 0.2; + Real nu23 = 0.3; + Real G12 = 2.; + Real G13 = 3.; + Real G23 = 1.; + + setParamNoUpdate("E1", E1); + setParamNoUpdate("E2", E2); + setParamNoUpdate("E3", E3); + setParamNoUpdate("nu12", nu12); + setParamNoUpdate("nu13", nu13); + setParamNoUpdate("nu23", nu23); + setParamNoUpdate("G12", G12); + setParamNoUpdate("G13", G13); + setParamNoUpdate("G23", G23); + + // material frame of reference is rotate by rotation_matrix starting from + // canonical basis + Matrix<Real> rotation_matrix = getRandomRotation3d(); + + // canonical basis as expressed in the material frame of reference, as + // required by MaterialElasticOrthotropic class (it is simply given by the + // columns of the rotation_matrix; the lines give the material basis expressed + // in the canonical frame of reference) + Vector<Real> v1(Dim); + Vector<Real> v2(Dim); + Vector<Real> v3(Dim); + for (UInt i = 0; i < Dim; ++i) { + v1[i] = rotation_matrix(i, 0); + v2[i] = rotation_matrix(i, 1); + v3[i] = rotation_matrix(i, 2); + } + + setParamNoUpdate("n1", v1.normalize()); + setParamNoUpdate("n2", v2.normalize()); + setParamNoUpdate("n3", v3.normalize()); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // gradient in material frame of reference + auto grad_u = this->getComposedStrain(2.); + + // gradient in canonical basis (we need to rotate *back* to the canonical + // basis) + auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); + + // stress in the canonical basis + Matrix<Real> sigma_rot(3, 3); + this->computeStressOnQuad(grad_u_rot, sigma_rot); + + // stress in the material reference (we need to apply the rotation) + auto sigma = this->applyRotation(sigma_rot, rotation_matrix); + + // construction of Cijkl engineering tensor in the *material* frame of + // reference + // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 + Real nu21 = nu12 * E2 / E1; + Real nu31 = nu13 * E3 / E1; + Real nu32 = nu23 * E3 / E2; + Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - + 2 * nu21 * nu32 * nu13); + + Matrix<Real> C_expected(6, 6); + C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32); + C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31); + C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21); + + C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23); + C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32); + C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31); + + C_expected(3, 3) = G23; + C_expected(4, 4) = G13; + C_expected(5, 5) = G12; + + // epsilon is computed directly in the *material* frame of reference + Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose()); + + // sigma_expected is computed directly in the *material* frame of reference + Matrix<Real> sigma_expected(Dim, Dim); + for (UInt i = 0; i < Dim; ++i) { + for (UInt j = 0; j < Dim; ++j) { + sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j); + } + } + + sigma_expected(0, 1) = C_expected(5, 5) * 2 * epsilon(0, 1); + sigma_expected(0, 2) = C_expected(4, 4) * 2 * epsilon(0, 2); + sigma_expected(1, 2) = C_expected(3, 3) * 2 * epsilon(1, 2); + sigma_expected(1, 0) = sigma_expected(0, 1); + sigma_expected(2, 0) = sigma_expected(0, 2); + sigma_expected(2, 1) = sigma_expected(1, 2); + + // sigmas are checked in the *material* frame of reference + auto diff = sigma - sigma_expected; + Real stress_error = diff.norm<L_inf>(); + ASSERT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<2>>::testPushWaveSpeed() { - Real E = 1.; - Real nu = .3; - Real rho = 2; - setParam("E", E); - setParam("nu", nu); - setParam("rho", rho); - auto wave_speed = this->getPushWaveSpeed(Element()); +template <> +void FriendMaterial<MaterialElasticOrthotropic<3>>::testEnergyDensity() { + Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; + Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; + Real epot = 0; + Real solution = 5.5; + this->computePotentialEnergyOnQuad(eps, sigma, epot); + ASSERT_NEAR(epot, solution, 1e-14); +} - Real K = E / (3 * (1 - 2 * nu)); - Real mu = E / (2 * (1 + nu)); - Real sol = std::sqrt((K + 4. / 3 * mu) / rho); +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial<MaterialElasticOrthotropic<3>>::testComputeTangentModuli() { + + // Note: for this test material and canonical basis coincide + UInt Dim = 3; + Vector<Real> n1 = {1, 0, 0}; + Vector<Real> n2 = {0, 1, 0}; + Vector<Real> n3 = {0, 0, 1}; + Real E1 = 1.; + Real E2 = 2.; + Real E3 = 3.; + Real nu12 = 0.1; + Real nu13 = 0.2; + Real nu23 = 0.3; + Real G12 = 2.; + Real G13 = 3.; + Real G23 = 1.; + + setParamNoUpdate("n1", n1); + setParamNoUpdate("n2", n2); + setParamNoUpdate("n3", n3); + setParamNoUpdate("E1", E1); + setParamNoUpdate("E2", E2); + setParamNoUpdate("E3", E3); + setParamNoUpdate("nu12", nu12); + setParamNoUpdate("nu13", nu13); + setParamNoUpdate("nu23", nu23); + setParamNoUpdate("G12", G12); + setParamNoUpdate("G13", G13); + setParamNoUpdate("G23", G23); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // construction of Cijkl engineering tensor in the *material* frame of + // reference + // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 + Real nu21 = nu12 * E2 / E1; + Real nu31 = nu13 * E3 / E1; + Real nu32 = nu23 * E3 / E2; + Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - + 2 * nu21 * nu32 * nu13); + + Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0); + C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32); + C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31); + C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21); - ASSERT_NEAR(wave_speed, sol, 1e-14); + C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23); + C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32); + C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31); + + C_expected(3, 3) = G23; + C_expected(4, 4) = G13; + C_expected(5, 5) = G12; + + Matrix<Real> tangent(6, 6); + this->computeTangentModuliOnQuad(tangent); + + Real tangent_error = (tangent - C_expected).norm<L_2>(); + ASSERT_NEAR(tangent_error, 0, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<2>>::testShearWaveSpeed() { - Real E = 1.; - Real nu = .3; - Real rho = 2; - setParam("E", E); - setParam("nu", nu); - setParam("rho", rho); - auto wave_speed = this->getShearWaveSpeed(Element()); +template <> void FriendMaterial<MaterialElasticOrthotropic<3>>::testCelerity() { - Real mu = E / (2 * (1 + nu)); - Real sol = std::sqrt(mu / rho); + // Note: for this test material and canonical basis coincide + UInt Dim = 3; + Vector<Real> n1 = {1, 0, 0}; + Vector<Real> n2 = {0, 1, 0}; + Vector<Real> n3 = {0, 0, 1}; + Real E1 = 1.; + Real E2 = 2.; + Real E3 = 3.; + Real nu12 = 0.1; + Real nu13 = 0.2; + Real nu23 = 0.3; + Real G12 = 2.; + Real G13 = 3.; + Real G23 = 1.; + Real rho = 2.3; + + setParamNoUpdate("n1", n1); + setParamNoUpdate("n2", n2); + setParamNoUpdate("n3", n3); + setParamNoUpdate("E1", E1); + setParamNoUpdate("E2", E2); + setParamNoUpdate("E3", E3); + setParamNoUpdate("nu12", nu12); + setParamNoUpdate("nu13", nu13); + setParamNoUpdate("nu23", nu23); + setParamNoUpdate("G12", G12); + setParamNoUpdate("G13", G13); + setParamNoUpdate("G23", G23); + setParamNoUpdate("rho", rho); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // construction of Cijkl engineering tensor in the *material* frame of + // reference + // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13 + Real nu21 = nu12 * E2 / E1; + Real nu31 = nu13 * E3 / E1; + Real nu32 = nu23 * E3 / E2; + Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 - + 2 * nu21 * nu32 * nu13); + + Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0); + C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32); + C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31); + C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21); + + C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23); + C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32); + C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31); + + C_expected(3, 3) = G23; + C_expected(4, 4) = G13; + C_expected(5, 5) = G12; - ASSERT_NEAR(wave_speed, sol, 1e-14); + Vector<Real> eig_expected(6); + C_expected.eig(eig_expected); + + auto celerity_expected = std::sqrt(eig_expected(0) / rho); + + auto celerity = this->getCelerity(Element()); + + ASSERT_NEAR(celerity_expected, celerity, 1e-14); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<2>>::testComputeStress() { - Real E = 1.; - Real nu = .3; - Real sigma_th = 0.3; // thermal stress - setParam("E", E); - setParam("nu", nu); +template <> +void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testComputeStress() { + UInt Dim = 2; + Matrix<Real> C = { + {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5}, + }; + + setParamNoUpdate("C11", C(0, 0)); + setParamNoUpdate("C12", C(0, 1)); + setParamNoUpdate("C13", C(0, 2)); + setParamNoUpdate("C22", C(1, 1)); + setParamNoUpdate("C23", C(1, 2)); + setParamNoUpdate("C33", C(2, 2)); + // material frame of reference is rotate by rotation_matrix starting from + // canonical basis Matrix<Real> rotation_matrix = getRandomRotation2d(); - auto grad_u = this->getDeviatoricStrain(1.).block(0, 0, 2, 2); + // canonical basis as expressed in the material frame of reference, as + // required by MaterialElasticLinearAnisotropic class (it is simply given by + // the columns of the rotation_matrix; the lines give the material basis + // expressed in the canonical frame of reference) + Vector<Real> v1(Dim); + Vector<Real> v2(Dim); + for (UInt i = 0; i < Dim; ++i) { + v1[i] = rotation_matrix(i, 0); + v2[i] = rotation_matrix(i, 1); + } - auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix); + setParamNoUpdate("n1", v1.normalize()); + setParamNoUpdate("n2", v2.normalize()); + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // gradient in material frame of reference + auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2); + + // gradient in canonical basis (we need to rotate *back* to the canonical + // basis) + auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); + + // stress in the canonical basis Matrix<Real> sigma_rot(2, 2); - this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th); + this->computeStressOnQuad(grad_u_rot, sigma_rot); - auto sigma = this->reverseRotation(sigma_rot, rotation_matrix); + // stress in the material reference (we need to apply the rotation) + auto sigma = this->applyRotation(sigma_rot, rotation_matrix); - Matrix<Real> identity(2, 2); - identity.eye(); + // epsilon is computed directly in the *material* frame of reference + Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose()); + Vector<Real> epsilon_voigt(3); + epsilon_voigt(0) = epsilon(0, 0); + epsilon_voigt(1) = epsilon(1, 1); + epsilon_voigt(2) = 2 * epsilon(0, 1); - Matrix<Real> sigma_expected = - 0.5 * E / (1 + nu) * (grad_u + grad_u.transpose()) + sigma_th * identity; + // sigma_expected is computed directly in the *material* frame of reference + Vector<Real> sigma_voigt = C * epsilon_voigt; + Matrix<Real> sigma_expected(Dim, Dim); + sigma_expected(0, 0) = sigma_voigt(0); + sigma_expected(1, 1) = sigma_voigt(1); + sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(2); + // sigmas are checked in the *material* frame of reference auto diff = sigma - sigma_expected; Real stress_error = diff.norm<L_inf>(); - ASSERT_NEAR(stress_error, 0., 1e-14); + ASSERT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ template <> -void FriendMaterial<MaterialElastic<2>>::testComputeTangentModuli() { - Real E = 1.; - Real nu = .3; - setParam("E", E); - setParam("nu", nu); - Matrix<Real> tangent(3, 3); +void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testEnergyDensity() { + Matrix<Real> sigma = {{1, 2}, {2, 4}}; + Matrix<Real> eps = {{1, 0}, {0, 1}}; + Real epot = 0; + Real solution = 2.5; + this->computePotentialEnergyOnQuad(eps, sigma, epot); + ASSERT_NEAR(epot, solution, 1e-14); +} - /* Plane Strain */ - // clang-format off - Matrix<Real> solution = { - {1 - nu, nu, 0}, - {nu, 1 - nu, 0}, - {0, 0, (1 - 2 * nu) / 2}, +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial< + MaterialElasticLinearAnisotropic<2>>::testComputeTangentModuli() { + + // Note: for this test material and canonical basis coincide + Matrix<Real> C = { + {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5}, }; - // clang-format on - solution *= E / ((1 + nu) * (1 - 2 * nu)); + setParamNoUpdate("C11", C(0, 0)); + setParamNoUpdate("C12", C(0, 1)); + setParamNoUpdate("C13", C(0, 2)); + setParamNoUpdate("C22", C(1, 1)); + setParamNoUpdate("C23", C(1, 2)); + setParamNoUpdate("C33", C(2, 2)); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + Matrix<Real> tangent(3, 3); this->computeTangentModuliOnQuad(tangent); - Real tangent_error = (tangent - solution).norm<L_2>(); + + Real tangent_error = (tangent - C).norm<L_2>(); ASSERT_NEAR(tangent_error, 0, 1e-14); +} - /* Plane Stress */ - this->plane_stress = true; +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testCelerity() { + + // Note: for this test material and canonical basis coincide + Matrix<Real> C = { + {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5}, + }; + + Real rho = 2.7; + + setParamNoUpdate("C11", C(0, 0)); + setParamNoUpdate("C12", C(0, 1)); + setParamNoUpdate("C13", C(0, 2)); + setParamNoUpdate("C22", C(1, 1)); + setParamNoUpdate("C23", C(1, 2)); + setParamNoUpdate("C33", C(2, 2)); + setParamNoUpdate("rho", rho); + + // set internal Cijkl matrix expressed in the canonical frame of reference this->updateInternalParameters(); - // clang-format off - solution = { - {1, nu, 0}, - {nu, 1, 0}, - {0, 0, (1 - nu) / 2}, + + Vector<Real> eig_expected(3); + C.eig(eig_expected); + + auto celerity_expected = std::sqrt(eig_expected(0) / rho); + + auto celerity = this->getCelerity(Element()); + + ASSERT_NEAR(celerity_expected, celerity, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testComputeStress() { + UInt Dim = 3; + Matrix<Real> C = { + {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2}, + {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4}, + {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2}, }; - // clang-format on - solution *= E / (1 - nu * nu); - this->computeTangentModuliOnQuad(tangent); - tangent_error = (tangent - solution).norm<L_2>(); - ASSERT_NEAR(tangent_error, 0, 1e-14); + setParamNoUpdate("C11", C(0, 0)); + setParamNoUpdate("C12", C(0, 1)); + setParamNoUpdate("C13", C(0, 2)); + setParamNoUpdate("C14", C(0, 3)); + setParamNoUpdate("C15", C(0, 4)); + setParamNoUpdate("C16", C(0, 5)); + setParamNoUpdate("C22", C(1, 1)); + setParamNoUpdate("C23", C(1, 2)); + setParamNoUpdate("C24", C(1, 3)); + setParamNoUpdate("C25", C(1, 4)); + setParamNoUpdate("C26", C(1, 5)); + setParamNoUpdate("C33", C(2, 2)); + setParamNoUpdate("C34", C(2, 3)); + setParamNoUpdate("C35", C(2, 4)); + setParamNoUpdate("C36", C(2, 5)); + setParamNoUpdate("C44", C(3, 3)); + setParamNoUpdate("C45", C(3, 4)); + setParamNoUpdate("C46", C(3, 5)); + setParamNoUpdate("C55", C(4, 4)); + setParamNoUpdate("C56", C(4, 5)); + setParamNoUpdate("C66", C(5, 5)); + + // material frame of reference is rotate by rotation_matrix starting from + // canonical basis + Matrix<Real> rotation_matrix = getRandomRotation3d(); + + // canonical basis as expressed in the material frame of reference, as + // required by MaterialElasticLinearAnisotropic class (it is simply given by + // the columns of the rotation_matrix; the lines give the material basis + // expressed in the canonical frame of reference) + Vector<Real> v1(Dim); + Vector<Real> v2(Dim); + Vector<Real> v3(Dim); + for (UInt i = 0; i < Dim; ++i) { + v1[i] = rotation_matrix(i, 0); + v2[i] = rotation_matrix(i, 1); + v3[i] = rotation_matrix(i, 2); + } + + setParamNoUpdate("n1", v1.normalize()); + setParamNoUpdate("n2", v2.normalize()); + setParamNoUpdate("n3", v3.normalize()); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + // gradient in material frame of reference + auto grad_u = this->getComposedStrain(2.); + + // gradient in canonical basis (we need to rotate *back* to the canonical + // basis) + auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix); + + // stress in the canonical basis + Matrix<Real> sigma_rot(3, 3); + this->computeStressOnQuad(grad_u_rot, sigma_rot); + + // stress in the material reference (we need to apply the rotation) + auto sigma = this->applyRotation(sigma_rot, rotation_matrix); + + // epsilon is computed directly in the *material* frame of reference + Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose()); + Vector<Real> epsilon_voigt(6); + epsilon_voigt(0) = epsilon(0, 0); + epsilon_voigt(1) = epsilon(1, 1); + epsilon_voigt(2) = epsilon(2, 2); + epsilon_voigt(3) = 2 * epsilon(1, 2); + epsilon_voigt(4) = 2 * epsilon(0, 2); + epsilon_voigt(5) = 2 * epsilon(0, 1); + + // sigma_expected is computed directly in the *material* frame of reference + Vector<Real> sigma_voigt = C * epsilon_voigt; + Matrix<Real> sigma_expected(Dim, Dim); + sigma_expected(0, 0) = sigma_voigt(0); + sigma_expected(1, 1) = sigma_voigt(1); + sigma_expected(2, 2) = sigma_voigt(2); + sigma_expected(1, 2) = sigma_expected(2, 1) = sigma_voigt(3); + sigma_expected(0, 2) = sigma_expected(2, 0) = sigma_voigt(4); + sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(5); + + // sigmas are checked in the *material* frame of reference + auto diff = sigma - sigma_expected; + Real stress_error = diff.norm<L_inf>(); + ASSERT_NEAR(stress_error, 0., 1e-13); } /* -------------------------------------------------------------------------- */ -template <> void FriendMaterial<MaterialElastic<2>>::testEnergyDensity() { - Matrix<Real> sigma = {{1, 2}, {2, 4}}; - Matrix<Real> eps = {{1, 0}, {0, 1}}; +template <> +void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testEnergyDensity() { + Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}}; + Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; Real epot = 0; - Real solution = 2.5; + Real solution = 5.5; this->computePotentialEnergyOnQuad(eps, sigma, epot); ASSERT_NEAR(epot, solution, 1e-14); } /* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial< + MaterialElasticLinearAnisotropic<3>>::testComputeTangentModuli() { + + // Note: for this test material and canonical basis coincide + Matrix<Real> C = { + {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2}, + {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4}, + {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2}, + }; + + setParamNoUpdate("C11", C(0, 0)); + setParamNoUpdate("C12", C(0, 1)); + setParamNoUpdate("C13", C(0, 2)); + setParamNoUpdate("C14", C(0, 3)); + setParamNoUpdate("C15", C(0, 4)); + setParamNoUpdate("C16", C(0, 5)); + setParamNoUpdate("C22", C(1, 1)); + setParamNoUpdate("C23", C(1, 2)); + setParamNoUpdate("C24", C(1, 3)); + setParamNoUpdate("C25", C(1, 4)); + setParamNoUpdate("C26", C(1, 5)); + setParamNoUpdate("C33", C(2, 2)); + setParamNoUpdate("C34", C(2, 3)); + setParamNoUpdate("C35", C(2, 4)); + setParamNoUpdate("C36", C(2, 5)); + setParamNoUpdate("C44", C(3, 3)); + setParamNoUpdate("C45", C(3, 4)); + setParamNoUpdate("C46", C(3, 5)); + setParamNoUpdate("C55", C(4, 4)); + setParamNoUpdate("C56", C(4, 5)); + setParamNoUpdate("C66", C(5, 5)); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + Matrix<Real> tangent(6, 6); + this->computeTangentModuliOnQuad(tangent); + + Real tangent_error = (tangent - C).norm<L_2>(); + ASSERT_NEAR(tangent_error, 0, 1e-14); +} + +/* -------------------------------------------------------------------------- */ +template <> +void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testCelerity() { + + // Note: for this test material and canonical basis coincide + Matrix<Real> C = { + {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2}, + {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4}, + {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2}, + }; + Real rho = 2.9; + + setParamNoUpdate("C11", C(0, 0)); + setParamNoUpdate("C12", C(0, 1)); + setParamNoUpdate("C13", C(0, 2)); + setParamNoUpdate("C14", C(0, 3)); + setParamNoUpdate("C15", C(0, 4)); + setParamNoUpdate("C16", C(0, 5)); + setParamNoUpdate("C22", C(1, 1)); + setParamNoUpdate("C23", C(1, 2)); + setParamNoUpdate("C24", C(1, 3)); + setParamNoUpdate("C25", C(1, 4)); + setParamNoUpdate("C26", C(1, 5)); + setParamNoUpdate("C33", C(2, 2)); + setParamNoUpdate("C34", C(2, 3)); + setParamNoUpdate("C35", C(2, 4)); + setParamNoUpdate("C36", C(2, 5)); + setParamNoUpdate("C44", C(3, 3)); + setParamNoUpdate("C45", C(3, 4)); + setParamNoUpdate("C46", C(3, 5)); + setParamNoUpdate("C55", C(4, 4)); + setParamNoUpdate("C56", C(4, 5)); + setParamNoUpdate("C66", C(5, 5)); + setParamNoUpdate("rho", rho); + + // set internal Cijkl matrix expressed in the canonical frame of reference + this->updateInternalParameters(); + + Vector<Real> eig_expected(6); + C.eig(eig_expected); + + auto celerity_expected = std::sqrt(eig_expected(0) / rho); + + auto celerity = this->getCelerity(Element()); + + ASSERT_NEAR(celerity_expected, celerity, 1e-14); +} + +/* -------------------------------------------------------------------------- */ + namespace { template <typename T> class TestElasticMaterialFixture : public ::TestMaterialFixture<T> {}; TYPED_TEST_CASE(TestElasticMaterialFixture, types); TYPED_TEST(TestElasticMaterialFixture, ElasticComputeStress) { this->material->testComputeStress(); } TYPED_TEST(TestElasticMaterialFixture, ElasticEnergyDensity) { this->material->testEnergyDensity(); } TYPED_TEST(TestElasticMaterialFixture, ElasticComputeTangentModuli) { this->material->testComputeTangentModuli(); } -TYPED_TEST(TestElasticMaterialFixture, ElasticComputePushWaveSpeed) { - this->material->testPushWaveSpeed(); +TYPED_TEST(TestElasticMaterialFixture, ElasticComputeCelerity) { + this->material->testCelerity(); } -TYPED_TEST(TestElasticMaterialFixture, ElasticComputeShearWaveSpeed) { - this->material->testShearWaveSpeed(); -} } // namespace diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc index b1f0219b8..570314f6a 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc @@ -1,61 +1,57 @@ /* -------------------------------------------------------------------------- */ #include "material_neohookean.hh" #include "solid_mechanics_model.hh" #include "test_material_fixtures.hh" #include <gtest/gtest.h> #include <type_traits> /* -------------------------------------------------------------------------- */ using namespace akantu; using types = ::testing::Types< Traits<MaterialNeohookean, 1>, Traits<MaterialNeohookean, 2>, Traits<MaterialNeohookean, 3>>; /*****************************************************************/ template <> void FriendMaterial<MaterialNeohookean<3>>::testComputeStress() { TO_IMPLEMENT; } /*****************************************************************/ template <> void FriendMaterial<MaterialNeohookean<3>>::testComputeTangentModuli() { TO_IMPLEMENT; } /*****************************************************************/ template <> void FriendMaterial<MaterialNeohookean<3>>::testEnergyDensity() { TO_IMPLEMENT; } /*****************************************************************/ namespace { template <typename T> class TestFiniteDefMaterialFixture : public ::TestMaterialFixture<T> {}; TYPED_TEST_CASE(TestFiniteDefMaterialFixture, types); TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeStress) { this->material->testComputeStress(); } TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefEnergyDensity) { this->material->testEnergyDensity(); } TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeTangentModuli) { this->material->testComputeTangentModuli(); } -TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputePushWaveSpeed) { - this->material->testPushWaveSpeed(); -} - -TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeShearWaveSpeed) { - this->material->testShearWaveSpeed(); +TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeCelerity) { + this->material->testCelerity(); } } /*****************************************************************/ diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh index eb4d93b77..97d814c89 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh @@ -1,171 +1,190 @@ /* -------------------------------------------------------------------------- */ #include "material_elastic.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> #include <random> #include <type_traits> /* -------------------------------------------------------------------------- */ #define TO_IMPLEMENT AKANTU_EXCEPTION("TEST TO IMPLEMENT") using namespace akantu; /* -------------------------------------------------------------------------- */ template <typename T> class FriendMaterial : public T { public: ~FriendMaterial() = default; - + virtual void testComputeStress() { TO_IMPLEMENT; }; virtual void testComputeTangentModuli() { TO_IMPLEMENT; }; virtual void testEnergyDensity() { TO_IMPLEMENT; }; - virtual void testPushWaveSpeed() { TO_IMPLEMENT; } - virtual void testShearWaveSpeed() { TO_IMPLEMENT; } + virtual void testCelerity() { TO_IMPLEMENT; } static inline Matrix<Real> getDeviatoricStrain(Real intensity); - static inline Matrix<Real> getHydrostaticStrain(Real intensity); + static inline Matrix<Real> getComposedStrain(Real intensity); static inline const Matrix<Real> reverseRotation(Matrix<Real> mat, Matrix<Real> rotation_matrix) { Matrix<Real> R = rotation_matrix; Matrix<Real> m2 = mat * R; Matrix<Real> m1 = R.transpose(); return m1 * m2; }; static inline const Matrix<Real> applyRotation(Matrix<Real> mat, const Matrix<Real> rotation_matrix) { Matrix<Real> R = rotation_matrix; Matrix<Real> m2 = mat * R.transpose(); Matrix<Real> m1 = R; return m1 * m2; }; static inline Matrix<Real> getRandomRotation3d(); static inline Matrix<Real> getRandomRotation2d(); using T::T; }; /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getDeviatoricStrain(Real intensity) { Matrix<Real> dev = {{0, 1, 2}, {1, 0, 3}, {2, 3, 0}}; dev *= intensity; return dev; } /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getHydrostaticStrain(Real intensity) { - Matrix<Real> dev = {{1, 0, 0}, {0, 2, 0}, {0, 0, 3}}; + Matrix<Real> dev = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; dev *= intensity; return dev; } +/* -------------------------------------------------------------------------- */ + +template <typename T> +Matrix<Real> FriendMaterial<T>::getComposedStrain(Real intensity) { + Matrix<Real> s = FriendMaterial<T>::getHydrostaticStrain(intensity) + + FriendMaterial<T>::getDeviatoricStrain(intensity); + s *= intensity; + return s; +} + /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation3d() { constexpr UInt Dim = 3; // Seed with a real random value, if available std::random_device rd; std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::uniform_real_distribution<> dis; Vector<Real> v1(Dim); Vector<Real> v2(Dim); Vector<Real> v3(Dim); for (UInt i = 0; i < Dim; ++i) { v1(i) = dis(gen); v2(i) = dis(gen); } v1.normalize(); v2.normalize(); auto d = v1.dot(v2); v2 -= v1 * d; v2.normalize(); d = v1.dot(v2); v2 -= v1 * d; v2.normalize(); - v3.crossProduct(v2, v1); + v3.crossProduct(v1, v2); + + Vector<Real> test_axis(3); + test_axis.crossProduct(v1, v2); + test_axis -= v3; + if (test_axis.norm() > 8 * std::numeric_limits<Real>::epsilon()) { + AKANTU_DEBUG_ERROR("The axis vectors do not form a right-handed coordinate " + << "system. I. e., ||n1 x n2 - n3|| should be zero, but " + << "it is " << test_axis.norm() << "."); + } Matrix<Real> mat(Dim, Dim); for (UInt i = 0; i < Dim; ++i) { mat(0, i) = v1[i]; mat(1, i) = v2[i]; mat(2, i) = v3[i]; } return mat; } /* -------------------------------------------------------------------------- */ template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation2d() { constexpr UInt Dim = 2; // Seed with a real random value, if available std::random_device rd; std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::uniform_real_distribution<> dis; - Vector<Real> v1(Dim); - Vector<Real> v2(Dim); + // v1 and v2 are such that they form a right-hand basis with prescribed v3, + // it's need (at least) for 2d linear elastic anisotropic and (orthotropic) + // materials to rotate the tangent stiffness + + Vector<Real> v1(3); + Vector<Real> v2(3); + Vector<Real> v3 = {0, 0, 1}; for (UInt i = 0; i < Dim; ++i) { v1(i) = dis(gen); - v2(i) = dis(gen); + // v2(i) = dis(gen); } v1.normalize(); - v2.normalize(); - - auto d = v1.dot(v2); - v2 -= v1 * d; - v2.normalize(); + v2.crossProduct(v3, v1); Matrix<Real> mat(Dim, Dim); for (UInt i = 0; i < Dim; ++i) { mat(0, i) = v1[i]; mat(1, i) = v2[i]; } return mat; } /* -------------------------------------------------------------------------- */ template <typename T> class TestMaterialFixture : public ::testing::Test { public: using mat_class = typename T::mat_class; void SetUp() override { constexpr auto spatial_dimension = T::Dim; mesh = std::make_unique<Mesh>(spatial_dimension); model = std::make_unique<SolidMechanicsModel>(*mesh); material = std::make_unique<friend_class>(*model); } void TearDown() override { material.reset(nullptr); model.reset(nullptr); mesh.reset(nullptr); } using friend_class = FriendMaterial<mat_class>; protected: std::unique_ptr<Mesh> mesh; std::unique_ptr<SolidMechanicsModel> model; std::unique_ptr<friend_class> material; }; /* -------------------------------------------------------------------------- */ template <template <UInt> class T, UInt _Dim> struct Traits { using mat_class = T<_Dim>; static constexpr UInt Dim = _Dim; }; /* -------------------------------------------------------------------------- */ diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc index aef6ce6da..0c89bc0cc 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc @@ -1,43 +1,161 @@ /* -------------------------------------------------------------------------- */ #include "material_linear_isotropic_hardening.hh" #include "solid_mechanics_model.hh" #include "test_material_fixtures.hh" #include <gtest/gtest.h> #include <type_traits> /* -------------------------------------------------------------------------- */ using namespace akantu; using types = ::testing::Types<Traits<MaterialLinearIsotropicHardening, 1>, Traits<MaterialLinearIsotropicHardening, 2>, Traits<MaterialLinearIsotropicHardening, 3>>; -/*****************************************************************/ +/* -------------------------------------------------------------------------- */ + +template <> +void FriendMaterial<MaterialLinearIsotropicHardening<3>>::testComputeStress() { + + Real E = 1.; + // Real nu = .3; + Real nu = 0.; + Real rho = 1.; + Real sigma_0 = 1.; + Real h = 0.; + Real bulk_modulus_K = E / 3. / (1 - 2. * nu); + Real shear_modulus_mu = 0.5 * E / (1 + nu); + + setParam("E", E); + setParam("nu", nu); + setParam("rho", rho); + setParam("sigma_y", sigma_0); + setParam("h", h); + + Matrix<Real> rotation_matrix = getRandomRotation3d(); + + Real max_strain = 10.; + Real strain_steps = 100; + Real dt = max_strain / strain_steps; + std::vector<double> steps(strain_steps); + std::iota(steps.begin(), steps.end(), 0.); + + Matrix<Real> previous_grad_u_rot = Matrix<Real>(3, 3, 0.); + Matrix<Real> previous_sigma = Matrix<Real>(3, 3, 0.); + Matrix<Real> previous_sigma_rot = Matrix<Real>(3, 3, 0.); + Matrix<Real> inelastic_strain_rot = Matrix<Real>(3, 3, 0.); + Matrix<Real> inelastic_strain = Matrix<Real>(3, 3, 0.); + Matrix<Real> previous_inelastic_strain = Matrix<Real>(3, 3, 0.); + Matrix<Real> previous_inelastic_strain_rot = Matrix<Real>(3, 3, 0.); + Matrix<Real> sigma_rot(3, 3, 0.); + Real iso_hardening = 0.; + Real previous_iso_hardening = 0.; + + // hydrostatic loading (should not plastify) + for (auto && i : steps) { + auto t = i * dt; + + auto grad_u = this->getHydrostaticStrain(t); + auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix); + + this->computeStressOnQuad(grad_u_rot, previous_grad_u_rot, sigma_rot, + previous_sigma_rot, inelastic_strain_rot, + previous_inelastic_strain_rot, iso_hardening, + previous_iso_hardening, 0., 0.); + + auto sigma = this->reverseRotation(sigma_rot, rotation_matrix); + + Matrix<Real> sigma_expected = + t * 3. * bulk_modulus_K * Matrix<Real>::eye(3, 1.); + + Real stress_error = (sigma - sigma_expected).norm<L_inf>(); + + ASSERT_NEAR(stress_error, 0., 1e-13); + ASSERT_NEAR(inelastic_strain_rot.norm<L_inf>(), 0., 1e-13); + + previous_grad_u_rot = grad_u_rot; + previous_sigma_rot = sigma_rot; + previous_inelastic_strain_rot = inelastic_strain_rot; + previous_iso_hardening = iso_hardening; + } + + // deviatoric loading (should plastify) + // stress at onset of plastication + Real beta = sqrt(42); + Real t_P = sigma_0 / 2. / shear_modulus_mu / beta; + Matrix<Real> sigma_P = sigma_0 / beta * this->getDeviatoricStrain(1.); + + for (auto && i : steps) { + + auto t = i * dt; + auto grad_u = this->getDeviatoricStrain(t); + auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix); + Real iso_hardening, previous_iso_hardening; + + this->computeStressOnQuad(grad_u_rot, previous_grad_u_rot, sigma_rot, + previous_sigma_rot, inelastic_strain_rot, + previous_inelastic_strain_rot, iso_hardening, + previous_iso_hardening, 0., 0.); + + auto sigma = this->reverseRotation(sigma_rot, rotation_matrix); + auto inelastic_strain = + this->reverseRotation(inelastic_strain_rot, rotation_matrix); + + if (t < t_P) { + + Matrix<Real> sigma_expected = + shear_modulus_mu * (grad_u + grad_u.transpose()); + + Real stress_error = (sigma - sigma_expected).norm<L_inf>(); + ASSERT_NEAR(stress_error, 0., 1e-13); + ASSERT_NEAR(inelastic_strain_rot.norm<L_inf>(), 0., 1e-13); + } else if (t > t_P + dt) { + // skip the transition from non plastic to plastic + + auto delta_lambda_expected = + dt / t * previous_sigma.doubleDot(grad_u + grad_u.transpose()) / 2.; + auto delta_inelastic_strain_expected = + delta_lambda_expected * 3. / 2. / sigma_0 * previous_sigma; + auto inelastic_strain_expected = + delta_inelastic_strain_expected + previous_inelastic_strain; + ASSERT_NEAR((inelastic_strain - inelastic_strain_expected).norm<L_inf>(), + 0., 1e-13); + auto delta_sigma_expected = + 2. * shear_modulus_mu * + (0.5 * dt / t * (grad_u + grad_u.transpose()) - + delta_inelastic_strain_expected); + + auto delta_sigma = sigma - previous_sigma; + ASSERT_NEAR((delta_sigma_expected - delta_sigma).norm<L_inf>(), 0., + 1e-13); + } + previous_sigma = sigma; + previous_sigma_rot = sigma_rot; + previous_grad_u_rot = grad_u_rot; + previous_inelastic_strain = inelastic_strain; + previous_inelastic_strain_rot = inelastic_strain_rot; + } +} namespace { template <typename T> class TestPlasticMaterialFixture : public ::TestMaterialFixture<T> {}; TYPED_TEST_CASE(TestPlasticMaterialFixture, types); TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeStress) { this->material->testComputeStress(); } TYPED_TEST(TestPlasticMaterialFixture, PlasticEnergyDensity) { this->material->testEnergyDensity(); } TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeTangentModuli) { this->material->testComputeTangentModuli(); } - -TYPED_TEST(TestPlasticMaterialFixture, PlasticComputePushWaveSpeed) { - this->material->testPushWaveSpeed(); -} - -TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeShearWaveSpeed) { - this->material->testShearWaveSpeed(); +TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeCelerity) { + this->material->testCelerity(); } } /*****************************************************************/ diff --git a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc index df4124325..fb0bfad88 100644 --- a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc +++ b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc @@ -1,314 +1,314 @@ /** * @file test_solid_mechanics_model_cube3d.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Wed Aug 04 2010 * @date last modification: Thu Aug 06 2015 * * @brief test of the class SolidMechanicsModel on the 3d cube * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition_functor.hh" #include "test_solid_mechanics_model_fixture.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; namespace { const Real A = 1e-1; const Real E = 1.; const Real poisson = 3. / 10; const Real lambda = E * poisson / (1 + poisson) / (1 - 2 * poisson); const Real mu = E / 2 / (1. + poisson); const Real rho = 1.; const Real cp = std::sqrt((lambda + 2 * mu) / rho); const Real cs = std::sqrt(mu / rho); const Real c = std::sqrt(E / rho); const Vector<Real> k = {.5, 0., 0.}; const Vector<Real> psi1 = {0., 0., 1.}; const Vector<Real> psi2 = {0., 1., 0.}; const Real knorm = k.norm(); /* -------------------------------------------------------------------------- */ template <UInt dim> struct Verification {}; /* -------------------------------------------------------------------------- */ template <> struct Verification<1> { void displacement(Vector<Real> & disp, const Vector<Real> & coord, Real current_time) { const auto & x = coord(_x); const Real omega = c * k[0]; disp(_x) = A * cos(k[0] * x - omega * current_time); } void velocity(Vector<Real> & vel, const Vector<Real> & coord, Real current_time) { const auto & x = coord(_x); const Real omega = c * k[0]; vel(_x) = omega * A * sin(k[0] * x - omega * current_time); } }; /* -------------------------------------------------------------------------- */ template <> struct Verification<2> { void displacement(Vector<Real> & disp, const Vector<Real> & X, Real current_time) { Vector<Real> kshear = {k[1], k[0]}; Vector<Real> kpush = {k[0], k[1]}; const Real omega_p = knorm * cp; const Real omega_s = knorm * cs; Real phase_p = X.dot(kpush) - omega_p * current_time; Real phase_s = X.dot(kpush) - omega_s * current_time; disp = A * (kpush * cos(phase_p) + kshear * cos(phase_s)); } void velocity(Vector<Real> & vel, const Vector<Real> & X, Real current_time) { Vector<Real> kshear = {k[1], k[0]}; Vector<Real> kpush = {k[0], k[1]}; const Real omega_p = knorm * cp; const Real omega_s = knorm * cs; Real phase_p = X.dot(kpush) - omega_p * current_time; Real phase_s = X.dot(kpush) - omega_s * current_time; vel = A * (kpush * omega_p * cos(phase_p) + kshear * omega_s * cos(phase_s)); } }; /* -------------------------------------------------------------------------- */ template <> struct Verification<3> { void displacement(Vector<Real> & disp, const Vector<Real> & coord, Real current_time) { const auto & X = coord; Vector<Real> kpush = k; Vector<Real> kshear1(3); Vector<Real> kshear2(3); kshear1.crossProduct(k, psi1); kshear2.crossProduct(k, psi2); const Real omega_p = knorm * cp; const Real omega_s = knorm * cs; Real phase_p = X.dot(kpush) - omega_p * current_time; Real phase_s = X.dot(kpush) - omega_s * current_time; disp = A * (kpush * cos(phase_p) + kshear1 * cos(phase_s) + kshear2 * cos(phase_s)); } void velocity(Vector<Real> & vel, const Vector<Real> & coord, Real current_time) { const auto & X = coord; Vector<Real> kpush = k; Vector<Real> kshear1(3); Vector<Real> kshear2(3); kshear1.crossProduct(k, psi1); kshear2.crossProduct(k, psi2); const Real omega_p = knorm * cp; const Real omega_s = knorm * cs; Real phase_p = X.dot(kpush) - omega_p * current_time; Real phase_s = X.dot(kpush) - omega_s * current_time; vel = A * (kpush * omega_p * cos(phase_p) + kshear1 * omega_s * cos(phase_s) + kshear2 * omega_s * cos(phase_s)); } }; /* -------------------------------------------------------------------------- */ template <ElementType _type> class SolutionFunctor : public BC::Dirichlet::DirichletFunctor { public: SolutionFunctor(Real current_time, SolidMechanicsModel & model) : current_time(current_time), model(model) {} public: static constexpr UInt dim = ElementClass<_type>::getSpatialDimension(); inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const { flags(0) = true; auto & vel = model.getVelocity(); auto it = vel.begin(model.getSpatialDimension()); Vector<Real> v = it[node]; Verification<dim> verif; verif.displacement(primal, coord, current_time); verif.velocity(v, coord, current_time); } private: Real current_time; SolidMechanicsModel & model; }; /* -------------------------------------------------------------------------- */ // This fixture uses somewhat finer meshes representing bars. template <typename type_> class TestSMMFixtureBar : public TestSMMFixture<std::tuple_element_t<0, type_>> { using parent = TestSMMFixture<std::tuple_element_t<0, type_>>; public: void SetUp() override { - this->mesh_file = "bar" + aka::to_string(this->type) + ".msh"; + this->mesh_file = "../patch_tests/data/bar" + aka::to_string(this->type) + ".msh"; parent::SetUp(); getStaticParser().parse("test_solid_mechanics_model_" "dynamics_material.dat"); auto analysis_method = std::tuple_element_t<1, type_>::value; this->model->initFull(_analysis_method = analysis_method); if (this->dump_paraview) { std::stringstream base_name; base_name << "bar" << analysis_method << this->type; this->model->setBaseName(base_name.str()); this->model->addDumpFieldVector("displacement"); this->model->addDumpField("mass"); this->model->addDumpField("velocity"); this->model->addDumpField("acceleration"); this->model->addDumpFieldVector("external_force"); this->model->addDumpFieldVector("internal_force"); this->model->addDumpField("stress"); this->model->addDumpField("strain"); } time_step = this->model->getStableTimeStep() / 10.; this->model->setTimeStep(time_step); // std::cout << "timestep: " << time_step << std::endl; const auto & position = this->mesh->getNodes(); auto & displacement = this->model->getDisplacement(); auto & velocity = this->model->getVelocity(); constexpr auto dim = parent::spatial_dimension; Verification<dim> verif; for (auto && tuple : zip(make_view(position, dim), make_view(displacement, dim), make_view(velocity, dim))) { verif.displacement(std::get<1>(tuple), std::get<0>(tuple), 0.); verif.velocity(std::get<2>(tuple), std::get<0>(tuple), 0.); } if (dump_paraview) this->model->dump(); /// boundary conditions this->model->applyBC(SolutionFunctor<parent::type>(0., *this->model), "BC"); wave_velocity = 1.; // sqrt(E/rho) = sqrt(1/1) = 1 simulation_time = 5 / wave_velocity; max_steps = simulation_time / time_step; // 100 auto ndump = 50; dump_freq = max_steps / ndump; } protected: Real time_step; Real wave_velocity; Real simulation_time; UInt max_steps; UInt dump_freq; bool dump_paraview{false}; }; template <AnalysisMethod t> using analysis_method_t = std::integral_constant<AnalysisMethod, t>; #ifdef AKANTU_IMPLICIT using TestAnalysisTypes = std::tuple<analysis_method_t<_implicit_dynamic>, analysis_method_t<_explicit_lumped_mass>>; #else using TestAnalysisTypes = std::tuple<analysis_method_t<_explicit_lumped_mass>>; #endif using TestTypes = gtest_list_t<cross_product_t<TestElementTypes, TestAnalysisTypes>>; TYPED_TEST_CASE(TestSMMFixtureBar, TestTypes); /* -------------------------------------------------------------------------- */ TYPED_TEST(TestSMMFixtureBar, DynamicsExplicit) { constexpr auto dim = TestFixture::spatial_dimension; Real current_time = 0.; const auto & position = this->mesh->getNodes(); const auto & displacement = this->model->getDisplacement(); UInt nb_nodes = this->mesh->getNbNodes(); UInt nb_global_nodes = this->mesh->getNbGlobalNodes(); Real max_error{0.}; Array<Real> displacement_solution(nb_nodes, dim); Verification<dim> verif; for (UInt s = 0; s < this->max_steps; ++s, current_time += this->time_step) { if (s % this->dump_freq == 0 && this->dump_paraview) this->model->dump(); /// boundary conditions this->model->applyBC( SolutionFunctor<TestFixture::type>(current_time, *this->model), "BC"); // compute the disp solution for (auto && tuple : zip(make_view(position, dim), make_view(displacement_solution, dim))) { verif.displacement(std::get<1>(tuple), std::get<0>(tuple), current_time); } // compute the error solution Real disp_error = 0.; for (auto && tuple : zip(make_view(displacement, dim), make_view(displacement_solution, dim))) { auto diff = std::get<1>(tuple) - std::get<0>(tuple); disp_error += diff.dot(diff); } this->mesh->getCommunicator().allReduce(disp_error, SynchronizerOperation::_sum); disp_error = sqrt(disp_error) / nb_global_nodes; max_error = std::max(disp_error, max_error); - ASSERT_NEAR(disp_error, 0., 1e-3); + ASSERT_NEAR(disp_error, 0., 2e-3); this->model->solveStep(); } // std::cout << "max error: " << max_error << std::endl; } } diff --git a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh index 57400aa38..ff2979628 100644 --- a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh +++ b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh @@ -1,61 +1,55 @@ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" #include "test_gtest_utils.hh" #include "communicator.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TEST_SOLID_MECHANICS_MODEL_FIXTURE_HH__ #define __AKANTU_TEST_SOLID_MECHANICS_MODEL_FIXTURE_HH__ using namespace akantu; // This fixture uses very small meshes with a volume of 1. template <typename type_> class TestSMMFixture : public ::testing::Test { public: static constexpr ElementType type = type_::value; static constexpr size_t spatial_dimension = ElementClass<type>::getSpatialDimension(); void SetUp() override { this->mesh = std::make_unique<Mesh>(this->spatial_dimension); -#if defined(AKANTU_PARALLEL) if(Communicator::getStaticCommunicator().whoAmI() == 0) { -#endif - this->mesh->read(this->mesh_file); - -#if defined(AKANTU_PARALLEL) } mesh->distribute(); -#endif SCOPED_TRACE(aka::to_string(this->type).c_str()); model = std::make_unique<SolidMechanicsModel>(*mesh, _all_dimensions, aka::to_string(this->type)); } void TearDown() override { model.reset(nullptr); mesh.reset(nullptr); } protected: std::string mesh_file{aka::to_string(this->type) + ".msh"}; std::unique_ptr<Mesh> mesh; std::unique_ptr<SolidMechanicsModel> model; }; template <typename type_> constexpr ElementType TestSMMFixture<type_>::type; template <typename type_> constexpr size_t TestSMMFixture<type_>::spatial_dimension; using gtest_element_types = gtest_list_t<TestElementTypes>; TYPED_TEST_CASE(TestSMMFixture, gtest_element_types); #endif /* __AKANTU_TEST_SOLID_MECHANICS_MODEL_FIXTURE_HH__ */ diff --git a/test/test_model/test_structural_mechanics_model/CMakeLists.txt b/test/test_model/test_structural_mechanics_model/CMakeLists.txt index 46000bf54..856cd66ea 100644 --- a/test/test_model/test_structural_mechanics_model/CMakeLists.txt +++ b/test/test_model/test_structural_mechanics_model/CMakeLists.txt @@ -1,63 +1,68 @@ #=============================================================================== # @file CMakeLists.txt # # @author Fabian Barras <fabian.barras@epfl.ch> # # @date creation: Fri Sep 03 2010 # @date last modification: Mon Dec 07 2015 # # @brief Structural Mechanics Model Tests # # @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 <http://www.gnu.org/licenses/>. # #=============================================================================== # Adding sources register_gtest_sources( SOURCES test_structural_mechanics_model_bernoulli_beam_2.cc PACKAGE implicit structural_mechanics ) register_gtest_sources( SOURCES test_structural_mechanics_model_bernoulli_beam_3.cc PACKAGE implicit structural_mechanics ) +register_gtest_sources( + SOURCES test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc + PACKAGE implicit structural_mechanics +) + #=============================================================================== # Adding meshes for element types package_get_element_types(structural_mechanics _types) foreach(_type ${_types}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_type}.msh) list(APPEND _meshes ${_type}.msh) #register_fem_test(fe_engine_precomputation ${_type }) else() if(NOT ${_type} STREQUAL _point_1) message("The mesh ${_type}.msh is missing, the fe_engine test cannot be activated without it") endif() endif() endforeach() #=============================================================================== # Registering google test register_gtest_test(test_structural_mechanics FILES_TO_COPY ${_meshes}) diff --git a/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh b/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh index 741047074..03e36a496 100644 --- a/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh +++ b/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh @@ -1,50 +1,18 @@ $MeshFormat 2.2 0 8 $EndMeshFormat $Nodes -13 +5 1 0 0 0 -2 1 0 0 -3 1 1 0 -4 0 1 0 -5 0.4999999999990217 0 0 -6 1 0.4999999999990217 0 -7 0.5000000000013878 1 0 -8 0 0.5000000000013878 0 -9 0.5000000000000262 0.5000000000000762 0 -10 0.2500000000004626 0.7500000000004626 0 -11 0.7500000000004626 0.7499999999996739 0 -12 0.7499999999996739 0.2499999999996739 0 -13 0.24999999999961 0.2500000000004752 0 +2 40 0 0 +3 40 20 0 +4 0 20 0 +5 15 15 0 $EndNodes $Elements -28 -1 15 2 0 101 1 -2 15 2 0 102 2 -3 15 2 0 103 3 -4 15 2 0 104 4 -5 1 2 0 101 1 5 -6 1 2 0 101 5 2 -7 1 2 0 102 2 6 -8 1 2 0 102 6 3 -9 1 2 0 103 3 7 -10 1 2 0 103 7 4 -11 1 2 0 104 4 8 -12 1 2 0 104 8 1 -13 2 2 0 101 4 10 7 -14 2 2 0 101 1 13 8 -15 2 2 0 101 3 11 6 -16 2 2 0 101 2 12 5 -17 2 2 0 101 8 9 10 -18 2 2 0 101 7 10 9 -19 2 2 0 101 7 9 11 -20 2 2 0 101 8 13 9 -21 2 2 0 101 6 11 9 -22 2 2 0 101 5 9 13 -23 2 2 0 101 5 12 9 -24 2 2 0 101 6 9 12 -25 2 2 0 101 1 5 13 -26 2 2 0 101 4 8 10 -27 2 2 0 101 2 6 12 -28 2 2 0 101 3 7 11 +4 +1 2 2 1 1 1 5 2 +2 2 2 1 2 2 5 3 +3 2 2 1 3 3 4 5 +4 2 2 1 4 1 4 5 $EndElements diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc index 0883df322..8337bb9c2 100644 --- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc +++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc @@ -1,113 +1,114 @@ /** * @file test_structural_mechanics_model_bernoulli_beam_2.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Sun Oct 19 2014 * * @brief Computation of the analytical exemple 1.1 in the TGC vol 6 * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "test_structural_mechanics_model_fixture.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> using namespace akantu; /* -------------------------------------------------------------------------- */ class TestStructBernoulli2 : public TestStructuralFixture<element_type_t<_bernoulli_beam_2>> { using parent = TestStructuralFixture<element_type_t<_bernoulli_beam_2>>; public: void addMaterials() override { mat.E = 3e10; mat.I = 0.0025; mat.A = 0.01; this->model->addMaterial(mat); mat.E = 3e10; mat.I = 0.00128; mat.A = 0.01; this->model->addMaterial(mat); } void assignMaterials() override { auto & materials = this->model->getElementMaterial(parent::type); materials(0) = 0; materials(1) = 1; } void setDirichlets() override { auto boundary = this->model->getBlockedDOFs().begin(parent::ndof); // clang-format off *boundary = {true, true, true}; ++boundary; *boundary = {false, true, false}; ++boundary; *boundary = {false, true, false}; ++boundary; // clang-format on } void setNeumanns() override { Real M = 3600; // Nm Real q = -6000; // kN/m Real L = 10; // m auto & forces = this->model->getExternalForce(); forces(2, 2) = -M; // moment on last node #if 1 // as long as integration is not available forces(0, 1) = q * L / 2; forces(0, 2) = q * L * L / 12; forces(1, 1) = q * L / 2; forces(1, 2) = -q * L * L / 12; #else auto & group = mesh.createElementGroup("lin_force"); group.add({type, 0, _not_ghost}); Vector<Real> lin_force = {0, q, 0}; // a linear force is not actually a *boundary* condition // it is equivalent to a volume force model.applyBC(BC::Neumann::FromSameDim(lin_force), group); #endif forces(2, 0) = mat.E * mat.A / 18; } protected: StructuralMaterial mat; }; /* -------------------------------------------------------------------------- */ TEST_F(TestStructBernoulli2, TestDisplacements) { + model->solveStep(); auto d1 = model->getDisplacement()(1, 2); auto d2 = model->getDisplacement()(2, 2); auto d3 = model->getDisplacement()(1, 0); Real tol = Math::getTolerance(); EXPECT_NEAR(d1, 5.6 / 4800, tol); // first rotation EXPECT_NEAR(d2, -3.7 / 4800, tol); // second rotation EXPECT_NEAR(d3, 10. / 18, tol); // axial deformation } diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc index 7e522852a..b3e649e5e 100644 --- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc +++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc @@ -1,99 +1,100 @@ /** * @file test_structural_mechanics_model_bernoulli_beam_3.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Mon Jan 22 2018 * * @brief Computation of the analytical exemple 1.1 in the TGC vol 6 * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "test_structural_mechanics_model_fixture.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> /* -------------------------------------------------------------------------- */ using namespace akantu; class TestStructBernoulli3 : public TestStructuralFixture<element_type_t<_bernoulli_beam_3>> { using parent = TestStructuralFixture<element_type_t<_bernoulli_beam_3>>; public: void readMesh(std::string filename) override { parent::readMesh(filename); auto & normals = this->mesh->registerData<Real>("extra_normal") .alloc(0, parent::spatial_dimension, parent::type, _not_ghost); Vector<Real> normal = {0, 0, 1}; normals.push_back(normal); normal = {0, 0, 1}; normals.push_back(normal); } void addMaterials() override { StructuralMaterial mat; mat.E = 1; mat.Iz = 1; mat.Iy = 1; mat.A = 1; mat.GJ = 1; this->model->addMaterial(mat); } void setDirichlets() { // Boundary conditions (blocking all DOFs of nodes 2 & 3) auto boundary = ++this->model->getBlockedDOFs().begin(parent::ndof); // clang-format off *boundary = {true, true, true, true, true, true}; ++boundary; *boundary = {true, true, true, true, true, true}; ++boundary; // clang-format on } void setNeumanns() override { // Forces Real P = 1; // N auto & forces = this->model->getExternalForce(); forces.clear(); forces(0, 2) = -P; // vertical force on first node } void assignMaterials() override { model->getElementMaterial(parent::type).set(0); } }; /* -------------------------------------------------------------------------- */ TEST_F(TestStructBernoulli3, TestDisplacements) { + model->solveStep(); auto vz = model->getDisplacement()(0, 2); auto thy = model->getDisplacement()(0, 4); auto thx = model->getDisplacement()(0, 3); auto thz = model->getDisplacement()(0, 5); Real tol = Math::getTolerance(); EXPECT_NEAR(vz, -5. / 48, tol); EXPECT_NEAR(thy, -std::sqrt(2) / 8, tol); EXPECT_NEAR(thz, 0, tol); EXPECT_NEAR(thx, 0, tol); } diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc similarity index 53% copy from test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc copy to test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc index 0883df322..f33fd4e01 100644 --- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc +++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc @@ -1,113 +1,107 @@ /** * @file test_structural_mechanics_model_bernoulli_beam_2.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Sun Oct 19 2014 * * @brief Computation of the analytical exemple 1.1 in the TGC vol 6 * * @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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "test_structural_mechanics_model_fixture.hh" +#include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> using namespace akantu; /* -------------------------------------------------------------------------- */ -class TestStructBernoulli2 - : public TestStructuralFixture<element_type_t<_bernoulli_beam_2>> { - using parent = TestStructuralFixture<element_type_t<_bernoulli_beam_2>>; +class TestStructDKT18 + : public TestStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>> { + using parent = TestStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>>; public: void addMaterials() override { - mat.E = 3e10; - mat.I = 0.0025; - mat.A = 0.01; - - this->model->addMaterial(mat); - - mat.E = 3e10; - mat.I = 0.00128; - mat.A = 0.01; + mat.E = 1; + mat.t = 1; + mat.nu = 0.3; this->model->addMaterial(mat); } void assignMaterials() override { auto & materials = this->model->getElementMaterial(parent::type); - materials(0) = 0; - materials(1) = 1; + std::fill(materials.begin(), materials.end(), 0); } void setDirichlets() override { - auto boundary = this->model->getBlockedDOFs().begin(parent::ndof); + this->model->getBlockedDOFs().set(true); + auto center_node = this->model->getBlockedDOFs().end(parent::ndof) - 1; + *center_node = {false, false, false, false, false, true}; + + this->model->getDisplacement().clear(); + auto disp = ++this->model->getDisplacement().begin(parent::ndof); + + // Displacement field from Batoz Vol. 2 p. 392 + // with theta to beta correction from discrete Kirchhoff condition + // see also the master thesis of Michael Lozano // clang-format off - *boundary = {true, true, true}; ++boundary; - *boundary = {false, true, false}; ++boundary; - *boundary = {false, true, false}; ++boundary; + // *disp = {40, 20, -800 , -20, 40, 0}; ++disp; + // *disp = {50, 40, -1400, -40, 50, 0}; ++disp; + // *disp = {10, 20, -200 , -20, 10, 0}; ++disp; + *disp = {0, 0, -800 , -20, 40, 0}; ++disp; + *disp = {0, 0, -1400, -40, 50, 0}; ++disp; + *disp = {0, 0, -200 , -20, 10, 0}; ++disp; // clang-format on } - void setNeumanns() override { - Real M = 3600; // Nm - Real q = -6000; // kN/m - Real L = 10; // m - auto & forces = this->model->getExternalForce(); - forces(2, 2) = -M; // moment on last node -#if 1 // as long as integration is not available - forces(0, 1) = q * L / 2; - forces(0, 2) = q * L * L / 12; - forces(1, 1) = q * L / 2; - forces(1, 2) = -q * L * L / 12; -#else - auto & group = mesh.createElementGroup("lin_force"); - group.add({type, 0, _not_ghost}); - Vector<Real> lin_force = {0, q, 0}; - // a linear force is not actually a *boundary* condition - // it is equivalent to a volume force - model.applyBC(BC::Neumann::FromSameDim(lin_force), group); -#endif - forces(2, 0) = mat.E * mat.A / 18; - } + void setNeumanns() override {} protected: StructuralMaterial mat; }; /* -------------------------------------------------------------------------- */ -TEST_F(TestStructBernoulli2, TestDisplacements) { - auto d1 = model->getDisplacement()(1, 2); - auto d2 = model->getDisplacement()(2, 2); - auto d3 = model->getDisplacement()(1, 0); +// Batoz Vol 2. patch test, ISBN 2-86601-259-3 +TEST_F(TestStructDKT18, TestDisplacements) { + model->solveStep(); + model->getDOFManager().getMatrix("K").saveMatrix("K.mtx"); + model->getDOFManager().getMatrix("J").saveMatrix("J.mtx"); + Vector<Real> solution = {22.5, 22.5, -337.5, -22.5, 22.5, 0}; + auto nb_nodes = this->model->getDisplacement().size(); + + Vector<Real> center_node_disp = + model->getDisplacement().begin(solution.size())[nb_nodes - 1]; + + std::cout << center_node_disp << std::endl; + + auto error = solution - center_node_disp; Real tol = Math::getTolerance(); - EXPECT_NEAR(d1, 5.6 / 4800, tol); // first rotation - EXPECT_NEAR(d2, -3.7 / 4800, tol); // second rotation - EXPECT_NEAR(d3, 10. / 18, tol); // axial deformation + EXPECT_NEAR(error.norm<L_2>(), 0., tol); } diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh index cd92c3e5d..a1f5f221e 100644 --- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh +++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh @@ -1,76 +1,75 @@ /* -------------------------------------------------------------------------- */ #include "element_class_structural.hh" #include "structural_mechanics_model.hh" #include "test_gtest_utils.hh" /* -------------------------------------------------------------------------- */ #include <gtest/gtest.h> #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TEST_STRUCTURAL_MECHANICS_MODEL_FIXTURE_HH__ #define __AKANTU_TEST_STRUCTURAL_MECHANICS_MODEL_FIXTURE_HH__ using namespace akantu; template <typename type_> class TestStructuralFixture : public ::testing::Test { public: static constexpr const ElementType type = type_::value; static constexpr const size_t spatial_dimension = ElementClass<type>::getSpatialDimension(); static const UInt ndof = ElementClass<type>::getNbDegreeOfFreedom(); void SetUp() override { const auto spatial_dimension = this->spatial_dimension; mesh = std::make_unique<Mesh>(spatial_dimension); readMesh(makeMeshName()); std::stringstream element_type; element_type << this->type; model = std::make_unique<StructuralMechanicsModel>(*mesh, _all_dimensions, element_type.str()); addMaterials(); model->initFull(); assignMaterials(); setDirichlets(); setNeumanns(); - model->solveStep(); } virtual void readMesh(std::string filename) { mesh->read(filename, _miot_gmsh_struct); } virtual std::string makeMeshName() { std::stringstream element_type; element_type << type; SCOPED_TRACE(element_type.str().c_str()); return element_type.str() + ".msh"; } void TearDown() override { model.reset(nullptr); mesh.reset(nullptr); } virtual void addMaterials() = 0; virtual void assignMaterials() = 0; virtual void setDirichlets() = 0; virtual void setNeumanns() = 0; protected: std::unique_ptr<Mesh> mesh; std::unique_ptr<StructuralMechanicsModel> model; }; template <typename type_> constexpr ElementType TestStructuralFixture<type_>::type; template <typename type_> constexpr size_t TestStructuralFixture<type_>::spatial_dimension; template <typename type_> const UInt TestStructuralFixture<type_>::ndof; // using types = gtest_list_t<StructuralTestElementTypes>; // TYPED_TEST_CASE(TestStructuralFixture, types); #endif /* __AKANTU_TEST_STRUCTURAL_MECHANICS_MODEL_FIXTURE_HH__ */ diff --git a/third-party/iohelper/src/iohelper_common.hh b/third-party/iohelper/src/iohelper_common.hh index 7acab3a40..f12affbad 100644 --- a/third-party/iohelper/src/iohelper_common.hh +++ b/third-party/iohelper/src/iohelper_common.hh @@ -1,295 +1,298 @@ /** * @file iohelper_common.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Mar 11 2010 * @date last modification: Thu Oct 10 2013 * * @brief header for common types * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * IOHelper 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. * * IOHelper 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 IOHelper. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __IOHELPER_COMMON_H__ #define __IOHELPER_COMMON_H__ /* -------------------------------------------------------------------------- */ #define USING_ZLIB #include <iostream> #include <string> #include <sstream> #define __BEGIN_IOHELPER__ namespace iohelper { #define __END_IOHELPER__ } #include <string.h> #include <stdlib.h> /* -------------------------------------------------------------------------- */ __BEGIN_IOHELPER__ using UInt = unsigned int; using Int = int; using Real = double; /* -------------------------------------------------------------------------- */ enum DataType { _bool, _uint, _int, _float, _double, _int64, _uint64 }; enum IndexingMode{ C_MODE = 0, FORTRAN_MODE = 1 }; /* -------------------------------------------------------------------------- */ #if __cplusplus <= 199711L enum ElemType { #else enum ElemType : unsigned int { #endif TRIANGLE1 , TRIANGLE2 , TETRA1 , TETRA2 , POINT_SET , LINE1 , LINE2 , QUAD1 , QUAD2 , HEX1 , HEX2 , BEAM2 , BEAM3 , PRISM1 , PRISM2 , + COH1D2 , COH2D4 , COH2D6 , COH3D6 , COH3D12 , COH3D8 , MAX_ELEM_TYPE }; /* -------------------------------------------------------------------------- */ enum FileStorageMode{ TEXT = 0, BASE64 = 1, COMPRESSED = 2 }; enum TextDumpMode { _tdm_space, _tdm_csv }; /* -------------------------------------------------------------------------- */ static UInt nb_node_per_elem[MAX_ELEM_TYPE] __attribute__((unused)) = { 3, // TRIANGLE1 6, // TRIANGLE2 4, // TETRA1 10, // TETRA2 1, // POINT_SET 2, // LINE1 3, // LINE2 4, // QUAD1 8, // QUAD2 8, // HEX1 20, // HEX2 2, // BEAM2 2, // BEAM3 6, // PRISM1 15, // PRISM2 + 2, // COH1D2 4, // COH2D4 6, // COH2D6 6, // COH3D6 12, // COH3D12 8, // COH3D8 }; /* -------------------------------------------------------------------------- */ static UInt nb_quad_points[MAX_ELEM_TYPE] __attribute__((unused)) = { 1, // TRIANGLE1 3, // TRIANGLE2 1, // TETRA1 4, // TETRA2 0, // POINT_SET 1, // LINE1 2, // LINE2 4, // QUAD1 9, // QUAD2 8, // HEX1 27, // HEX2 2, // BEAM2 3, // BEAM3 6, // PRISM1 8, // PRISM2 + 1, // COH1D2 1, // COH2D4 2, // COH2D6 1, // COH3D6 3, // COH3D12 1, // COH3D8 }; /* -------------------------------------------------------------------------- */ template <typename T> class IOHelperVector { public: virtual ~IOHelperVector() = default; inline IOHelperVector(T * ptr, UInt size){ this->ptr = ptr; this->_size = size; }; inline UInt size() const {return _size;}; inline const T & operator[] (UInt i) const { return ptr[i]; }; inline const T * getPtr() const { return ptr; }; private: T* ptr; UInt _size; }; /* -------------------------------------------------------------------------- */ /* Iterator interface */ /* -------------------------------------------------------------------------- */ template< typename T, class daughter, class ret_cont = IOHelperVector<T> > class iterator { public: using type = ret_cont; virtual ~iterator() = default; virtual bool operator!=(const daughter & it) const = 0; virtual daughter & operator++() = 0; virtual ret_cont operator*() = 0; //! This function is only for the element iterators virtual ElemType element_type() { return MAX_ELEM_TYPE; } }; /* -------------------------------------------------------------------------- */ class IOHelperException : public std::exception { public: enum ErrorType { _et_non_homogeneous_data, _et_unknown_visitor_stage, _et_file_error, _et_missing_field, _et_data_type, _et_options_error }; public: IOHelperException(const std::string & message, const ErrorType type) noexcept { this->message = message; this->type = type; }; ~IOHelperException() noexcept override = default; const char * what() const noexcept override { return message.c_str(); }; private: std::string message; ErrorType type; }; /* -------------------------------------------------------------------------- */ #define IOHELPER_THROW(x,type) { \ std::stringstream ioh_throw_sstr; \ ioh_throw_sstr << __FILE__ << ":" << __LINE__ << ":" \ << __PRETTY_FUNCTION__ << ": " << x; \ std::string ioh_message(ioh_throw_sstr.str()); \ throw ::iohelper::IOHelperException(ioh_message, \ ::iohelper::IOHelperException::type); \ } /* -------------------------------------------------------------------------- */ template <typename T> DataType getDataType(); #define DEFINE_GET_DATA_TYPE(type, data_type ) \ template <> inline DataType getDataType<type>() { return data_type; } DEFINE_GET_DATA_TYPE(bool, _bool) DEFINE_GET_DATA_TYPE(ElemType, _int) DEFINE_GET_DATA_TYPE(int, _int) DEFINE_GET_DATA_TYPE(unsigned int, _uint) DEFINE_GET_DATA_TYPE(float, _float) DEFINE_GET_DATA_TYPE(double, _double) DEFINE_GET_DATA_TYPE(long int, _int64) DEFINE_GET_DATA_TYPE(unsigned long int, _uint64) #undef DEFINE_GET_DATA_TYPE inline std::ostream & operator <<(std::ostream & stream, DataType type) { switch(type) { case _bool : stream << "bool" ; break; case _uint : stream << "uint32" ; break; case _int : stream << "int32" ; break; case _float : stream << "float32" ; break; case _double : stream << "float64" ; break; case _uint64 : stream << "uint64" ; break; case _int64 : stream << "int64" ; break; } return stream; } inline std::ostream & operator <<(std::ostream & stream, TextDumpMode mode) { switch(mode) { case _tdm_space : stream << "space" ; break; case _tdm_csv : stream << "csv" ; break; } return stream; } __END_IOHELPER__ #endif /* __IOHELPER_COMMON_H__ */ diff --git a/third-party/iohelper/src/paraview_helper.cc b/third-party/iohelper/src/paraview_helper.cc index 7f2447257..2d6840453 100644 --- a/third-party/iohelper/src/paraview_helper.cc +++ b/third-party/iohelper/src/paraview_helper.cc @@ -1,312 +1,313 @@ /** * @file paraview_helper.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Oct 12 2012 * @date last modification: Wed Jun 05 2013 * * @brief implementation of paraview helper * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * IOHelper 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. * * IOHelper 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 IOHelper. If not, see <http://www.gnu.org/licenses/>. * */ #include "paraview_helper.hh" #include <fstream> /* -------------------------------------------------------------------------- */ #if defined(__INTEL_COMPILER) /// remark #981: operands are evaluated in unspecified order #pragma warning ( disable : 981 ) /// remark #383: value copied to temporary, reference to temporary used #pragma warning ( disable : 383 ) #endif //defined(__INTEL_COMPILER) __BEGIN_IOHELPER__ /* -------------------------------------------------------------------------- */ ParaviewHelper::ParaviewHelper(File & f, UInt mode): b64(f), file(f), position_flag(false) { bflag = BASE64; compteur = 0; setMode(mode); this->paraview_code_type[TRIANGLE1] = VTK_TRIANGLE; this->paraview_code_type[TRIANGLE2] = VTK_QUADRATIC_TRIANGLE; this->paraview_code_type[TETRA1 ] = VTK_TETRA; this->paraview_code_type[TETRA2 ] = VTK_QUADRATIC_TETRA; this->paraview_code_type[POINT_SET] = VTK_POLY_VERTEX; this->paraview_code_type[LINE1 ] = VTK_LINE; this->paraview_code_type[LINE2 ] = VTK_QUADRATIC_EDGE; this->paraview_code_type[QUAD1 ] = VTK_QUAD; this->paraview_code_type[QUAD2 ] = VTK_QUADRATIC_QUAD; this->paraview_code_type[HEX1 ] = VTK_HEXAHEDRON; this->paraview_code_type[HEX2 ] = VTK_QUADRATIC_HEXAHEDRON; this->paraview_code_type[BEAM2 ] = VTK_LINE; this->paraview_code_type[BEAM3 ] = VTK_LINE; this->paraview_code_type[PRISM1 ] = VTK_WEDGE; this->paraview_code_type[PRISM2 ] = VTK_QUADRATIC_WEDGE; + this->paraview_code_type[COH1D2 ] = VTK_LINE; this->paraview_code_type[COH2D4 ] = VTK_POLYGON; this->paraview_code_type[COH2D6 ] = VTK_POLYGON; this->paraview_code_type[COH3D6 ] = VTK_WEDGE; this->paraview_code_type[COH3D12 ] = VTK_QUADRATIC_LINEAR_WEDGE; this->paraview_code_type[COH3D8 ] = VTK_HEXAHEDRON; std::map<ElemType, VTKCellType>::iterator it; for(it = paraview_code_type.begin(); it != paraview_code_type.end(); ++it) { UInt nb_nodes = nb_node_per_elem[it->first]; UInt * tmp = new UInt[nb_nodes]; for (UInt i = 0; i < nb_nodes; ++i) { tmp[i] = i; } switch(it->first) { case COH3D12: tmp[ 0] = 0; tmp[ 1] = 1; tmp[ 2] = 2; tmp[ 3] = 6; tmp[ 4] = 7; tmp[ 5] = 8; tmp[ 6] = 3; tmp[ 7] = 4; tmp[ 8] = 5; tmp[ 9] = 9; tmp[10] = 10; tmp[11] = 11; break; case COH2D6: tmp[0] = 0; tmp[1] = 2; tmp[2] = 1; tmp[3] = 4; tmp[4] = 5; tmp[5] = 3; break; case COH2D4: tmp[0] = 0; tmp[1] = 1; tmp[2] = 3; tmp[3] = 2; break; case HEX2: tmp[12] = 16; tmp[13] = 17; tmp[14] = 18; tmp[15] = 19; tmp[16] = 12; tmp[17] = 13; tmp[18] = 14; tmp[19] = 15; break; case PRISM2: tmp[ 0] = 0; tmp[ 1] = 1; tmp[ 2] = 2; tmp[ 3] = 3; tmp[ 4] = 4; tmp[ 5] = 5; tmp[ 6] = 6; tmp[ 7] = 7; tmp[ 8] = 8; tmp[ 9] = 12; tmp[10] = 13; tmp[11] = 14; tmp[12] = 9; tmp[13] = 10; tmp[14] = 11; break; default: //nothing to change break; } this->write_reorder[it->first] = tmp; } } /* -------------------------------------------------------------------------- */ ParaviewHelper::~ParaviewHelper(){ std::map<ElemType, VTKCellType>::iterator it; for(it = this->paraview_code_type.begin(); it != this->paraview_code_type.end(); ++it) { delete [] this->write_reorder[it->first]; } } /* -------------------------------------------------------------------------- */ void ParaviewHelper::writeTimePVD(const std::string & filename, const std::vector< std::pair<Real, std::string> > & pvtus) { std::ofstream pvd_file; pvd_file.open(filename.c_str()); if(!pvd_file.good()) { IOHELPER_THROW("DumperParaview was not able to open the file \"" << filename, _et_file_error); } pvd_file << "<?xml version=\"1.0\"?>" << std::endl << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl << " <Collection>" << std::endl; std::vector< std::pair<Real, std::string> >::const_iterator it = pvtus.begin(); std::vector< std::pair<Real, std::string> >::const_iterator end = pvtus.end(); for (;it != end; ++it) { pvd_file << " <DataSet timestep=\"" << it->first << "\" group=\"\" part=\"0\" file=\"" << it->second << "\"/>" << std::endl; } pvd_file << " </Collection>" << std::endl << "</VTKFile>" << std::endl; pvd_file.close(); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::writeHeader(int nb_nodes,int nb_elems){ file << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" " ; file << "byte_order=\"LittleEndian\">" << std::endl; file << " <UnstructuredGrid>" << std::endl << " <Piece NumberOfPoints= \"" << nb_nodes << "\" NumberOfCells=\"" << nb_elems << "\">" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::PDataArray(const std::string & name, int nb_components, const std::string & type){ file << " <PDataArray type=\"" << type << "\" NumberOfComponents=\"" << nb_components << "\" Name=\"" << name << "\" format=\""; if (bflag == BASE64) file << "binary"; else file << "ascii"; file << "\"></PDataArray>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::write_conclusion(){ file << " </Piece>" << std::endl; file << " </UnstructuredGrid>" << std::endl; file << "</VTKFile>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startData(const std::string & name, int nb_components, const std::string & type){ file << " <DataArray type=\"" << type << "\" "; if (nb_components) file << "NumberOfComponents=\"" << nb_components << "\" "; file << "Name=\"" << name << "\" format=\""; if (bflag == BASE64) file << "binary"; else file << "ascii"; file << "\">" << std::endl; if (bflag == BASE64) b64.CreateHeader(); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endData(){ if (bflag == BASE64) b64.WriteHeader(); file << std::endl << " </DataArray>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startDofList(int dimension){ file << " <Points>" << std::endl; startData("positions", dimension, "Float64"); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endDofList(){ endData(); file << " </Points>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startCells(){ file << " <Cells>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endCells(){ file << " </Cells>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startCellsConnectivityList(){ startData("connectivity",0,"Int32"); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endCellsConnectivityList(){ endData(); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startCellsoffsetsList(){ startData("offsets",0,"Int32"); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endCellsoffsetsList(){ endData(); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startCellstypesList(){ startData("types",0,"UInt32"); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endCellstypesList(){ endData(); } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startPointDataList(){ file << " <PointData>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endPointDataList(){ file << " </PointData>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::startCellDataList(){ file << " <CellData>" << std::endl; } /* -------------------------------------------------------------------------- */ void ParaviewHelper::endCellDataList(){ file << " </CellData>" << std::endl; } /* -------------------------------------------------------------------------- */ __END_IOHELPER__