diff --git a/cmake/AkantuMacros.cmake b/cmake/AkantuMacros.cmake index 65326f516..15d9822f8 100644 --- a/cmake/AkantuMacros.cmake +++ b/cmake/AkantuMacros.cmake @@ -1,152 +1,152 @@ #=============================================================================== # @file AkantuMacros.cmake # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Thu Feb 17 2011 # @date last modification: Tue Aug 19 2014 # # @brief Set of macros used by akantu cmake files # # @section LICENSE # # Copyright (©) 2010-2012, 2014 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/>. # #=============================================================================== #=============================================================================== function(set_third_party_shared_libirary_name _var _lib) set(${_var} ${PROJECT_BINARY_DIR}/third-party/lib/${CMAKE_SHARED_LIBRARY_PREFIX}${_lib}${CMAKE_SHARED_LIBRARY_SUFFIX} CACHE FILEPATH "" FORCE) endfunction() #=============================================================================== # Generate the list of currently loaded materials function(generate_material_list) message(STATUS "Determining the list of recognized materials...") - package_get_include_directories( + package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) - package_get_external_informations( + package_get_all_external_informations( AKANTU_EXTERNAL_INCLUDE_DIR AKANTU_EXTERNAL_LIBRARIES ) set(_include_dirs ${AKANTU_INCLUDE_DIRS} ${AKANTU_EXTERNAL_INCLUDE_DIR}) try_run(_material_list_run _material_list_compile ${CMAKE_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/material_lister.cc CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${_include_dirs}" COMPILE_DEFINITIONS "-DAKANTU_CMAKE_LIST_MATERIALS" COMPILE_OUTPUT_VARIABLE _compile_results RUN_OUTPUT_VARIABLE _result_material_list) if(_material_list_compile AND "${_material_list_run}" EQUAL 0) message(STATUS "Materials included in Akantu:") string(REPLACE "\n" ";" _material_list "${_result_material_list}") foreach(_mat ${_material_list}) string(REPLACE ":" ";" _mat_key "${_mat}") list(GET _mat_key 0 _key) list(GET _mat_key 1 _class) list(LENGTH _mat_key _l) if("${_l}" GREATER 2) list(REMOVE_AT _mat_key 0 1) set(_opt " -- options: [") foreach(_o ${_mat_key}) set(_opt "${_opt} ${_o}") endforeach() set(_opt "${_opt} ]") else() set(_opt "") endif() message(STATUS " ${_class} -- key: ${_key}${_opt}") endforeach() else() message(STATUS "Could not determine the list of materials.") message("${_compile_results}") endif() endfunction() #=============================================================================== if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) return() endif() set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) # first set all result variables to empty/FALSE foreach(arg_name ${_singleArgNames} ${_multiArgNames}) set(${prefix}_${arg_name}) endforeach(arg_name) foreach(option ${_optionNames}) set(${prefix}_${option} FALSE) endforeach(option) set(${prefix}_UNPARSED_ARGUMENTS) set(insideValues FALSE) set(currentArgName) # now iterate over all arguments and fill the result variables foreach(currentArg ${ARGN}) list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) if(insideValues) if("${insideValues}" STREQUAL "SINGLE") set(${prefix}_${currentArgName} ${currentArg}) set(insideValues FALSE) elseif("${insideValues}" STREQUAL "MULTI") list(APPEND ${prefix}_${currentArgName} ${currentArg}) endif() else(insideValues) list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) endif(insideValues) else() if(NOT ${optionIndex} EQUAL -1) set(${prefix}_${currentArg} TRUE) set(insideValues FALSE) elseif(NOT ${singleArgIndex} EQUAL -1) set(currentArgName ${currentArg}) set(${prefix}_${currentArgName}) set(insideValues "SINGLE") elseif(NOT ${multiArgIndex} EQUAL -1) set(currentArgName ${currentArg}) set(${prefix}_${currentArgName}) set(insideValues "MULTI") endif() endif() endforeach(currentArg) # propagate the result variables to the caller: foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) endforeach(arg_name) set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) diff --git a/cmake/Modules/CMakePackagesSystem.cmake b/cmake/Modules/CMakePackagesSystem.cmake index a68c32a8a..196ef26f4 100644 --- a/cmake/Modules/CMakePackagesSystem.cmake +++ b/cmake/Modules/CMakePackagesSystem.cmake @@ -1,1209 +1,1213 @@ #=============================================================================== # @file CMakePackagesSystem.cmake # # @author Nicolas Richart <nicolas.richart@epfl.ch> # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # # @date creation: Thu Dec 20 2012 # @date last modification: Wed Sep 10 2014 # # @brief Set of macros used by akantu to handle the package system # # @section LICENSE # # Copyright (©) 2014 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(CMakeParseArguments) #=============================================================================== # Package Management #=============================================================================== if(__CMAKE_PACKAGES_SYSTEM) return() endif() set(__CMAKE_PACKAGES_SYSTEM TRUE) include(CMakeDebugMessages) cmake_register_debug_message_module(PackagesSystem) #=============================================================================== option(AUTO_MOVE_UNKNOWN_FILES "Give to cmake the permission to move the unregistered files to the ${PROJECT_SOURCE_DIR}/tmp directory" FALSE) mark_as_advanced(AUTO_MOVE_UNKNOWN_FILES) # ============================================================================== # Accessors # ============================================================================== # Package name function(package_get_name pkg pkg_name) string(TOUPPER ${PROJECT_NAME} _project) string(REPLACE "-" "_" _str_pkg "${pkg}") string(TOUPPER ${_str_pkg} _u_package) set(${pkg_name} ${_project}_PKG_${_u_package} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Real name function(package_get_real_name pkg_name real_name) set(${real_name} ${${pkg_name}} PARENT_SCOPE) endfunction() function(_package_set_real_name pkg_name real_name) set(${pkg_name} ${real_name} CACHE INTERNAL "" FORCE) endfunction() # ------------------------------------------------------------------------------ # Option name function(package_get_option_name pkg_name opt_name) string(TOUPPER "${PROJECT_NAME}" _project) package_get_real_name(${pkg_name} _real_name) string(TOUPPER "${_real_name}" _u_package) package_get_nature(${pkg_name} _nature) if(${_nature} MATCHES "internal" OR ${_nature} MATCHES "meta") set(${opt_name} ${_project}_${_u_package} PARENT_SCOPE) elseif(${_nature} MATCHES "external") set(${opt_name} ${_project}_USE_${_u_package} PARENT_SCOPE) else() set(${opt_name} UNKNOWN_NATURE_${_project}_${_u_package} PARENT_SCOPE) endif() endfunction() # ------------------------------------------------------------------------------ # Set if system package or compile external lib function(_package_set_system_option pkg_name default) string(TOUPPER "${PROJECT_NAME}" _project) package_get_real_name(${pkg_name} _real_name) string(TOUPPER "${_real_name}" _u_package) option(${_project}_USE_SYSTEM_${_u_package} "Should akantu compile the third-party: \"${_real_name}\"" ${default}) mark_as_advanced(${_project}_USE_SYSTEM_${_u_package}) endfunction() function(package_use_system pkg_name use) string(TOUPPER "${PROJECT_NAME}" _project) package_get_real_name(${pkg_name} _real_name) string(TOUPPER "${_real_name}" _u_package) if(DEFINED ${_project}_USE_SYSTEM_${_u_package}) set(${use} ${${_project}_USE_SYSTEM_${_u_package}} PARENT_SCOPE) else() set(${use} TRUE PARENT_SCOPE) endif() endfunction() # ------------------------------------------------------------------------------ # Nature function(_package_set_nature pkg_name NATURE) set(${pkg_name}_NATURE ${NATURE} CACHE INTERNAL "" FORCE) endfunction() function(package_get_nature pkg_name NATURE) if(${pkg_name}_NATURE) set(${NATURE} ${${pkg_name}_NATURE} PARENT_SCOPE) else() set(${NATURE} "unknown" PARENT_SCOPE) endif() endfunction() # ------------------------------------------------------------------------------ # Description function(_package_set_description pkg_name DESC) set(${pkg_name}_DESC ${DESC} CACHE INTERNAL "" FORCE) endfunction() function(package_get_description pkg_name DESC) if(${pkg_name}_DESC) set(${DESC} ${${pkg_name}_DESC} PARENT_SCOPE) else() message("No description set for the package ${${pkg_name}}") endif() endfunction() # ------------------------------------------------------------------------------ # Package file name function(_package_set_filename pkg_name FILE) set(${pkg_name}_FILE ${FILE} CACHE INTERNAL "" FORCE) endfunction() function(package_get_filename pkg_name FILE) if(${pkg_name}_FILE) set(${FILE} ${${pkg_name}_FILE} PARENT_SCOPE) else() message(ERROR "No filename set for the package ${${pkg_name}}") endif() endfunction() # ------------------------------------------------------------------------------ # Source folder function(_package_set_sources_folder pkg_name src_folder) set(${pkg_name}_SRCS_FOLDER ${src_folder} CACHE INTERNAL "" FORCE) endfunction() function(package_get_sources_folder pkg_name src_folder) set(${src_folder} ${${pkg_name}_SRCS_FOLDER} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Test folder function(_package_set_tests_folder pkg_name test_folder) set(${pkg_name}_TESTS_FOLDER ${test_folder} CACHE INTERNAL "" FORCE) endfunction() function(package_get_tests_folder pkg_name test_folder) set(${test_folder} ${${pkg_name}_TESTS_FOLDER} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Manual folder function(_package_set_manual_folder pkg_name manual_folder) set(${pkg_name}_MANUAL_FOLDER ${manual_folder} CACHE INTERNAL "" FORCE) endfunction() function(package_get_manual_folder pkg_name manual_folder) set(${manual_folder} ${${pkg_name}_MANUAL_FOLDER} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Extra option for the find_package function(_package_set_extra_options pkg_name) set(${pkg_name}_OPTIONS ${ARGN} CACHE INTERNAL "Extra option for the fin_package function" FORCE) endfunction() function(package_get_extra_options pkg_name options) set(${options} "${${pkg_name}_OPTIONS}" PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Compilation flags function(_package_set_compile_flags pkg_name) set(${pkg_name}_COMPILE_FLAGS ${ARGN} CACHE INTERNAL "Additional compile flags" FORCE) endfunction() function(package_get_compile_flags pkg_name flags) set(${flags} "${${pkg_name}_COMPILE_FLAGS}" PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Include dir function(package_set_include_dir pkg_name) package_get_real_name(${pkg_name} _real_name) set(${pkg_name}_INCLUDE_DIR "${ARGN}" CACHE INTERNAL "Include folder for the package ${_real_name}" FORCE) endfunction() function(package_get_include_dir pkg_name include_dir) set(${include_dir} ${${pkg_name}_INCLUDE_DIR} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Libraries function(package_set_libraries pkg_name) package_get_real_name(${pkg_name} _real_name) set(${pkg_name}_LIBRARIES "${ARGN}" CACHE INTERNAL "Libraries for the package ${_real_name}" FORCE) endfunction() function(package_get_libraries pkg_name libraries) set(${libraries} ${${pkg_name}_LIBRARIES} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Extra dependencies like custom commands of ExternalProject function(package_add_extra_dependency PACKAGE) package_get_name(${PACKAGE} _pkg_name) set(_tmp_dep ${${pkg_name}_EXTRA_DEPENDS}) list(APPEND _tmp_dep ${ARGN}) list(REMOVE_DUPLICATES _tmp_dep) set(${pkg_name}_EXTRA_DEPENDS ${_tmp_dep} CACHE INTERNAL "External dependencies" FORCE) endfunction() function(package_get_extra_dependency PACKAGE deps) package_get_name(${PACKAGE} _pkg_name) set(${deps} ${${pkg_name}_EXTRA_DEPENDS} PARENT_SCOPE) endfunction() function(_package_unset_extra_dependency pkg_name) unset(${pkg_name}_EXTRA_DEPENDS CACHE) endfunction() # ------------------------------------------------------------------------------ # Activate/deactivate function(package_activate pkg_name) set(${pkg_name}_STATE ON CACHE INTERNAL "" FORCE) endfunction() function(package_deactivate pkg_name) set(${pkg_name}_STATE OFF CACHE INTERNAL "" FORCE) endfunction() function(package_is_activated pkg_name _act) if(DEFINED ${pkg_name}_STATE AND ${pkg_name}_STATE) set(${_act} TRUE PARENT_SCOPE) else() set(${_act} FALSE PARENT_SCOPE) endif() endfunction() function(package_is_deactivated pkg_name _act) if(DEFINED ${pkg_name}_STATE AND NOT ${pkg_name}_STATE) set(${_act} TRUE PARENT_SCOPE) else() set(${_act} FALSE PARENT_SCOPE) endif() endfunction() function(_package_unset_activated pkg_name) unset(${pkg_name}_STATE CACHE) endfunction() # ------------------------------------------------------------------------------ # Direct dependencies function(_package_set_dependencies pkg_name) set(${pkg_name}_DEPENDENCIES "${ARGN}" CACHE INTERNAL "List of dependencies for package ${_opt_name}" FORCE) endfunction() function(package_get_dependencies pkg_name dependencies) set(${dependencies} "${${pkg_name}_DEPENDENCIES}" PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Functions to handle reverse dependencies # ------------------------------------------------------------------------------ function(_package_set_rdependencies pkg_name) set(${pkg_name}_RDEPENDENCIES "${ARGN}" CACHE INTERNAL "Dependencies ON with package ${pkg_name}" FORCE) endfunction() function(package_get_rdependencies pkg_name RDEPENDENCIES) set(${RDEPENDENCIES} "${${pkg_name}_RDEPENDENCIES}" PARENT_SCOPE) endfunction() function(_package_add_rdependency pkg_name rdep) # store the reverse dependency set(_rdeps ${${pkg_name}_RDEPENDENCIES}) list(APPEND _rdeps ${rdep}) list(REMOVE_DUPLICATES _rdeps) _package_set_rdependencies(${pkg_name} ${_rdeps}) endfunction() function(_package_remove_rdependency pkg_name rdep) set(_rdeps ${${pkg_name}_RDEPENDENCIES}) list(FIND _rdeps ${rdep} pos) if(NOT pos EQUAL -1) list(REMOVE_AT _rdeps ${pos}) _package_set_rdependencies(${pkg_name} ${_rdeps}) endif() endfunction() # ------------------------------------------------------------------------------ # Function to handle forcing dependencies (Package turn ON that enforce their # dependencies ON) # ------------------------------------------------------------------------------ function(_package_set_fdependencies pkg_name) set(${pkg_name}_FDEPENDENCIES "${ARGN}" CACHE INTERNAL "Dependencies ON with package ${pkg_name}" FORCE) endfunction() function(package_get_fdependencies pkg_name fdependencies) set(${fdependencies} "${${pkg_name}_FDEPENDENCIES}" PARENT_SCOPE) endfunction() function(_package_add_fdependency pkg_name fdep) # store the enforcing dependency set(_fdeps ${${pkg_name}_FDEPENDENCIES}) list(APPEND _fdeps ${fdep}) list(REMOVE_DUPLICATES _fdeps) _package_set_fdependencies(${pkg_name} ${_fdeps}) endfunction() function(_package_remove_fdependency pkg_name fdep) set(_fdeps ${${pkg_name}_FDEPENDENCIES}) list(FIND _fdeps ${fdep} pos) if(NOT pos EQUAL -1) list(REMOVE_AT _fdeps ${pos}) _package_set_fdependencies(${pkg_name} ${_fdeps}) endif() endfunction() # ------------------------------------------------------------------------------ # Documentation related functions # ------------------------------------------------------------------------------ function(package_declare_documentation pkg) # \n replaced by && and \\ by ££ to avoid cache problems set(_doc_str "") foreach(_str ${ARGN}) set(_doc_str "${_doc_str}&&${_str}") endforeach() string(REPLACE "\\" "££" _doc_escaped "${_doc_str}") package_get_name(${pkg} _pkg_name) set(${_pkg_name}_DOCUMENTATION "${_doc_escaped}" CACHE INTERNAL "Latex doc of package ${pkg}" FORCE) endfunction() function(package_get_documentation pkg _doc) # \n replaced by && and \\ by ££ to avoid cache problems package_get_name(${pkg} _pkg_name) if (DEFINED ${_pkg_name}_DOCUMENTATION) set(_doc_tmp ${${_pkg_name}_DOCUMENTATION}) string(REPLACE "££" "\\" _doc_escaped "${_doc_tmp}") string(REPLACE "&&" "\n" _doc_newlines "${_doc_escaped}") set(${_doc} "${_doc_newlines}" PARENT_SCOPE) else() set(${_doc} "" PARENT_SCOPE) endif() endfunction() # ------------------------------------------------------------------------------ function(package_declare_documentation_files pkg) package_get_name(${pkg} _pkg_name) set(${_pkg_name}_DOCUMENTATION_FILES "${ARGN}" CACHE INTERNAL "Latex doc files for package ${pkg}" FORCE) endfunction() # ------------------------------------------------------------------------------ function(package_get_documentation_files pkg_name doc_files) if(DEFINED ${pkg_name}_DOCUMENTATION_FILES) set(${doc_files} ${${pkg_name}_DOCUMENTATION_FILES} PARENT_SCOPE) else() set(${doc_files} "" PARENT_SCOPE) endif() endfunction() # ============================================================================== # Internal functions # ============================================================================== # ------------------------------------------------------------------------------ # Build the reverse dependencies from the dependencies # ------------------------------------------------------------------------------ function(_package_build_rdependencies) string(TOUPPER ${PROJECT_NAME} _project) # set empty lists foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) set(${_pkg_name}_rdeps) endforeach() # fill the dependencies list foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) package_get_dependencies(${_pkg_name} _deps) foreach(_dep_name ${_deps}) list(APPEND ${_dep_name}_rdeps ${_pkg_name}) endforeach() endforeach() # clean and set the reverse dependencies foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) if(${_pkg_name}_rdeps) list(REMOVE_DUPLICATES ${_pkg_name}_rdeps) _package_set_rdependencies(${_pkg_name} ${${_pkg_name}_rdeps}) endif() endforeach() endfunction() # ------------------------------------------------------------------------------ # This function resolve the dependance order run the needed find_packages # ------------------------------------------------------------------------------ function(_package_load_packages) string(TOUPPER ${PROJECT_NAME} _project) foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) _package_unset_activated(${_pkg_name}) _package_unset_extra_dependency(${_pkg_name}) endforeach() # Activate the dependencies of activated package and generate an ordered list # of dependencies set(ordered_loading_list) foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) _package_load_dependencies_package(${_pkg_name} ordered_loading_list) endforeach() # Load the packages in the propoer order foreach(_pkg_name ${ordered_loading_list}) package_get_option_name(${_pkg_name} _option_name) package_is_deactivated(${_pkg_name} _deactivated) if(NOT _deactivated AND ${_option_name}) _package_load_package(${_pkg_name}) endif() endforeach() # generates the activated and unactivated lists of packages set(_packages_activated) set(_packages_deactivated) foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) package_is_activated(${_pkg_name} _act) if(_act) list(APPEND _packages_activated ${_pkg_name}) else() list(APPEND _packages_deactivated ${_pkg_name}) endif() endforeach() # generate the list usable by the calling code set(${_project}_ACTIVATED_PACKAGE_LIST "${_packages_activated}" CACHE INTERNAL "List of activated packages" FORCE) set(${_project}_DEACTIVATED_PACKAGE_LIST "${_packages_deactivated}" CACHE INTERNAL "List of deactivated packages" FORCE) endfunction() # ------------------------------------------------------------------------------ # This load an external package and recursively all its dependencies # ------------------------------------------------------------------------------ function(_package_load_dependencies_package pkg_name loading_list) # Get packages informations package_get_option_name(${pkg_name} _pkg_option_name) package_get_dependencies(${pkg_name} _dependencies) # handle the dependencies foreach(_dep_name ${_dependencies}) package_get_description(${_dep_name} _dep_desc) package_get_option_name(${_dep_name} _dep_option_name) package_get_fdependencies(${_dep_name} _fdeps) if(${_pkg_option_name}) if("${_fdeps}" STREQUAL "") set(${_dep_name}_OLD ${${_dep_option_name}} CACHE INTERNAL "" FORCE) endif() # set the option to on set(${_dep_option_name} ON CACHE BOOL "${_dep_desc}" FORCE) # store the reverse dependency _package_add_fdependency(${_dep_name} ${pkg_name}) else() # check if this is the last reverse dependency list(LENGTH _fdeps len) list(FIND _fdeps ${pkg_name} pos) if((len EQUAL 1) AND (NOT pos EQUAL -1)) set(${_dep_option_name} ${${_dep_name}_OLD} CACHE BOOL "${_dep_desc}" FORCE) unset(${_dep_name}_OLD CACHE) endif() # remove the pkg_name form the reverse dependency _package_remove_fdependency(${_dep_name} ${pkg_name}) endif() # recusively load the dependencies _package_load_dependencies_package(${_dep_name} ${loading_list}) endforeach() # get the compile flags package_get_compile_flags(${pkg_name} _pkg_comile_flags) # if package option is on add it in the list if(${_pkg_option_name}) list(FIND ${loading_list} ${pkg_name} _pos) if(_pos EQUAL -1) set(_tmp_loading_list ${${loading_list}}) list(APPEND _tmp_loading_list ${pkg_name}) set(${loading_list} "${_tmp_loading_list}" PARENT_SCOPE) endif() #add the comilation flags if needed if(_pkg_comile_flags) add_flags(cxx ${_pkg_comile_flags}) endif() else() # deactivate the packages than can already be deactivated package_deactivate(${pkg_name}) #remove the comilation flags if needed if(_pkg_comile_flags) remove_flags(cxx ${_pkg_comile_flags}) endif() endif() endfunction() # ------------------------------------------------------------------------------ # Load the package if it is an external one # ------------------------------------------------------------------------------ function(_package_load_package pkg_name) # load the package if it is an external package_get_nature(${pkg_name} _nature) if(${_nature} MATCHES "external") package_use_system(${pkg_name} _use_system) set(_activated TRUE) if(_use_system) _package_load_external_package(${pkg_name} _activated) endif() if(_activated) package_activate(${pkg_name}) elseif() package_deactivate(${pkg_name}) endif() else(${_nature}) package_activate(${pkg_name}) endif() endfunction() # ------------------------------------------------------------------------------ # Load external packages # ------------------------------------------------------------------------------ function(_package_load_external_package pkg_name activate) string(TOUPPER ${PROJECT_NAME} _project) package_get_extra_options(${pkg_name} _options) if(_options) cmake_parse_arguments(_opt_pkg "" "LANGUAGE" "PREFIX;FOUND;ARGS" ${_options}) if(_opt_pkg_UNPARSED_ARGUMENTS) message("You passed too many options for the find_package related to ${${pkg_name}} \"${_opt_pkg_UNPARSED_ARGUMENTS}\"") endif() endif() if(_opt_pkg_LANGUAGE) foreach(_language ${_opt_pkg_LANGUAGE}) enable_language(${_language}) endforeach() endif() package_get_real_name(${pkg_name} _real_name) # find the package find_package(${_real_name} REQUIRED ${_opt_pkg_ARGS}) # check if the package is found if(_opt_pkg_PREFIX) set(_package_prefix ${_opt_pkg_PREFIX}) else() string(TOUPPER ${${pkg_name}} _u_package) set(_package_prefix ${_u_package}) endif() set(_act FALSE) set(_prefix_to_consider) if(_opt_pkg_FOUND) set(_act TRUE) set(_prefix_to_consider ${_package_prefix}) else() foreach(_prefix ${_package_prefix}) if(${_prefix}_FOUND) set(_act TRUE) list(APPEND _prefix_to_consider ${_prefix}) endif() endforeach() endif() if(_act) foreach(_prefix ${_prefix_to_consider}) # Generate the include dir for the package if(DEFINED ${_prefix}_INCLUDE_DIRS) package_set_include_dir(${_pkg_name} ${${_prefix}_INCLUDE_DIRS}) elseif(DEFINED ${_prefix}_INCLUDE_DIR) package_set_include_dir(${_pkg_name} ${${_prefix}_INCLUDE_DIR}) elseif(DEFINED ${_prefix}_INCLUDE_PATH) package_set_include_dir(${_pkg_name} ${${_prefix}_INCLUDE_PATH}) endif() # Generate the libraries for the package - package_set_libraries(${_pkg_name} ${${_prefix}_LIBRARIES}) + if(DEFINED ${_prefix}_LIBRARIES) + package_set_libraries(${_pkg_name} ${${_prefix}_LIBRARIES}) + elseif(DEFINED ${_prefix}_LIBRARY) + package_set_libraries(${_pkg_name} ${${_prefix}_LIBRARY}) + endif() endforeach() endif() set(${activate} ${_act} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Sanity check functions # ------------------------------------------------------------------------------ function(_package_check_files_exists) string(TOUPPER ${PROJECT_NAME} _project) set(_message FALSE) foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) set(_pkg_files ${${_pkg_name}_SRCS} ${${_pkg_name}_PUBLIC_HEADERS} ${${_pkg_name}_PRIVATE_HEADERS} ) package_get_real_name(${_pkg_name} _real_name) foreach(_file ${_pkg_files}) if(NOT EXISTS "${_file}") if(NOT _message) set(_message TRUE) message("This file(s) is(are) present in a package but are not present on disk.") endif() message(" PACKAGE ${_real_name} FILE ${_file}") endif() endforeach() endforeach() if(_message) message(SEND_ERROR "Please check the content of your packages to correct this warnings") endif() endfunction() # ------------------------------------------------------------------------------ function(_package_check_files_registered) set(_pkg_files) # generates a file list of registered files foreach(_pkg_name ${${_project}_ALL_PACKAGES_LIST}) list(APPEND _pkg_files ${${_pkg_name}_SRCS} ${${_pkg_name}_PUBLIC_HEADERS} ${${_pkg_name}_PRIVATE_HEADERS} ) endforeach() # generates the list of files in the source folders set(_all_src_files) foreach(_src_folder ${ARGN}) foreach(_ext "cc" "hh" "c" "h" "hpp") file(GLOB_RECURSE _src_files "${_src_folder}/*.${_ext}") list(APPEND _all_src_files ${_src_files}) endforeach() endforeach() if(_all_src_files) list(REMOVE_DUPLICATES _all_src_files) endif() set(_not_registerd_files) # check only sources files ine the source folders foreach(_src_folder ${ARGN}) foreach(_file ${_all_src_files}) if("${_file}" MATCHES "${_src_folder}") list(FIND _pkg_files "${_file}" _index) if (_index EQUAL -1) list(APPEND _not_registerd_files ${_file}) endif() endif() endforeach() endforeach() if(AUTO_MOVE_UNKNOWN_FILES) file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/tmp/) endif() # warn the user and move the files if needed if(_not_registerd_files) if(EXISTS ${PROJECT_BINARY_DIR}/missing_files_in_packages) file(REMOVE ${PROJECT_BINARY_DIR}/missing_files_in_packages) endif() message("This files are present in the source folders but are not registered in any package") foreach(_file ${_not_registerd_files}) message(" ${_file}") if(AUTO_MOVE_UNKNOWN_FILES) get_filename_component(_file_name ${_file} NAME) file(RENAME ${_file} ${PROJECT_SOURCE_DIR}/tmp/${_file_name}) endif() file(APPEND ${PROJECT_BINARY_DIR}/missing_files_in_packages "${_file} ") endforeach() if(AUTO_MOVE_UNKNOWN_FILES) message(SEND_ERROR "The files where moved in the followinf folder ${PROJECT_SOURCE_DIR}/tmp/") endif() message(SEND_ERROR "Please register them in the good package or clean the sources") endif() endfunction() # ============================================================================== # User Functions # ============================================================================== # ------------------------------------------------------------------------------ # list all the packages in the PACKAGE_FOLDER # extra packages can be given with an EXTRA_PACKAGE_FOLDER # <package_folder>/<package>.cmake # # Extra packages folder structure # <extra_package_folder>/<package>/package.cmake # /src # /test # /manual # # ------------------------------------------------------------------------------ function(package_list_packages PACKAGE_FOLDER) cmake_parse_arguments(_opt_pkg "" "SOURCE_FOLDER;EXTRA_PACKAGES_FOLDER;TEST_FOLDER;MANUAL_FOLDER" "" ${ARGN}) string(TOUPPER ${PROJECT_NAME} _project) if(_opt_pkg_SOURCE_FOLDER) set(_src_folder "${_opt_pkg_SOURCE_FOLDER}") else() set(_src_folder "src/") endif() get_filename_component(_abs_src_folder ${_src_folder} ABSOLUTE) if(_opt_pkg_TEST_FOLDER) set(_test_folder "${_opt_pkg_TEST_FOLDER}") else() set(_test_folder "test/") endif() if(_opt_pkg_MANUAL_FOLDER) set(_manual_folder "${_opt_pkg_MANUAL_FOLDER}") else() set(_manual_folder "doc/manual") endif() get_filename_component(_abs_test_folder ${_test_folder} ABSOLUTE) get_filename_component(_abs_manual_folder ${_manual_folder} ABSOLUTE) # check all the packages in the <package_folder> file(GLOB _package_list "${PACKAGE_FOLDER}/*.cmake") set(_package_files) foreach(_pkg ${_package_list}) get_filename_component(_basename ${_pkg} NAME) list(APPEND _package_files ${_basename}) endforeach() if(_package_files) list(SORT _package_files) endif() # check all packages set(_packages_list_all) foreach(_pkg_file ${_package_files}) string(REGEX REPLACE "[0-9]+_" "" _pkg_file_stripped ${_pkg_file}) string(REGEX REPLACE "\\.cmake" "" _pkg ${_pkg_file_stripped}) package_get_name(${_pkg} _pkg_name) _package_set_filename(${_pkg_name} "${PACKAGE_FOLDER}/${_pkg_file}") _package_set_sources_folder(${_pkg_name} "${_abs_src_folder}") _package_set_tests_folder(${_pkg_name} "${_abs_test_folder}") _package_set_manual_folder(${_pkg_name} "${_abs_manual_folder}") list(APPEND _packages_list_all ${_pkg_name}) include("${PACKAGE_FOLDER}/${_pkg_file}") endforeach() # check the extra_packages if they exists if(_opt_pkg_EXTRA_PACKAGES_FOLDER) file(GLOB _extra_package_list RELATIVE "${_opt_pkg_EXTRA_PACKAGES_FOLDER}" "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/*") foreach(_pkg ${_extra_package_list}) if(EXISTS "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/package.cmake") package_get_name(${_pkg} _pkg_name) _package_set_filename(${_pkg_name} "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/package.cmake") _package_set_sources_folder(${_pkg_name} "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/src") if(EXISTS "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/test") _package_set_tests_folder(${_pkg_name} "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/test") endif() if(EXISTS "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/manual") _package_set_manual_folder(${_pkg_name} "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/manual") endif() list(APPEND _extra_pkg_src_folders "${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/src") list(APPEND _packages_list_all ${_pkg_name}) include("${_opt_pkg_EXTRA_PACKAGES_FOLDER}/${_pkg}/package.cmake") endif() endforeach() endif() # Store the list of packages string(TOUPPER ${PROJECT_NAME} _project) set(${_project}_ALL_PACKAGES_LIST ${_packages_list_all} CACHE INTERNAL "List of available packages" FORCE) _package_build_rdependencies() _package_load_packages() _package_check_files_exists() _package_check_files_registered(${_abs_src_folder} ${_extra_pkg_src_folders}) # Load boost components if boost was loaded package_get_name(Boost _boost_pkg) package_is_activated(${_boost_pkg} _ret) if(_ret) package_load_boost_components() endif() endfunction() # ------------------------------------------------------------------------------ # macro to include internal/external packages packages # package_declare(<package real name> # [EXTERNAL] [META] [ADVANCED] [NOT_OPTIONAL] # [DESCRIPTION <description>] [DEFAULT <default_value>] # [DEPENDS <pkg> ...] # [EXTRA_PACKAGE_OPTIONS <opt> ...] # [COMPILE_FLAGS <flags>]) # ------------------------------------------------------------------------------ function(package_declare PACKAGE) package_get_name(${PACKAGE} _pkg_name) _package_set_real_name(${_pkg_name} ${PACKAGE}) cmake_parse_arguments(_opt_pkg "EXTERNAL;NOT_OPTIONAL;META;ADVANCED" "DEFAULT;DESCRIPTION;SYSTEM" "DEPENDS;EXTRA_PACKAGE_OPTIONS;COMPILE_FLAGS" ${ARGN}) if(_opt_pkg_UNPARSED_ARGUMENTS) message("You gave to many arguments while registering the package ${PACKAGE} \"${_opt_pkg_UNPARSED_ARGUMENTS}\"") endif() # set description if(_opt_pkg_DESCRIPTION) _package_set_description(${_pkg_name} ${_opt_pkg_DESCRIPTION}) else() _package_set_description(${_pkg_name} "") endif() # set the nature if(_opt_pkg_EXTERNAL) _package_set_nature(${_pkg_name} "external") elseif(_opt_pkg_META) _package_set_nature(${_pkg_name} "meta") else() _package_set_nature(${_pkg_name} "internal") endif() package_get_option_name(${_pkg_name} _option_name) package_get_description(${_pkg_name} _description) # get the default value if(DEFINED _opt_pkg_DEFAULT) set(_default ${_opt_pkg_DEFAULT}) else() if(_opt_pkg_NOT_OPTIONAL) set(_default ON) else() set(_default OFF) endif() endif() # set the option if needed if(_opt_pkg_NOT_OPTIONAL) package_get_nature(${_pkg_name} _nature) _package_set_nature(${_pkg_name} "${_nature}_not_optional") set(${_option_name} ${_default} CACHE INTERNAL "${_description}" FORCE) else() option(${_option_name} "${_description}" ${_default}) if(_opt_pkg_ADVANCED OR _opt_pkg_EXTERNAL) mark_as_advanced(${_option_name}) endif() endif() # Set the option for third-partie that can be compiled as an ExternalProject if(DEFINED _opt_pkg_SYSTEM) _package_set_system_option(${_pkg_name} ${_opt_pkg_SYSTEM}) endif() # set the dependecies if(_opt_pkg_DEPENDS) set(_depends) foreach(_dep ${_opt_pkg_DEPENDS}) package_get_name(${_dep} _dep_pkg_name) list(APPEND _depends ${_dep_pkg_name}) endforeach() _package_set_dependencies(${_pkg_name} ${_depends}) package_get_dependencies(${_pkg_name} _deps) endif() # keep the extra option for the future find package if(_opt_pkg_EXTRA_PACKAGE_OPTIONS) _package_set_extra_options(${_pkg_name} "${_opt_pkg_EXTRA_PACKAGE_OPTIONS}") endif() # register the compilation flags if(_opt_pkg_COMPILE_FLAGS) _package_set_compile_flags(${_pkg_name} "${_opt_pkg_COMPILE_FLAGS}") endif() endfunction() # ------------------------------------------------------------------------------ # declare the source files of a given package # # package_declare_sources(<package> <list of sources> # SOURCES <source file> ... # PUBLIC_HEADER <header file> ... # PRIVATE_HEADER <header file> ...) # ------------------------------------------------------------------------------ function(package_declare_sources pkg) package_get_name(${pkg} _pkg_name) # get 3 lists, if none of the options given try to distinguish the different lists cmake_parse_arguments(_opt_pkg "" "" "SOURCES;PUBLIC_HEADERS;PRIVATE_HEADERS" ${ARGN}) set(_tmp_srcs ${_opt_pkg_SOURCES}) set(_tmp_pub_hdrs ${_opt_pkg_PUBLIC_HEADER}) set(_tmp_pri_hdrs ${_opt_pkg_PRIVATE_HEADERS}) foreach(_file ${_opt_pkg_UNPARSED_ARGUMENTS}) if(${_file} MATCHES ".*inline.*\\.cc") list(APPEND _tmp_pub_hdrs ${_file}) elseif(${_file} MATCHES ".*\\.h+") list(APPEND _tmp_pub_hdrs ${_file}) else() list(APPEND _tmp_srcs ${_file}) endif() endforeach() package_get_sources_folder(${_pkg_name} _src_folder) foreach(_type _srcs _pub_hdrs _pri_hdrs) set(${_type}) foreach(_file ${_tmp${_type}}) # get the full name list(APPEND ${_type} "${_src_folder}/${_file}") endforeach() endforeach() set(${_pkg_name}_SRCS "${_srcs}" CACHE INTERNAL "List of sources files" FORCE) set(${_pkg_name}_PUBLIC_HEADERS "${_pub_hdrs}" CACHE INTERNAL "List of public header files" FORCE) set(${_pkg_name}_PRIVATE_HEADERS "${_pri_hdrs}" CACHE INTERNAL "List of private header files" FORCE) endfunction() # ------------------------------------------------------------------------------ # get the list of source files for a given package # ------------------------------------------------------------------------------ function(package_get_source_files PKG SRCS PUBLIC_HEADERS PRIVATE_HEADERS) string(TOUPPER ${PROJECT_NAME} _project) set(tmp_SRCS) set(tmp_PUBLIC_HEADERS) set(tmp_PRIVATE_HEADERS) foreach(_type SRCS PUBLIC_HEADERS PRIVATE_HEADERS) foreach(_file ${${PKG}_${_type}}) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" _rel_file "${_file}") list(APPEND tmp_${_type} "${_rel_file}") endforeach() endforeach() # message(__tmp_SRCS ": " ${tmp_SRCS}) set(${SRCS} ${tmp_SRCS} PARENT_SCOPE) set(${PUBLIC_HEADERS} ${tmp_PUBLIC_HEADERS} PARENT_SCOPE) set(${PRIVATE_HEADERS} ${tmp_PRIVATE_HEADERS} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # get the list of source files # ------------------------------------------------------------------------------ function(package_get_all_source_files SRCS PUBLIC_HEADERS PRIVATE_HEADERS) string(TOUPPER ${PROJECT_NAME} _project) set(tmp_SRCS) set(tmp_PUBLIC_HEADERS) set(tmp_PRIVATE_HEADERS) foreach(_pkg_name ${${_project}_ACTIVATED_PACKAGE_LIST}) package_get_source_files(${_pkg_name} _tmp_SRCS _tmp_PUBLIC_HEADERS _tmp_PRIVATE_HEADERS) list(APPEND tmp_SRCS ${_tmp_SRCS}) list(APPEND tmp_PUBLIC_HEADERS ${tmp_PUBLIC_HEADERS}) list(APPEND tmp_PRIVATE_HEADERS ${tmp_PRIVATE_HEADERS}) endforeach() set(${SRCS} ${tmp_SRCS} PARENT_SCOPE) set(${PUBLIC_HEADERS} ${tmp_PUBLIC_HEADERS} PARENT_SCOPE) set(${PRIVATE_HEADERS} ${tmp_PRIVATE_HEADERS} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Get include directories # ------------------------------------------------------------------------------ function(package_get_all_include_directories inc_dirs) string(TOUPPER ${PROJECT_NAME} _project) set(_tmp) foreach(_pkg_name ${${_project}_ACTIVATED_PACKAGE_LIST}) foreach(_type SRCS PUBLIC_HEADERS PRIVATE_HEADERS) foreach(_file ${${_pkg_name}_${_type}}) get_filename_component(_path "${_file}" PATH) list(APPEND _tmp "${_path}") endforeach() endforeach() endforeach() list(REMOVE_DUPLICATES _tmp) set(${inc_dirs} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Get external libraries informations # ------------------------------------------------------------------------------ function(package_get_all_external_informations INCLUDE_DIR LIBRARIES) string(TOUPPER ${PROJECT_NAME} _project) set(tmp_INCLUDE_DIR) set(tmp_LIBRARIES) foreach(_pkg_name ${${_project}_ACTIVATED_PACKAGE_LIST}) package_get_nature(${_pkg_name} _nature) if(${_nature} MATCHES "external") package_get_include_dir(${_pkg_name} _inc) package_get_libraries (${_pkg_name} _lib) list(APPEND tmp_INCLUDE_DIR ${_inc}) list(APPEND tmp_LIBRARIES ${_lib}) endif() endforeach() set(${INCLUDE_DIR} ${tmp_INCLUDE_DIR} PARENT_SCOPE) set(${LIBRARIES} ${tmp_LIBRARIES} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Get definitions like external projects # ------------------------------------------------------------------------------ function(package_get_all_definitions definitions) set(_tmp) string(TOUPPER ${PROJECT_NAME} _project) foreach(_pkg_name ${${_project}_ACTIVATED_PACKAGE_LIST}) package_get_option_name(${_pkg_name} _option_name) list(APPEND _tmp ${_option_name}) endforeach() set(${definitions} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Get extra dependencies like external projects # ------------------------------------------------------------------------------ function(package_get_all_extra_dependency DEPS) string(TOUPPER ${PROJECT_NAME} _project) set(_tmp_DEPS) foreach(_pkg_name ${${_project}_ACTIVATED_PACKAGE_LIST}) package_get_extra_dependency(${_pkg_name} _dep) list(APPEND _tmp_DEPS ${_dep}) endforeach() if(_tmp_DEPS) list(REMOVE_DUPLICATES _tmp_DEPS) endif() set(${DEPS} ${_tmp_DEPS} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Get extra infos # ------------------------------------------------------------------------------ function(package_get_all_test_folders TEST_DIRS) string(TOUPPER ${PROJECT_NAME} _project) set(_tmp_TEST_DIRS) foreach(_pkg_name ${${_project}_ACTIVATED_PACKAGE_LIST}) package_get_tests_folder(${_pkg_name} _test_dir) list(APPEND _tmp_TEST_DIRS ${_test_dir}) endforeach() if(_tmp_TEST_DIRS) list(REMOVE_DUPLICATES _tmp_TEST_DIRS) endif() set(${TEST_DIRS} ${_tmp_TEST_DIRS} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ function(package_get_all_documentation_files doc_files) string(TOUPPER ${PROJECT_NAME} _project) set(_tmp_DOC_FILES) foreach(_pkg_name ${${_project}_ACTIVATED_PACKAGE_LIST}) package_get_manual_folder(${_pkg_name} _doc_dir) package_get_documentation_files(${_pkg_name} _doc_files) foreach(_doc_file ${_doc_files}) list(APPEND _tmp_DOC_FILES ${_doc_dir}/${_doc_file}) endforeach() endforeach() if(_tmp_DOC_FILES) list(REMOVE_DUPLICATES _tmp_DOC_FILES) endif() set(${doc_files} ${_tmp_DOC_FILES} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ function(package_get_all_activated_packages activated_list) string(TOUPPER ${PROJECT_NAME} _project) set(${activated_list} ${${_project}_ACTIVATED_PACKAGE_LIST} PARENT_SCOPE) endfunction() function(package_get_all_packages packages_list) string(TOUPPER ${PROJECT_NAME} _project) set(${packages_list} ${${_project}_ALL_PACKAGES_LIST} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Special boost thingy # ------------------------------------------------------------------------------ function(package_boost_component_needed) string(TOUPPER ${PROJECT_NAME} _project) set(_tmp ${${_project}_BOOST_COMPONENTS_NEEDED}) list(APPEND _tmp ${ARGN}) list(REMOVE_DUPLICATES _tmp) set(${_project}_BOOST_COMPONENTS_NEEDED ${_tmp} CACHE INTERNAL "List of Boost component needed by ${PROJECT_NAME}" FORCE) endfunction() function(package_load_boost_components) string(TOUPPER ${PROJECT_NAME} _project) package_get_name(Boost _pkg_name) if(${_project}_BOOST_COMPONENTS_NEEDED) message(STATUS "Looking for Boost liraries") foreach(_comp ${${_project}_BOOST_COMPONENTS_NEEDED}) find_package(Boost COMPONENTS ${_comp} QUIET) string(TOUPPER ${_comp} _u_comp) if(Boost_${_u_comp}_FOUND) message(STATUS " ${_comp}: FOUND") set(${_project}_BOOST_${_u_comp} TRUE CACHE INTERNAL "" FORCE) # Generate the libraries for the package package_set_libraries(${_pkg_name} ${Boost_${_u_comp}_LIBRARY}) else() message(STATUS " ${_comp}: NOT FOUND") endif() endforeach() endif() endfunction() diff --git a/packages/80_cpparray.cmake b/packages/80_cpparray.cmake index 94d6c5296..dadd0aade 100644 --- a/packages/80_cpparray.cmake +++ b/packages/80_cpparray.cmake @@ -1,83 +1,66 @@ #=============================================================================== # @file cpp_array.cmake # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date Mon Nov 21 18:19:15 2011 # # @brief package description for cpp_array project # # @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/>. # #=============================================================================== package_declare(CppArray EXTERNAL DESCRIPTION "Use cpp-array library" SYSTEM OFF) -if(AKANTU_USE_CPPARRAY AND AKANTU_USE_THIRD_PARTY_CPPARRAY) - find_package(Git) +package_get_name(CppArray _pkg_name) +package_use_system(${_pkg_name} _use_system) +package_get_option_name(${_pkg_name} _option_name) - if(GIT_FOUND) - if(EXISTS ${PROJECT_SOURCE_DIR}/third-party/cpp-array) - execute_process( - COMMAND ${GIT_EXECUTABLE} pull - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/third-party/cpp-array - OUTPUT_VARIABLE _revision) - message(STATUS "Updating Cpp-Array") - else() - message(STATUS "Cloning Cpp-Array") - execute_process( - COMMAND ${GIT_EXECUTABLE} clone https://code.google.com/p/cpp-array.git ${PROJECT_SOURCE_DIR}/third-party/cpp-array - OUTPUT_QUIET) +if(NOT ${_use_system}) + if(${_option_name}) + if(TARGET cpparray) + return() endif() - endif() - - if(EXISTS ${PROJECT_SOURCE_DIR}/third-party/cpp-array/) - set(cpp-array_TESTS OFF CACHE BOOL "cpparray tests" FORCE) - add_subdirectory(${PROJECT_SOURCE_DIR}/third-party/cpp-array/) - set(cpp-array_TESTS OFF CACHE BOOL "cpparray tests" FORCE) - mark_as_advanced(cpp-array_DEV) - mark_as_advanced(cpp-array_DOCUMENTATION) - mark_as_advanced(cpp-array_TESTS) - mark_as_advanced(CUDA) - mark_as_advanced(ARRAY_USER_LIB_PATH) + set(CPPARRAY_DIR ${PROJECT_BINARY_DIR}/third-party) - list(APPEND AKANTU_EXTERNAL_LIB_INCLUDE_DIR ${cpp-array_INCLUDE_DIRS} ${CPP-ARRAY_INCLUDE_DIRS}) - list(APPEND AKANTU_EXTERNAL_LIBRARIES ${CPP-ARRAY_LIBRARIES}) - list(APPEND AKANTU_EXTERNAL_LIB_INCLUDE_DIR ${CPP-ARRAY_INCLUDE_DIRS}) - list(APPEND CPACK_SOURCE_IGNORE_FILES ${PROJECT_SOURCE_DIR}/third-party/cpp-array/) - set(AKANTU_CPPARRAY_INCLUDE_DIR ${cpp-array_INCLUDE_DIRS} ${CPP-ARRAY_INCLUDE_DIRS}) + include(ExternalProject) + ExternalProject_Add(cpparray + PREFIX ${CPPARRAY_DIR} + GIT_REPOSITORY https://code.google.com/p/cpp-array.git + CMAKE_ARGS <SOURCE_DIR>/cpp-array + CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -Dcpp-array_TESTS:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_COMPILER:PATH=${CMAKE_CXX_COMPILER} -DCMAKE_Fortran_COMPILER:PATH=${CMAKE_Fortran_COMPILER} + ) + set(CPPARRAY_INCLUDE_DIR ${CPPARRAY_DIR}/include CACHE PATH "" FORCE) - set(AKANTU_CPPARRAY ON) - list(APPEND AKANTU_OPTION_LIST CPPARRAY) - set(AKANTU_CPPARRAY ${AKANTU_CPPARRAY} CACHE INTERNAL "Use cpp-array library" FORCE) - else() - message(STATUS "Cpp-Array could not be found! Please install git and/or place cpp-array in the third-party folder of Akantu") + package_set_include_dir(${_pkg_name} ${CPPARRAY_INCLUDE_DIR}) + package_add_extra_dependency(CppArray cpparray) endif() endif() package_declare_documentation(CppArray "This package provides access to the \\href{https://code.google.com/p/cpp-array/}{cpp-array}" "open-source project. If internet is accessible when configuring the project (during cmake call)" "this package will be auto-downloaded." ) diff --git a/packages/80_nlopt.cmake b/packages/80_nlopt.cmake index c506d4dd9..2f6269bc0 100644 --- a/packages/80_nlopt.cmake +++ b/packages/80_nlopt.cmake @@ -1,79 +1,82 @@ #=============================================================================== # @file 80_nlopt.cmake # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Thu Jun 05 2014 # @date last modification: Thu Sep 18 2014 # # @brief package for the opitmization library NLopt # # @section LICENSE # # Copyright (©) 2014 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(nlopt EXTERNAL DESCRIPTION "Use NLOPT library" SYSTEM OFF) -set(NLOPT_VERSION "2.4.2") -set(NLOPT_ARCHIVE "${PROJECT_SOURCE_DIR}/third-party/nlopt-${NLOPT_VERSION}.tar.gz") -set(NLOPT_ARCHIVE_HASH "MD5=d0b8f139a4acf29b76dbae69ade8ac54") -if(NOT EXISTS ${NLOPT_ARCHIVE}) - set(NLOPT_ARCHIVE "http://ab-initio.mit.edu/nlopt/nlopt-${NLOPT_VERSION}.tar.gz") -endif() +package_get_name(nlopt _pkg_name) +package_use_system(${_pkg_name} _use_system) -if (AKANTU_USE_THIRD_PARTY_NLOPT AND AKANTU_USE_NLOPT) - set(NLOPT_CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR> --enable-shared --with-cxx) - set(NLOPT_DIR ${PROJECT_BINARY_DIR}/third-party) +if(NOT ${_use_system}) + package_get_option_name(${_pkg_name} _option_name) - include(ExternalProject) + if(${_option_name}) + set(NLOPT_VERSION "2.4.2") + set(NLOPT_ARCHIVE "${PROJECT_SOURCE_DIR}/third-party/nlopt-${NLOPT_VERSION}.tar.gz") + set(NLOPT_ARCHIVE_HASH "MD5=d0b8f139a4acf29b76dbae69ade8ac54") + if(NOT EXISTS ${NLOPT_ARCHIVE}) + set(NLOPT_ARCHIVE "http://ab-initio.mit.edu/nlopt/nlopt-${NLOPT_VERSION}.tar.gz") + endif() - ExternalProject_Add(NLopt - PREFIX ${NLOPT_DIR} - URL ${NLOPT_ARCHIVE} - URL_HASH ${NLOPT_ARCHIVE_HASH} - CONFIGURE_COMMAND ${NLOPT_CONFIGURE_COMMAND} - BUILD_COMMAND make - INSTALL_COMMAND make install - ) + string(TOUPPER "${CMAKE_BUILD_TYPE}" _u_build_type) + set(NLOPT_CONFIGURE_COMMAND CXX=${CMAKE_CXX_COMPILER} CXX_FLAGS=${CMAKE_CXX_FLAGS_${_u_build_type}} <SOURCE_DIR>/configure + --prefix=<INSTALL_DIR> --enable-shared --with-cxx --without-threadlocal + --without-guile --without-python --without-octave --without-matlab) + set(NLOPT_DIR ${PROJECT_BINARY_DIR}/third-party) - set(NLOPT_LIBRARIES ${NLOPT_DIR}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}nlopt_cxx${CMAKE_SHARED_LIBRARY_SUFFIX} CACHE PATH "Libraries for NLopt" FORCE) - set(NLOPT_INCLUDE_DIR ${NLOPT_DIR}/include CACHE PATH "Include directories for NLopt" FORCE) + include(ExternalProject) - mark_as_advanced(NLOPT_INCLUDE_DIR NLOPT_LIBRARIES) + ExternalProject_Add(NLopt + PREFIX ${NLOPT_DIR} + URL ${NLOPT_ARCHIVE} + URL_HASH ${NLOPT_ARCHIVE_HASH} + CONFIGURE_COMMAND ${NLOPT_CONFIGURE_COMMAND} + BUILD_COMMAND make + INSTALL_COMMAND make install + ) - list(APPEND AKANTU_EXTERNAL_LIBRARIES ${NLOPT_LIBRARIES}) - list(APPEND AKANTU_EXTERNAL_LIB_INCLUDE_DIR ${NLOPT_INCLUDE_DIR}) - set(AKANTU_NLOPT_INCLUDE_DIR ${NLOPT_INCLUDE_DIR}) - set(AKANTU_NLOPT_LIBRARIES ${NLOPT_LIBRARIES}) - list(APPEND AKANTU_OPTION_LIST NLOPT) - set(NLOPT_FOUND TRUE CACHE INTERNAL "" FORCE) - set(AKANTU_NLOPT ON) + set_third_party_shared_libirary_name(NLOPT_LIBRARIES nlopt_cxx) + set(NLOPT_INCLUDE_DIR ${NLOPT_DIR}/include CACHE PATH "Include directories for NLopt" FORCE) + mark_as_advanced(NLOPT_INCLUDE_DIR) - list(APPEND AKANTU_EXTRA_TARGET_DEPENDENCIES NLopt) -endif() + package_set_libraries(${_pkg_name} ${NLOPT_LIBRARIES}) + package_set_include_dir(${_pkg_name} ${NLOPT_INCLUDE_DIR}) + package_add_extra_dependency(nlopt NLopt) + endif() +endif() package_declare_documentation(nlopt "This package enable the use of the optimization alogorithm library \\href{http://ab-initio.mit.edu/wiki/index.php/NLopt}{NLopt}." "Since there are no packaging for the common operating system by default \\akantu compiles it as a third-party project. This behavior can be modified with the option \\code{AKANTU\\_USE\\_THIRD\\_PARTY\\_NLOPT}." "" "If the automated download fails please download \\href{http://ab-initio.mit.edu/nlopt/nlopt-${NLOPT_VERSION}.tar.gz}{nlopt-${NLOPT_VERSION}.tar.gz} and place it in \\shellcode{<akantu source>/third-party} download." ) diff --git a/packages/84_petsc.cmake b/packages/84_petsc.cmake index 46623d851..6412f42ab 100644 --- a/packages/84_petsc.cmake +++ b/packages/84_petsc.cmake @@ -1,51 +1,46 @@ #=============================================================================== # @file petsc.cmake # # @author Nicolas Richart <nicolas.richart@epfl.ch> # @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> # @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> # # @date Mon Nov 21 18:19:15 2011 # # @brief package description for PETSc support # # @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/>. # #=============================================================================== package_declare(PETSc EXTERNAL DESCRIPTION "Add PETSc support in akantu" EXTRA_PACKAGE_OPTIONS ARGS COMPONENTS CXX DEPENDS parallel) package_declare_sources(petsc solver/petsc_matrix.hh solver/petsc_matrix.cc solver/petsc_matrix_inline_impl.cc solver/solver_petsc.hh solver/solver_petsc.cc solver/petsc_wrapper.hh ) -set(AKANTU_PETSC_TESTS - test_petsc_matrix_profile - test_petsc_matrix_apply_boundary - test_solver_petsc - ) diff --git a/src/common/aka_fwd.hh b/src/common/aka_fwd.hh index c452445fa..d5c0c4a99 100644 --- a/src/common/aka_fwd.hh +++ b/src/common/aka_fwd.hh @@ -1,71 +1,70 @@ /** * @file aka_fwd.hh * * @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jan 04 2013 * @date last modification: Mon Jun 02 2014 * * @brief File containing forward declarations in akantu. * This file helps if circular #include would be needed because two classes * refer both to each other. This file usually does not need any modification. * * @section LICENSE * * Copyright (©) 2014 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_FWD_HH__ #define __AKANTU_FWD_HH__ namespace cppargparse { class ArgumentParser; } namespace akantu { - // forward declaration template <int dim, class model_type> struct ContactData; - + template<typename T> class Matrix; template<typename T> class Vector; template<typename T> class Tensor3; template<typename T, bool is_scal = is_scalar<T>::value > class Array; template <class T> class SpatialGrid; // Model element template <class ModelPolicy> class ModelElement; extern const Array<UInt> empty_filter; class Parser; class ParserSection; extern Parser static_parser; extern cppargparse::ArgumentParser static_argparser; } #endif /* __AKANTU_FWD_HH__ */ diff --git a/src/fe_engine/fe_engine.hh b/src/fe_engine/fe_engine.hh index 61ee2f43b..c24dd3a79 100644 --- a/src/fe_engine/fe_engine.hh +++ b/src/fe_engine/fe_engine.hh @@ -1,393 +1,398 @@ /** * @file fe_engine.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 20 2010 * @date last modification: Mon Jul 07 2014 * * @brief FEM class * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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_FE_ENGINE_HH__ #define __AKANTU_FE_ENGINE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "mesh.hh" #include "element_class.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Integrator; class ShapeFunctions; } __BEGIN_AKANTU__ class QuadraturePoint : public Element { public: typedef Vector<Real> position_type; public: + QuadraturePoint(const Element & element, UInt num_point = 0, UInt nb_quad_per_element = 0) : + Element(element), num_point(num_point), + global_num(element.element*nb_quad_per_element + num_point), + position((Real *)NULL, 0) { }; + QuadraturePoint(ElementType type = _not_defined, UInt element = 0, UInt num_point = 0, GhostType ghost_type = _not_ghost) : Element(type, element, ghost_type), num_point(num_point), global_num(0), position((Real *)NULL, 0) { }; QuadraturePoint(UInt element, UInt num_point, UInt global_num, const position_type & position, ElementType type, GhostType ghost_type = _not_ghost) : Element(type, element, ghost_type), num_point(num_point), global_num(global_num), position((Real *)NULL, 0) { this->position.shallowCopy(position); }; QuadraturePoint(const QuadraturePoint & quad) : Element(quad), num_point(quad.num_point), global_num(quad.global_num), position((Real *) NULL, 0) { position.shallowCopy(quad.position); }; inline QuadraturePoint & operator=(const QuadraturePoint & q) { if(this != &q) { element = q.element; type = q.type; ghost_type = q.ghost_type; num_point = q.num_point; global_num = q.global_num; position.shallowCopy(q.position); } return *this; } AKANTU_GET_MACRO(Position, position, const position_type &); void setPosition(const position_type & position) { this->position.shallowCopy(position); } /// 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 << space << "QuadraturePoint ["; Element::printself(stream, 0); stream << ", " << num_point << "]"; } public: UInt num_point; UInt global_num; private: position_type position; }; /** * The generic FEEngine class derived in a FEEngineTemplate class containing the * shape functions and the integration method */ class FEEngine : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: FEEngine(Mesh & mesh, UInt spatial_dimension = _all_dimensions, ID id = "fem", MemoryID memory_id = 0); virtual ~FEEngine(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// pre-compute all the shape functions, their derivatives and the jacobians virtual void initShapeFunctions(const GhostType & ghost_type = _not_ghost) = 0; /// extract the nodal values and store them per element template<typename T> static void extractNodalToElementField(const Mesh & mesh, const Array<T> & nodal_f, Array<T> & elemental_f, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter); /// filter a field template<typename T> static void filterElementalData(const Mesh & mesh, const Array<T> & quad_f, Array<T> & filtered_f, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter); /* ------------------------------------------------------------------------ */ /* Integration method bridges */ /* ------------------------------------------------------------------------ */ /// integrate f for all elements of type "type" virtual void integrate(const Array<Real> & f, Array<Real> &intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// integrate a scalar value on all elements of type "type" virtual Real integrate(const Array<Real> & f, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// integrate f for all quadrature points of type "type" but don't sum over all quadrature points virtual void integrateOnQuadraturePoints(const Array<Real> & f, Array<Real> &intf, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; /// integrate one element scalar value on all elements of type "type" virtual Real integrate(const Vector<Real> & f, const ElementType & type, UInt index, const GhostType & ghost_type = _not_ghost) const = 0; /* ------------------------------------------------------------------------ */ /* compatibility with old FEEngine fashion */ /* ------------------------------------------------------------------------ */ #ifndef SWIG /// get the number of quadrature points virtual UInt getNbQuadraturePoints(const ElementType & type, const GhostType & ghost_type = _not_ghost) const = 0; /// get the precomputed shapes const virtual Array<Real> & getShapes(const ElementType & type, const GhostType & ghost_type = _not_ghost, UInt id = 0) const = 0; /// get the derivatives of shapes const virtual Array<Real> & getShapesDerivatives(const ElementType & type, const GhostType & ghost_type = _not_ghost, UInt id = 0) const = 0; /// get quadrature points const virtual Matrix<Real> & getQuadraturePoints(const ElementType & type, const GhostType & ghost_type = _not_ghost) const = 0; #endif /* ------------------------------------------------------------------------ */ /* Shape method bridges */ /* ------------------------------------------------------------------------ */ virtual void gradientOnQuadraturePoints(const Array<Real> &u, Array<Real> &nablauq, const UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; virtual void interpolateOnQuadraturePoints(const Array<Real> &u, Array<Real> &uq, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const = 0; virtual void interpolateOnQuadraturePoints(const Array<Real> & u, ElementTypeMapArray<Real> & uq, const ElementTypeMapArray<UInt> * filter_elements = NULL) const = 0; /* ------------------------------------------------------------------------ */ /* Other methods */ /* ------------------------------------------------------------------------ */ /// pre-compute normals on control points virtual void computeNormalsOnControlPoints(const GhostType & ghost_type = _not_ghost) = 0; /// pre-compute normals on control points virtual void computeNormalsOnControlPoints(__attribute__((unused)) const Array<Real> & field, __attribute__((unused)) const GhostType & ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// pre-compute normals on control points virtual void computeNormalsOnControlPoints(__attribute__((unused)) const Array<Real> & field, __attribute__((unused)) Array<Real> & normal, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type = _not_ghost) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// assemble vectors void assembleArray(const Array<Real> & elementary_vect, Array<Real> & nodal_values, const Array<Int> & equation_number, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter, Real scale_factor = 1) const; /// assemble matrix in the complete sparse matrix void assembleMatrix(const Array<Real> & elementary_mat, SparseMatrix & matrix, UInt nb_degree_of_freedom, const ElementType & type, const GhostType & ghost_type = _not_ghost, const Array<UInt> & filter_elements = empty_filter) const; /// assemble a field as a lumped matrix (ex. rho in lumped mass) virtual void assembleFieldLumped(__attribute__ ((unused)) const Array<Real> & field_1, __attribute__ ((unused)) UInt nb_degree_of_freedom, __attribute__ ((unused)) Array<Real> & lumped, __attribute__ ((unused)) const Array<Int> & equation_number, __attribute__ ((unused)) ElementType type, __attribute__ ((unused)) const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); }; /// assemble a field as a matrix (ex. rho to mass matrix) virtual void assembleFieldMatrix(__attribute__ ((unused)) const Array<Real> & field_1, __attribute__ ((unused)) UInt nb_degree_of_freedom, __attribute__ ((unused)) SparseMatrix & matrix, __attribute__ ((unused)) ElementType type, __attribute__ ((unused)) const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); } #ifdef AKANTU_STRUCTURAL_MECHANICS virtual void assembleFieldMatrix(__attribute__ ((unused)) const Array<Real> & field_1, __attribute__ ((unused)) UInt nb_degree_of_freedom, __attribute__ ((unused)) SparseMatrix & M, __attribute__ ((unused)) Array<Real> * n, __attribute__ ((unused)) ElementTypeMapArray<Real> & rotation_mat, __attribute__ ((unused)) ElementType type, __attribute__ ((unused)) const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); } virtual void computeShapesMatrix(__attribute__ ((unused))const ElementType & type, __attribute__ ((unused))UInt nb_degree_of_freedom, __attribute__ ((unused))UInt nb_nodes_per_element, __attribute__ ((unused))Array<Real> * n, __attribute__ ((unused))UInt id, __attribute__ ((unused))UInt degree_to_interpolate, __attribute__ ((unused))UInt degree_interpolated, __attribute__ ((unused))const bool sign, __attribute__ ((unused))const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); } #endif /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; private: /// initialise the class void init(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the dimension of the element handeled by this fe_engine object AKANTU_GET_MACRO(ElementDimension, element_dimension, UInt); /// get the mesh contained in the fem object AKANTU_GET_MACRO(Mesh, mesh, const Mesh &); /// get the mesh contained in the fem object AKANTU_GET_MACRO_NOT_CONST(Mesh, mesh, Mesh &); /// get the in-radius of an element static inline Real getElementInradius(const Matrix<Real> & coord, const ElementType & type); /// get the normals on quadrature points AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(NormalsOnQuadPoints, normals_on_quad_points, Real); /// get cohesive element type for a given facet type static inline ElementType getCohesiveElementType(const ElementType & type_facet); /// get the interpolation element associated to an element type static inline InterpolationType getInterpolationType(const ElementType & el_type); virtual const ShapeFunctions & getShapeFunctionsInterface() const = 0; virtual const Integrator & getIntegratorInterface() const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// spatial dimension of the problem UInt element_dimension; /// the mesh on which all computation are made Mesh & mesh; /// normals at quadrature points ElementTypeMapArray<Real> normals_on_quad_points; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const FEEngine & _this) { _this.printself(stream); return stream; } /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const QuadraturePoint & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #include "fe_engine_inline_impl.cc" #include "fe_engine_template.hh" #endif /* __AKANTU_FE_ENGINE_HH__ */ diff --git a/src/io/dumper/dumper_material_padders.hh b/src/io/dumper/dumper_material_padders.hh index a54fad56f..db4a43bb2 100644 --- a/src/io/dumper/dumper_material_padders.hh +++ b/src/io/dumper/dumper_material_padders.hh @@ -1,168 +1,167 @@ /** * @file dumper_material_padders.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Sep 02 2014 * @date last modification: Fri Sep 19 2014 * * @brief Material padders for plane stress/ plane strain * * @section LICENSE * * Copyright (©) 2014 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_DUMPER_MATERIAL_PADDERS_HH__ #define __AKANTU_DUMPER_MATERIAL_PADDERS_HH__ /* -------------------------------------------------------------------------- */ #include "dumper_padding_helper.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template<class T, class R> class MaterialPadder : public PadderGeneric<Vector<T>, R > { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialPadder(const SolidMechanicsModel & model) : model(model), - element_index_by_material(model.getElementIndexByMaterial()) { } + material_index(model.getMaterialByElement()) {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ /// return the material from the global element index const Material & getMaterialFromGlobalIndex(Element global_index){ UInt index = global_index.getIndex(); - UInt material_id = element_index_by_material(global_index.getType())(index); + UInt material_id = material_index(global_index.getType())(index); const Material & material = model.getMaterial(material_id); return material; } /// return the type of the element from global index ElementType getElementTypeFromGlobalIndex(Element global_index){ return global_index.getType(); } protected: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ /// all material padders probably need access to solid mechanics model const SolidMechanicsModel & model; /// they also need an access to the map from global ids to material id and local ids - const ElementTypeMapArray<UInt> & element_index_by_material; + const ElementTypeMapArray<UInt> & material_index; + /// the number of data per element const ElementTypeMapArray<UInt> nb_data_per_element; }; /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> class StressPadder : public MaterialPadder<Real,Matrix<Real> > { public: StressPadder(const SolidMechanicsModel & model) : MaterialPadder<Real, Matrix<Real> >(model){ this->setPadding(3,3); } inline Matrix<Real> func(const Vector<Real> & in, Element global_element_id){ - UInt nrows = spatial_dimension; UInt ncols = in.size() / nrows; - UInt nb_data = in.size() / (ncols*ncols); + UInt nb_data = in.size() / (nrows*nrows); Matrix<Real> stress = this->pad(in, nrows,ncols, nb_data); const Material & material = this->getMaterialFromGlobalIndex(global_element_id); bool plane_strain = true; if(spatial_dimension == 2) plane_strain = !material.getParam<bool>("Plane_Stress"); if(plane_strain) { Real nu = material.getParam<Real>("nu"); for (UInt d = 0; d < nb_data; ++d) { stress(2, 2 + 3*d) = nu * (stress(0, 0 + 3*d) + stress(1, 1 + 3*d)); } } return stress; } UInt getDim(){return 9;}; UInt getNbComponent(UInt old_nb_comp){ return this->getDim(); }; - }; /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class StrainPadder : public MaterialPadder<Real, Matrix<Real> > { public: StrainPadder(const SolidMechanicsModel & model) : MaterialPadder<Real, Matrix<Real> >(model) { this->setPadding(3,3); } inline Matrix<Real> func(const Vector<Real> & in, Element global_element_id){ UInt nrows = spatial_dimension; UInt ncols = in.size() / nrows; UInt nb_data = in.size() / ncols; Matrix<Real> strain = this->pad(in, nrows,ncols, nb_data); const Material & material = this->getMaterialFromGlobalIndex(global_element_id); bool plane_stress = material.getParam<bool>("Plane_Stress"); if(plane_stress) { Real nu = material.getParam<Real>("nu"); for (UInt d = 0; d < nb_data; ++d) { strain(2, 2 + 3*d) = nu / (nu - 1) * (strain(0, 0 + 3*d) + strain(1, 1 + 3*d)); } } return strain; } UInt getDim(){return 9;}; UInt getNbComponent(UInt old_nb_comp){ return this->getDim(); }; }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ __END_AKANTU__ #endif /* __AKANTU_DUMPER_MATERIAL_PADDERS_HH__ */ diff --git a/src/model/solid_mechanics/fragment_manager.cc b/src/model/solid_mechanics/fragment_manager.cc index 2516987f5..a571afa86 100644 --- a/src/model/solid_mechanics/fragment_manager.cc +++ b/src/model/solid_mechanics/fragment_manager.cc @@ -1,644 +1,646 @@ /** * @file fragment_manager.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Thu Jan 23 2014 * @date last modification: Tue Aug 19 2014 * * @brief Group manager to handle fragments * * @section LICENSE * * Copyright (©) 2014 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 "fragment_manager.hh" #include "material_cohesive.hh" #include <numeric> #include <algorithm> #include <functional> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ FragmentManager::FragmentManager(SolidMechanicsModelCohesive & model, bool dump_data, const ID & id, const MemoryID & memory_id) : GroupManager(model.getMesh(), id, memory_id), model(model), mass_center(0, model.getSpatialDimension(), "mass_center"), mass(0, model.getSpatialDimension(), "mass"), velocity(0, model.getSpatialDimension(), "velocity"), inertia_moments(0, model.getSpatialDimension(), "inertia_moments"), principal_directions(0, model.getSpatialDimension() * model.getSpatialDimension(), "principal_directions"), quad_coordinates("quad_coordinates", id), mass_density("mass_density", id), nb_elements_per_fragment(0, 1, "nb_elements_per_fragment"), dump_data(dump_data) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); /// compute quadrature points' coordinates mesh.initElementTypeMapArray(quad_coordinates, spatial_dimension, spatial_dimension, _not_ghost); model.getFEEngine().interpolateOnQuadraturePoints(model.getMesh().getNodes(), quad_coordinates); /// store mass density per quadrature point mesh.initElementTypeMapArray(mass_density, 1, spatial_dimension, _not_ghost); storeMassDensityPerQuadraturePoint(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ class CohesiveElementFilter : public GroupManager::ClusteringFilter { public: CohesiveElementFilter(const SolidMechanicsModelCohesive & model, const Real max_damage = 1.) : model(model), is_unbroken(max_damage) {} bool operator() (const Element & el) const { if (el.kind == _ek_regular) return true; - const Array<UInt> & el_id_by_mat = model.getElementIndexByMaterial(el.type, - el.ghost_type); + const Array<UInt> & mat_indexes = model.getMaterialByElement(el.type, + el.ghost_type); + const Array<UInt> & mat_loc_num = model.getMaterialLocalNumbering(el.type, + el.ghost_type); const MaterialCohesive & mat = static_cast<const MaterialCohesive &> - (model.getMaterial(el_id_by_mat(el.element, 0))); + (model.getMaterial(mat_indexes(el.element))); - UInt el_index = el_id_by_mat(el.element, 1); + UInt el_index = mat_loc_num(el.element); UInt nb_quad_per_element = model.getFEEngine("CohesiveFEEngine").getNbQuadraturePoints(el.type, el.ghost_type); const Array<Real> & damage_array = mat.getDamage(el.type, el.ghost_type); AKANTU_DEBUG_ASSERT(nb_quad_per_element * el_index < damage_array.getSize(), "This quadrature point is out of range"); const Real * element_damage = damage_array.storage() + nb_quad_per_element * el_index; UInt unbroken_quads = std::count_if(element_damage, element_damage + nb_quad_per_element, is_unbroken); if (unbroken_quads > 0) return true; return false; } private: struct IsUnbrokenFunctor { IsUnbrokenFunctor(const Real & max_damage) : max_damage(max_damage) {} bool operator() (const Real & x) {return x < max_damage;} const Real max_damage; }; const SolidMechanicsModelCohesive & model; const IsUnbrokenFunctor is_unbroken; }; /* -------------------------------------------------------------------------- */ void FragmentManager::buildFragments(Real damage_limit) { AKANTU_DEBUG_IN(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) DistributedSynchronizer * cohesive_synchronizer = const_cast<DistributedSynchronizer *>(model.getCohesiveSynchronizer()); if (cohesive_synchronizer) { cohesive_synchronizer->computeBufferSize(model, _gst_smmc_damage); cohesive_synchronizer->asynchronousSynchronize(model, _gst_smmc_damage); cohesive_synchronizer->waitEndSynchronize(model, _gst_smmc_damage); } #endif DistributedSynchronizer & synchronizer = const_cast<DistributedSynchronizer &>(model.getSynchronizer()); Mesh & mesh_facets = const_cast<Mesh &>(mesh.getMeshFacets()); UInt spatial_dimension = model.getSpatialDimension(); std::string fragment_prefix("fragment"); /// generate fragments global_nb_fragment = createClusters(spatial_dimension, fragment_prefix, CohesiveElementFilter(model, damage_limit), &synchronizer, &mesh_facets); nb_fragment = getNbElementGroups(spatial_dimension); fragment_index.resize(nb_fragment); UInt * fragment_index_it = fragment_index.storage(); /// loop over fragments for(const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { /// get fragment index std::string fragment_index_string = it->first.substr(fragment_prefix.size() + 1); std::stringstream sstr(fragment_index_string.c_str()); sstr >> *fragment_index_it; AKANTU_DEBUG_ASSERT(!sstr.fail(), "fragment_index is not an integer"); } /// compute fragments' mass computeMass(); if (dump_data) { createDumpDataArray(fragment_index, "fragments", true); createDumpDataArray(mass, "fragments mass"); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeMass() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); /// create a unit field per quadrature point, since to compute mass /// it's neccessary to integrate only density ElementTypeMapArray<Real> unit_field("unit_field", id); mesh.initElementTypeMapArray(unit_field, spatial_dimension, spatial_dimension, _not_ghost); ElementTypeMapArray<Real>::type_iterator it = unit_field.firstType(spatial_dimension, _not_ghost, _ek_regular); ElementTypeMapArray<Real>::type_iterator end = unit_field.lastType(spatial_dimension, _not_ghost, _ek_regular); for (; it != end; ++it) { ElementType type = *it; Array<Real> & field_array = unit_field(type); UInt nb_element = mesh.getNbElement(type); UInt nb_quad_per_element = model.getFEEngine().getNbQuadraturePoints(type); field_array.resize(nb_element * nb_quad_per_element); field_array.set(1.); } integrateFieldOnFragments(unit_field, mass); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeCenterOfMass() { AKANTU_DEBUG_IN(); /// integrate position multiplied by density integrateFieldOnFragments(quad_coordinates, mass_center); /// divide it by the fragments' mass Real * mass_storage = mass.storage(); Real * mass_center_storage = mass_center.storage(); UInt total_components = mass_center.getSize() * mass_center.getNbComponent(); for (UInt i = 0; i < total_components; ++i) mass_center_storage[i] /= mass_storage[i]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeVelocity() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); /// compute velocity per quadrature point ElementTypeMapArray<Real> velocity_field("velocity_field", id); mesh.initElementTypeMapArray(velocity_field, spatial_dimension, spatial_dimension, _not_ghost); model.getFEEngine().interpolateOnQuadraturePoints(model.getVelocity(), velocity_field); /// integrate on fragments integrateFieldOnFragments(velocity_field, velocity); /// divide it by the fragments' mass Real * mass_storage = mass.storage(); Real * velocity_storage = velocity.storage(); UInt total_components = velocity.getSize() * velocity.getNbComponent(); for (UInt i = 0; i < total_components; ++i) velocity_storage[i] /= mass_storage[i]; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Given the distance @f$ \mathbf{r} @f$ between a quadrature point * and its center of mass, the moment of inertia is computed as \f[ * I_\mathrm{CM} = \mathrm{tr}(\mathbf{r}\mathbf{r}^\mathrm{T}) * \mathbf{I} - \mathbf{r}\mathbf{r}^\mathrm{T} \f] for more * information check Wikipedia * (http://en.wikipedia.org/wiki/Moment_of_inertia#Identities_for_a_skew-symmetric_matrix) * */ void FragmentManager::computeInertiaMoments() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); computeCenterOfMass(); /// compute local coordinates products with respect to the center of match ElementTypeMapArray<Real> moments_coords("moments_coords", id); mesh.initElementTypeMapArray(moments_coords, spatial_dimension * spatial_dimension, spatial_dimension, _not_ghost); /// resize the by element type ElementTypeMapArray<Real>::type_iterator it = moments_coords.firstType(spatial_dimension, _not_ghost, _ek_regular); ElementTypeMapArray<Real>::type_iterator end = moments_coords.lastType(spatial_dimension, _not_ghost, _ek_regular); for (; it != end; ++it) { ElementType type = *it; Array<Real> & field_array = moments_coords(type); UInt nb_element = mesh.getNbElement(type); UInt nb_quad_per_element = model.getFEEngine().getNbQuadraturePoints(type); field_array.resize(nb_element * nb_quad_per_element); } /// compute coordinates Array<Real>::const_vector_iterator mass_center_it = mass_center.begin(spatial_dimension); /// loop over fragments for(const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++mass_center_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); ElementTypeMapArray<UInt>::type_iterator type_it = el_list.firstType(spatial_dimension, _not_ghost, _ek_regular); ElementTypeMapArray<UInt>::type_iterator type_end = el_list.lastType(spatial_dimension, _not_ghost, _ek_regular); /// loop over elements of the fragment for (; type_it != type_end; ++type_it) { ElementType type = *type_it; UInt nb_quad_per_element = model.getFEEngine().getNbQuadraturePoints(type); Array<Real> & moments_coords_array = moments_coords(type); const Array<Real> & quad_coordinates_array = quad_coordinates(type); const Array<UInt> & el_list_array = el_list(type); Array<Real>::matrix_iterator moments_begin = moments_coords_array.begin(spatial_dimension, spatial_dimension); Array<Real>::const_vector_iterator quad_coordinates_begin = quad_coordinates_array.begin(spatial_dimension); Vector<Real> relative_coords(spatial_dimension); for (UInt el = 0; el < el_list_array.getSize(); ++el) { UInt global_el = el_list_array(el); /// loop over quadrature points for (UInt q = 0; q < nb_quad_per_element; ++q) { UInt global_q = global_el * nb_quad_per_element + q; Matrix<Real> & moments_matrix = moments_begin[global_q]; const Vector<Real> & quad_coord_vector = quad_coordinates_begin[global_q]; /// to understand this read the documentation written just /// before this function relative_coords = quad_coord_vector; relative_coords -= *mass_center_it; moments_matrix.outerProduct(relative_coords, relative_coords); Real trace = moments_matrix.trace(); moments_matrix *= -1.; moments_matrix += Matrix<Real>::eye(spatial_dimension, trace); } } } } /// integrate moments Array<Real> integrated_moments(global_nb_fragment, spatial_dimension * spatial_dimension); integrateFieldOnFragments(moments_coords, integrated_moments); /// compute and store principal moments inertia_moments.resize(global_nb_fragment); principal_directions.resize(global_nb_fragment); Array<Real>::matrix_iterator integrated_moments_it = integrated_moments.begin(spatial_dimension, spatial_dimension); Array<Real>::vector_iterator inertia_moments_it = inertia_moments.begin(spatial_dimension); Array<Real>::matrix_iterator principal_directions_it = principal_directions.begin(spatial_dimension, spatial_dimension); for (UInt frag = 0; frag < global_nb_fragment; ++frag, ++integrated_moments_it, ++inertia_moments_it, ++principal_directions_it) { integrated_moments_it->eig(*inertia_moments_it, *principal_directions_it); } if (dump_data) createDumpDataArray(inertia_moments, "moments of inertia"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeAllData() { AKANTU_DEBUG_IN(); buildFragments(); computeVelocity(); computeInertiaMoments(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::storeMassDensityPerQuadraturePoint() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator end = mesh.lastType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; Array<Real> & mass_density_array = mass_density(type); UInt nb_element = mesh.getNbElement(type); UInt nb_quad_per_element = model.getFEEngine().getNbQuadraturePoints(type); mass_density_array.resize(nb_element * nb_quad_per_element); - Array<UInt> & el_index_by_mat = model.getElementIndexByMaterial(type); + const Array<UInt> & mat_indexes = model.getMaterialByElement(type); Real * mass_density_it = mass_density_array.storage(); /// store mass_density for each element and quadrature point for (UInt el = 0; el < nb_element; ++el) { - Material & mat = model.getMaterial(el_index_by_mat(el, 0)); + Material & mat = model.getMaterial(mat_indexes(el)); for (UInt q = 0; q < nb_quad_per_element; ++q, ++mass_density_it) *mass_density_it = mat.getRho(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::integrateFieldOnFragments(ElementTypeMapArray<Real> & field, Array<Real> & output) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); UInt nb_component = output.getNbComponent(); /// integration part output.resize(global_nb_fragment); output.clear(); UInt * fragment_index_it = fragment_index.storage(); Array<Real>::vector_iterator output_begin = output.begin(nb_component); /// loop over fragments for(const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); ElementTypeMapArray<UInt>::type_iterator type_it = el_list.firstType(spatial_dimension, _not_ghost, _ek_regular); ElementTypeMapArray<UInt>::type_iterator type_end = el_list.lastType(spatial_dimension, _not_ghost, _ek_regular); /// loop over elements of the fragment for (; type_it != type_end; ++type_it) { ElementType type = *type_it; UInt nb_quad_per_element = model.getFEEngine().getNbQuadraturePoints(type); const Array<Real> & density_array = mass_density(type); Array<Real> & field_array = field(type); const Array<UInt> & elements = el_list(type); UInt nb_element = elements.getSize(); /// generate array to be integrated by filtering fragment's elements Array<Real> integration_array(elements.getSize() * nb_quad_per_element, nb_component); Array<Real>::matrix_iterator int_array_it = integration_array.begin_reinterpret(nb_quad_per_element, nb_component, nb_element); Array<Real>::matrix_iterator int_array_end = integration_array.end_reinterpret(nb_quad_per_element, nb_component, nb_element); Array<Real>::matrix_iterator field_array_begin = field_array.begin_reinterpret(nb_quad_per_element, nb_component, field_array.getSize() / nb_quad_per_element); Array<Real>::const_vector_iterator density_array_begin = density_array.begin_reinterpret(nb_quad_per_element, density_array.getSize() / nb_quad_per_element); for (UInt el = 0; int_array_it != int_array_end; ++int_array_it, ++el) { UInt global_el = elements(el); *int_array_it = field_array_begin[global_el]; /// multiply field by density const Vector<Real> & density_vector = density_array_begin[global_el]; for (UInt i = 0; i < nb_quad_per_element; ++i) { for (UInt j = 0; j < nb_component; ++j) { (*int_array_it)(i, j) *= density_vector(i); } } } /// integrate the field over the fragment Array<Real> integrated_array(elements.getSize(), nb_component); model.getFEEngine().integrate(integration_array, integrated_array, nb_component, type, _not_ghost, elements); /// sum over all elements and store the result output_begin[*fragment_index_it] += std::accumulate(integrated_array.begin(nb_component), integrated_array.end(nb_component), Vector<Real>(nb_component)); } } /// sum output over all processors StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); comm.allReduce(output.storage(), global_nb_fragment * nb_component, _so_sum); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FragmentManager::computeNbElementsPerFragment() { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); nb_elements_per_fragment.resize(global_nb_fragment); nb_elements_per_fragment.clear(); UInt * fragment_index_it = fragment_index.storage(); /// loop over fragments for(const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { const ElementTypeMapArray<UInt> & el_list = it->second->getElements(); ElementTypeMapArray<UInt>::type_iterator type_it = el_list.firstType(spatial_dimension, _not_ghost, _ek_regular); ElementTypeMapArray<UInt>::type_iterator type_end = el_list.lastType(spatial_dimension, _not_ghost, _ek_regular); /// loop over elements of the fragment for (; type_it != type_end; ++type_it) { ElementType type = *type_it; UInt nb_element = el_list(type).getSize(); nb_elements_per_fragment(*fragment_index_it) += nb_element; } } /// sum values over all processors StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); comm.allReduce(nb_elements_per_fragment.storage(), global_nb_fragment, _so_sum); if (dump_data) createDumpDataArray(nb_elements_per_fragment, "elements per fragment"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <typename T> void FragmentManager::createDumpDataArray(Array<T> & data, std::string name, bool fragment_index_output) { AKANTU_DEBUG_IN(); if (data.getSize() == 0) return; typedef typename Array<T>::template iterator< Vector<T> > data_iterator; Mesh & mesh_not_const = const_cast<Mesh &>(mesh); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_component = data.getNbComponent(); UInt * fragment_index_it = fragment_index.storage(); data_iterator data_begin = data.begin(nb_component); /// loop over fragments for(const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it, ++fragment_index_it) { const ElementGroup & fragment = *(it->second); /// loop over cluster types ElementGroup::type_iterator type_it = fragment.firstType(spatial_dimension); ElementGroup::type_iterator type_end = fragment.lastType(spatial_dimension); for(; type_it != type_end; ++type_it) { ElementType type = *type_it; /// init mesh data Array<T> * mesh_data = mesh_not_const.getDataPointer<T>(name, type, _not_ghost, nb_component); data_iterator mesh_data_begin = mesh_data->begin(nb_component); ElementGroup::const_element_iterator el_it = fragment.element_begin(type); ElementGroup::const_element_iterator el_end = fragment.element_end(type); /// fill mesh data if (fragment_index_output) { for (; el_it != el_end; ++el_it) mesh_data_begin[*el_it](0) = *fragment_index_it; } else { for (; el_it != el_end; ++el_it) mesh_data_begin[*el_it] = data_begin[*fragment_index_it]; } } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 69e0f11ad..3e4800bae 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1559 +1,1569 @@ /** * @file material.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Implementation of the common part of the material class * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Memory(id, model.getMemoryID()), Parsable(_st_material, id), is_init(false), finite_deformation(false), name(""), model(&model), spatial_dimension(this->model->getSpatialDimension()), element_filter("element_filter", id, this->memory_id), stress("stress", *this), eigenstrain("eigenstrain", *this), gradu("grad_u", *this), + green_strain("green_strain",*this), piola_kirchhoff_2("piola_kirchhoff_2", *this), // potential_energy_vector(false), 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 model.getMesh().initElementTypeMapArray(element_filter, 1, spatial_dimension, false, _ek_regular); registerParam("rho" , rho , 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 eigenstrain.initialize(spatial_dimension * spatial_dimension); gradu.initialize(spatial_dimension * spatial_dimension); stress.initialize(spatial_dimension * spatial_dimension); model.registerEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::~Material() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::initMaterial() { AKANTU_DEBUG_IN(); if(finite_deformation) { this->piola_kirchhoff_2.initialize(spatial_dimension * spatial_dimension); if(use_previous_stress) this->piola_kirchhoff_2.initializeHistory(); + this->green_strain.initialize(spatial_dimension * spatial_dimension); } if(use_previous_stress) this->stress.initializeHistory(); if(use_previous_gradu) this->gradu.initializeHistory(); for (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); is_init = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { if(it->second->hasHistory()) it->second->saveCurrentValues(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the residual by assembling @f$\int_{e} \sigma_e \frac{\partial * \varphi}{\partial X} dX @f$ * * @param[in] displacements nodes displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::updateResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); computeAllStresses(ghost_type); assembleResidual(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model->getSpatialDimension(); if(!finite_deformation){ Array<Real> & residual = const_cast<Array<Real> &>(model->getResidual()); Mesh & mesh = model->getFEEngine().getMesh(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { const Array<Real> & shapes_derivatives = model->getFEEngine().getShapesDerivatives(*it, ghost_type); Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(*it, ghost_type); UInt nb_element = elem_filter.getSize(); /// 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"); 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 = 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"); model->getFEEngine().integrate(*sigma_dphi_dx, *int_sigma_dphi_dx, size_of_shapes_derivatives, *it, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble model->getFEEngine().assembleArray(*int_sigma_dphi_dx, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, elem_filter, -1); delete int_sigma_dphi_dx; } } else{ switch (spatial_dimension){ case 1: this->assembleResidual<1>(ghost_type); break; case 2: this->assembleResidual<2>(ghost_type); break; case 3: this->assembleResidual<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(); Mesh::type_iterator it = model->getFEEngine().getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = model->getFEEngine().getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); Array<Real> & gradu_vect = gradu(*it, ghost_type); /// compute @f$\nabla u@f$ model->getFEEngine().gradientOnQuadraturePoints(model->getDisplacement(), gradu_vect, spatial_dimension, *it, ghost_type, elem_filter); gradu_vect -= eigenstrain(*it, ghost_type); /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$ computeStress(*it, 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."); //resizeInternalArray(stress); Mesh::type_iterator it = model->getFEEngine().getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = model->getFEEngine().getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) switch (spatial_dimension){ case 1: this->computeCauchyStress<1>(*it, ghost_type); break; case 2: this->computeCauchyStress<2>(*it, ghost_type); break; case 3: this->computeCauchyStress<3>(*it, 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(); Mesh::type_iterator it = model->getFEEngine().getMesh().firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = model->getFEEngine().getMesh().lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); Array<Real> & gradu_vect = gradu(*it, ghost_type); /// compute @f$\nabla u@f$ model->getFEEngine().gradientOnQuadraturePoints(displacement, gradu_vect, spatial_dimension, *it, ghost_type, elem_filter); setToSteadyState(*it, 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(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { if(finite_deformation){ switch (spatial_dimension) { case 1: { assembleStiffnessMatrixNL < 1 > (*it, ghost_type); assembleStiffnessMatrixL2 < 1 > (*it, ghost_type); break; } case 2: { assembleStiffnessMatrixNL < 2 > (*it, ghost_type); assembleStiffnessMatrixL2 < 2 > (*it, ghost_type); break; } case 3: { assembleStiffnessMatrixNL < 3 > (*it, ghost_type); assembleStiffnessMatrixL2 < 3 > (*it, ghost_type); break; } } } else { switch(spatial_dimension) { case 1: { assembleStiffnessMatrix<1>(*it, ghost_type); break; } case 2: { assembleStiffnessMatrix<2>(*it, ghost_type); break; } case 3: { assembleStiffnessMatrix<3>(*it, ghost_type); break; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void Material::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast<SparseMatrix &>(model->getStiffnessMatrix()); const Array<Real> & shapes_derivatives = model->getFEEngine().getShapesDerivatives(type, - ghost_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.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(type, - ghost_type); + ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); model->getFEEngine().gradientOnQuadraturePoints(model->getDisplacement(), - gradu_vect, dim, type, ghost_type, - elem_filter); + 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>(0, dim * nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(model->getFEEngine().getMesh(), shapes_derivatives, - *shapesd_filtered, type, ghost_type, elem_filter); + *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"); 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"); model->getFEEngine().integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model->getFEEngine().assembleMatrix(*K_e, K, spatial_dimension, type, ghost_type, - elem_filter); + elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void Material::assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast<SparseMatrix &> (model->getStiffnessMatrix()); const Array<Real> & shapes_derivatives = model->getFEEngine().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.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(type, ghost_type); //gradu_vect.resize(nb_quadrature_points * nb_element); // model->getFEEngine().gradientOnQuadraturePoints(model->getIncrement(), gradu_vect, // dim, type, ghost_type, &elem_filter); Array<Real> * shapes_derivatives_filtered = new Array<Real > (nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); Array<Real>::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_s_b_size = dim * nb_nodes_per_element; Array<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); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size); Array<Real>::matrix_iterator Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size); Array<Real>::matrix_iterator piola_it = piola_kirchhoff_2(type, ghost_type).begin(dim, dim); for (; Bt_S_B_it != Bt_S_B_end; ++Bt_S_B_it, ++shapes_derivatives_filtered_it, ++piola_it) { Matrix<Real> & Bt_S_B = *Bt_S_B_it; Matrix<Real> & 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.mul < true, false > (B, S); Bt_S_B.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"); model->getFEEngine().integrate(*bt_s_b, *K_e, bt_s_b_size * bt_s_b_size, type, ghost_type, elem_filter); delete bt_s_b; model->getFEEngine().assembleMatrix(*K_e, K, spatial_dimension, type, ghost_type, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void Material::assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast<SparseMatrix &> (model->getStiffnessMatrix()); const Array<Real> & shapes_derivatives = model->getFEEngine().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.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); model->getFEEngine().gradientOnQuadraturePoints(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"); Array<Real>::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array<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); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, 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 grad_u_it = gradu_vect.begin(dim, dim); 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, ++grad_u_it) { Matrix<Real> & grad_u = *grad_u_it; Matrix<Real> & D = *D_it; Matrix<Real> & 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.mul < true, false > (B, D); Bt_D_B.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"); model->getFEEngine().integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model->getFEEngine().assembleMatrix(*K_e, K, spatial_dimension, type, ghost_type, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void Material::assembleResidual(GhostType ghost_type){ AKANTU_DEBUG_IN(); Array<Real> & residual = const_cast<Array<Real> &> (model->getResidual()); Mesh & mesh = model->getFEEngine().getMesh(); Mesh::type_iterator it = element_filter.firstType(dim, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(dim, ghost_type); for (; it != last_type; ++it) { const Array<Real> & shapes_derivatives = model->getFEEngine().getShapesDerivatives(*it, ghost_type); Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_element = elem_filter.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(*it, ghost_type); 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>::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); //Set stress vectors UInt stress_size = getTangentStiffnessVoigtSize(dim); //Set matrices B and BNL* UInt bt_s_size = dim * nb_nodes_per_element; Array<Real> * bt_s = new Array<Real > (nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); Array<Real>::matrix_iterator grad_u_it = this->gradu(*it, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator grad_u_end = this->gradu(*it, ghost_type).end(dim, dim); Array<Real>::matrix_iterator stress_it = this->piola_kirchhoff_2(*it, 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) { Matrix<Real> & grad_u = *grad_u_it; Matrix<Real> & r_it = *bt_s_it; Matrix<Real> & 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.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"); model->getFEEngine().integrate(*bt_s, *r_e, bt_s_size, *it, ghost_type, elem_filter); delete bt_s; model->getFEEngine().assembleArray(*r_e, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, elem_filter, -1); delete r_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllStressesFromTangentModuli(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model->getSpatialDimension(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { switch(spatial_dimension) { case 1: { computeAllStressesFromTangentModuli<1>(*it, ghost_type); break; } case 2: { computeAllStressesFromTangentModuli<2>(*it, ghost_type); break; } case 3: { computeAllStressesFromTangentModuli<3>(*it, 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 = model->getFEEngine().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.getSize(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); Array<Real> & disp = model->getDisplacement(); model->getFEEngine().gradientOnQuadraturePoints(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>(0, dim* nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(model->getFEEngine().getMesh(), shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); Array<Real> filtered_u(nb_element, nb_nodes_per_element * spatial_dimension); FEEngine::extractNodalToElementField(model->getFEEngine().getMesh(), disp, filtered_u, type, ghost_type, elem_filter); /// compute @f$\mathbf{D} \mathbf{B} \mathbf{u}@f$ Array<Real>::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator D_it = tangent_moduli_tensors->begin(tangent_moduli_size, tangent_moduli_size); Array<Real>::matrix_iterator sigma_it = stress(type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::vector_iterator 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) { Vector<Real> & u = *u_it; Matrix<Real> & sigma = *sigma_it; Matrix<Real> & D = *D_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(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension); for(; it != last_type; ++it) { computePotentialEnergy(*it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if(!potential_energy.exists(el_type, ghost_type)) { UInt nb_element = element_filter(el_type, ghost_type).getSize(); UInt nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(el_type, _not_ghost); potential_energy.alloc(nb_element * nb_quadrature_points, 1, el_type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real epot = 0.; computePotentialEnergyByElements(); /// integrate the potential energy for each type of elements Mesh::type_iterator it = element_filter.firstType(spatial_dimension); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension); for(; it != last_type; ++it) { epot += model->getFEEngine().integrate(potential_energy(*it, _not_ghost), *it, _not_ghost, element_filter(*it, _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(model->getFEEngine().getNbQuadraturePoints(type)); computePotentialEnergyByElement(type, index, epot_on_quad_points); epot = model->getFEEngine().integrate(epot_on_quad_points, type, element_filter(type)(index)); AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(std::string type) { AKANTU_DEBUG_IN(); if(type == "potential") return getPotentialEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(std::string energy_id, ElementType type, UInt index) { AKANTU_DEBUG_IN(); if(energy_id == "potential") return getPotentialEnergy(type, index); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ void Material::computeQuadraturePointsCoordinates(ElementTypeMapArray<Real> & quadrature_points_coordinates, const GhostType & ghost_type) const { AKANTU_DEBUG_IN(); const Mesh & mesh = this->model->getFEEngine().getMesh(); Array<Real> nodes_coordinates(mesh.getNodes(), true); nodes_coordinates += this->model->getDisplacement(); Mesh::type_iterator it = this->element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = this->element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { const Array<UInt> & elem_filter = this->element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_tot_quad = this->model->getFEEngine().getNbQuadraturePoints(*it, ghost_type) * nb_element; Array<Real> & quads = quadrature_points_coordinates(*it, ghost_type); quads.resize(nb_tot_quad); this->model->getFEEngine().interpolateOnQuadraturePoints(nodes_coordinates, quads, spatial_dimension, *it, ghost_type, elem_filter); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::initElementalFieldInterpolation(const ElementTypeMapArray<Real> & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); const Mesh & mesh = model->getFEEngine().getMesh(); ElementTypeMapArray<Real> quadrature_points_coordinates("quadrature_points_coordinates_for_interpolation", getID()); mesh.initElementTypeMapArray(quadrature_points_coordinates, spatial_dimension, spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; computeQuadraturePointsCoordinates(quadrature_points_coordinates, ghost_type); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = element_filter.lastType(spatial_dimension, ghost_type); for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, ghost_type); if (nb_element == 0) continue; const Array<Real> & interp_points_coord = interpolation_points_coordinates(type, ghost_type); UInt nb_interpolation_points_per_elem = interp_points_coord.getSize() / nb_element; AKANTU_DEBUG_ASSERT(interp_points_coord.getSize() % nb_element == 0, "Number of interpolation points is wrong"); #define AKANTU_INIT_INTERPOLATE_ELEMENTAL_FIELD(type) \ initElementalFieldInterpolation<type>(quadrature_points_coordinates(type, ghost_type), \ - interp_points_coord, \ + interp_points_coord, \ nb_interpolation_points_per_elem, \ - ghost_type) \ + ghost_type) \ AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(AKANTU_INIT_INTERPOLATE_ELEMENTAL_FIELD); #undef AKANTU_INIT_INTERPOLATE_ELEMENTAL_FIELD } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void Material::initElementalFieldInterpolation(const Array<Real> & quad_coordinates, - const Array<Real> & interpolation_points_coordinates, + const Array<Real> & interpolation_points_coordinates, const UInt nb_interpolation_points_per_elem, - const GhostType ghost_type) { + const GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt size_inverse_coords = getSizeElementalFieldInterpolationCoodinates<type>(ghost_type); Array<UInt> & elem_fil = element_filter(type, ghost_type); UInt nb_element = elem_fil.getSize(); UInt nb_quad_per_element = model->getFEEngine().getNbQuadraturePoints(type, ghost_type); if(!interpolation_inverse_coordinates.exists(type, ghost_type)) interpolation_inverse_coordinates.alloc(nb_element, - size_inverse_coords*size_inverse_coords, - type, ghost_type); + size_inverse_coords*size_inverse_coords, + type, ghost_type); if(!interpolation_points_matrices.exists(type, ghost_type)) interpolation_points_matrices.alloc(nb_element, - nb_interpolation_points_per_elem * size_inverse_coords, - type, ghost_type); + nb_interpolation_points_per_elem * size_inverse_coords, + type, ghost_type); Array<Real> & interp_inv_coord = interpolation_inverse_coordinates(type, ghost_type); Array<Real> & interp_points_mat = interpolation_points_matrices(type, ghost_type); Matrix<Real> quad_coord_matrix(size_inverse_coords, size_inverse_coords); Array<Real>::const_matrix_iterator quad_coords_it = quad_coordinates.begin_reinterpret(spatial_dimension, - nb_quad_per_element, - nb_element); + nb_quad_per_element, + nb_element); Array<Real>::const_matrix_iterator points_coords_begin = interpolation_points_coordinates.begin_reinterpret(spatial_dimension, - nb_interpolation_points_per_elem, - interpolation_points_coordinates.getSize() / nb_interpolation_points_per_elem); + nb_interpolation_points_per_elem, + interpolation_points_coordinates.getSize() / nb_interpolation_points_per_elem); Array<Real>::matrix_iterator inv_quad_coord_it = interp_inv_coord.begin(size_inverse_coords, size_inverse_coords); Array<Real>::matrix_iterator inv_points_mat_it = interp_points_mat.begin(nb_interpolation_points_per_elem, size_inverse_coords); /// loop over the elements of the current material and element type for (UInt el = 0; el < nb_element; ++el, ++inv_quad_coord_it, ++inv_points_mat_it, ++quad_coords_it) { /// matrix containing the quadrature points coordinates const Matrix<Real> & quad_coords = *quad_coords_it; /// matrix to store the matrix inversion result Matrix<Real> & inv_quad_coord_matrix = *inv_quad_coord_it; /// insert the quad coordinates in a matrix compatible with the interpolation buildElementalFieldInterpolationCoodinates<type>(quad_coords, quad_coord_matrix); /// invert the interpolation matrix inv_quad_coord_matrix.inverse(quad_coord_matrix); /// matrix containing the interpolation points coordinates const Matrix<Real> & points_coords = points_coords_begin[elem_fil(el)]; /// matrix to store the interpolation points coordinates /// compatible with these functions Matrix<Real> & inv_points_coord_matrix = *inv_points_mat_it; /// insert the quad coordinates in a matrix compatible with the interpolation buildElementalFieldInterpolationCoodinates<type>(points_coords, - inv_points_coord_matrix); + inv_points_coord_matrix); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(ElementTypeMapArray<Real> & result, const GhostType ghost_type) { AKANTU_DEBUG_IN(); const Mesh & mesh = model->getFEEngine().getMesh(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = element_filter.lastType(spatial_dimension, ghost_type); for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, ghost_type); if (nb_element == 0) continue; Array<Real> & res = result(type, ghost_type); #define INTERPOLATE_ELEMENTAL_FIELD(type) \ interpolateElementalField<type>(stress(type, ghost_type), \ res, \ ghost_type) AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INTERPOLATE_ELEMENTAL_FIELD); #undef INTERPOLATE_ELEMENTAL_FIELD } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <ElementType type> void Material::interpolateElementalField(const Array<Real> & field, Array<Real> & result, const GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<UInt> & elem_fil = element_filter(type, ghost_type); UInt nb_element = elem_fil.getSize(); UInt nb_quad_per_element = model->getFEEngine().getNbQuadraturePoints(type, ghost_type); UInt size_inverse_coords = getSizeElementalFieldInterpolationCoodinates<type>(ghost_type); Matrix<Real> coefficients(nb_quad_per_element, field.getNbComponent()); const Array<Real> & interp_inv_coord = interpolation_inverse_coordinates(type, - ghost_type); + ghost_type); const Array<Real> & interp_points_coord = interpolation_points_matrices(type, - ghost_type); + ghost_type); UInt nb_interpolation_points_per_elem = interp_points_coord.getNbComponent() / size_inverse_coords; Array<Real>::const_matrix_iterator field_it = field.begin_reinterpret(field.getNbComponent(), - nb_quad_per_element, - nb_element); + nb_quad_per_element, + nb_element); Array<Real>::const_matrix_iterator interpolation_points_coordinates_it = interp_points_coord.begin(nb_interpolation_points_per_elem, size_inverse_coords); Array<Real>::matrix_iterator result_begin = result.begin_reinterpret(field.getNbComponent(), - nb_interpolation_points_per_elem, - result.getSize() / nb_interpolation_points_per_elem); + nb_interpolation_points_per_elem, + result.getSize() / nb_interpolation_points_per_elem); Array<Real>::const_matrix_iterator inv_quad_coord_it = interp_inv_coord.begin(size_inverse_coords, size_inverse_coords); /// loop over the elements of the current material and element type for (UInt el = 0; el < nb_element; ++el, ++field_it, ++inv_quad_coord_it, ++interpolation_points_coordinates_it) { /** * matrix containing the inversion of the quadrature points' * coordinates */ const Matrix<Real> & inv_quad_coord_matrix = *inv_quad_coord_it; /** * multiply it by the field values over quadrature points to get * the interpolation coefficients */ coefficients.mul<false, true>(inv_quad_coord_matrix, *field_it); /// matrix containing the points' coordinates const Matrix<Real> & coord = *interpolation_points_coordinates_it; /// multiply the coordinates matrix by the coefficients matrix and store the result result_begin[elem_fil(el)].mul<true, true>(coefficients, coord); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ 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_EXCEPTION("The material " << name << "(" <<getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ 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_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ const InternalField<Real> & Material::getInternal(const ID & int_id) const { std::map<ID, InternalField<Real> *>::const_iterator it = internal_vectors_real.find(getID() + ":" + int_id); if(it == internal_vectors_real.end()) { AKANTU_EXCEPTION("The material " << name << "(" << getID() - << ") does not contain an internal " - << int_id << " (" << (getID() + ":" + int_id) << ")"); + << ") does not contain an internal " + << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ InternalField<Real> & Material::getInternal(const ID & int_id) { std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.find(getID() + ":" + int_id); if(it == internal_vectors_real.end()) { AKANTU_EXCEPTION("The material " << name << "(" << getID() - << ") does not contain an internal " - << int_id << " (" << (getID() + ":" + int_id) << ")"); + << ") 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> & element_index_material = model->getElementIndexByMaterial(element.type, element.ghost_type); + 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); - element_index_material(element.element, 0) = mat_id; - element_index_material(element.element, 1) = index; + 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()); 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> & element_index_material = model->getElementIndexByMaterial(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.getSize(), 1, type, ghost_type); Array<UInt> & mat_renumbering = material_local_new_numbering(type, ghost_type); UInt nb_element = elem_filter.getSize(); element.kind=(*el_begin).kind; 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; - element_index_material(element.element, 1) = new_id; + mat_loc_num(element.element) = new_id; ++new_id; } else { mat_renumbering(el) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.getSize()); elem_filter.copy(elem_filter_tmp); } } for (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeQuadraturePoints(material_local_new_numbering); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeQuadraturePoints(material_local_new_numbering); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::resizeInternals() { AKANTU_DEBUG_IN(); for (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::onElementsAdded(__attribute__((unused)) const Array<Element> & element_list, __attribute__((unused)) const NewElementsEvent & event) { 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()); 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); + 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)){ Array<UInt> & elem_filter = element_filter(type, gt); - Array<UInt> & element_index_material = model->getElementIndexByMaterial(type, gt); - element_index_material.resize(model->getFEEngine().getMesh().getNbElement(type, gt)); // all materials will resize of the same size... + 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.getSize(), 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; el.type = type; el.ghost_type = gt; for (UInt i = 0; i < elem_filter.getSize(); ++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; - element_index_material(new_el, 0) = my_num; - element_index_material(new_el, 1) = 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.getSize()); elem_filter.copy(elem_filter); } } } for (std::map<ID, InternalField<Real> *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeQuadraturePoints(material_local_new_numbering); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeQuadraturePoints(material_local_new_numbering); } /* -------------------------------------------------------------------------- */ void Material::onBeginningSolveStep(const AnalysisMethod & method) { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::onEndSolveStep(const AnalysisMethod & method) { 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->updateEnergies(*it, _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) { if(!this->potential_energy.exists(*it, _not_ghost)) { UInt nb_element = this->element_filter(*it, _not_ghost).getSize(); UInt nb_quadrature_points = this->model->getFEEngine().getNbQuadraturePoints(*it, _not_ghost); this->potential_energy.alloc(nb_element * nb_quadrature_points, 1, *it, _not_ghost); } 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; } /* -------------------------------------------------------------------------- */ - void Material::flattenInternal(const std::string & field_id, - ElementTypeMapArray<Real> & internal_flat, - const GhostType ghost_type, + ElementTypeMapArray<Real> & internal_flat, + const GhostType ghost_type, ElementKind element_kind){ - typedef ElementTypeMapArray<UInt>::type_iterator iterator; - iterator tit = this->element_filter.firstType(this->spatial_dimension, - ghost_type, element_kind); - iterator end = this->element_filter.lastType(this->spatial_dimension, - ghost_type, element_kind); + typedef ElementTypeMapArray<UInt>::type_iterator iterator; + iterator tit = this->element_filter.firstType(this->spatial_dimension, + ghost_type, element_kind); + iterator end = this->element_filter.lastType(this->spatial_dimension, + ghost_type, element_kind); - for (; tit != end; ++tit) { - - ElementType type = *tit; + for (; tit != end; ++tit) { - try { - __attribute__((unused)) const Array<Real> & src_vect - = this->getArray(field_id,type,ghost_type); + ElementType type = *tit; - } catch(debug::Exception & e) { - continue; - } + try { + __attribute__((unused)) const Array<Real> & src_vect + = this->getArray(field_id,type,ghost_type); - const Array<Real> & src_vect = this->getArray(field_id,type,ghost_type); - const Array<UInt> & filter = this->element_filter(type,ghost_type); + } catch(debug::Exception & e) { + continue; + } - // total number of elements for a given type - UInt nb_element = this->model->mesh.getNbElement(type,ghost_type); - // number of filtered elements - UInt nb_element_src = filter.getSize(); - // number of quadrature points per elem - UInt nb_quad_per_elem = 0; - // number of data per quadrature point - UInt nb_data_per_quad = src_vect.getNbComponent(); + const Array<Real> & src_vect = this->getArray(field_id,type,ghost_type); + const Array<UInt> & filter = this->element_filter(type,ghost_type); - if (!internal_flat.exists(type,ghost_type)){ - internal_flat.alloc(nb_element*nb_quad_per_elem,nb_data_per_quad,type,ghost_type); } + // total number of elements for a given type + UInt nb_element = this->model->mesh.getNbElement(type,ghost_type); + // number of filtered elements + UInt nb_element_src = filter.getSize(); + // number of quadrature points per elem + UInt nb_quad_per_elem = 0; + // number of data per quadrature point + UInt nb_data_per_quad = src_vect.getNbComponent(); - if (nb_element_src == 0) continue; - nb_quad_per_elem = (src_vect.getSize()/nb_element_src); - - // number of data per element - UInt nb_data = nb_quad_per_elem * src_vect.getNbComponent(); + if (!internal_flat.exists(type,ghost_type)) { + internal_flat.alloc(nb_element*nb_quad_per_elem,nb_data_per_quad,type,ghost_type); + } - Array<Real> & dst_vect = internal_flat(type,ghost_type); - dst_vect.resize(nb_element*nb_quad_per_elem); + if (nb_element_src == 0) continue; + nb_quad_per_elem = (src_vect.getSize()/nb_element_src); - 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); + // number of data per element + UInt nb_data = nb_quad_per_elem * src_vect.getNbComponent(); - Array<Real>::vector_iterator it_dst = - dst_vect.begin_reinterpret(nb_data,nb_element); + Array<Real> & dst_vect = internal_flat(type,ghost_type); + dst_vect.resize(nb_element*nb_quad_per_elem); - for (; it != end ; ++it,++it_src) { - it_dst[*it] = *it_src; - } + 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); + + for (; it != end ; ++it,++it_src) { + it_dst[*it] = *it_src; } + } }; /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh index a1bdba331..46186b53a 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,575 +1,588 @@ /** * @file material.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Mother class for all materials * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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_memory.hh" #include "aka_voigthelper.hh" #include "parser.hh" #include "parsable.hh" #include "data_accessor.hh" #include "internal_field.hh" #include "random_internal_field.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_HH__ #define __AKANTU_MATERIAL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Model; class SolidMechanicsModel; } __BEGIN_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, public Parsable, public MeshEventHandler, protected SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Material(SolidMechanicsModel & model, const ID & id = ""); virtual ~Material(); /* ------------------------------------------------------------------------ */ /* 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: /// compute the p-wave speed in the material virtual Real getPushWaveSpeed(const Element & element) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the s-wave speed in the material virtual Real getShearWaveSpeed(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 assembleResidual(GhostType ghost_type); /// Operations before and after solveStep in implicit virtual void beforeSolveStep() {} virtual void afterSolveStep() {} /// 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 computeAllNonLocalStresses(__attribute__((unused)) 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); /// 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 virtual void printself(std::ostream & stream, int indent = 0) const; /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points */ void interpolateStress(ElementTypeMapArray<Real> & 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: /// assemble the residual template<UInt dim> void assembleResidual(GhostType ghost_type); /// Computation of Cauchy stress tensor in the case of finite deformation template<UInt dim> void computeCauchyStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost); 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); /// write the stress tensor in the Voigt notation. template<UInt dim> inline void SetCauchyStressArray(const Matrix<Real> & S_t, Matrix<Real> & Stress_vect); inline UInt getTangentStiffnessVoigtSize(UInt spatial_dimension) const; /// 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> & Stress_matrix); /// compute the potential energy by element void computePotentialEnergyByElements(); /// resize the intenals arrays void resizeInternals(); public: /// compute the coordinates of the quadrature points void computeQuadraturePointsCoordinates(ElementTypeMapArray<Real> & quadrature_points_coordinates, const GhostType & ghost_type) const; protected: /// interpolate an elemental field on given points for each element template <ElementType type> void interpolateElementalField(const Array<Real> & field, Array<Real> & result, const GhostType ghost_type); /// template function to initialize the elemental field interpolation template <ElementType type> void initElementalFieldInterpolation(const Array<Real> & quad_coordinates, const Array<Real> & interpolation_points_coordinates, const UInt nb_interpolation_points_per_elem, const GhostType ghost_type); /// build the coordinate matrix for the interpolation on elemental field template <ElementType type> inline void buildElementalFieldInterpolationCoodinates(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix); /// build interpolation coordinates for basic linear elements inline void buildElementalFieldInterpolationCoodinatesLinear(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix); /// build interpolation coordinates for basic quadratic elements inline void buildElementalFieldInterpolationCoodinatesQuadratic(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix); /// get the size of the coordiante matrix used in the interpolation template <ElementType type> inline UInt getSizeElementalFieldInterpolationCoodinates(GhostType ghost_type = _not_ghost); public: /* ------------------------------------------------------------------------ */ /* Conversion functions */ /* ------------------------------------------------------------------------ */ template<UInt dim> inline void gradUToF (const Matrix<Real> & grad_u, Matrix<Real> & F) const; inline void rightCauchy(const Matrix<Real> & F, Matrix<Real> & C) const; inline void leftCauchy (const Matrix<Real> & F, Matrix<Real> & B) const; template<UInt dim> inline void gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) const; template<UInt dim> inline void gradUToGreenStrain(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) const; +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 QuadraturePoint convertToLocalPoint(const QuadraturePoint & global_point) const; + /// converts local quadrature point to global quadrature point + inline QuadraturePoint convertToGlobalPoint(const QuadraturePoint & local_point) const; /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: virtual inline UInt getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const; virtual inline void packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const; virtual inline void unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag); 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: /* ------------------------------------------------------------------------ */ virtual void onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event); virtual void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event); /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void onBeginningSolveStep(const AnalysisMethod & method); virtual void onEndSolveStep(const AnalysisMethod & method); virtual void onDamageIteration(); virtual void onDamageUpdate(); virtual void onDump(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: 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); /// return the potential energy for the subset of elements contained by the material Real getPotentialEnergy(); /// return the potential energy for the provided element Real getPotentialEnergy(ElementType & type, UInt index); /// return the energy (identified by id) for the subset of elements contained by the material virtual Real getEnergy(std::string energy_id); /// return the energy (identified by id) for the provided element virtual Real getEnergy(std::string energy_id, ElementType type, UInt index); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementFilter, element_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(GradU, gradu, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PotentialEnergy, potential_energy, Real); AKANTU_GET_MACRO(GradU, gradu, const ElementTypeMapArray<Real> &); AKANTU_GET_MACRO(Stress, stress, const ElementTypeMapArray<Real> &); AKANTU_GET_MACRO(ElementFilter, element_filter, const ElementTypeMapArray<UInt> &); bool isNonLocal() const { return is_non_local; } const Array<Real> & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; Array<Real> & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost); const InternalField<Real> & getInternal(const ID & id) const; InternalField<Real> & getInternal(const ID & id); inline bool isInternal(const ID & id, const ElementKind & element_kind) const; inline 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 const T & getParam(const ID & param) const; void flattenInternal(const std::string & field_id, ElementTypeMapArray<Real> & internal_flat, const GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined); protected: bool isInit() const { return is_init; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// 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; protected: /// 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; /// eigenstrain arrays ordered by element types InternalField<Real> eigenstrain; /// 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; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_inline_impl.cc" /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Material & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #include "internal_field_tmpl.hh" #include "random_internal_field_tmpl.hh" /* -------------------------------------------------------------------------- */ /* Auto loop */ /* -------------------------------------------------------------------------- */ #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).getSize()); \ \ 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).getSize()); \ 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 \ } \ #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).getSize()); \ \ 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 \ } \ /* -------------------------------------------------------------------------- */ #define INSTANSIATE_MATERIAL(mat_name) \ template class mat_name<1>; \ template class mat_name<2>; \ template class mat_name<3> #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 918455b6e..f7e3fb1e4 100644 --- a/src/model/solid_mechanics/material_inline_impl.cc +++ b/src/model/solid_mechanics/material_inline_impl.cc @@ -1,432 +1,482 @@ /** * @file material_inline_impl.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Implementation of the inline functions of the class 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) * * 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/>. * */ __END_AKANTU__ #include "solid_mechanics_model.hh" #include <iostream> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const ElementType & type, UInt element, const GhostType & ghost_type) { Array<UInt> & el_filter = element_filter(type, ghost_type); el_filter.push_back(element); return el_filter.getSize()-1; } /* -------------------------------------------------------------------------- */ 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) const { 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) const { C.mul<true, false>(F, F); } /* -------------------------------------------------------------------------- */ inline void Material::leftCauchy(const Matrix<Real> & F, Matrix<Real> & B) const { B.mul<false, true>(F, F); } /* -------------------------------------------------------------------------- */ template<UInt dim> inline void Material::gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon) const { 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) const { 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)); } /* ---------------------------------------------------------------------------*/ template<UInt dim> inline void Material::SetCauchyStressArray(const Matrix<Real> & S_t, Matrix<Real> & Stress_vect) { AKANTU_DEBUG_IN(); Stress_vect.clear(); //UInt cauchy_matrix_size = getCauchyStressArraySize(dim); //see Finite ekement formulations for large deformation dynamic analysis, Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau /* * 1d: [ s11 ]' * 2d: [ s11 s22 s12 ]' * 3d: [ s11 s22 s33 s23 s13 s12 ] */ for (UInt i = 0; i < dim; ++i)//diagonal terms Stress_vect(i, 0) = S_t(i, i); for (UInt i = 1; i < dim; ++i)// term s12 in 2D and terms s23 s13 in 3D Stress_vect(dim+i-1, 0) = S_t(dim-i-1, dim-1); for (UInt i = 2; i < dim; ++i)//term s13 in 3D Stress_vect(dim+i, 0) = S_t(0, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> inline void Material::setCauchyStressMatrix(const Matrix<Real> & S_t, Matrix<Real> & Stress_matrix) { AKANTU_DEBUG_IN(); Stress_matrix.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) { Stress_matrix(i * dim + m, i * dim + n) = S_t(m, n); } } } //other terms from the diagonal /*for (UInt i = 0; i < 3 - dim; ++i) { Stress_matrix(dim * dim + i, dim * dim + i) = S_t(dim + i, dim + i); }*/ 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 QuadraturePoint Material::convertToLocalPoint(const QuadraturePoint & global_point) const { + const FEEngine & fem = this->model->getFEEngine(); + UInt nb_quad = fem.getNbQuadraturePoints(global_point.type); + Element el = this->convertToLocalElement(static_cast<const Element &>(global_point)); + QuadraturePoint tmp_quad(el, global_point.num_point, nb_quad); + return tmp_quad; +} + +/* -------------------------------------------------------------------------- */ +inline QuadraturePoint Material::convertToGlobalPoint(const QuadraturePoint & local_point) const { + const FEEngine & fem = this->model->getFEEngine(); + UInt nb_quad = fem.getNbQuadraturePoints(local_point.type); + Element el = this->convertToGlobalElement(static_cast<const Element &>(local_point)); + QuadraturePoint tmp_quad(el, local_point.num_point, nb_quad); + return tmp_quad; +} + /* -------------------------------------------------------------------------- */ template<ElementType type> inline void Material::buildElementalFieldInterpolationCoodinates(__attribute__((unused)) const Matrix<Real> & coordinates, __attribute__((unused)) Matrix<Real> & coordMatrix) { AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ inline void Material::buildElementalFieldInterpolationCoodinatesLinear(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { for (UInt i = 0; i < coordinates.cols(); ++i) coordMatrix(i, 0) = 1; } /* -------------------------------------------------------------------------- */ inline void Material::buildElementalFieldInterpolationCoodinatesQuadratic(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { UInt nb_quadrature_points = coordMatrix.cols(); for (UInt i = 0; i < coordinates.cols(); ++i) { coordMatrix(i, 0) = 1; for (UInt j = 1; j < nb_quadrature_points; ++j) coordMatrix(i, j) = coordinates(j-1, i); } } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_segment_2>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { buildElementalFieldInterpolationCoodinatesLinear(coordinates, coordMatrix); } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_segment_3>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { buildElementalFieldInterpolationCoodinatesQuadratic(coordinates, coordMatrix); } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_triangle_3>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { buildElementalFieldInterpolationCoodinatesLinear(coordinates, coordMatrix); } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_triangle_6>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { buildElementalFieldInterpolationCoodinatesQuadratic(coordinates, coordMatrix); } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_tetrahedron_4>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { buildElementalFieldInterpolationCoodinatesLinear(coordinates, coordMatrix); } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_tetrahedron_10>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { buildElementalFieldInterpolationCoodinatesQuadratic(coordinates, coordMatrix); } /** * @todo Write a more efficient interpolation for quadrangles by * dropping unnecessary quadrature points * */ /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_quadrangle_4>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { for (UInt i = 0; i < coordinates.cols(); ++i) { Real x = coordinates(0, i); Real y = coordinates(1, i); coordMatrix(i, 0) = 1; coordMatrix(i, 1) = x; coordMatrix(i, 2) = y; coordMatrix(i, 3) = x * y; } } /* -------------------------------------------------------------------------- */ template<> inline void Material::buildElementalFieldInterpolationCoodinates<_quadrangle_8>(const Matrix<Real> & coordinates, Matrix<Real> & coordMatrix) { for (UInt i = 0; i < coordinates.cols(); ++i) { UInt j = 0; Real x = coordinates(0, i); Real y = coordinates(1, i); for (UInt e = 0; e <= 2; ++e) { for (UInt n = 0; n <= 2; ++n) { coordMatrix(i, j) = std::pow(x, e) * std::pow(y, n); ++j; } } } } /* -------------------------------------------------------------------------- */ template<ElementType type> inline UInt Material::getSizeElementalFieldInterpolationCoodinates(GhostType ghost_type) { return model->getFEEngine().getNbQuadraturePoints(type, ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Material::getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const { if(tag == _gst_smm_stress) { return (this->isFiniteDeformation() ? 3 : 1) * spatial_dimension * spatial_dimension * sizeof(Real) * this->getModel().getNbQuadraturePoints(elements); } return 0; } /* -------------------------------------------------------------------------- */ inline void Material::packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, 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::unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) { if(tag == _gst_smm_stress) { if(this->isFiniteDeformation()) { unpackElementDataHelper(piola_kirchhoff_2, buffer, elements); unpackElementDataHelper(gradu, buffer, elements); } unpackElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ template <typename T> inline const T & Material::getParam(const ID & param) const { try { return get<T>(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::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, + 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::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()); } /* -------------------------------------------------------------------------- */ inline bool Material::isInternal(const ID & id, const ElementKind & element_kind) const { std::map<ID, InternalField<Real> *>::const_iterator internal_array = internal_vectors_real.find(this->getID()+":"+id); if (internal_array == internal_vectors_real.end()) return false; if (internal_array->second->getElementKind() != element_kind) return false; return true; } /* -------------------------------------------------------------------------- */ inline ElementTypeMap<UInt> Material::getInternalDataPerElem(const ID & id, const ElementKind & element_kind) const { std::map<ID, InternalField<Real> *>::const_iterator internal_array = internal_vectors_real.find(this->getID()+":"+id); if (internal_array == internal_vectors_real.end()) AKANTU_EXCEPTION("cannot find internal " << id); if (internal_array->second->getElementKind() != element_kind) AKANTU_EXCEPTION("cannot find internal " << id); InternalField<Real> & internal = *internal_array->second; InternalField<Real>::type_iterator it = internal.firstType(spatial_dimension, _not_ghost,element_kind); InternalField<Real>::type_iterator last_type = internal.lastType(spatial_dimension, _not_ghost,element_kind); ElementTypeMap<UInt> res; for(; it != last_type; ++it) { UInt nb_quadrature_points = 0; if (element_kind == _ek_regular) nb_quadrature_points = model->getFEEngine().getNbQuadraturePoints(*it); #if defined(AKANTU_COHESIVE_ELEMENT) else if (element_kind == _ek_cohesive) nb_quadrature_points = model->getFEEngine("CohesiveFEEngine").getNbQuadraturePoints(*it); #endif res(*it) = internal.getNbComponent() * nb_quadrature_points; } return res; } diff --git a/src/model/solid_mechanics/material_selector.hh b/src/model/solid_mechanics/material_selector.hh index a71d3a514..29f672bd4 100644 --- a/src/model/solid_mechanics/material_selector.hh +++ b/src/model/solid_mechanics/material_selector.hh @@ -1,100 +1,100 @@ /** * @file material_selector.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Nov 13 2013 * @date last modification: Thu Jun 05 2014 * * @brief class describing how to choose a material for a given element * * @section LICENSE * * Copyright (©) 2014 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 "mesh.hh" #ifndef __AKANTU_MATERIAL_SELECTOR_HH__ #define __AKANTU_MATERIAL_SELECTOR_HH__ __BEGIN_AKANTU__ class SolidMechanicsModel; /* -------------------------------------------------------------------------- */ class MaterialSelector { public: MaterialSelector() : fallback_value(0) {} virtual ~MaterialSelector() {} virtual UInt operator()(const Element & element) { return fallback_value; } void setFallback(UInt f) { fallback_value = f; } protected: UInt fallback_value; }; /* -------------------------------------------------------------------------- */ class DefaultMaterialSelector : public MaterialSelector { public: - DefaultMaterialSelector(const ElementTypeMapArray<UInt> & element_index_by_material) : - element_index_by_material(element_index_by_material) { } + DefaultMaterialSelector(const ElementTypeMapArray<UInt> & material_index) : + material_index(material_index) { } UInt operator()(const Element & element) { try { DebugLevel dbl = debug::getDebugLevel(); debug::setDebugLevel(dblError); - const Array<UInt> & el_by_mat = element_index_by_material(element.type, element.ghost_type); + const Array<UInt> & mat_indexes = material_index(element.type, element.ghost_type); UInt mat = this->fallback_value; - if(element.element < el_by_mat.getSize()) - mat = el_by_mat(element.element, 0); + if(element.element < mat_indexes.getSize()) + mat = mat_indexes(element.element); debug::setDebugLevel(dbl); return mat; } catch (...) { return MaterialSelector::operator()(element); } } private: - const ElementTypeMapArray<UInt> & element_index_by_material; + const ElementTypeMapArray<UInt> & material_index; }; /* -------------------------------------------------------------------------- */ template<typename T> class MeshDataMaterialSelector : public MaterialSelector { public: MeshDataMaterialSelector(const std::string & name, const SolidMechanicsModel & model) : mesh_data(name), model(model) { } UInt operator() (const Element & element) { return 0; } private: std::string mesh_data; const SolidMechanicsModel & model; }; __END_AKANTU__ #endif /* __AKANTU_MATERIAL_SELECTOR_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc index 20e395e06..2168ff6b9 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc +++ b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc @@ -1,618 +1,618 @@ /** * @file material_cohesive.cc * * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Feb 22 2012 * @date last modification: Tue Jul 29 2014 * * @brief Specialization of the material class for cohesive elements * * @section LICENSE * * Copyright (©) 2014 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 "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" #include "aka_random_generator.hh" #include "shape_cohesive.hh" __BEGIN_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), contact_tractions("contact_tractions", *this), contact_opening("contact_opening", *this), delta_max("delta max", *this), use_previous_delta_max(false), damage("damage", *this), sigma_c("sigma_c", *this) { 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, 0., _pat_parsable | _pat_readable, "Critical displacement"); this->model->getMesh().initElementTypeMapArray(this->element_filter, - 1, - spatial_dimension, - false, - _ek_cohesive); + 1, + spatial_dimension, + false, + _ek_cohesive); if (this->model->getIsExtrinsic()) this->model->getMeshFacets().initElementTypeMapArray(facet_filter, 1, spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MaterialCohesive::~MaterialCohesive() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); 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->contact_tractions.initialize(spatial_dimension); this->contact_opening .initialize(spatial_dimension); this->opening .initialize(spatial_dimension); this->delta_max .initialize(1 ); this->damage .initialize(1 ); if (model->getIsExtrinsic()) this->sigma_c.initialize(1); if (use_previous_delta_max) delta_max.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Tractions", tractions); #endif Array<Real> & residual = const_cast<Array<Real> &>(model->getResidual()); 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); for(; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; const Array<Real> & shapes = fem_cohesive->getShapes(*it, ghost_type); Array<Real> & traction = tractions(*it, ghost_type); Array<Real> & contact_traction = contact_tractions(*it, ghost_type); UInt size_of_shapes = shapes.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = fem_cohesive->getNbQuadraturePoints(*it, 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); Array<Real>::iterator<Matrix<Real> > traction_it = traction.begin(spatial_dimension, 1); Array<Real>::iterator<Matrix<Real> > contact_traction_it = contact_traction.begin(spatial_dimension, 1); Array<Real>::const_iterator<Matrix<Real> > shapes_filtered_begin = shapes.begin(1, size_of_shapes); Array<Real>::iterator<Matrix<Real> > 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, *it, 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->getFEEngineBoundary().assembleArray(*int_t_N, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, elem_filter, 1); delete int_t_N; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast<SparseMatrix &>(model->getStiffnessMatrix()); 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); for(; it != last_type; ++it) { UInt nb_quadrature_points = fem_cohesive->getNbQuadraturePoints(*it, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); const Array<Real> & shapes = fem_cohesive->getShapes(*it, ghost_type); Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); 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_val = shapes.storage(); Real * shapes_filtered_val = shapes_filtered->storage(); UInt * elem_filter_val = elem_filter.storage(); for (UInt el = 0; el < nb_element; ++el) { 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 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"); Array<Real> normal(nb_quadrature_points, spatial_dimension, "normal"); computeNormal(model->getCurrentPosition(), normal, *it, ghost_type); tangent_stiffness_matrix->clear(); computeTangentTraction(*it, *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, *it, ghost_type, elem_filter); delete at_nt_d_n_a; model->getFEEngine().assembleMatrix(*K_e, K, spatial_dimension, *it, ghost_type, 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 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); for(; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; UInt nb_quadrature_points = nb_element*fem_cohesive->getNbQuadraturePoints(*it, ghost_type); Array<Real> normal(nb_quadrature_points, spatial_dimension, "normal"); /// compute normals @f$\mathbf{n}@f$ computeNormal(model->getCurrentPosition(), normal, *it, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ computeOpening(model->getDisplacement(), opening(*it, ghost_type), *it, ghost_type); /// compute traction @f$\mathbf{t}@f$ computeTraction(normal, *it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeNormal(const Array<Real> & position, Array<Real> & normal, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (type == _cohesive_1d_2) fem_cohesive->computeNormalsOnControlPoints(position, normal, type, ghost_type); else { #define COMPUTE_NORMAL(type) \ fem_cohesive->getShapeFunctions(). \ computeNormalsOnControlPoints<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(); #define COMPUTE_OPENING(type) \ fem_cohesive->getShapeFunctions(). \ interpolateOnControlPoints<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() { AKANTU_DEBUG_IN(); Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); Real * memory_space = new Real[2*spatial_dimension]; Vector<Real> b(memory_space, spatial_dimension); Vector<Real> h(memory_space + spatial_dimension, spatial_dimension); for(; it != last_type; ++it) { Array<Real>::iterator<Real> erev = reversible_energy(*it, _not_ghost).begin(); Array<Real>::iterator<Real> etot = total_energy(*it, _not_ghost).begin(); Array<Real>::vector_iterator traction_it = tractions(*it, _not_ghost).begin(spatial_dimension); Array<Real>::vector_iterator traction_old_it = tractions_old(*it, _not_ghost).begin(spatial_dimension); Array<Real>::vector_iterator opening_it = opening(*it, _not_ghost).begin(spatial_dimension); Array<Real>::vector_iterator opening_old_it = opening_old(*it, _not_ghost).begin(spatial_dimension); Array<Real>::vector_iterator traction_end = tractions(*it, _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); } } delete [] memory_space; /// update old values it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); GhostType ghost_type = _not_ghost; for(; it != last_type; ++it) { tractions_old(*it, ghost_type).copy(tractions(*it, ghost_type)); opening_old(*it, ghost_type).copy(opening(*it, ghost_type)); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getReversibleEnergy() { AKANTU_DEBUG_IN(); Real erev = 0.; /// integrate reversible energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { erev += fem_cohesive->integrate(reversible_energy(*it, _not_ghost), *it, _not_ghost, element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return erev; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getDissipatedEnergy() { AKANTU_DEBUG_IN(); Real edis = 0.; /// integrate dissipated energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { Array<Real> dissipated_energy(total_energy(*it, _not_ghost)); dissipated_energy -= reversible_energy(*it, _not_ghost); edis += fem_cohesive->integrate(dissipated_energy, *it, _not_ghost, element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return edis; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getContactEnergy() { AKANTU_DEBUG_IN(); Real econ = 0.; /// integrate contact energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { Array<UInt> & el_filter = element_filter(*it, _not_ghost); UInt nb_quad_per_el = fem_cohesive->getNbQuadraturePoints(*it, _not_ghost); UInt nb_quad_points = el_filter.getSize() * nb_quad_per_el; Array<Real> contact_energy(nb_quad_points); Array<Real>::vector_iterator contact_traction_it = contact_tractions(*it, _not_ghost).begin(spatial_dimension); Array<Real>::vector_iterator contact_opening_it = contact_opening(*it, _not_ghost).begin(spatial_dimension); /// loop on each quadrature point for (UInt el = 0; el < nb_quad_points; ++contact_traction_it, ++contact_opening_it, ++el) { contact_energy(el) = .5 * contact_traction_it->dot(*contact_opening_it); } econ += fem_cohesive->integrate(contact_energy, *it, _not_ghost, el_filter); } AKANTU_DEBUG_OUT(); return econ; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getEnergy(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.; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_non_local.hh b/src/model/solid_mechanics/materials/material_non_local.hh index 0b3007bd9..905d6f3ff 100644 --- a/src/model/solid_mechanics/materials/material_non_local.hh +++ b/src/model/solid_mechanics/materials/material_non_local.hh @@ -1,180 +1,185 @@ /** * @file material_non_local.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 31 2011 * @date last modification: Thu Jun 05 2014 * * @brief Material class that handle the non locality of a law for example damage. * * @section LICENSE * * Copyright (©) 2014 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 "aka_grid_dynamic.hh" #include "fe_engine.hh" #include "weight_function.hh" namespace akantu { class GridSynchronizer; } /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_NON_LOCAL_HH__ #define __AKANTU_MATERIAL_NON_LOCAL_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt dim, template <UInt> class WeightFunction = BaseWeightFunction> class MaterialNonLocal : public virtual Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialNonLocal(SolidMechanicsModel & model, const ID & id = ""); virtual ~MaterialNonLocal(); - template<typename T> - class PairList : public ElementTypeMap< ElementTypeMapArray<T> > {}; + typedef std::vector< std::pair<QuadraturePoint, QuadraturePoint> > PairList; + /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter virtual void initMaterial(); virtual void updateResidual(GhostType ghost_type); virtual void computeAllNonLocalStresses(GhostType ghost_type = _not_ghost); void savePairs(const std::string & filename) const; void neighbourhoodStatistics(const std::string & filename) const; protected: void updatePairList(const ElementTypeMapArray<Real> & quadrature_points_coordinates); void computeWeights(const ElementTypeMapArray<Real> & quadrature_points_coordinates); void createCellList(ElementTypeMapArray<Real> & quadrature_points_coordinates); void cleanupExtraGhostElement(const ElementTypeMap<UInt> & nb_ghost_protected); void fillCellList(const ElementTypeMapArray<Real> & quadrature_points_coordinates, const GhostType & ghost_type); /// constitutive law virtual void computeNonLocalStresses(GhostType ghost_type = _not_ghost) = 0; template<typename T> - void weightedAvergageOnNeighbours(const ElementTypeMapArray<T> & to_accumulate, - ElementTypeMapArray<T> & accumulated, + void weightedAvergageOnNeighbours(const InternalField<T> & to_accumulate, + InternalField<T> & accumulated, UInt nb_degree_of_freedom, GhostType ghost_type2 = _not_ghost) const; virtual inline UInt getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const; virtual inline void packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const; virtual inline void unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag); - // virtual inline void onElementsAdded(const Array<Element> & element_list); + virtual inline void onElementsAdded(const Array<Element> & element_list); virtual inline void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: void registerNonLocalVariable(InternalField<Real> & local, InternalField<Real> & non_local, UInt nb_degree_of_freedom) { ID id = local.getID(); NonLocalVariable & non_local_variable = non_local_variables[id]; non_local_variable.local = &local; non_local_variable.non_local = &non_local; non_local_variable.nb_component = nb_degree_of_freedom; } - AKANTU_GET_MACRO(PairList, pair_list, const PairList<UInt> &) + AKANTU_GET_MACRO(PairList, pair_list, const PairList &) Real getRadius() const { return weight_func->getRadius(); } AKANTU_GET_MACRO(CellList, *spatial_grid, const SpatialGrid<QuadraturePoint> &) /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the weight function used WeightFunction<dim> * weight_func; private: - /// the pairs of quadrature points - PairList<UInt> pair_list; + /** + * the pairs of quadrature points + * 0: not ghost to not ghost + * 1: not ghost to ghost + */ + PairList pair_list[2]; + /// the weights associated to the pairs - PairList<Real> pair_weight; + Array<Real> * pair_weight[2]; /// the regular grid to construct/update the pair lists SpatialGrid<QuadraturePoint> * spatial_grid; /// the types of the existing pairs typedef std::set< std::pair<ElementType, ElementType> > pair_type; pair_type existing_pairs[2]; /// count the number of calls of computeStress UInt compute_stress_calls; struct NonLocalVariable { InternalField<Real> * local; InternalField<Real> * non_local; UInt nb_component; }; std::map<ID, NonLocalVariable> non_local_variables; bool is_creating_grid; GridSynchronizer * grid_synchronizer; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_non_local_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_NON_LOCAL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc b/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc index 3a0a5f204..d24e51914 100644 --- a/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_non_local_inline_impl.cc @@ -1,853 +1,781 @@ /** * @file material_non_local_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 31 2011 * @date last modification: Mon Jun 23 2014 * * @brief Non-local inline implementation * * @section LICENSE * * Copyright (©) 2014 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/>. * */ /* -------------------------------------------------------------------------- */ __END_AKANTU__ /* -------------------------------------------------------------------------- */ #include "aka_types.hh" #include "grid_synchronizer.hh" #include "synchronizer_registry.hh" #include "integrator.hh" /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ #if defined(AKANTU_DEBUG_TOOLS) # include "aka_debug_tools.hh" #endif __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt DIM, template <UInt> class WeightFunction> MaterialNonLocal<DIM, WeightFunction>::MaterialNonLocal(SolidMechanicsModel & model, const ID & id) : Material(model, id), weight_func(NULL), spatial_grid(NULL), compute_stress_calls(0), is_creating_grid(false), grid_synchronizer(NULL) { AKANTU_DEBUG_IN(); + + for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { + GhostType ghost_type = (GhostType) gt; + pair_weight[ghost_type] = NULL; + } + + this->is_non_local = true; this->weight_func = new WeightFunction<DIM>(*this); this->registerSubSection(_st_non_local, "weight_function", *weight_func); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> MaterialNonLocal<spatial_dimension, WeightFunction>::~MaterialNonLocal() { AKANTU_DEBUG_IN(); delete spatial_grid; delete weight_func; delete grid_synchronizer; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::initMaterial() { AKANTU_DEBUG_IN(); // Material::initMaterial(); Mesh & mesh = this->model->getFEEngine().getMesh(); InternalField<Real> quadrature_points_coordinates("quadrature_points_coordinates_tmp_nl", *this); quadrature_points_coordinates.initialize(spatial_dimension); ElementTypeMap<UInt> nb_ghost_protected; Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); for(; it != last_type; ++it) nb_ghost_protected(mesh.getNbElement(*it, _ghost), *it, _ghost); AKANTU_DEBUG_INFO("Creating cell list"); createCellList(quadrature_points_coordinates); AKANTU_DEBUG_INFO("Creating pairs"); updatePairList(quadrature_points_coordinates); #if not defined(AKANTU_NDEBUG) if(AKANTU_DEBUG_TEST(dblDump)) neighbourhoodStatistics("material_non_local.stats"); #endif AKANTU_DEBUG_INFO("Cleaning extra ghosts"); cleanupExtraGhostElement(nb_ghost_protected); AKANTU_DEBUG_INFO("Computing weights"); weight_func->setRadius(weight_func->getRadius()); weight_func->init(); computeWeights(quadrature_points_coordinates); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::cleanupExtraGhostElement(const ElementTypeMap<UInt> & nb_ghost_protected) { AKANTU_DEBUG_IN(); // Create list of element to keep std::set<Element> relevant_ghost_element; - pair_type::const_iterator first_pair_types = existing_pairs[1].begin(); - pair_type::const_iterator last_pair_types = existing_pairs[1].end(); - for (; first_pair_types != last_pair_types; ++first_pair_types) { - ElementType type2 = first_pair_types->second; - GhostType ghost_type2 = _ghost; - UInt nb_quad2 = this->model->getFEEngine().getNbQuadraturePoints(type2); - Array<UInt> & elem_filter = element_filter(type2, ghost_type2); - - const Array<UInt> & pairs = - pair_list(first_pair_types->first, _not_ghost)(first_pair_types->second, ghost_type2); - Array<UInt>::const_iterator< Vector<UInt> > first_pair = pairs.begin(2); - Array<UInt>::const_iterator< Vector<UInt> > last_pair = pairs.end(2); - for(;first_pair != last_pair; ++first_pair) { - UInt _q2 = (*first_pair)(1); - QuadraturePoint q2(type2, elem_filter(_q2 / nb_quad2), _q2 % nb_quad2, ghost_type2); - relevant_ghost_element.insert(q2); - } + PairList::const_iterator first_pair = pair_list[_ghost].begin(); + PairList::const_iterator last_pair = pair_list[_ghost].end(); + for(;first_pair != last_pair; ++first_pair) { + const QuadraturePoint & q2 = first_pair->second; + relevant_ghost_element.insert(q2); } // Create list of element to remove and new numbering for element to keep Mesh & mesh = this->model->getFEEngine().getMesh(); std::set<Element> ghost_to_erase; - Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); + Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); RemovedElementsEvent remove_elem(mesh); - Element element; - element.ghost_type = _ghost; + + Element element_global; // member element corresponds to global element number + element_global.ghost_type = _ghost; + for(; it != last_type; ++it) { - element.type = *it; + element_global.type = *it; UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); UInt nb_ghost_elem_protected = 0; try { nb_ghost_elem_protected = nb_ghost_protected(*it, _ghost); } catch (...) {} if(!remove_elem.getNewNumbering().exists(*it, _ghost)) remove_elem.getNewNumbering().alloc(nb_ghost_elem, 1, *it, _ghost); else remove_elem.getNewNumbering(*it, _ghost).resize(nb_ghost_elem); - Array<UInt> & elem_filter = element_filter(*it, _ghost); Array<UInt> & new_numbering = remove_elem.getNewNumbering(*it, _ghost); UInt ng = 0; for (UInt g = 0; g < nb_ghost_elem; ++g) { - element.element = g; - if(element.element >= nb_ghost_elem_protected && - (std::find(relevant_ghost_element.begin(), - relevant_ghost_element.end(), - element) == relevant_ghost_element.end())) { - remove_elem.getList().push_back(element); + if (element_global.element >= nb_ghost_elem_protected) { + Element element_local = this->convertToLocalElement(element_global); + + if (std::find(relevant_ghost_element.begin(), + relevant_ghost_element.end(), + element_local) == relevant_ghost_element.end()) { + remove_elem.getList().push_back(element_global); new_numbering(g) = UInt(-1); - } else { - new_numbering(g) = ng; + } + } else { + new_numbering(g) = ng; ++ng; } } } mesh.sendEvent(remove_elem); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::createCellList(ElementTypeMapArray<Real> & quadrature_points_coordinates) { AKANTU_DEBUG_IN(); const Real safety_factor = 1.2; // for the cell grid spacing Mesh & mesh = this->model->getFEEngine().getMesh(); mesh.computeBoundingBox(); const Vector<Real> & lower_bounds = mesh.getLocalLowerBounds(); const Vector<Real> & upper_bounds = mesh.getLocalUpperBounds(); Vector<Real> center = 0.5 * (upper_bounds + lower_bounds); Vector<Real> spacing(spatial_dimension, weight_func->getRadius() * safety_factor); spatial_grid = new SpatialGrid<QuadraturePoint>(spatial_dimension, spacing, center); this->computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); this->fillCellList(quadrature_points_coordinates, _not_ghost); - + is_creating_grid = true; SynchronizerRegistry & synch_registry = this->model->getSynchronizerRegistry(); std::stringstream sstr; sstr << getID() << ":grid_synchronizer"; grid_synchronizer = GridSynchronizer::createGridSynchronizer(mesh, *spatial_grid, + synch_registry, sstr.str()); synch_registry.registerSynchronizer(*grid_synchronizer, _gst_mnl_for_average); synch_registry.registerSynchronizer(*grid_synchronizer, _gst_mnl_weight); is_creating_grid = false; - + this->computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); fillCellList(quadrature_points_coordinates, _ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::fillCellList(const ElementTypeMapArray<Real> & quadrature_points_coordinates, const GhostType & ghost_type) { - Mesh & mesh = this->model->getFEEngine().getMesh(); - QuadraturePoint q; q.ghost_type = ghost_type; Mesh::type_iterator it = this->element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = this->element_filter.lastType (spatial_dimension, ghost_type); for(; it != last_type; ++it) { Array<UInt> & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_quad = this->model->getFEEngine().getNbQuadraturePoints(*it, ghost_type); const Array<Real> & quads = quadrature_points_coordinates(*it, ghost_type); q.type = *it; Array<Real>::const_vector_iterator quad = quads.begin(spatial_dimension); UInt * elem = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e) { q.element = *elem; for (UInt nq = 0; nq < nb_quad; ++nq) { q.num_point = nq; //q.setPosition(*quad); spatial_grid->insert(q, *quad); ++quad; } ++elem; } } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::updatePairList(const ElementTypeMapArray<Real> & quadrature_points_coordinates) { AKANTU_DEBUG_IN(); - Mesh & mesh = this->model->getFEEngine().getMesh(); - GhostType ghost_type = _not_ghost; - QuadraturePoint quad_point; - quad_point.ghost_type = ghost_type; + QuadraturePoint q1; + q1.ghost_type = ghost_type; // generate the pair of neighbor depending of the cell_list Mesh::type_iterator it = this->element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = this->element_filter.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { // Preparing datas const Array<Real> & quads = quadrature_points_coordinates(*it, ghost_type); - Array<Real>::const_vector_iterator first_quad = quads.begin(spatial_dimension); - Array<Real>::const_vector_iterator last_quad = quads.end(spatial_dimension); + Array<Real>::const_vector_iterator q1_coord_it = quads.begin(spatial_dimension); + Array<Real>::const_vector_iterator last_quad = quads.end(spatial_dimension); - ElementTypeMapArray<UInt> & pairs = pair_list(ElementTypeMapArray<UInt>("pairs", getID(), memory_id), - *it, - ghost_type); - - ElementType current_element_type = _not_defined; - GhostType current_ghost_type = _casper; - UInt existing_pairs_num = 0; - - Array<UInt> * neighbors = NULL; - Array<UInt>::const_iterator< Vector<UInt> > element_index_material_it; - Array<Real>::const_vector_iterator quad_coord_it; - - UInt my_num_quad = 0; - quad_point.type = *it; + q1.type = *it; + q1.global_num = 0; // loop over quad points - for(;first_quad != last_quad; ++first_quad, ++my_num_quad) { - SpatialGrid<QuadraturePoint>::CellID cell_id = spatial_grid->getCellID(*first_quad); - + for(;q1_coord_it != last_quad; ++q1_coord_it, ++(q1.global_num)) { + UInt nb_quad1 = + this->model->getFEEngine().getNbQuadraturePoints(q1.type, + q1.ghost_type); + q1.element = q1.global_num / nb_quad1; + const Vector<Real> & q1_coord = *q1_coord_it; + + SpatialGrid<QuadraturePoint>::CellID cell_id = spatial_grid->getCellID(q1_coord); SpatialGrid<QuadraturePoint>::neighbor_cells_iterator first_neigh_cell = spatial_grid->beginNeighborCells(cell_id); SpatialGrid<QuadraturePoint>::neighbor_cells_iterator last_neigh_cell = spatial_grid->endNeighborCells(cell_id); - UInt nb_quad_per_elem_1 = - this->model->getFEEngine().getNbQuadraturePoints(*it, quad_point.ghost_type); - - quad_point.element = my_num_quad / nb_quad_per_elem_1; - // loop over neighbors cells of the one containing the current quadrature // point for (; first_neigh_cell != last_neigh_cell; ++first_neigh_cell) { SpatialGrid<QuadraturePoint>::Cell::iterator first_neigh_quad = spatial_grid->beginCell(*first_neigh_cell); SpatialGrid<QuadraturePoint>::Cell::iterator last_neigh_quad = spatial_grid->endCell(*first_neigh_cell); // loop over the quadrature point in the current cell of the cell list for (;first_neigh_quad != last_neigh_quad; ++first_neigh_quad){ - QuadraturePoint quad = *first_neigh_quad; - UInt nb_quad_per_elem_2 = - this->model->getFEEngine().getNbQuadraturePoints(quad.type, - quad.ghost_type); - - // little optimization to not search in the map at each quad points - if(quad.type != current_element_type || - quad.ghost_type != current_ghost_type) { - - current_element_type = quad.type; - current_ghost_type = quad.ghost_type; - existing_pairs_num = quad.ghost_type == _not_ghost ? 0 : 1; - if(!pairs.exists(current_element_type, current_ghost_type)) { - neighbors = &(pairs.alloc(0, 2, - current_element_type, - current_ghost_type)); - } else { - neighbors = &(pairs(current_element_type, - current_ghost_type)); - } - existing_pairs[existing_pairs_num].insert(std::pair<ElementType, - ElementType>(*it, - current_element_type)); - - element_index_material_it = this->model->getElementIndexByMaterial(current_element_type, - current_ghost_type).begin(2); - - quad_coord_it = quadrature_points_coordinates(current_element_type, - current_ghost_type).begin(spatial_dimension); - } + QuadraturePoint q2 = this->convertToLocalPoint(*first_neigh_quad); - const Vector<UInt> & el_mat = element_index_material_it[quad.element]; - UInt neigh_num_quad = el_mat(1) * nb_quad_per_elem_2 + quad.num_point; - const Vector<Real> & neigh_quad = quad_coord_it[neigh_num_quad]; + Array<Real>::const_vector_iterator q2_coord_it = + quadrature_points_coordinates(q2.type, + q2.ghost_type).begin(spatial_dimension); - if(neigh_num_quad > (element_filter(quad.type, quad.ghost_type).getSize()*nb_quad_per_elem_2)) { - std::cout << "AAAAAAAAAAAAAAAA: " << quad << " " << neigh_num_quad << " " << el_mat << std::endl; - } + const Vector<Real> & q2_coord = q2_coord_it[q2.global_num]; + + Real distance = q1_coord.distance(q2_coord); - Real distance = first_quad->distance(neigh_quad); if(distance <= weight_func->getRadius() && - (quad.ghost_type == _ghost || - (quad.ghost_type == _not_ghost && my_num_quad <= neigh_num_quad))) { // storing only half lists - UInt pair[2]; - pair[0] = my_num_quad; - pair[1] = neigh_num_quad; - neighbors->push_back(pair); + (q2.ghost_type == _ghost || + (q2.ghost_type == _not_ghost && q1.global_num <= q2.global_num))) { // storing only half lists + pair_list[q2.ghost_type].push_back(std::make_pair(q1, q2)); } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::computeWeights(const ElementTypeMapArray<Real> & quadrature_points_coordinates) { AKANTU_DEBUG_IN(); - GhostType ghost_type1; - ghost_type1 = _not_ghost; - InternalField<Real> quadrature_points_volumes("quadrature_points_volumes", *this); quadrature_points_volumes.initialize(1); const FEEngine & fem = this->model->getFEEngine(); weight_func->updateInternals(quadrature_points_volumes); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; - UInt existing_pairs_num = gt - _not_ghost; - pair_type::iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); - pair_type::iterator last_pair_types = existing_pairs[existing_pairs_num].end(); - - // Compute the weights - for (; first_pair_types != last_pair_types; ++first_pair_types) { - ElementType type1 = first_pair_types->first; - ElementType type2 = first_pair_types->second; - - const Array<UInt> & pairs = pair_list(type1, ghost_type1)(type2, ghost_type2); + if(!(pair_weight[ghost_type2])) { std::string ghost_id = ""; - if (ghost_type1 == _ghost) ghost_id = ":ghost"; + if (ghost_type2 == _ghost) ghost_id = ":ghost"; + std::stringstream sstr; sstr << getID() << ":pair_weight:" << ghost_id; + pair_weight[ghost_type2] = new Array<Real>(0, 2, sstr.str()); + } - ElementTypeMapArray<Real> & weights_type_1 = pair_weight(type1, ghost_type1); - std::stringstream sstr; sstr << getID() << ":pair_weight:" << type1 << ghost_id; - weights_type_1.setID(sstr.str()); + pair_weight[ghost_type2]->resize(pair_list[ghost_type2].size()); + pair_weight[ghost_type2]->clear(); - Array<Real> * tmp_weight = NULL; - if(!weights_type_1.exists(type2, ghost_type2)) { - tmp_weight = &(weights_type_1.alloc(0, 2, type2, ghost_type2)); - } else { - tmp_weight = &(weights_type_1(type2, ghost_type2)); - } - Array<Real> & weights = *tmp_weight; - weights.resize(pairs.getSize()); - weights.clear(); + PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); + PairList::const_iterator last_pair = pair_list[ghost_type2].end(); - const Array<Real> & jacobians_1 = fem.getIntegratorInterface().getJacobians(type1, ghost_type1); - const Array<Real> & jacobians_2 = fem.getIntegratorInterface().getJacobians(type2, ghost_type2); + Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); - const Array<UInt> & elem_mat_1 = element_filter(type1, ghost_type1); - const Array<UInt> & elem_mat_2 = element_filter(type2, ghost_type2); + // Compute the weights + for(;first_pair != last_pair; ++first_pair, ++weight_it) { + Vector<Real> & weight = *weight_it; + + const QuadraturePoint & lq1 = first_pair->first; + const QuadraturePoint & lq2 = first_pair->second; - UInt nb_quad1 = fem.getNbQuadraturePoints(type1); - UInt nb_quad2 = fem.getNbQuadraturePoints(type2); + QuadraturePoint gq1 = this->convertToGlobalPoint(lq1); + QuadraturePoint gq2 = this->convertToGlobalPoint(lq2); - Array<Real> & quads_volumes1 = quadrature_points_volumes(type1, ghost_type1); - Array<Real> & quads_volumes2 = quadrature_points_volumes(type2, ghost_type2); + const Real & q2_wJ = fem.getIntegratorInterface().getJacobians(gq2.type, gq2.ghost_type)(gq2.global_num); - Array<Real>::const_vector_iterator iquads1; - Array<Real>::const_vector_iterator iquads2; - iquads1 = quadrature_points_coordinates(type1, ghost_type1).begin(spatial_dimension); - iquads2 = quadrature_points_coordinates(type2, ghost_type2).begin(spatial_dimension); + Real & q1_volume = quadrature_points_volumes(lq1.type, lq1.ghost_type)(lq1.global_num); - Array<UInt>::const_iterator< Vector<UInt> > first_pair = pairs.begin(2); - Array<UInt>::const_iterator< Vector<UInt> > last_pair = pairs.end(2); - Array<Real>::vector_iterator weight = weights.begin(2); + const Vector<Real> & q1_coord = + quadrature_points_coordinates(lq1.type, lq1.ghost_type).begin(spatial_dimension)[lq1.global_num]; + const Vector<Real> & q2_coord = + quadrature_points_coordinates(lq1.type, lq1.ghost_type).begin(spatial_dimension)[lq2.global_num]; - this->weight_func->selectType(type1, ghost_type1, type2, ghost_type2); + this->weight_func->selectType(lq1.type, lq1.ghost_type, lq2.type, lq2.ghost_type); // Weight function - for(;first_pair != last_pair; ++first_pair, ++weight) { - UInt _q1 = (*first_pair)(0); - UInt _q2 = (*first_pair)(1); - const Vector<Real> & pos1 = iquads1[_q1]; - const Vector<Real> & pos2 = iquads2[_q2]; - QuadraturePoint q1(_q1 / nb_quad1, _q1 % nb_quad1, _q1, pos1, type1, ghost_type1); - QuadraturePoint q2(_q2 / nb_quad2, _q2 % nb_quad2, _q2, pos2, type2, ghost_type2); - - Real r = pos1.distance(pos2); - - Real w2J2 = jacobians_2(elem_mat_2(q2.element)*nb_quad2 + q2.num_point); - Real w = this->weight_func->operator()(r, q1, q2); - (*weight)(0) = w2J2 * w; - quads_volumes1(_q1) += (*weight)(0); - - if(ghost_type2 != _ghost && _q1 != _q2) { - Real w1J1 = jacobians_1(elem_mat_1(q1.element)*nb_quad1 + q1.num_point); - (*weight)(1) = w1J1 * this->weight_func->operator()(r, q2, q1); - quads_volumes2(_q2) += (*weight)(1); - } else - (*weight)(1) = 0; - } + Real r = q1_coord.distance(q2_coord); + Real w1 = this->weight_func->operator()(r, lq1, lq2); + weight(0) = q2_wJ * w1; + q1_volume += weight(0); + + if(lq2.ghost_type != _ghost && lq1.global_num != lq2.global_num) { + const Real & q1_wJ = fem.getIntegratorInterface().getJacobians(gq1.type, gq1.ghost_type)(gq1.global_num); + Real & q2_volume = quadrature_points_volumes(lq2.type, lq2.ghost_type)(lq2.global_num); + + Real w2 = this->weight_func->operator()(r, lq2, lq1); + weight(1) = q1_wJ * w2; + + q2_volume += weight(1); + } else + weight(1) = 0.; } } //normalize the weights for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; - UInt existing_pairs_num = gt - _not_ghost; - pair_type::iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); - pair_type::iterator last_pair_types = existing_pairs[existing_pairs_num].end(); - first_pair_types = existing_pairs[existing_pairs_num].begin(); - for (; first_pair_types != last_pair_types; ++first_pair_types) { - ElementType type1 = first_pair_types->first; - ElementType type2 = first_pair_types->second; + PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); + PairList::const_iterator last_pair = pair_list[ghost_type2].end(); - const Array<UInt> & pairs = pair_list(type1, ghost_type1)(type2, ghost_type2); - Array<Real> & weights = pair_weight(type1, ghost_type1)(type2, ghost_type2); + Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); - Array<Real> & quads_volumes1 = quadrature_points_volumes(type1, ghost_type1); - Array<Real> & quads_volumes2 = quadrature_points_volumes(type2, ghost_type2); + // Compute the weights + for(;first_pair != last_pair; ++first_pair, ++weight_it) { + Vector<Real> & weight = *weight_it; - Array<UInt>::const_iterator< Vector<UInt> > first_pair = pairs.begin(2); - Array<UInt>::const_iterator< Vector<UInt> > last_pair = pairs.end(2); - Array<Real>::vector_iterator weight = weights.begin(2); + const QuadraturePoint & lq1 = first_pair->first; + const QuadraturePoint & lq2 = first_pair->second; - for(;first_pair != last_pair; ++first_pair, ++weight) { - UInt q1 = (*first_pair)(0); - UInt q2 = (*first_pair)(1); + Real & q1_volume = quadrature_points_volumes(lq1.type, lq1.ghost_type)(lq1.global_num); - (*weight)(0) *= 1. / quads_volumes1(q1); - if(ghost_type2 != _ghost) (*weight)(1) *= 1. / quads_volumes2(q2); + weight(0) *= 1. / q1_volume; + if(ghost_type2 != _ghost) { + Real & q2_volume = quadrature_points_volumes(lq2.type, lq2.ghost_type)(lq2.global_num); + weight(1) *= 1. / q2_volume; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> template<typename T> -void MaterialNonLocal<spatial_dimension, WeightFunction>::weightedAvergageOnNeighbours(const ElementTypeMapArray<T> & to_accumulate, - ElementTypeMapArray<T> & accumulated, +void MaterialNonLocal<spatial_dimension, WeightFunction>::weightedAvergageOnNeighbours(const InternalField<T> & to_accumulate, + InternalField<T> & accumulated, UInt nb_degree_of_freedom, GhostType ghost_type2) const { AKANTU_DEBUG_IN(); - UInt existing_pairs_num = 0; - if (ghost_type2 == _ghost) existing_pairs_num = 1; + if(ghost_type2 == _not_ghost) { + accumulated.reset(); + } - pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); - pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); + PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); + PairList::const_iterator last_pair = pair_list[ghost_type2].end(); - GhostType ghost_type1 = _not_ghost; // does not make sens the ghost vs ghost so this should always by _not_ghost + Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); - for (; first_pair_types != last_pair_types; ++first_pair_types) { - const Array<UInt> & pairs = - pair_list(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); - const Array<Real> & weights = - pair_weight(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); + // Compute the weights + for(;first_pair != last_pair; ++first_pair, ++weight_it) { + Vector<Real> & weight = *weight_it; - const Array<T> & to_acc = to_accumulate(first_pair_types->second, ghost_type2); - Array<T> & acc = accumulated(first_pair_types->first, ghost_type1); + const QuadraturePoint & lq1 = first_pair->first; + const QuadraturePoint & lq2 = first_pair->second; - if(ghost_type2 == _not_ghost) acc.clear(); + const Vector<T> & q2_to_acc = to_accumulate(lq2.type, lq2.ghost_type).begin(nb_degree_of_freedom)[lq2.global_num]; + Vector<T> & q1_acc = accumulated(lq1.type, lq1.ghost_type).begin(nb_degree_of_freedom)[lq1.global_num]; - Array<UInt>::const_iterator< Vector<UInt> > first_pair = pairs.begin(2); - Array<UInt>::const_iterator< Vector<UInt> > last_pair = pairs.end(2); - Array<Real>::const_vector_iterator pair_w = weights.begin(2); + q1_acc += weight(0) * q2_to_acc; - for(;first_pair != last_pair; ++first_pair, ++pair_w) { - UInt q1 = (*first_pair)(0); - UInt q2 = (*first_pair)(1); - for(UInt d = 0; d < nb_degree_of_freedom; ++d){ - acc(q1, d) += (*pair_w)(0) * to_acc(q2, d); - if(ghost_type2 != _ghost) acc(q2, d) += (*pair_w)(1) * to_acc(q1, d); - } + if(ghost_type2 != _ghost) { + const Vector<T> & q1_to_acc = to_accumulate(lq1.type, lq1.ghost_type).begin(nb_degree_of_freedom)[lq1.global_num]; + Vector<T> & q2_acc = accumulated(lq2.type, lq2.ghost_type).begin(nb_degree_of_freedom)[lq2.global_num]; + + q2_acc += weight(1) * q1_to_acc; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::updateResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); // Update the weights for the non local variable averaging if(ghost_type == _not_ghost && this->weight_func->getUpdateRate() && (this->compute_stress_calls % this->weight_func->getUpdateRate() == 0)) { ElementTypeMapArray<Real> quadrature_points_coordinates("quadrature_points_coordinates", getID()); Mesh & mesh = this->model->getFEEngine().getMesh(); mesh.initElementTypeMapArray(quadrature_points_coordinates, spatial_dimension, spatial_dimension); computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); computeWeights(quadrature_points_coordinates); } if(ghost_type == _not_ghost) ++this->compute_stress_calls; computeAllStresses(ghost_type); computeNonLocalStresses(ghost_type); assembleResidual(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::computeAllNonLocalStresses(GhostType ghost_type) { // Update the weights for the non local variable averaging if(ghost_type == _not_ghost) { if(this->weight_func->getUpdateRate() && (this->compute_stress_calls % this->weight_func->getUpdateRate() == 0)) { this->model->getSynchronizerRegistry().asynchronousSynchronize(_gst_mnl_weight); ElementTypeMapArray<Real> quadrature_points_coordinates("quadrature_points_coordinates", getID()); Mesh & mesh = this->model->getFEEngine().getMesh(); mesh.initElementTypeMapArray(quadrature_points_coordinates, spatial_dimension, spatial_dimension); computeQuadraturePointsCoordinates(quadrature_points_coordinates, _not_ghost); computeQuadraturePointsCoordinates(quadrature_points_coordinates, _ghost); this->model->getSynchronizerRegistry().waitEndSynchronize(_gst_mnl_weight); computeWeights(quadrature_points_coordinates); } typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); for(;it != end; ++it) { NonLocalVariable & non_local_variable = it->second; non_local_variable.non_local->resize(); this->weightedAvergageOnNeighbours(*non_local_variable.local, *non_local_variable.non_local, non_local_variable.nb_component, _not_ghost); } ++this->compute_stress_calls; } else { typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); for(;it != end; ++it) { NonLocalVariable & non_local_variable = it->second; this->weightedAvergageOnNeighbours(*non_local_variable.local, *non_local_variable.non_local, non_local_variable.nb_component, _ghost); } computeNonLocalStresses(_not_ghost); } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::savePairs(const std::string & filename) const { std::ofstream pout; std::stringstream sstr; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); - GhostType ghost_type1; - ghost_type1 = _not_ghost; - for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; - UInt existing_pairs_num = gt - _not_ghost; - - pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); - pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); - for (; first_pair_types != last_pair_types; ++first_pair_types) { - const Array<UInt> & pairs = - (*pair_list(first_pair_types->first, ghost_type1))(first_pair_types->second, ghost_type2); - const Array<Real> & weights = - (*pair_weight(first_pair_types->first, ghost_type1))(first_pair_types->second, ghost_type2); + PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); + PairList::const_iterator last_pair = pair_list[ghost_type2].end(); - pout << "Types : " << first_pair_types->first << " (" << ghost_type1 << ") - " << first_pair_types->second << " (" << ghost_type2 << ")" << std::endl; + Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); - Array<UInt>::const_iterator< Vector<UInt> > first_pair = pairs.begin(2); - Array<UInt>::const_iterator< Vector<UInt> > last_pair = pairs.end(2); - Array<Real>::const_vector_iterator pair_w = weights.begin(2); + for(;first_pair != last_pair; ++first_pair, ++weight_it) { + Vector<Real> & weight = *weight_it; - for(;first_pair != last_pair; ++first_pair, ++pair_w) { - UInt q1 = (*first_pair)(0); - UInt q2 = (*first_pair)(1); - pout << q1 << " " << q2 << " "<< (*pair_w)(0) << " " << (*pair_w)(1) << std::endl; - } + const QuadraturePoint & lq1 = first_pair->first; + const QuadraturePoint & lq2 = first_pair->second; + pout << lq1 << " " << lq2 << " " << weight << std::endl; } } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> void MaterialNonLocal<spatial_dimension, WeightFunction>::neighbourhoodStatistics(const std::string & filename) const { - std::ofstream pout; - pout.open(filename.c_str()); - - const Mesh & mesh = this->model->getFEEngine().getMesh(); - - GhostType ghost_type1; - ghost_type1 = _not_ghost; - - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - Int prank = comm.whoAmI(); - - InternalField<UInt> nb_neighbors("nb_neighbours", *const_cast<MaterialNonLocal *>(this)); - nb_neighbors.initialize(1); - - for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { - GhostType ghost_type2 = (GhostType) gt; - UInt existing_pairs_num = gt - _not_ghost; - - pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); - pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); - - for (; first_pair_types != last_pair_types; ++first_pair_types) { - const Array<UInt> & pairs = - pair_list(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); - if(prank == 0) { - pout << ghost_type2 << " "; - pout << "Types : " << first_pair_types->first << " " << first_pair_types->second << std::endl; - } - Array<UInt>::const_iterator< Vector<UInt> > first_pair = pairs.begin(2); - Array<UInt>::const_iterator< Vector<UInt> > last_pair = pairs.end(2); - Array<UInt> & nb_neigh_1 = nb_neighbors(first_pair_types->first, ghost_type1); - Array<UInt> & nb_neigh_2 = nb_neighbors(first_pair_types->second, ghost_type2); - for(;first_pair != last_pair; ++first_pair) { - UInt q1 = (*first_pair)(0); - UInt q2 = (*first_pair)(1); - ++(nb_neigh_1(q1)); - if(q1 != q2) ++(nb_neigh_2(q2)); - } - } - - Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type1); - Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type1); - UInt nb_quads = 0; - Real sum_nb_neig = 0; - UInt max_nb_neig = 0; - UInt min_nb_neig = std::numeric_limits<UInt>::max(); - for(; it != last_type; ++it) { - Array<UInt> & nb_neighor = nb_neighbors(*it, ghost_type1); - Array<UInt>::iterator<UInt> nb_neigh = nb_neighor.begin(); - Array<UInt>::iterator<UInt> end_neigh = nb_neighor.end(); - - for (; nb_neigh != end_neigh; ++nb_neigh, ++nb_quads) { - UInt nb = *nb_neigh; - sum_nb_neig += nb; - max_nb_neig = std::max(max_nb_neig, nb); - min_nb_neig = std::min(min_nb_neig, nb); - } - } - - - comm.allReduce(&nb_quads, 1, _so_sum); - comm.allReduce(&sum_nb_neig, 1, _so_sum); - comm.allReduce(&max_nb_neig, 1, _so_max); - comm.allReduce(&min_nb_neig, 1, _so_min); - - if(prank == 0) { - pout << ghost_type2 << " "; - pout << "Nb quadrature points: " << nb_quads << std::endl; - - Real mean_nb_neig = sum_nb_neig / Real(nb_quads); - pout << ghost_type2 << " "; - pout << "Average nb neighbors: " << mean_nb_neig << "(" << sum_nb_neig << ")" << std::endl; - - pout << ghost_type2 << " "; - pout << "Max nb neighbors: " << max_nb_neig << std::endl; - - pout << ghost_type2 << " "; - pout << "Min nb neighbors: " << min_nb_neig << std::endl; - } - } - pout.close(); + // std::ofstream pout; + // pout.open(filename.c_str()); + + // const Mesh & mesh = this->model->getFEEngine().getMesh(); + + // GhostType ghost_type1; + // ghost_type1 = _not_ghost; + + // StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + // Int prank = comm.whoAmI(); + + // InternalField<UInt> nb_neighbors("nb_neighbours", *const_cast<MaterialNonLocal *>(this)); + // nb_neighbors.initialize(1); + + // for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { + // GhostType ghost_type2 = (GhostType) gt; + // UInt existing_pairs_num = gt - _not_ghost; + + // pair_type::const_iterator first_pair_types = existing_pairs[existing_pairs_num].begin(); + // pair_type::const_iterator last_pair_types = existing_pairs[existing_pairs_num].end(); + + // for (; first_pair_types != last_pair_types; ++first_pair_types) { + // const Array<UInt> & pairs = + // pair_list(first_pair_types->first, ghost_type1)(first_pair_types->second, ghost_type2); + // if(prank == 0) { + // pout << ghost_type2 << " "; + // pout << "Types : " << first_pair_types->first << " " << first_pair_types->second << std::endl; + // } + // Array<UInt>::const_iterator< Vector<UInt> > first_pair = pairs.begin(2); + // Array<UInt>::const_iterator< Vector<UInt> > last_pair = pairs.end(2); + // Array<UInt> & nb_neigh_1 = nb_neighbors(first_pair_types->first, ghost_type1); + // Array<UInt> & nb_neigh_2 = nb_neighbors(first_pair_types->second, ghost_type2); + // for(;first_pair != last_pair; ++first_pair) { + // UInt q1 = (*first_pair)(0); + // UInt q2 = (*first_pair)(1); + // ++(nb_neigh_1(q1)); + // if(q1 != q2) ++(nb_neigh_2(q2)); + // } + // } + + // Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type1); + // Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type1); + // UInt nb_quads = 0; + // Real sum_nb_neig = 0; + // UInt max_nb_neig = 0; + // UInt min_nb_neig = std::numeric_limits<UInt>::max(); + // for(; it != last_type; ++it) { + // Array<UInt> & nb_neighor = nb_neighbors(*it, ghost_type1); + // Array<UInt>::iterator<UInt> nb_neigh = nb_neighor.begin(); + // Array<UInt>::iterator<UInt> end_neigh = nb_neighor.end(); + + // for (; nb_neigh != end_neigh; ++nb_neigh, ++nb_quads) { + // UInt nb = *nb_neigh; + // sum_nb_neig += nb; + // max_nb_neig = std::max(max_nb_neig, nb); + // min_nb_neig = std::min(min_nb_neig, nb); + // } + // } + + + // comm.allReduce(&nb_quads, 1, _so_sum); + // comm.allReduce(&sum_nb_neig, 1, _so_sum); + // comm.allReduce(&max_nb_neig, 1, _so_max); + // comm.allReduce(&min_nb_neig, 1, _so_min); + + // if(prank == 0) { + // pout << ghost_type2 << " "; + // pout << "Nb quadrature points: " << nb_quads << std::endl; + + // Real mean_nb_neig = sum_nb_neig / Real(nb_quads); + // pout << ghost_type2 << " "; + // pout << "Average nb neighbors: " << mean_nb_neig << "(" << sum_nb_neig << ")" << std::endl; + + // pout << ghost_type2 << " "; + // pout << "Max nb neighbors: " << max_nb_neig << std::endl; + + // pout << ghost_type2 << " "; + // pout << "Min nb neighbors: " << min_nb_neig << std::endl; + // } + // } + // pout.close(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> inline UInt MaterialNonLocal<spatial_dimension, WeightFunction>::getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const { UInt nb_quadrature_points = this->getModel().getNbQuadraturePoints(elements); UInt size = 0; if(tag == _gst_mnl_for_average) { typename std::map<ID, NonLocalVariable>::const_iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::const_iterator end = non_local_variables.end(); for(;it != end; ++it) { const NonLocalVariable & non_local_variable = it->second; size += non_local_variable.nb_component * sizeof(Real) * nb_quadrature_points; } } size += weight_func->getNbDataForElements(elements, tag); return size; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> inline void MaterialNonLocal<spatial_dimension, WeightFunction>::packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const { if(tag == _gst_mnl_for_average) { typename std::map<ID, NonLocalVariable>::const_iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::const_iterator end = non_local_variables.end(); for(;it != end; ++it) { const NonLocalVariable & non_local_variable = it->second; this->packElementDataHelper(*non_local_variable.local, buffer, elements); } } weight_func->packElementData(buffer, elements, tag); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> inline void MaterialNonLocal<spatial_dimension, WeightFunction>::unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) { if(tag == _gst_mnl_for_average) { typename std::map<ID, NonLocalVariable>::iterator it = non_local_variables.begin(); typename std::map<ID, NonLocalVariable>::iterator end = non_local_variables.end(); for(;it != end; ++it) { NonLocalVariable & non_local_variable = it->second; this->unpackElementDataHelper(*non_local_variable.local, buffer, elements); } } weight_func->unpackElementData(buffer, elements, tag); } /* -------------------------------------------------------------------------- */ -// template<UInt spatial_dimension, template <UInt> class WeightFunction> -// inline void MaterialNonLocal<spatial_dimension, WeightFunction>::onElementsAdded(const Array<Element> & element_list) { -// AKANTU_DEBUG_IN(); - -// Material::onElementsAdded(element_list, event); - -// AKANTU_DEBUG_OUT(); -// } +template<UInt spatial_dimension, template <UInt> class WeightFunction> +inline void MaterialNonLocal<spatial_dimension, WeightFunction>::onElementsAdded(const Array<Element> & element_list) { + AKANTU_DEBUG_IN(); + AKANTU_DEBUG_ERROR("This is a case not taken into account!!!"); + AKANTU_DEBUG_OUT(); +} /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension, template <UInt> class WeightFunction> inline void MaterialNonLocal<spatial_dimension, WeightFunction>::onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); + // Change the pairs in new global numbering + for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { + GhostType ghost_type2 = (GhostType) gt; + + PairList::iterator first_pair = pair_list[ghost_type2].begin(); + PairList::iterator last_pair = pair_list[ghost_type2].end(); + + // Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); + + for(;first_pair != last_pair; ++first_pair) { + QuadraturePoint & q1 = first_pair->first; + QuadraturePoint gq1 = this->convertToGlobalPoint(q1); + q1 = gq1; + + if(new_numbering.exists(q1.type, q1.ghost_type)) { + UInt q1_new_el = new_numbering(q1.type, q1.ghost_type)(gq1.element); + AKANTU_DEBUG_ASSERT(q1_new_el != UInt(-1), "A local quadrature_point as been removed instead of just being renumbered"); + q1.element = q1_new_el; + } + + + QuadraturePoint & q2 = first_pair->second; + QuadraturePoint gq2 = this->convertToGlobalPoint(q2); + q2 = gq2; + + if(new_numbering.exists(q2.type, q2.ghost_type)) { + UInt q2_new_el = new_numbering(q2.type, q2.ghost_type)(gq2.element); + AKANTU_DEBUG_ASSERT(q2_new_el != UInt(-1), "A local quadrature_point as been removed instead of just being renumbered"); + q2.element = q2_new_el; + } + } + } + + + // Change the material numbering Material::onElementsRemoved(element_list, new_numbering, event); - pair_type::const_iterator first_pair_types = existing_pairs[1].begin(); - pair_type::const_iterator last_pair_types = existing_pairs[1].end(); + // Change back the pairs to the new material numbering + for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { + GhostType ghost_type2 = (GhostType) gt; + + PairList::iterator first_pair = pair_list[ghost_type2].begin(); + PairList::iterator last_pair = pair_list[ghost_type2].end(); - // Renumber element to keep - for (; first_pair_types != last_pair_types; ++first_pair_types) { - ElementType type2 = first_pair_types->second; - GhostType ghost_type2 = _ghost; - UInt nb_quad2 = this->model->getFEEngine().getNbQuadraturePoints(type2); + // Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); - Array<UInt> & pairs = - pair_list(first_pair_types->first, _not_ghost)(first_pair_types->second, ghost_type2); - Array<UInt>::iterator< Vector<UInt> > first_pair = pairs.begin(2); - Array<UInt>::iterator< Vector<UInt> > last_pair = pairs.end(2); for(;first_pair != last_pair; ++first_pair) { - UInt _q2 = (*first_pair)(1); - const Array<UInt> & renumbering = new_numbering(type2, ghost_type2); - UInt el = _q2 / nb_quad2; - UInt new_el = renumbering(el); - AKANTU_DEBUG_ASSERT(new_el != UInt(-1), "A local quad as been removed instead f just renumbered"); - (*first_pair)(1) = new_el * nb_quad2 + _q2 % nb_quad2; + first_pair->first = this->convertToLocalPoint(first_pair->first ); + first_pair->second = this->convertToLocalPoint(first_pair->second); } } AKANTU_DEBUG_OUT(); } diff --git a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc index f3c0d5ad7..c55e1d2ec 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc @@ -1,144 +1,201 @@ /** * @file material_linear_isotropic_hardening.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> + * @author Benjamin Paccaud <benjamin.paccaud@epfl.ch> * * @date creation: Thu Oct 03 2013 * @date last modification: Fri Jun 13 2014 * * @brief Specialization of the material class for isotropic finite deformation linear hardening plasticity * * @section LICENSE * * Copyright (©) 2014 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_linear_isotropic_hardening.hh" #include "solid_mechanics_model.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt dim> MaterialLinearIsotropicHardening<dim>::MaterialLinearIsotropicHardening(SolidMechanicsModel & model, const ID & id) : Material(model, id), MaterialPlastic<dim>(model, id) { AKANTU_DEBUG_IN(); - + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialLinearIsotropicHardening<spatial_dimension>::computeStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialThermal<spatial_dimension>::computeStress(el_type, ghost_type); - + // infinitesimal and finite deformation Array<Real>::iterator<> sigma_th_it = this->sigma_th(el_type, ghost_type).begin(); Array<Real>::iterator<> previous_sigma_th_it = this->sigma_th.previous(el_type, ghost_type).begin(); Array<Real>::matrix_iterator previous_gradu_it = this->gradu.previous(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator previous_stress_it = this->stress.previous(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator inelastic_strain_it = this->inelastic_strain(el_type, ghost_type).begin(spatial_dimension,spatial_dimension); Array<Real>::matrix_iterator previous_inelastic_strain_it = this->inelastic_strain.previous(el_type, ghost_type).begin(spatial_dimension,spatial_dimension); Array<Real>::iterator<> iso_hardening_it = this->iso_hardening(el_type, ghost_type).begin(); Array<Real>::iterator<> previous_iso_hardening_it = this->iso_hardening.previous(el_type, ghost_type).begin(); + + + + // + // Finite Deformations + // + if (this->finite_deformation) { + Array<Real>::matrix_iterator previous_piola_kirchhoff_2_it = + this->piola_kirchhoff_2.previous(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); + + Array<Real>::matrix_iterator green_strain_it = + this->green_strain(el_type, ghost_type).begin(spatial_dimension,spatial_dimension); + + + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); + + Matrix<Real> & inelastic_strain_tensor = *inelastic_strain_it; + Matrix<Real> & previous_inelastic_strain_tensor = *previous_inelastic_strain_it; + Matrix<Real> & previous_grad_u = *previous_gradu_it; + Matrix<Real> & previous_sigma = *previous_piola_kirchhoff_2_it; + + Matrix<Real> & green_strain = *green_strain_it; + this->template gradUToGreenStrain<spatial_dimension>(grad_u, green_strain); + Matrix<Real> previous_green_strain(spatial_dimension,spatial_dimension); + this->template gradUToGreenStrain<spatial_dimension>(previous_grad_u, previous_green_strain); + Matrix<Real> F_tensor(spatial_dimension,spatial_dimension); + this->template gradUToF<spatial_dimension>(grad_u,F_tensor); + + computeStressOnQuad(green_strain, + previous_green_strain, + sigma, + previous_sigma, + inelastic_strain_tensor, + previous_inelastic_strain_tensor, + *iso_hardening_it, + *previous_iso_hardening_it, + *sigma_th_it, + *previous_sigma_th_it, + F_tensor); - - MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); - Matrix<Real> & inelastic_strain_tensor = *inelastic_strain_it; - Matrix<Real> & previous_inelastic_strain_tensor = *previous_inelastic_strain_it; - Matrix<Real> & previous_grad_u = *previous_gradu_it; - Matrix<Real> & previous_sigma = *previous_stress_it; - - computeStressOnQuad(grad_u, - previous_grad_u, - sigma, - previous_sigma, - inelastic_strain_tensor, - previous_inelastic_strain_tensor, - *iso_hardening_it, - *previous_iso_hardening_it, - *sigma_th_it, - *previous_sigma_th_it); ++sigma_th_it; ++inelastic_strain_it; ++iso_hardening_it; ++previous_sigma_th_it; - ++previous_stress_it; + //++previous_stress_it; ++previous_gradu_it; + ++green_strain_it; ++previous_inelastic_strain_it; ++previous_iso_hardening_it; - + ++previous_piola_kirchhoff_2_it; + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; + } + // Infinitesimal deformations + else { + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); + + Matrix<Real> & inelastic_strain_tensor = *inelastic_strain_it; + Matrix<Real> & previous_inelastic_strain_tensor = *previous_inelastic_strain_it; + Matrix<Real> & previous_grad_u = *previous_gradu_it; + Matrix<Real> & previous_sigma = *previous_stress_it; + + computeStressOnQuad(grad_u, + previous_grad_u, + sigma, + previous_sigma, + inelastic_strain_tensor, + previous_inelastic_strain_tensor, + *iso_hardening_it, + *previous_iso_hardening_it, + *sigma_th_it, + *previous_sigma_th_it); + ++sigma_th_it; + ++inelastic_strain_it; + ++iso_hardening_it; + ++previous_sigma_th_it; + ++previous_stress_it; + ++previous_gradu_it; + ++previous_inelastic_strain_it; + ++previous_iso_hardening_it; + + MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; + } + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialLinearIsotropicHardening<spatial_dimension>::computeTangentModuli(__attribute__((unused)) const ElementType & el_type, Array<Real> & tangent_matrix, __attribute__((unused)) GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<Real>::const_matrix_iterator previous_gradu_it = this->gradu.previous(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::const_matrix_iterator previous_stress_it = this->stress.previous(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::const_scalar_iterator iso_hardening= this->iso_hardening(el_type, ghost_type).begin(); MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix); computeTangentModuliOnQuad(tangent, grad_u, *previous_gradu_it, sigma_tensor, *previous_stress_it, *iso_hardening); ++previous_gradu_it; ++previous_stress_it; ++iso_hardening; MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialLinearIsotropicHardening); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh index f7611c93d..1cc27030a 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh +++ b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh @@ -1,100 +1,113 @@ /** * @file material_linear_isotropic_hardening.hh * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> * * @date creation: Thu Oct 03 2013 * @date last modification: Mon Apr 07 2014 * * @brief Specialization of the material class for isotropic finite deformation linear hardening plasticity * * @section LICENSE * * Copyright (©) 2014 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_plastic.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_LINEAR_ISOTROPIC_HARDENING_HH__ #define __AKANTU_MATERIAL_LINEAR_ISOTROPIC_HARDENING_HH__ __BEGIN_AKANTU__ /** * Material plastic with a linear evolution of the yielding stress */ template <UInt spatial_dimension> class MaterialLinearIsotropicHardening : public MaterialPlastic<spatial_dimension> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialLinearIsotropicHardening(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// constitutive law for all element of a type virtual void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost); /// compute the tangent stiffness matrix for an element type void computeTangentModuli(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost); protected: + /// Infinitesimal deformations inline void computeStressOnQuad(const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelas_strain, const Matrix<Real> & previous_inelas_strain, Real & iso_hardening, const Real & previous_iso_hardening, const Real & sigma_th, const Real & previous_sigma_th); + /// Finite deformations + inline void computeStressOnQuad(const Matrix<Real> & grad_u, + const Matrix<Real> & previous_grad_u, + Matrix<Real> & sigma, + const Matrix<Real> & previous_sigma, + Matrix<Real> & inelas_strain, + const Matrix<Real> & previous_inelas_strain, + Real & iso_hardening, + const Real & previous_iso_hardening, + const Real & sigma_th, + const Real & previous_sigma_th, + const Matrix<Real> & F_tensor); inline void computeTangentModuliOnQuad(Matrix<Real> & tangent, const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, const Matrix<Real> & sigma_tensor, const Matrix<Real> & previous_sigma_tensor, const Real & iso_hardening) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_linear_isotropic_hardening_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_LINEAR_ISOTROPIC_HARDENING_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc index 0c744dfcf..0477f4fca 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc @@ -1,178 +1,301 @@ /** * @file material_linear_isotropic_hardening_inline_impl.cc * * @author Lucas Frerot <lucas.frerot@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch> + * @author Benjamin Paccaud <benjamin.paccaud@epfl.ch> * * @date creation: Thu Oct 03 2013 * @date last modification: Mon Jun 09 2014 * * @brief Implementation of the inline functions of the material plasticity * * @section LICENSE * * Copyright (©) 2014 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_linear_isotropic_hardening.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +///Infinitesimal deformations template<UInt dim> inline void MaterialLinearIsotropicHardening<dim>::computeStressOnQuad(const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, Matrix<Real> & sigma, const Matrix<Real> & previous_sigma, Matrix<Real> & inelastic_strain, const Matrix<Real> & previous_inelastic_strain, Real & iso_hardening, const Real & previous_iso_hardening, const Real & sigma_th, const Real & previous_sigma_th) { //Infinitesimal plasticity //Real r=iso_hardening; Real dp=0.0; Real d_dp=0.0; UInt n=0; Real delta_sigma_th = sigma_th - previous_sigma_th; Matrix<Real> grad_delta_u(grad_u); grad_delta_u -= previous_grad_u; //Compute trial stress, sigma_tr Matrix<Real> sigma_tr(dim, dim); MaterialElastic<dim>::computeStressOnQuad(grad_delta_u, sigma_tr, delta_sigma_th); sigma_tr += previous_sigma; // Compute deviatoric trial stress, sigma_tr_dev Matrix<Real> sigma_tr_dev(sigma_tr); sigma_tr_dev -= Matrix<Real>::eye(dim, sigma_tr.trace() / 3.0); // Compute effective deviatoric trial stress Real s = sigma_tr_dev.doubleDot(sigma_tr_dev); Real sigma_tr_dev_eff = std::sqrt(3./2. * s); const Real iso_hardening_t = previous_iso_hardening; + iso_hardening = iso_hardening_t; + //Loop for correcting stress based on yield function - while ((sigma_tr_dev_eff - iso_hardening - this->sigma_y) > 0) { + bool initial_yielding = ( (sigma_tr_dev_eff - iso_hardening - this->sigma_y) > 0) ; + while ( initial_yielding && std::abs(sigma_tr_dev_eff - iso_hardening - this->sigma_y) > Math::getTolerance() ) { d_dp = (sigma_tr_dev_eff - 3. * this->mu *dp - iso_hardening - this->sigma_y) / (3. * this->mu + this->h); - //r = r + h * dp; - iso_hardening = iso_hardening_t + this->h * d_dp; + //r = r + h * dp; dp = dp + d_dp; + iso_hardening = iso_hardening_t + this->h * dp; ++n; - + /// TODO : explicit this criterion with an error message if ((d_dp < 1e-5) || (n>50)) - break; + { + break; + } } //Update internal variable Matrix<Real> delta_inelastic_strain(dim, dim, 0.); if (std::abs(sigma_tr_dev_eff) > sigma_tr_dev.norm<L_inf>() * Math::getTolerance()) { delta_inelastic_strain.copy(sigma_tr_dev); delta_inelastic_strain *= 3./2. * dp / sigma_tr_dev_eff; } MaterialPlastic<dim>::computeStressAndInelasticStrainOnQuad(grad_delta_u, sigma, previous_sigma, inelastic_strain, previous_inelastic_strain, delta_inelastic_strain); } /* -------------------------------------------------------------------------- */ +///Finite deformations +template<UInt dim> +inline void +MaterialLinearIsotropicHardening<dim>::computeStressOnQuad(const Matrix<Real> & grad_u, + const Matrix<Real> & previous_grad_u, + Matrix<Real> & sigma, + const Matrix<Real> & previous_sigma, + Matrix<Real> & inelastic_strain, + const Matrix<Real> & previous_inelastic_strain, + Real & iso_hardening, + const Real & previous_iso_hardening, + const Real & sigma_th, + const Real & previous_sigma_th, + const Matrix<Real> & F_tensor) { + //Finite plasticity + Real dp=0.0; + Real d_dp=0.0; + UInt n=0; + + Real delta_sigma_th = sigma_th - previous_sigma_th; + + Matrix<Real> grad_delta_u(grad_u); + grad_delta_u -= previous_grad_u; + + //Compute trial stress, sigma_tr + Matrix<Real> sigma_tr(dim, dim); + MaterialElastic<dim>::computeStressOnQuad(grad_delta_u, sigma_tr, delta_sigma_th); + sigma_tr += previous_sigma; + + // Compute deviatoric trial stress, sigma_tr_dev + Matrix<Real> sigma_tr_dev(sigma_tr); + sigma_tr_dev -= Matrix<Real>::eye(dim, sigma_tr.trace() / 3.0); + + // Compute effective deviatoric trial stress + Real s = sigma_tr_dev.doubleDot(sigma_tr_dev); + Real sigma_tr_dev_eff = std::sqrt(3./2. * s); + + // compute the cauchy stress to apply the Von-Mises criterion + Matrix<Real> cauchy_stress(dim,dim); + Material::computeCauchyStressOnQuad<dim>(F_tensor,sigma_tr,cauchy_stress); + Matrix<Real> cauchy_stress_dev(cauchy_stress); + cauchy_stress_dev -= Matrix<Real>::eye(dim, cauchy_stress.trace() / 3.0); + Real c = cauchy_stress_dev.doubleDot(cauchy_stress_dev); + Real cauchy_stress_dev_eff = std::sqrt(3./2. * c); + + + const Real iso_hardening_t = previous_iso_hardening; + iso_hardening = iso_hardening_t; + //Loop for correcting stress based on yield function + + // F is written in terms of S + // bool initial_yielding = ( (sigma_tr_dev_eff - iso_hardening - this->sigma_y) > 0) ; + // while ( initial_yielding && std::abs(sigma_tr_dev_eff - iso_hardening - this->sigma_y) > Math::getTolerance() ) { + + // d_dp = (sigma_tr_dev_eff - 3. * this->mu *dp - iso_hardening - this->sigma_y) + // / (3. * this->mu + this->h); + + // //r = r + h * dp; + // dp = dp + d_dp; + // iso_hardening = iso_hardening_t + this->h * dp; + + // ++n; + + // /// TODO : explicit this criterion with an error message + // if ((std::abs(d_dp) < 1e-9) || (n>50)){ + // AKANTU_DEBUG_INFO("convergence of increment of plastic strain. d_dp:" << d_dp << "\tNumber of iteration:"<<n); + // break; + // } + // } + + // F is written in terms of cauchy stress + bool initial_yielding = ( (cauchy_stress_dev_eff - iso_hardening - this->sigma_y) > 0) ; + while ( initial_yielding && std::abs(cauchy_stress_dev_eff - iso_hardening - this->sigma_y) > Math::getTolerance() ) { + + d_dp = ( cauchy_stress_dev_eff - 3. * this->mu *dp - iso_hardening - this->sigma_y) + / (3. * this->mu + this->h); + + //r = r + h * dp; + dp = dp + d_dp; + iso_hardening = iso_hardening_t + this->h * dp; + + + ++n; + /// TODO : explicit this criterion with an error message + if ((d_dp < 1e-5) || (n>50)){ + AKANTU_DEBUG_INFO("convergence of increment of plastic strain. d_dp:" << d_dp << "\tNumber of iteration:"<<n); + break; + } + } + + //Update internal variable + Matrix<Real> delta_inelastic_strain(dim, dim, 0.); + if (std::abs(sigma_tr_dev_eff) > + sigma_tr_dev.norm<L_inf>() * Math::getTolerance()) { + + // /// compute the direction of the plastic strain as \frac{\partial F}{\partial S} = \frac{3}{2J\sigma_{effective}}} Ft \sigma_{dev} F + Matrix<Real> cauchy_dev_F(dim,dim); + cauchy_dev_F.mul<false,false>(F_tensor,cauchy_stress_dev); + Real J = F_tensor.det(); + Real constant = J ? 1./J : 0; + constant *= 3. * dp / (2. * cauchy_stress_dev_eff); + delta_inelastic_strain.mul<true,false>(F_tensor,cauchy_dev_F,constant); + + //Direction given by the piola kirchhoff deviatoric tensor \frac{\partial F}{\partial S} = \frac{3}{2\sigma_{effective}}}S_{dev} + // delta_inelastic_strain.copy(sigma_tr_dev); + // delta_inelastic_strain *= 3./2. * dp / sigma_tr_dev_eff; + } + + MaterialPlastic<dim>::computeStressAndInelasticStrainOnQuad(grad_delta_u, sigma, previous_sigma, + inelastic_strain, previous_inelastic_strain, + delta_inelastic_strain); +} + +/* -------------------------------------------------------------------------- */ + + template<UInt dim> inline void MaterialLinearIsotropicHardening<dim>::computeTangentModuliOnQuad(Matrix<Real> & tangent, const Matrix<Real> & grad_u, const Matrix<Real> & previous_grad_u, const Matrix<Real> & sigma_tensor, const Matrix<Real> & previous_sigma_tensor, const Real & iso_hardening) const { // Real r=iso_hardening; // Matrix<Real> grad_delta_u(grad_u); // grad_delta_u -= previous_grad_u; // //Compute trial stress, sigma_tr // Matrix<Real> sigma_tr(dim, dim); // MaterialElastic<dim>::computeStressOnQuad(grad_delta_u, sigma_tr); // sigma_tr += previous_sigma_tensor; // // Compute deviatoric trial stress, sigma_tr_dev // Matrix<Real> sigma_tr_dev(sigma_tr); // sigma_tr_dev -= Matrix<Real>::eye(dim, sigma_tr.trace() / 3.0); // // Compute effective deviatoric trial stress // Real s = sigma_tr_dev.doubleDot(sigma_tr_dev); // Real sigma_tr_dev_eff=std::sqrt(3./2. * s); // // Compute deviatoric stress, sigma_dev // Matrix<Real> sigma_dev(sigma_tensor); // sigma_dev -= Matrix<Real>::eye(dim, sigma_tensor.trace() / 3.0); // // Compute effective deviatoric stress // s = sigma_dev.doubleDot(sigma_dev); // Real sigma_dev_eff = std::sqrt(3./2. * s); // Real xr = 0.0; // if(sigma_tr_dev_eff > sigma_dev_eff * Math::getTolerance()) // xr = sigma_dev_eff / sigma_tr_dev_eff; // Real __attribute__((unused)) q = 1.5 * (1. / (1. + 3. * this->mu / this->h) - xr); UInt cols = tangent.cols(); UInt rows = tangent.rows(); for (UInt m = 0; m < rows; ++m) { UInt i = VoigtHelper<dim>::vec[m][0]; UInt j = VoigtHelper<dim>::vec[m][1]; for (UInt n = 0; n < cols; ++n) { UInt k = VoigtHelper<dim>::vec[n][0]; UInt l = VoigtHelper<dim>::vec[n][1]; // This section of the code is commented // There were some problems with the convergence of plastic-coupled simulations with thermal expansion // XXX: DO NOT REMOVE /*if (((sigma_tr_dev_eff-iso_hardening-sigmay) > 0) && (xr > 0)) { tangent(m,n) = 2. * this->mu * q * (sigma_tr_dev (i,j) / sigma_tr_dev_eff) * (sigma_tr_dev (k,l) / sigma_tr_dev_eff) + (i==k) * (j==l) * 2. * this->mu * xr + (i==j) * (k==l) * (this->kpa - 2./3. * this->mu * xr); if ((m == n) && (m>=dim)) tangent(m, n) = tangent(m, n) - this->mu * xr; } else {*/ tangent(m,n) = (i==k) * (j==l) * 2. * this->mu + (i==j) * (k==l) * this->lambda; tangent(m,n) -= (m==n) * (m>=dim) * this->mu; //} //correct tangent stiffness for shear component } } } diff --git a/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc b/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc index f35c6e322..716b9db4e 100644 --- a/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc +++ b/src/model/solid_mechanics/materials/material_plastic/material_plastic.cc @@ -1,184 +1,187 @@ /** * @file material_plastic.cc * * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date creation: Mon Apr 07 2014 * @date last modification: Fri Jun 13 2014 * * @brief Implemantation of the akantu::MaterialPlastic class * * @section LICENSE * * Copyright (©) 2014 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_plastic.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> MaterialPlastic<spatial_dimension>::MaterialPlastic(SolidMechanicsModel & model, const ID & id) : Material(model, id), MaterialElastic<spatial_dimension>(model, id), iso_hardening("iso_hardening", *this), inelastic_strain("inelastic_strain", *this), plastic_energy("plastic_energy", *this), d_plastic_energy("d_plastic_energy", *this) { AKANTU_DEBUG_IN(); this->registerParam("h", h, 0., _pat_parsable | _pat_modifiable, "Hardening modulus"); this->registerParam("sigma_y", sigma_y, 0., _pat_parsable | _pat_modifiable, "Yield stress"); + + //already registered in material + // this->registerParam("finite_deformation",finite_deformation, false, _pat_parsable | _pat_modifiable, "Flag for large deformation"); + this->iso_hardening.initialize(1); this->iso_hardening.initializeHistory(); this->plastic_energy.initialize(1); this->d_plastic_energy.initialize(1); - this->finite_deformation = false; this->use_previous_stress = true; this->use_previous_gradu = true; this->use_previous_stress_thermal = true; this->inelastic_strain.initialize(spatial_dimension * spatial_dimension); this->inelastic_strain.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> Real MaterialPlastic<spatial_dimension>::getEnergy(std::string type) { AKANTU_DEBUG_IN(); if (type == "plastic") return getPlasticEnergy(); else return MaterialElastic<spatial_dimension>::getEnergy(type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> Real MaterialPlastic<spatial_dimension>::getPlasticEnergy() { AKANTU_DEBUG_IN(); Real penergy = 0.; const Mesh & mesh = this->model->getFEEngine().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost); Mesh::type_iterator end = mesh.lastType(spatial_dimension, _not_ghost); for(; it != end; ++it) { penergy += this->model->getFEEngine().integrate(plastic_energy(*it, _not_ghost), *it, _not_ghost, this->element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return penergy; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialPlastic<spatial_dimension>::computePotentialEnergy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if(ghost_type != _not_ghost) return; Array<Real>::scalar_iterator epot = this->potential_energy(el_type, ghost_type).begin(); Array<Real>::const_iterator< Matrix<Real> > inelastic_strain_it = this->inelastic_strain(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> elastic_strain(spatial_dimension, spatial_dimension); elastic_strain.copy(grad_u); elastic_strain -= *inelastic_strain_it; MaterialElastic<spatial_dimension>::computePotentialEnergyOnQuad(elastic_strain, sigma, *epot); ++epot; ++inelastic_strain_it; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialPlastic<spatial_dimension>::updateEnergies(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialElastic<spatial_dimension>::updateEnergies(el_type, ghost_type); Array<Real>::iterator<> pe_it = this->plastic_energy(el_type, ghost_type).begin(); Array<Real>::iterator<> wp_it = this->d_plastic_energy(el_type, ghost_type).begin(); Array<Real>::iterator< Matrix<Real> > inelastic_strain_it = this->inelastic_strain(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::iterator< Matrix<Real> > previous_inelastic_strain_it = this->inelastic_strain.previous(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator previous_sigma = this->stress.previous(el_type, ghost_type).begin(spatial_dimension, spatial_dimension); MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type); Matrix<Real> delta_strain_it(*inelastic_strain_it); delta_strain_it -= *previous_inelastic_strain_it; Matrix<Real> sigma_h(sigma); sigma_h += *previous_sigma; *wp_it = .5 * sigma_h.doubleDot(delta_strain_it); *pe_it += *wp_it; ++pe_it; ++wp_it; ++inelastic_strain_it; ++previous_inelastic_strain_it; ++previous_sigma; MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialPlastic); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/weight_function.hh b/src/model/solid_mechanics/materials/weight_function.hh index 224825d2f..2b22ac394 100644 --- a/src/model/solid_mechanics/materials/weight_function.hh +++ b/src/model/solid_mechanics/materials/weight_function.hh @@ -1,398 +1,369 @@ /** * @file weight_function.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Cyprien Wolff <cyprien.wolff@epfl.ch> * * @date creation: Fri Apr 13 2012 * @date last modification: Thu Jun 05 2014 * * @brief Weight functions for non local materials * * @section LICENSE * * Copyright (©) 2014 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_types.hh" #include "solid_mechanics_model.hh" #include "parsable.hh" #include <cmath> #if defined(AKANTU_DEBUG_TOOLS) #include "aka_debug_tools.hh" #include <string> #endif /* -------------------------------------------------------------------------- */ #include <vector> #ifndef __AKANTU_WEIGHT_FUNCTION_HH__ #define __AKANTU_WEIGHT_FUNCTION_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Normal weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class BaseWeightFunction : public Parsable { public: BaseWeightFunction(Material & material, const std::string & type = "base") : Parsable(_st_non_local, "weight_function:" + type), material(material), type(type) { this->registerParam("radius" , R , 100., _pat_parsable | _pat_readable , "Non local radius"); this->registerParam("update_rate" , update_rate, 0U , _pat_parsmod, "Update frequency"); } virtual ~BaseWeightFunction() {} virtual void init() { R2 = R * R; }; virtual void updateInternals(__attribute__((unused)) const ElementTypeMapArray<Real> & quadrature_points_coordinates) {}; /* ------------------------------------------------------------------------ */ inline void setRadius(Real radius) { R = radius; R2 = R * R; } /* ------------------------------------------------------------------------ */ inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, __attribute__((unused)) ElementType type2, __attribute__((unused)) GhostType ghost_type2) { } /* ------------------------------------------------------------------------ */ inline Real operator()(Real r, - __attribute__((unused)) QuadraturePoint & q1, - __attribute__((unused)) QuadraturePoint & q2) { + const __attribute__((unused)) QuadraturePoint & q1, + const __attribute__((unused)) QuadraturePoint & q2) { Real w = 0; if(r <= R) { Real alpha = (1. - r*r / R2); w = alpha * alpha; // *weight = 1 - sqrt(r / radius); } return w; } void printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "WeightFunction " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } public: Real getRadius() { return R; } UInt getUpdateRate() { return update_rate; } public: virtual UInt getNbDataForElements(__attribute__((unused)) const Array<Element> & elements, __attribute__((unused)) SynchronizationTag tag) const { return 0; } virtual inline void packElementData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const Array<Element> & elements, __attribute__((unused)) SynchronizationTag tag) const {} virtual inline void unpackElementData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const Array<Element> & elements, __attribute__((unused)) SynchronizationTag tag) {} protected: Material & material; Real R; Real R2; UInt update_rate; const std::string type; }; /* -------------------------------------------------------------------------- */ /* Damage weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class DamagedWeightFunction : public BaseWeightFunction<spatial_dimension> { public: DamagedWeightFunction(Material & material) : BaseWeightFunction<spatial_dimension>(material, "damaged") {} inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_damage = &this->material.getArray("damage", type2, ghost_type2); } - inline Real operator()(Real r, __attribute__((unused)) QuadraturePoint & q1, QuadraturePoint & q2) { + inline Real operator()(Real r, + const __attribute__((unused)) QuadraturePoint & q1, + const QuadraturePoint & q2) { UInt quad = q2.global_num; Real D = (*selected_damage)(quad); Real Radius_t = 0; Real Radius_init = this->R2; // if(D <= 0.5) // { // Radius_t = 2*D*Radius_init; // } // else // { // Radius_t = 2*Radius_init*(1-D); // } // Radius_t = Radius_init*(1-D); Radius_init *= Radius_init; Radius_t *= Radius_t; if(Radius_t < Math::getTolerance()) { Radius_t = 0.001*Radius_init; } Real expb = (2*std::log(0.51))/(std::log(1.0-0.49*Radius_t/Radius_init)); Int expb_floor=std::floor(expb); Real b = expb_floor + expb_floor%2; Real alpha = std::max(0., 1. - r*r / Radius_init); Real w = std::pow(alpha,b); return w; } private: const Array<Real> * selected_damage; }; /* -------------------------------------------------------------------------- */ /* Remove damaged weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class RemoveDamagedWeightFunction : public BaseWeightFunction<spatial_dimension> { public: RemoveDamagedWeightFunction(Material & material) : BaseWeightFunction<spatial_dimension>(material, "remove_damaged") { this->registerParam("damage_limit", this->damage_limit, 1., _pat_parsable, "Damage Threshold"); } inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_damage = &this->material.getArray("damage", type2, ghost_type2); } - inline Real operator()(Real r, __attribute__((unused)) QuadraturePoint & q1, QuadraturePoint & q2) { + inline Real operator()(Real r, + const __attribute__((unused)) QuadraturePoint & q1, + const QuadraturePoint & q2) { UInt quad = q2.global_num; if(q1 == q2) return 1.; Real D = (*selected_damage)(quad); Real w = 0.; if(D < damage_limit) { Real alpha = std::max(0., 1. - r*r / this->R2); w = alpha * alpha; } return w; } virtual UInt getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const { if(tag == _gst_mnl_weight) return this->material.getModel().getNbQuadraturePoints(elements) * sizeof(Real); return 0; } virtual inline void packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const { if(tag == _gst_mnl_weight) { ElementTypeMapArray<Real> & damage = this->material.getInternal("damage"); this->material.packElementDataHelper(damage, buffer, elements); -#if defined(AKANTU_DEBUG_TOOLS) -#if defined(AKANTU_CORE_CXX11) - debug::element_manager.print(debug::_dm_material, - [&elements, &mat](const Element & el)->std::string { - std::stringstream out; - UInt pos = elements.find(el); - if(pos != UInt(-1)) { - Real d = mat.getArray("damage", el.type, el.ghost_type)(el.element); - if(d > 0.3) - out << " damage sent: " << d; - } - return out.str(); - }); -#else - debug::element_manager.printData(debug::_dm_material, "RemoveDamagedWeightFunction: packElementData", - mat.getDamage(), mat.getElementFilter()); -#endif -#endif } } virtual inline void unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) { if(tag == _gst_mnl_weight) { ElementTypeMapArray<Real> & damage = this->material.getInternal("damage"); this->material.unpackElementDataHelper(damage, buffer, elements); -#if defined(AKANTU_DEBUG_TOOLS) -#if defined(AKANTU_CORE_CXX11) - debug::element_manager.print(debug::_dm_material, - [&elements, &mat](const Element & el)->std::string { - std::stringstream out; - UInt pos = elements.find(el); - if(pos != UInt(-1)) { - Real d = mat.getArray("damage", el.type, el.ghost_type)(el.element); - if(d > 0.3) - out << " damage recv: " << d; - } - return out.str(); - }); -#else - debug::element_manager.printData(debug::_dm_material, "RemoveDamagedWeightFunction: unpackElementData", - mat.getDamage(), mat.getElementFilter()); -#endif -#endif - } } private: /// limit at which a point is considered as complitely broken Real damage_limit; /// internal pointer to the current damage vector const Array<Real> * selected_damage; }; /* -------------------------------------------------------------------------- */ /* Remove damaged with damage rate weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class RemoveDamagedWithDamageRateWeightFunction : public BaseWeightFunction<spatial_dimension> { public: RemoveDamagedWithDamageRateWeightFunction(Material & material) : BaseWeightFunction<spatial_dimension>(material, "remove_damage_with_damage_rate") { this->registerParam("damage_limit", this->damage_limit_with_damage_rate, 1, _pat_parsable, "Damage Threshold"); } inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_damage_with_damage_rate = &(this->material.getArray("damage",type2, ghost_type2)); selected_damage_rate_with_damage_rate = &(this->material.getArray("damage-rate",type2, ghost_type2)); } - inline Real operator()(Real r, __attribute__((unused)) QuadraturePoint & q1, QuadraturePoint & q2) { + inline Real operator()(Real r, + const __attribute__((unused)) QuadraturePoint & q1, + const QuadraturePoint & q2) { UInt quad = q2.global_num; if(q1.global_num == quad) return 1.; Real D = (*selected_damage_with_damage_rate)(quad); Real w = 0.; Real alphaexp = 1.; Real betaexp = 2.; if(D < damage_limit_with_damage_rate) { Real alpha = std::max(0., 1. - pow((r*r / this->R2),alphaexp)); w = pow(alpha, betaexp); } return w; } private: /// limit at which a point is considered as complitely broken Real damage_limit_with_damage_rate; /// internal pointer to the current damage vector const Array<Real> * selected_damage_with_damage_rate; /// internal pointer to the current damage rate vector const Array<Real> * selected_damage_rate_with_damage_rate; }; /* -------------------------------------------------------------------------- */ /* Stress Based Weight */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> class StressBasedWeightFunction : public BaseWeightFunction<spatial_dimension> { public: StressBasedWeightFunction(Material & material); void init(); virtual void updateInternals(__attribute__((unused)) const ElementTypeMapArray<Real> & quadrature_points_coordinates) { updatePrincipalStress(_not_ghost); updatePrincipalStress(_ghost); }; void updatePrincipalStress(GhostType ghost_type); inline void updateQuadraturePointsCoordinates(ElementTypeMapArray<Real> & quadrature_points_coordinates); inline void selectType(ElementType type1, GhostType ghost_type1, ElementType type2, GhostType ghost_type2); - inline Real operator()(Real r, QuadraturePoint & q1, QuadraturePoint & q2); + inline Real operator()(Real r, + const QuadraturePoint & q1, + const QuadraturePoint & q2); inline Real computeRhoSquare(Real r, Vector<Real> & eigs, Matrix<Real> & eigenvects, Vector<Real> & x_s); private: Real ft; InternalField<Real> stress_diag; Array<Real> * selected_stress_diag; InternalField<Real> stress_base; Array<Real> * selected_stress_base; // InternalField<Real> quadrature_points_coordinates; Array<Real> * selected_position_1; Array<Real> * selected_position_2; InternalField<Real> characteristic_size; Array<Real> * selected_characteristic_size; }; template<UInt spatial_dimension> inline std::ostream & operator <<(std::ostream & stream, const BaseWeightFunction<spatial_dimension> & _this) { _this.printself(stream); return stream; } #include "weight_function_tmpl.hh" __END_AKANTU__ #endif /* __AKANTU_WEIGHT_FUNCTION_HH__ */ diff --git a/src/model/solid_mechanics/materials/weight_function_tmpl.hh b/src/model/solid_mechanics/materials/weight_function_tmpl.hh index 516b3b5e4..92dc9dabd 100644 --- a/src/model/solid_mechanics/materials/weight_function_tmpl.hh +++ b/src/model/solid_mechanics/materials/weight_function_tmpl.hh @@ -1,279 +1,279 @@ /** * @file weight_function_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Apr 13 2012 * @date last modification: Thu Jun 05 2014 * * @brief implementation of the weight function classes * * @section LICENSE * * Copyright (©) 2014 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/>. * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* Stress based weight function */ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> StressBasedWeightFunction<spatial_dimension>::StressBasedWeightFunction(Material & material) : BaseWeightFunction<spatial_dimension>(material, "stress_based"), stress_diag("stress_diag", material), selected_stress_diag(NULL), stress_base("stress_base", material), selected_stress_base(NULL), characteristic_size("lc", material), selected_characteristic_size(NULL) { this->registerParam("ft", this->ft, 0., _pat_parsable, "Tensile strength"); stress_diag.initialize(spatial_dimension); stress_base.initialize(spatial_dimension * spatial_dimension); characteristic_size.initialize(1); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void StressBasedWeightFunction<spatial_dimension>::init() { const Mesh & mesh = this->material.getModel().getFEEngine().getMesh(); for (UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = GhostType(g); Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, gt); for(; it != last_type; ++it) { UInt nb_quadrature_points = this->material.getModel().getFEEngine().getNbQuadraturePoints(*it, gt); const Array<UInt> & element_filter = this->material.getElementFilter(*it, gt); UInt nb_element = element_filter.getSize(); Array<Real> ones(nb_element*nb_quadrature_points, 1, 1.); Array<Real> & lc = characteristic_size(*it, gt); this->material.getModel().getFEEngine().integrateOnQuadraturePoints(ones, lc, 1, *it, gt, element_filter); for (UInt q = 0; q < nb_quadrature_points * nb_element; q++) { lc(q) = pow(lc(q), 1./ Real(spatial_dimension)); } } } } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void StressBasedWeightFunction<spatial_dimension>::updatePrincipalStress(GhostType ghost_type) { AKANTU_DEBUG_IN(); const Mesh & mesh = this->material.getModel().getFEEngine().getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { Array<Real>::const_matrix_iterator sigma = this->material.getStress(*it, ghost_type).begin(spatial_dimension, spatial_dimension); Array<Real>::vector_iterator eigenvalues = stress_diag(*it, ghost_type).begin(spatial_dimension); Array<Real>::vector_iterator eigenvalues_end = stress_diag(*it, ghost_type).end(spatial_dimension); Array<Real>::matrix_iterator eigenvector = stress_base(*it, ghost_type).begin(spatial_dimension, spatial_dimension); #ifndef __trick__ Array<Real>::iterator<Real> cl = characteristic_size(*it, ghost_type).begin(); #endif UInt q = 0; for(;eigenvalues != eigenvalues_end; ++sigma, ++eigenvalues, ++eigenvector, ++cl, ++q) { sigma->eig(*eigenvalues, *eigenvector); *eigenvalues /= ft; #ifndef __trick__ // specify a lower bound for principal stress based on the size of the element for (UInt i = 0; i < spatial_dimension; ++i) { (*eigenvalues)(i) = std::max(*cl / this->R, (*eigenvalues)(i)); } #endif } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> inline void StressBasedWeightFunction<spatial_dimension>::selectType(ElementType type1, GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_stress_diag = &stress_diag(type2, ghost_type2); selected_stress_base = &stress_base(type2, ghost_type2); selected_characteristic_size = &characteristic_size(type1, ghost_type1); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> inline Real StressBasedWeightFunction<spatial_dimension>::operator()(Real r, - QuadraturePoint & q1, - QuadraturePoint & q2) { + const QuadraturePoint & q1, + const QuadraturePoint & q2) { Real zero = std::numeric_limits<Real>::epsilon(); if(r < zero) return 1.; // means x and s are the same points const Vector<Real> & x = q1.getPosition(); const Vector<Real> & s = q2.getPosition(); Vector<Real> eigs = selected_stress_diag->begin(spatial_dimension)[q2.global_num]; Matrix<Real> eigenvects = selected_stress_base->begin(spatial_dimension, spatial_dimension)[q2.global_num]; Real min_rho_lc = selected_characteristic_size->begin()[q1.global_num]; Vector<Real> x_s(spatial_dimension); x_s = x; x_s -= s; Real rho_2 = computeRhoSquare(r, eigs, eigenvects, x_s); Real rho_lc_2 = std::max(this->R2 * rho_2, min_rho_lc*min_rho_lc); // Real w = std::max(0., 1. - r*r / rho_lc_2); // w = w*w; Real w = exp(- 2*2*r*r / rho_lc_2); return w; } /* -------------------------------------------------------------------------- */ template<> inline Real StressBasedWeightFunction<1>::computeRhoSquare(__attribute__ ((unused)) Real r, Vector<Real> & eigs, __attribute__ ((unused)) Matrix<Real> & eigenvects, __attribute__ ((unused)) Vector<Real> & x_s) { return eigs[0]; } /* -------------------------------------------------------------------------- */ template<> inline Real StressBasedWeightFunction<2>::computeRhoSquare(__attribute__ ((unused)) Real r, Vector<Real> & eigs, Matrix<Real> & eigenvects, Vector<Real> & x_s) { Vector<Real> u1(eigenvects.storage(), 2); Real cos_t = x_s.dot(u1) / (x_s.norm() * u1.norm()); Real cos_t_2; Real sin_t_2; Real sigma1_2 = eigs[0]*eigs[0]; Real sigma2_2 = eigs[1]*eigs[1]; #ifdef __trick__ Real zero = std::numeric_limits<Real>::epsilon(); if(std::abs(cos_t) < zero) { cos_t_2 = 0; sin_t_2 = 1; } else { cos_t_2 = cos_t * cos_t; sin_t_2 = (1 - cos_t_2); } Real rhop1 = std::max(0., cos_t_2 / sigma1_2); Real rhop2 = std::max(0., sin_t_2 / sigma2_2); #else cos_t_2 = cos_t * cos_t; sin_t_2 = (1 - cos_t_2); Real rhop1 = cos_t_2 / sigma1_2; Real rhop2 = sin_t_2 / sigma2_2; #endif return 1./ (rhop1 + rhop2); } /* -------------------------------------------------------------------------- */ template<> inline Real StressBasedWeightFunction<3>::computeRhoSquare(Real r, Vector<Real> & eigs, Matrix<Real> & eigenvects, Vector<Real> & x_s) { Vector<Real> u1(eigenvects.storage() + 0*3, 3); //Vector<Real> u2(eigenvects.storage() + 1*3, 3); Vector<Real> u3(eigenvects.storage() + 2*3, 3); Real zero = std::numeric_limits<Real>::epsilon(); Vector<Real> tmp(3); tmp.crossProduct(x_s, u3); Vector<Real> u3_C_x_s_C_u3(3); u3_C_x_s_C_u3.crossProduct(u3, tmp); Real norm_u3_C_x_s_C_u3 = u3_C_x_s_C_u3.norm(); Real cos_t = 0.; if(std::abs(norm_u3_C_x_s_C_u3) > zero) { Real inv_norm_u3_C_x_s_C_u3 = 1. / norm_u3_C_x_s_C_u3; cos_t = u1.dot(u3_C_x_s_C_u3) * inv_norm_u3_C_x_s_C_u3; } Real cos_p = u3.dot(x_s) / r; Real cos_t_2; Real sin_t_2; Real cos_p_2; Real sin_p_2; Real sigma1_2 = eigs[0]*eigs[0]; Real sigma2_2 = eigs[1]*eigs[1]; Real sigma3_2 = eigs[2]*eigs[2]; #ifdef __trick__ if(std::abs(cos_t) < zero) { cos_t_2 = 0; sin_t_2 = 1; } else { cos_t_2 = cos_t * cos_t; sin_t_2 = (1 - cos_t_2); } if(std::abs(cos_p) < zero) { cos_p_2 = 0; sin_p_2 = 1; } else { cos_p_2 = cos_p * cos_p; sin_p_2 = (1 - cos_p_2); } Real rhop1 = std::max(0., sin_p_2 * cos_t_2 / sigma1_2); Real rhop2 = std::max(0., sin_p_2 * sin_t_2 / sigma2_2); Real rhop3 = std::max(0., cos_p_2 / sigma3_2); #else cos_t_2 = cos_t * cos_t; sin_t_2 = (1 - cos_t_2); cos_p_2 = cos_p * cos_p; sin_p_2 = (1 - cos_p_2); Real rhop1 = sin_p_2 * cos_t_2 / sigma1_2; Real rhop2 = sin_p_2 * sin_t_2 / sigma2_2; Real rhop3 = cos_p_2 / sigma3_2; #endif return 1./ (rhop1 + rhop2 + rhop3); } diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index 43eb5e79e..ed785385a 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1793 +1,1796 @@ /** * @file solid_mechanics_model.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @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> * * @date creation: Tue Jul 27 2010 * @date last modification: Fri Sep 19 2014 * * @brief Implementation of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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_math.hh" #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "group_manager_inline_impl.cc" #include "dumpable_inline_impl.hh" #include "integration_scheme_2nd_order.hh" #include "element_group.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" #include "element_group.hh" #include <cmath> #ifdef AKANTU_USE_MUMPS #include "solver_mumps.hh" #endif #ifdef AKANTU_USE_PETSC #include "solver_petsc.hh" #include "petsc_matrix.hh" #endif #ifdef AKANTU_USE_IOHELPER # include "dumper_field.hh" # include "dumper_paraview.hh" # include "dumper_homogenizing_field.hh" # include "dumper_material_internal_field.hh" # include "dumper_elemental_field.hh" # include "dumper_material_padders.hh" # include "dumper_element_partition.hh" # include "dumper_iohelper.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const SolidMechanicsModelOptions default_solid_mechanics_model_options(_explicit_lumped_mass, false); /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), BoundaryCondition<SolidMechanicsModel>(), time_step(NAN), f_m2a(1.0), mass_matrix(NULL), velocity_damping_matrix(NULL), stiffness_matrix(NULL), jacobian_matrix(NULL), - element_index_by_material("element index by material", id), - material_selector(new DefaultMaterialSelector(element_index_by_material)), + material_index("material index", id), + material_local_numbering("material local numbering", id), + material_selector(new DefaultMaterialSelector(material_index)), is_default_material_selector(true), integrator(NULL), increment_flag(false), solver(NULL), synch_parallel(NULL), are_materials_instantiated(false) { AKANTU_DEBUG_IN(); createSynchronizerRegistry(this); registerFEEngineObject<MyFEEngineType>("SolidMechanicsFEEngine", mesh, spatial_dimension); this->displacement = NULL; this->mass = NULL; this->velocity = NULL; this->acceleration = NULL; this->force = NULL; this->residual = NULL; this->blocked_dofs = NULL; this->increment = NULL; this->increment_acceleration = NULL; this->dof_synchronizer = NULL; this->previous_displacement = NULL; materials.clear(); mesh.registerEventHandler(*this); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { delete *mat_it; } materials.clear(); delete integrator; delete solver; delete mass_matrix; delete velocity_damping_matrix; if(stiffness_matrix && stiffness_matrix != jacobian_matrix) delete stiffness_matrix; delete jacobian_matrix; delete synch_parallel; if(is_default_material_selector) { delete material_selector; material_selector = NULL; } AKANTU_DEBUG_OUT(); } void SolidMechanicsModel::setTimeStep(Real time_step) { this->time_step = time_step; #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilities */ void SolidMechanicsModel::initFull(const ModelOptions & options) { Model::initFull(options); const SolidMechanicsModelOptions & smm_options = dynamic_cast<const SolidMechanicsModelOptions &>(options); method = smm_options.analysis_method; // initialize the vectors initArrays(); // set the initial condition to 0 force->clear(); velocity->clear(); acceleration->clear(); displacement->clear(); // initialize pcb if(pbc_pair.size()!=0) initPBC(); // initialize the time integration schemes switch(method) { case _explicit_lumped_mass: initExplicit(); break; case _explicit_consistent_mass: initSolver(); initExplicit(); break; case _implicit_dynamic: initImplicit(true); break; case _static: initImplicit(false); break; default: AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel"); break; } // initialize the materials if(this->parser->getLastParsedFile() != "") { instantiateMaterials(); } if(!smm_options.no_init_materials) { initMaterials(); } if(increment_flag) initBC(*this, *displacement, *increment, *force); else initBC(*this, *displacement, *force); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initParallel(MeshPartition * partition, DataAccessor * data_accessor) { AKANTU_DEBUG_IN(); if (data_accessor == NULL) data_accessor = this; synch_parallel = &createParallelSynch(partition,data_accessor); synch_registry->registerSynchronizer(*synch_parallel, _gst_material_id); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_mass); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_stress); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnControlPoints(_not_ghost); fem_boundary.computeNormalsOnControlPoints(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initExplicit(AnalysisMethod analysis_method) { AKANTU_DEBUG_IN(); //in case of switch from implicit to explicit if(!this->isExplicit()) method = analysis_method; if (integrator) delete integrator; integrator = new CentralDifference(); UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); std::stringstream sstr; sstr << id << ":increment_acceleration"; increment_acceleration = &(alloc<Real>(sstr.str(), nb_nodes, nb_degree_of_freedom, Real())); AKANTU_DEBUG_OUT(); } void SolidMechanicsModel::initArraysPreviousDisplacment() { AKANTU_DEBUG_IN(); SolidMechanicsModel::setIncrementFlagOn(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp_t; sstr_disp_t << id << ":previous_displacement"; previous_displacement = &(alloc<Real > (sstr_disp_t.str(), nb_nodes, spatial_dimension, 0.)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Allocate all the needed vectors. By default their are not necessarily set to * 0 * */ void SolidMechanicsModel::initArrays() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":displacement"; // std::stringstream sstr_mass; sstr_mass << id << ":mass"; std::stringstream sstr_velo; sstr_velo << id << ":velocity"; std::stringstream sstr_acce; sstr_acce << id << ":acceleration"; std::stringstream sstr_forc; sstr_forc << id << ":force"; std::stringstream sstr_resi; sstr_resi << id << ":residual"; std::stringstream sstr_boun; sstr_boun << id << ":blocked_dofs"; displacement = &(alloc<Real>(sstr_disp.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); // mass = &(alloc<Real>(sstr_mass.str(), nb_nodes, spatial_dimension, 0)); velocity = &(alloc<Real>(sstr_velo.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); acceleration = &(alloc<Real>(sstr_acce.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); force = &(alloc<Real>(sstr_forc.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); residual = &(alloc<Real>(sstr_resi.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); blocked_dofs = &(alloc<bool>(sstr_boun.str(), nb_nodes, spatial_dimension, false)); std::stringstream sstr_curp; sstr_curp << id << ":current_position"; current_position = &(alloc<Real>(sstr_curp.str(), 0, spatial_dimension, REAL_INIT_VALUE)); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, gt); - element_index_by_material.alloc(nb_element, 2, *it, gt); + material_index.alloc(nb_element, 1, *it, gt); + material_local_numbering.alloc(nb_element, 1, *it, gt); } } dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian * */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initPBC() { Model::initPBC(); registerPBCSynchronizer(); // as long as there are ones on the diagonal of the matrix, we can put boudandary true for slaves std::map<UInt, UInt>::iterator it = pbc_pair.begin(); std::map<UInt, UInt>::iterator end = pbc_pair.end(); UInt dim = mesh.getSpatialDimension(); while(it != end) { for (UInt i=0; i<dim; ++i) (*blocked_dofs)((*it).first,i) = true; ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::registerPBCSynchronizer(){ PBCSynchronizer * synch = new PBCSynchronizer(pbc_pair); synch_registry->registerSynchronizer(*synch, _gst_smm_uv); synch_registry->registerSynchronizer(*synch, _gst_smm_mass); synch_registry->registerSynchronizer(*synch, _gst_smm_res); synch_registry->registerSynchronizer(*synch, _gst_for_dump); changeLocalEquationNumberForPBC(pbc_pair, mesh.getSpatialDimension()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); current_position->resize(nb_nodes); Real * current_position_val = current_position->storage(); Real * position_val = mesh.getNodes().storage(); Real * displacement_val = displacement->storage(); /// compute current_position = initial_position + displacement memcpy(current_position_val, position_val, nb_nodes*spatial_dimension*sizeof(Real)); for (UInt n = 0; n < nb_nodes*spatial_dimension; ++n) { *current_position_val++ += *displacement_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeUpdateResidualData() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); residual->resize(nb_nodes); /// copy the forces in residual for boundary conditions memcpy(residual->storage(), force->storage(), nb_nodes*spatial_dimension*sizeof(Real)); // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); updateCurrentPosition(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Explicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * This function compute the second member of the motion equation. That is to * say the sum of forces @f$ r = F_{ext} - F_{int} @f$. @f$ F_{ext} @f$ is given * by the user in the force vector, and @f$ F_{int} @f$ is computed as @f$ * F_{int} = \int_{\Omega} N \sigma d\Omega@f$ * */ void SolidMechanicsModel::updateResidual(bool need_initialize) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); // f = f_ext - f_int // f = f_ext if(need_initialize) initializeUpdateResidualData(); AKANTU_DEBUG_INFO("Compute local stresses"); std::vector<Material *>::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } #ifdef AKANTU_DAMAGE_NON_LOCAL /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ synch_registry->asynchronousSynchronize(_gst_mnl_for_average); AKANTU_DEBUG_INFO("Compute non local stresses for local elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_not_ghost); } AKANTU_DEBUG_INFO("Wait distant non local stresses"); synch_registry->waitEndSynchronize(_gst_mnl_for_average); AKANTU_DEBUG_INFO("Compute non local stresses for ghosts elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_ghost); } #endif /* ------------------------------------------------------------------------ */ /* assembling the forces internal */ // communicate the stress AKANTU_DEBUG_INFO("Send data for residual assembly"); synch_registry->asynchronousSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for local elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_not_ghost); } AKANTU_DEBUG_INFO("Wait distant stresses"); // finalize communications synch_registry->waitEndSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeStresses() { if (isExplicit()) { // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); // compute stresses on all local elements for each materials std::vector<Material *>::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ #ifdef AKANTU_DAMAGE_NON_LOCAL /* Computation of the non local part */ synch_registry->asynchronousSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_not_ghost); } synch_registry->waitEndSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_ghost); } #endif } else { std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStressesFromTangentModuli(_not_ghost); } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateResidualInternal() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Update the residual"); // f = f_ext - f_int - Ma - Cv = r - Ma - Cv; if(method != _static) { // f -= Ma if(mass_matrix) { // if full mass_matrix Array<Real> * Ma = new Array<Real>(*acceleration, true, "Ma"); *Ma *= *mass_matrix; /// \todo check unit conversion for implicit dynamics // *Ma /= f_m2a *residual -= *Ma; delete Ma; } else if (mass) { // else lumped mass UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); Real * mass_val = mass->storage(); Real * accel_val = acceleration->storage(); Real * res_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *res_val -= *accel_val * *mass_val /f_m2a; } blocked_dofs_val++; res_val++; mass_val++; accel_val++; } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } // f -= Cv if(velocity_damping_matrix) { Array<Real> * Cv = new Array<Real>(*velocity); *Cv *= *velocity_damping_matrix; *residual -= *Cv; delete Cv; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateAcceleration() { AKANTU_DEBUG_IN(); updateResidualInternal(); if(method == _explicit_lumped_mass) { /* residual = residual_{n+1} - M * acceleration_n therefore solution = increment acceleration not acceleration */ solveLumped(*increment_acceleration, *mass, *residual, *blocked_dofs, f_m2a); } else if (method == _explicit_consistent_mass) { solve<NewmarkBeta::_acceleration_corrector>(*increment_acceleration); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveLumped(Array<Real> & x, const Array<Real> & A, const Array<Real> & b, const Array<bool> & blocked_dofs, Real alpha) { Real * A_val = A.storage(); Real * b_val = b.storage(); Real * x_val = x.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); UInt nb_degrees_of_freedom = x.getSize() * x.getNbComponent(); for (UInt n = 0; n < nb_degrees_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *x_val = alpha * (*b_val / *A_val); } x_val++; A_val++; b_val++; blocked_dofs_val++; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitPred() { AKANTU_DEBUG_IN(); if(increment_flag) { if(previous_displacement) increment->copy(*previous_displacement); else increment->copy(*displacement); } AKANTU_DEBUG_ASSERT(integrator,"itegrator should have been allocated: " << "have called initExplicit ? " << "or initImplicit ?"); integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); if(increment_flag) { Real * inc_val = increment->storage(); Real * dis_val = displacement->storage(); UInt nb_degree_of_freedom = displacement->getSize() * displacement->getNbComponent(); for (UInt n = 0; n < nb_degree_of_freedom; ++n) { *inc_val = *dis_val - *inc_val; inc_val++; dis_val++; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitCorr() { AKANTU_DEBUG_IN(); integrator->integrationSchemeCorrAccel(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment_acceleration); if(previous_displacement) previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveStep() { AKANTU_DEBUG_IN(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); this->explicitPred(); this->updateResidual(); this->updateAcceleration(); this->explicitCorr(); EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Implicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * Initialize the solver and create the sparse matrices needed. * */ void SolidMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) { #if !defined(AKANTU_USE_MUMPS) && !defined(AKANTU_USE_PETSC)// or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake AKANTU_DEBUG_ERROR("You should at least activate one solver."); #else UInt nb_global_nodes = mesh.getNbGlobalNodes(); delete jacobian_matrix; std::stringstream sstr; sstr << id << ":jacobian_matrix"; #ifdef AKANTU_USE_PETSC jacobian_matrix = new PETScMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); #else jacobian_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); #endif //AKANTU_USE PETSC jacobian_matrix->buildProfile(mesh, *dof_synchronizer, spatial_dimension); if (!isExplicit()) { delete stiffness_matrix; std::stringstream sstr_sti; sstr_sti << id << ":stiffness_matrix"; #ifdef AKANTU_USE_PETSC stiffness_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); stiffness_matrix->buildProfile(mesh, *dof_synchronizer, spatial_dimension); #else stiffness_matrix = new SparseMatrix(*jacobian_matrix, sstr_sti.str(), memory_id); #endif //AKANTU_USE_PETSC } std::stringstream sstr_solv; sstr_solv << id << ":solver"; #ifdef AKANTU_USE_PETSC solver = new SolverPETSc(*jacobian_matrix, sstr_solv.str()); #elif defined(AKANTU_USE_MUMPS) solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS if(solver) solver->initialize(options); #endif //AKANTU_HAS_SOLVER } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initJacobianMatrix() { #if defined(AKANTU_USE_MUMPS) && !defined(AKANTU_USE_PETSC) // @todo make it more flexible: this is an ugly patch to treat the case of non // fix profile of the K matrix delete jacobian_matrix; std::stringstream sstr_sti; sstr_sti << id << ":jacobian_matrix"; jacobian_matrix = new SparseMatrix(*stiffness_matrix, sstr_sti.str(), memory_id); std::stringstream sstr_solv; sstr_solv << id << ":solver"; delete solver; solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); if(solver) solver->initialize(_solver_no_options); #else AKANTU_DEBUG_ERROR("You need to activate the solver mumps."); #endif } /* -------------------------------------------------------------------------- */ /** * Initialize the implicit solver, either for dynamic or static cases, * * @param dynamic */ void SolidMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); method = dynamic ? _implicit_dynamic : _static; if (!increment) setIncrementFlagOn(); initSolver(solver_options); if(method == _implicit_dynamic) { if(integrator) delete integrator; integrator = new TrapezoidalRule2(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initialAcceleration() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving Ma = f"); Solver * acc_solver = NULL; std::stringstream sstr; sstr << id << ":tmp_mass_matrix"; SparseMatrix * tmp_mass = new SparseMatrix(*mass_matrix, sstr.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solver; sstr << id << ":solver_mass_matrix"; acc_solver = new SolverMumps(*mass_matrix, sstr_solver.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS acc_solver->initialize(); tmp_mass->applyBoundary(*blocked_dofs); acc_solver->setRHS(*residual); acc_solver->solve(*acceleration); delete acc_solver; delete tmp_mass; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); stiffness_matrix->clear(); // call compute stiffness matrix on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->assembleStiffnessMatrix(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix & SolidMechanicsModel::initVelocityDampingMatrix() { if(!velocity_damping_matrix) velocity_damping_matrix = new SparseMatrix(*jacobian_matrix, id + ":velocity_damping_matrix", memory_id); return *velocity_damping_matrix; } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_increment>(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); Real * displacement_val = displacement->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val) && is_local_node) { norm[0] += *increment_val * *increment_val; norm[1] += *displacement_val * *displacement_val; } blocked_dofs_val++; increment_val++; displacement_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum); norm[0] = sqrt(norm[0]); norm[1] = sqrt(norm[1]); AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something goes wrong in the solve phase"); if (norm[1] < Math::getTolerance()) { error = norm[0]; AKANTU_DEBUG_OUT(); // cout<<"Error 1: "<<error<<endl; return error < tolerance; } AKANTU_DEBUG_OUT(); if(norm[1] > Math::getTolerance()) error = norm[0] / norm[1]; else error = norm[0]; //In case the total displacement is zero! // cout<<"Error 2: "<<error<<endl; return (error < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_residual>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < spatial_dimension; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val; } blocked_dofs_val++; residual_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_residual_mass_wgh>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->storage(); Real * mass_val = this->mass->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < spatial_dimension; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val/(*mass_val * *mass_val); } blocked_dofs_val++; residual_val++; mass_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; mass_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitPred() { AKANTU_DEBUG_IN(); if(previous_displacement) previous_displacement->copy(*displacement); if(method == _implicit_dynamic) integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitCorr() { AKANTU_DEBUG_IN(); if(method == _implicit_dynamic) { integrator->integrationSchemeCorrDispl(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment); } else { UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); bool * boun_val = blocked_dofs->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++boun_val){ *incr_val *= (1. - *boun_val); *disp_val += *incr_val; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateIncrement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); Real * prev_disp_val = previous_displacement->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++prev_disp_val) *incr_val = (*disp_val - *prev_disp_val); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updatePreviousDisplacement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeBoundaries() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initParallel?"); synch_registry->synchronize(_gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeResidual() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initPBC?"); synch_registry->synchronize(_gst_smm_res); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setIncrementFlagOn() { AKANTU_DEBUG_IN(); if(!increment) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_inc; sstr_inc << id << ":increment"; increment = &(alloc<Real>(sstr_inc.str(), nb_nodes, spatial_dimension, 0.)); } increment_flag = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors StaticCommunicator::getStaticCommunicator().allReduce(&min_dt, 1, _so_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Material ** mat_val = &(materials.at(0)); Real min_dt = std::numeric_limits<Real>::max(); updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; elem.kind = _ek_regular; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { elem.type = *it; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); UInt nb_element = mesh.getNbElement(*it); - Array<UInt>::iterator< Vector<UInt> > eibm = - element_index_by_material(*it, ghost_type).begin(2); + Array<UInt>::const_scalar_iterator mat_indexes = material_index(*it, ghost_type).begin(); + Array<UInt>::const_scalar_iterator mat_loc_num = material_local_numbering(*it, ghost_type).begin(); Array<Real> X(0, nb_nodes_per_element*spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, *it, _not_ghost); Array<Real>::matrix_iterator X_el = X.begin(spatial_dimension, nb_nodes_per_element); - for (UInt el = 0; el < nb_element; ++el, ++X_el, ++eibm) { - elem.element = (*eibm)(1); + for (UInt el = 0; el < nb_element; ++el, ++X_el, ++mat_indexes, ++mat_loc_num) { + elem.element = *mat_loc_num; Real el_h = getFEEngine().getElementInradius(*X_el, *it); - Real el_c = mat_val[(*eibm)(0)]->getCelerity(elem); + Real el_c = mat_val[*mat_indexes]->getCelerity(elem); Real el_dt = el_h / el_c; min_dt = std::min(min_dt, el_dt); } } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real energy = 0.; /// call update residual on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getPotentialEnergy(); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy() { AKANTU_DEBUG_IN(); if (!mass && !mass_matrix) AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); Real * vel_val = velocity->storage(); Real * mass_val = mass->storage(); for (UInt n = 0; n < nb_nodes; ++n) { Real mv2 = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { if (count_node) mv2 += *vel_val * *vel_val * *mass_val; vel_val++; mass_val++; } ekin += mv2; } StaticCommunicator::getStaticCommunicator().allReduce(&ekin, 1, _so_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(type); Array<Real> vel_on_quad(nb_quadrature_points, spatial_dimension); Array<UInt> filter_element(1, 1, index); getFEEngine().interpolateOnQuadraturePoints(*velocity, vel_on_quad, spatial_dimension, type, _not_ghost, filter_element); Array<Real>::vector_iterator vit = vel_on_quad.begin(spatial_dimension); Array<Real>::vector_iterator vend = vel_on_quad.end(spatial_dimension); Vector<Real> rho_v2(nb_quadrature_points); - Real rho = materials[element_index_by_material(type)(index, 0)]->getRho(); + Real rho = materials[material_index(type)(index)]->getRho(); for (UInt q = 0; vit != vend; ++vit, ++q) { rho_v2(q) = rho * vit->dot(*vit); } AKANTU_DEBUG_OUT(); return .5*getFEEngine().integrate(rho_v2, type, index); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); Real * velo = velocity->storage(); Real * forc = force->storage(); Real * resi = residual->storage(); bool * boun = blocked_dofs->storage(); Real work = 0.; UInt nb_nodes = mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { if (count_node) { if(*boun) work -= *resi * *velo * time_step; else work += *forc * *velo * time_step; } ++velo; ++forc; ++resi; ++boun; } } StaticCommunicator::getStaticCommunicator().allReduce(&work, 1, _so_sum); AKANTU_DEBUG_OUT(); return work; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(); } else if (energy_id == "external work"){ return getExternalWork(); } Real energy = 0.; std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getEnergy(energy_id); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id, const ElementType & type, UInt index){ AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(type, index); } std::vector<Material *>::iterator mat_it; - Vector<UInt> mat = element_index_by_material(type, _not_ghost).begin(2)[index]; - Real energy = materials[mat(0)]->getEnergy(energy_id, type, mat(1)); + UInt mat_index = this->material_index(type, _not_ghost)(index); + UInt mat_loc_num = this->material_local_numbering(type, _not_ghost)(index); + Real energy = this->materials[mat_index]->getEnergy(energy_id, type, mat_loc_num); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array<UInt> & nodes_list, __attribute__((unused)) const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if(displacement) displacement->resize(nb_nodes); if(mass ) mass ->resize(nb_nodes); if(velocity ) velocity ->resize(nb_nodes); if(acceleration) acceleration->resize(nb_nodes); if(force ) force ->resize(nb_nodes); if(residual ) residual ->resize(nb_nodes); if(blocked_dofs) blocked_dofs->resize(nb_nodes); if(previous_displacement) previous_displacement->resize(nb_nodes); if(increment_acceleration) increment_acceleration->resize(nb_nodes); if(increment) increment->resize(nb_nodes); if(current_position) current_position->resize(nb_nodes); delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onNodesAdded(nodes_list, event); } if (method != _explicit_lumped_mass) { this->initJacobianMatrix(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = this->mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = this->mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = this->mesh.getNbElement(*it, gt); - if(!element_index_by_material.exists(*it, gt)) - this->element_index_by_material.alloc(nb_element, 2, *it, gt); - else - this->element_index_by_material(*it, gt).resize(nb_element); + if(!material_index.exists(*it, gt)) { + this->material_index .alloc(nb_element, 1, *it, gt); + this->material_local_numbering.alloc(nb_element, 1, *it, gt); + } else { + this->material_index (*it, gt).resize(nb_element); + this->material_local_numbering(*it, gt).resize(nb_element); + } } } Array<Element>::const_iterator<Element> it = element_list.begin(); Array<Element>::const_iterator<Element> end = element_list.end(); ElementTypeMapArray<UInt> filter("new_element_filter", this->getID()); for (UInt el = 0; it != end; ++it, ++el) { const Element & elem = *it; if(!filter.exists(elem.type, elem.ghost_type)) - filter.alloc(0, 2, elem.type, elem.ghost_type); + filter.alloc(0, 1, elem.type, elem.ghost_type); filter(elem.type, elem.ghost_type).push_back(elem.element); } this->assignMaterialToElements(&filter); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsAdded(element_list, event); } if(method == _explicit_lumped_mass) this->assembleMassLumped(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved(__attribute__((unused)) const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) { this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsRemoved(element_list, new_numbering, event); } - - this->element_index_by_material.onElementsRemoved(new_numbering); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesRemoved(__attribute__((unused)) const Array<UInt> & element_list, const Array<UInt> & new_numbering, __attribute__((unused)) const RemovedNodesEvent & event) { if(displacement) mesh.removeNodesFromArray(*displacement, new_numbering); if(mass ) mesh.removeNodesFromArray(*mass , new_numbering); if(velocity ) mesh.removeNodesFromArray(*velocity , new_numbering); if(acceleration) mesh.removeNodesFromArray(*acceleration, new_numbering); if(force ) mesh.removeNodesFromArray(*force , new_numbering); if(residual ) mesh.removeNodesFromArray(*residual , new_numbering); if(blocked_dofs) mesh.removeNodesFromArray(*blocked_dofs, new_numbering); if(increment_acceleration) mesh.removeNodesFromArray(*increment_acceleration, new_numbering); if(increment) mesh.removeNodesFromArray(*increment , new_numbering); delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::isInternal(const std::string & field_name, const ElementKind & element_kind){ bool is_internal = false; /// check if at least one material contains field_id as an internal for (UInt m = 0; m < materials.size() && !is_internal; ++m) { is_internal |= materials[m]->isInternal(field_name, element_kind); } return is_internal; } /* -------------------------------------------------------------------------- */ ElementTypeMap<UInt> SolidMechanicsModel::getInternalDataPerElem(const std::string & field_name, const ElementKind & element_kind){ if (!(this->isInternal(field_name,element_kind))) AKANTU_EXCEPTION("unknown internal " << field_name); for (UInt m = 0; m < materials.size() ; ++m) { if (materials[m]->isInternal(field_name, element_kind)) return materials[m]->getInternalDataPerElem(field_name,element_kind); } return ElementTypeMap<UInt>(); } /* -------------------------------------------------------------------------- */ ElementTypeMapArray<Real> & SolidMechanicsModel::flattenInternal(const std::string & field_name, const ElementKind & kind){ std::pair<std::string,ElementKind> key(field_name,kind); if (this->registered_internals.count(key) == 0){ this->registered_internals[key] = new ElementTypeMapArray<Real>(field_name,this->id); } ElementTypeMapArray<Real> * internal_flat = this->registered_internals[key]; for (UInt m = 0; m < materials.size(); ++m) materials[m]->flattenInternal(field_name,*internal_flat,_not_ghost,kind); return *internal_flat; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::flattenAllRegisteredInternals(const ElementKind & kind){ std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *> ::iterator it = this->registered_internals.begin(); std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *>::iterator end = this->registered_internals.end(); while (it != end){ if (kind == it->first.second) this->flattenInternal(it->first.first,kind); ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onDump(){ this->flattenAllRegisteredInternals(_ek_regular); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind){ dumper::Field * field = NULL; if(field_name == "partitions") field = mesh.createElementalField<UInt, dumper::ElementPartitionField>(mesh.getConnectivities(),group_name,this->spatial_dimension,kind); - else if(field_name == "element_index_by_material") - field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(element_index_by_material,group_name,this->spatial_dimension,kind); + else if(field_name == "material_index") + field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(material_index,group_name,this->spatial_dimension,kind); else { bool is_internal = this->isInternal(field_name,kind); if (is_internal) { - ElementTypeMap<UInt> nb_data_per_elem = this->getInternalDataPerElem(field_name,kind); ElementTypeMapArray<Real> & internal_flat = this->flattenInternal(field_name,kind); field = mesh.createElementalField<Real, dumper::InternalMaterialField>(internal_flat, group_name, this->spatial_dimension,kind,nb_data_per_elem); //treat the paddings if (padding_flag){ if (field_name == "stress"){ if (this->spatial_dimension == 2) { dumper::StressPadder<2> * foo = new dumper::StressPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } // else if (field_name == "strain"){ // if (this->spatial_dimension == 2) { // dumper::StrainPadder<2> * foo = new dumper::StrainPadder<2>(*this); // field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); // } // } } // homogenize the field dumper::ComputeFunctorInterface * foo = dumper::HomogenizerProxy::createHomogenizer(*field); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string,Array<Real>* > real_nodal_fields; real_nodal_fields["displacement" ] = displacement; real_nodal_fields["mass" ] = mass; real_nodal_fields["velocity" ] = velocity; real_nodal_fields["acceleration" ] = acceleration; real_nodal_fields["force" ] = force; real_nodal_fields["residual" ] = residual; real_nodal_fields["increment" ] = increment; dumper::Field * field = NULL; if (padding_flag) field = mesh.createNodalField(real_nodal_fields[field_name],group_name, 3); else field = mesh.createNodalField(real_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, 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; } /* -------------------------------------------------------------------------- */ #else /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind){ return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump() { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeCauchyStresses() { AKANTU_DEBUG_IN(); // call compute stiffness matrix on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; if(mat.isFiniteDeformation()) mat.computeAllCauchyStresses(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::saveStressAndStrainBeforeDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::BeginningOfDamageIterationEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateEnergiesAfterDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::AfterDamageEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); mass ->printself(stream, indent + 2); velocity ->printself(stream, indent + 2); acceleration->printself(stream, indent + 2); force ->printself(stream, indent + 2); residual ->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; - stream << space << " + connectivity type information [" << std::endl; - element_index_by_material.printself(stream, indent + 2); + stream << space << " + material information [" << std::endl; + material_index.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + materials [" << std::endl; std::vector<Material *>::const_iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { const Material & mat = *(*mat_it); mat.printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index 2575a72db..568500513 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,738 +1,741 @@ /** * @file solid_mechanics_model.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Model of Solid Mechanics * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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_SOLID_MECHANICS_MODEL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_types.hh" #include "model.hh" #include "data_accessor.hh" #include "mesh.hh" #include "dumpable.hh" #include "boundary_condition.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "integration_scheme_2nd_order.hh" #include "solver.hh" #include "material_selector.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Material; class IntegrationScheme2ndOrder; class SparseMatrix; class DumperIOHelper; } /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ struct SolidMechanicsModelOptions : public ModelOptions { SolidMechanicsModelOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool no_init_materials = false) : analysis_method(analysis_method), no_init_materials(no_init_materials) { } AnalysisMethod analysis_method; bool no_init_materials; }; extern const SolidMechanicsModelOptions default_solid_mechanics_model_options; class SolidMechanicsModel : public Model, public DataAccessor, public MeshEventHandler, public BoundaryCondition<SolidMechanicsModel>, public EventHandlerManager<SolidMechanicsModelEventHandler> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewMaterialElementsEvent : public NewElementsEvent { public: AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array <UInt> &); AKANTU_GET_MACRO(MaterialList, material, const Array <UInt> &); protected: Array <UInt> material; }; typedef FEEngineTemplate <IntegratorGauss, ShapeLagrange> MyFEEngineType; protected: typedef EventHandlerManager <SolidMechanicsModelEventHandler> EventManager; public: SolidMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize completely the model virtual void initFull(const ModelOptions & options = default_solid_mechanics_model_options); /// initialize the fem object needed for boundary conditions void initFEEngineBoundary(); /// register the tags associated with the parallel synchronizer void initParallel(MeshPartition *partition, DataAccessor *data_accessor = NULL); /// allocate all vectors void initArrays(); /// allocate all vectors void initArraysPreviousDisplacment(); /// initialize all internal arrays for materials virtual void initMaterials(); /// initialize the model virtual void initModel(); /// init PBC synchronizer void initPBC(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* PBC */ /* ------------------------------------------------------------------------ */ public: /// change the equation number for proper assembly when using PBC // void changeEquationNumberforPBC(std::map <UInt, UInt> & pbc_pair); /// synchronize Residual for output void synchronizeResidual(); protected: /// register PBC synchronizer void registerPBCSynchronizer(); /* ------------------------------------------------------------------------ */ /* Explicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the stuff for the explicit scheme void initExplicit(AnalysisMethod analysis_method = _explicit_lumped_mass); bool isExplicit() { return method == _explicit_lumped_mass || method == _explicit_consistent_mass; } /// initialize the array needed by updateResidual (residual, current_position) void initializeUpdateResidualData(); /// update the current position vector void updateCurrentPosition(); /// assemble the residual for the explicit scheme virtual void updateResidual(bool need_initialize = true); /** * \brief compute the acceleration from the residual * this function is the explicit equivalent to solveDynamic in implicit * In the case of lumped mass just divide the residual by the mass * In the case of not lumped mass call solveDynamic<_acceleration_corrector> */ void updateAcceleration(); void updateIncrement(); void updatePreviousDisplacement(); void saveStressAndStrainBeforeDamage(); void updateEnergiesAfterDamage(); /// Solve the system @f[ A x = \alpha b @f] with A a lumped matrix void solveLumped(Array <Real> & x, const Array <Real> & A, const Array <Real> & b, const Array <bool> & blocked_dofs, Real alpha); /// explicit integration predictor void explicitPred(); /// explicit integration corrector void explicitCorr(); public: void solveStep(); /* ------------------------------------------------------------------------ */ /* Implicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver and the jacobian_matrix (called by initImplicit) void initSolver(SolverOptions & options = _solver_no_options); /// initialize the stuff for the implicit solver void initImplicit(bool dynamic = false, SolverOptions & solver_options = _solver_no_options); /// solve Ma = f to get the initial acceleration void initialAcceleration(); /// assemble the stiffness matrix void assembleStiffnessMatrix(); public: /** * solve a step (predictor + convergence loop + corrector) using the * the given convergence method (see akantu::SolveConvergenceMethod) * and the given convergence criteria (see * akantu::SolveConvergenceCriteria) **/ template <SolveConvergenceMethod method, SolveConvergenceCriteria criteria> bool solveStep(Real tolerance, UInt max_iteration = 100); template <SolveConvergenceMethod method, SolveConvergenceCriteria criteria> bool solveStep(Real tolerance, Real & error, UInt max_iteration = 100, bool do_not_factorize = false); public: /** * solve Ku = f using the the given convergence method (see * akantu::SolveConvergenceMethod) and the given convergence * criteria (see akantu::SolveConvergenceCriteria) **/ template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> bool solveStatic(Real tolerance, UInt max_iteration, bool do_not_factorize = false); /// test if the system is converged template <SolveConvergenceCriteria criteria> bool testConvergence(Real tolerance, Real & error); /// test the convergence (norm of increment) bool testConvergenceIncrement(Real tolerance) __attribute__((deprecated)); bool testConvergenceIncrement(Real tolerance, Real & error) __attribute__((deprecated)); /// test the convergence (norm of residual) bool testConvergenceResidual(Real tolerance) __attribute__((deprecated)); bool testConvergenceResidual(Real tolerance, Real & error) __attribute__((deprecated)); /// create and return the velocity damping matrix SparseMatrix & initVelocityDampingMatrix(); /// implicit time integration predictor void implicitPred(); /// implicit time integration corrector void implicitCorr(); /// compute the Cauchy stress on user demand. void computeCauchyStresses(); protected: /// finish the computation of residual to solve in increment void updateResidualInternal(); /// compute the support reaction and store it in force void updateSupportReaction(); public: //protected: Daniel changed it just for a test /// compute A and solve @f[ A\delta u = f_ext - f_int @f] template <NewmarkBeta::IntegrationSchemeCorrectorType type> void solve(Array<Real> &increment, Real block_val = 1., bool need_factorize = true, bool has_profile_changed = false); private: /// re-initialize the J matrix (to use if the profile of K changed) void initJacobianMatrix(); /* ------------------------------------------------------------------------ */ /* Explicit/Implicit */ /* ------------------------------------------------------------------------ */ public: /// Update the stresses for the computation of the residual of the Stiffness /// matrix in the case of finite deformation void computeStresses(); /// synchronize the ghost element boundaries values void synchronizeBoundaries(); /* ------------------------------------------------------------------------ */ /* Materials (solid_mechanics_model_material.cc) */ /* ------------------------------------------------------------------------ */ public: /// registers all the custom materials of a given type present in the input file template <typename M> void registerNewCustomMaterials(const ID & mat_type); /// register an empty material of a given type template <typename M> Material & registerNewEmptyMaterial(const std::string & name); // /// Use a UIntData in the mesh to specify the material to use per element // void setMaterialIDsFromIntData(const std::string & data_name); /// reassigns materials depending on the material selector virtual void reassignMaterial(); protected: /// register a material in the dynamic database template <typename M> Material & registerNewMaterial(const ParserSection & mat_section); /// read the material files to instantiate all the materials void instantiateMaterials(); /// set the element_id_by_material and add the elements to the good materials void assignMaterialToElements(const ElementTypeMapArray<UInt> * filter = NULL); /* ------------------------------------------------------------------------ */ /* Mass (solid_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); protected: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); /// fill a vector of rho void computeRho(Array <Real> & rho, ElementType type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline virtual UInt getNbDataForElements(const Array <Element> & elements, SynchronizationTag tag) const; inline virtual void packElementData(CommunicationBuffer & buffer, const Array <Element> & elements, SynchronizationTag tag) const; inline virtual void unpackElementData(CommunicationBuffer & buffer, const Array <Element> & elements, SynchronizationTag tag); inline virtual UInt getNbDataToPack(SynchronizationTag tag) const; inline virtual UInt getNbDataToUnpack(SynchronizationTag tag) const; inline virtual void packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const; inline virtual void unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag); protected: inline void splitElementByMaterial(const Array <Element> & elements, Array <Element> * elements_per_mat) const; /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: virtual void onNodesAdded(const Array <UInt> & nodes_list, const NewNodesEvent & event); virtual void onNodesRemoved(const Array <UInt> & element_list, const Array <UInt> & new_numbering, const RemovedNodesEvent & event); virtual void onElementsAdded(const Array <Element> & nodes_list, const NewElementsEvent & event); virtual void onElementsRemoved(const Array <Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event); /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ public: virtual void onDump(); //! decide wether a field is a material internal or not bool isInternal(const std::string & field_name, const ElementKind & element_kind); #ifndef SWIG //! give the amount of data per element ElementTypeMap<UInt> getInternalDataPerElem(const std::string & field_name, const ElementKind & kind); //! flatten a given material internal field ElementTypeMapArray<Real> & flattenInternal(const std::string & field_name, const ElementKind & kind); //! flatten all the registered material internals void flattenAllRegisteredInternals(const ElementKind & kind); #endif 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); virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); virtual void dump(); virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the current value of the time step AKANTU_GET_MACRO(TimeStep, time_step, Real); /// set the value of the time step void setTimeStep(Real time_step); /// get the value of the conversion from forces/ mass to acceleration AKANTU_GET_MACRO(F_M2A, f_m2a, Real); /// set the value of the conversion from forces/ mass to acceleration AKANTU_SET_MACRO(F_M2A, f_m2a, Real); /// get the SolidMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array <Real> &); /// get the SolidMechanicsModel::previous_displacement vector AKANTU_GET_MACRO(PreviousDisplacement, *previous_displacement, Array <Real> &); /// get the SolidMechanicsModel::current_position vector \warn only consistent /// after a call to SolidMechanicsModel::updateCurrentPosition AKANTU_GET_MACRO(CurrentPosition, *current_position, const Array <Real> &); /// get the SolidMechanicsModel::increment vector \warn only consistent if /// SolidMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *increment, Array <Real> &); /// get the lumped SolidMechanicsModel::mass vector AKANTU_GET_MACRO(Mass, *mass, Array <Real> &); /// get the SolidMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array <Real> &); /// get the SolidMechanicsModel::acceleration vector, updated by /// SolidMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array <Real> &); /// get the SolidMechanicsModel::force vector (boundary forces) AKANTU_GET_MACRO(Force, *force, Array <Real> &); /// get the SolidMechanicsModel::residual vector, computed by /// SolidMechanicsModel::updateResidual AKANTU_GET_MACRO(Residual, *residual, Array <Real> &); /// get the SolidMechanicsModel::blocked_dofs vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array <bool> &); /// get the SolidMechnicsModel::incrementAcceleration vector AKANTU_GET_MACRO(IncrementAcceleration, *increment_acceleration, Array <Real> &); /// get the value of the SolidMechanicsModel::increment_flag AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool); /// get a particular material (by material index) inline Material & getMaterial(UInt mat_index); /// get a particular material (by material index) inline const Material & getMaterial(UInt mat_index) const; /// get a particular material (by material name) inline Material & getMaterial(const std::string & name); /// get a particular material (by material name) inline const Material & getMaterial(const std::string & name) const; /// get a particular material id from is name inline UInt getMaterialIndex(const std::string & name) const; /// give the number of materials inline UInt getNbMaterials() const { return materials.size(); } inline void setMaterialSelector(MaterialSelector & selector); /// give the material internal index from its id Int getInternalIndexFromID(const ID & id) const; /// compute the stable time step Real getStableTimeStep(); /// compute the potential energy Real getPotentialEnergy(); /// compute the kinetic energy Real getKineticEnergy(); Real getKineticEnergy(const ElementType & type, UInt index); /// compute the external work (for impose displacement, the velocity should be given too) Real getExternalWork(); /// get the energies Real getEnergy(const std::string & energy_id); /// compute the energy for energy Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index); /** * @brief set the SolidMechanicsModel::increment_flag to on, the activate the * update of the SolidMechanicsModel::increment vector */ void setIncrementFlagOn(); /// get the stiffness matrix AKANTU_GET_MACRO(StiffnessMatrix, *stiffness_matrix, SparseMatrix &); /// get the global jacobian matrix of the system AKANTU_GET_MACRO(GlobalJacobianMatrix, *jacobian_matrix, const SparseMatrix &); /// get the mass matrix AKANTU_GET_MACRO(MassMatrix, *mass_matrix, SparseMatrix &); /// get the velocity damping matrix AKANTU_GET_MACRO(VelocityDampingMatrix, *velocity_damping_matrix, SparseMatrix &); /// get the FEEngine object to integrate or interpolate on the boundary inline FEEngine & getFEEngineBoundary(const ID & name = ""); /// get integrator AKANTU_GET_MACRO(Integrator, *integrator, const IntegrationScheme2ndOrder &); /// get access to the internal solver AKANTU_GET_MACRO(Solver, *solver, Solver &); /// get synchronizer AKANTU_GET_MACRO(Synchronizer, *synch_parallel, const DistributedSynchronizer &); - AKANTU_GET_MACRO(ElementIndexByMaterial, element_index_by_material, const ElementTypeMapArray <UInt> &); + AKANTU_GET_MACRO(MaterialByElement, material_index, const ElementTypeMapArray<UInt> &); /// vectors containing local material element index for each global element index - AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementIndexByMaterial, element_index_by_material, UInt); - AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementIndexByMaterial, element_index_by_material, UInt); + AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialByElement, material_index, UInt); + AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialByElement, material_index, UInt); + AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialLocalNumbering, material_local_numbering, UInt); + AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialLocalNumbering, material_local_numbering, UInt); /// Get the type of analysis method used AKANTU_GET_MACRO(AnalysisMethod, method, AnalysisMethod); - template <int dim, class model_type> friend struct ContactData; template <int Dim, AnalysisMethod s, ContactResolutionMethod r> friend class ContactResolution; - protected: friend class Material; protected: /// compute the stable time step Real getStableTimeStep(const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array <Real> *displacement; /// displacements array at the previous time step (used in finite deformation) Array <Real> *previous_displacement; /// lumped mass array Array <Real> *mass; /// velocities array Array <Real> *velocity; /// accelerations array Array <Real> *acceleration; /// accelerations array Array <Real> *increment_acceleration; /// forces array Array <Real> *force; /// residuals array Array <Real> *residual; /// array specifing if a degree of freedom is blocked or not Array <bool> *blocked_dofs; /// array of current position used during update residual Array <Real> *current_position; /// mass matrix SparseMatrix *mass_matrix; /// velocity damping matrix SparseMatrix *velocity_damping_matrix; /// stiffness matrix SparseMatrix *stiffness_matrix; /// jacobian matrix @f[A = cM + dD + K@f] with @f[c = \frac{1}{\beta \Delta /// t^2}, d = \frac{\gamma}{\beta \Delta t} @f] SparseMatrix *jacobian_matrix; - /// vectors containing local material element index for each global element index - ElementTypeMapArray<UInt> element_index_by_material; + /// Arrays containing the material index for each element + ElementTypeMapArray<UInt> material_index; + + /// Arrays containing the position in the element filter of the material (material's local numbering) + ElementTypeMapArray<UInt> material_local_numbering; /// list of used materials std::vector <Material *> materials; /// mapping between material name and material internal id std::map <std::string, UInt> materials_names_to_id; /// class defining of to choose a material MaterialSelector *material_selector; /// define if it is the default selector or not bool is_default_material_selector; /// integration scheme of second order used IntegrationScheme2ndOrder *integrator; /// increment of displacement Array <Real> *increment; /// flag defining if the increment must be computed or not bool increment_flag; /// solver for implicit Solver *solver; /// analysis method check the list in akantu::AnalysisMethod AnalysisMethod method; /// internal synchronizer for parallel computations DistributedSynchronizer *synch_parallel; /// tells if the material are instantiated bool are_materials_instantiated; /// map a registered internals to be flattened for dump purposes std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *> registered_internals; }; /* -------------------------------------------------------------------------- */ namespace BC { namespace Neumann { typedef FromHigherDim FromStress; typedef FromSameDim FromTraction; } } __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "material.hh" __BEGIN_AKANTU__ #include "solid_mechanics_model_tmpl.hh" #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "solid_mechanics_model_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator << (std::ostream & stream, const SolidMechanicsModel &_this) { _this.printself(stream); return stream; } __END_AKANTU__ #include "material_selector_tmpl.hh" #endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc index a77393efa..526a01317 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc @@ -1,906 +1,862 @@ /** * @file solid_mechanics_model_cohesive.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Fri Sep 05 2014 * * @brief Solid mechanics model for cohesive elements * * @section LICENSE * * Copyright (©) 2014 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 "shape_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "dumpable_inline_impl.hh" #include "material_cohesive.hh" #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const SolidMechanicsModelCohesiveOptions default_solid_mechanics_model_cohesive_options(_explicit_lumped_mass, false, false, true); /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::SolidMechanicsModelCohesive(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, dim, id, memory_id), tangents("tangents", id), stress_on_facet("stress_on_facet", id), facet_stress("facet_stress", id), facet_material("facet_material", id) { AKANTU_DEBUG_IN(); inserter = NULL; #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) facet_synchronizer = NULL; facet_stress_synchronizer = NULL; cohesive_distributed_synchronizer = NULL; global_connectivity = NULL; #endif delete material_selector; material_selector = new DefaultMaterialCohesiveSelector(*this); this->registerEventHandler(*this); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("cohesive elements", id); this->mesh.addDumpMeshToDumper("cohesive elements", - mesh, spatial_dimension, _not_ghost, _ek_cohesive); + mesh, spatial_dimension, _not_ghost, _ek_cohesive); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::~SolidMechanicsModelCohesive() { AKANTU_DEBUG_IN(); delete inserter; #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) delete cohesive_distributed_synchronizer; delete facet_synchronizer; delete facet_stress_synchronizer; #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::setTimeStep(Real time_step) { SolidMechanicsModel::setTimeStep(time_step); #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper("cohesive elements").setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initFull(const ModelOptions & options) { AKANTU_DEBUG_IN(); const SolidMechanicsModelCohesiveOptions & smmc_options = dynamic_cast<const SolidMechanicsModelCohesiveOptions &>(options); this->stress_interpolation = smmc_options.stress_interpolation; this->is_extrinsic = smmc_options.extrinsic; if (!inserter) inserter = new CohesiveElementInserter(mesh, is_extrinsic, synch_parallel, id+":cohesive_element_inserter"); SolidMechanicsModel::initFull(options); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) if (facet_synchronizer != NULL) inserter->initParallel(facet_synchronizer); #endif if (is_extrinsic) initAutomaticInsertion(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ 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 = 0; while ((dynamic_cast<MaterialCohesive *>(materials[cohesive_index]) == NULL) && cohesive_index <= materials.size()) ++cohesive_index; AKANTU_DEBUG_ASSERT(cohesive_index != materials.size(), "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 if (is_extrinsic) { const Mesh & mesh_facets = inserter->getMeshFacets(); mesh_facets.initElementTypeMapArray(facet_material, 1, spatial_dimension - 1); Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { element.ghost_type = *gt; Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1, *gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, *gt); for(;first != last; ++first) { element.type = *first; Array<UInt> & f_material = facet_material(*first, *gt); UInt nb_element = mesh_facets.getNbElement(*first, *gt); f_material.resize(nb_element); f_material.set(cohesive_index); for (UInt el = 0; el < nb_element; ++el) { element.element = el; UInt mat_index = (*material_selector)(element); f_material(el) = mat_index; MaterialCohesive & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]); mat.addFacet(element); } } } } else { 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_cohesive); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_cohesive); for(;first != last; ++first) { - Array<UInt> & el_id_by_mat = element_index_by_material(*first, *gt); - Vector<UInt> el_mat(2); el_mat(0) = cohesive_index; el_mat(1) = 0; - el_id_by_mat.set(el_mat); + Array<UInt> & mat_indexes = this->material_index(*first, *gt); + Array<UInt> & mat_loc_num = this->material_local_numbering(*first, *gt); + mat_indexes.set(cohesive_index); + mat_loc_num.clear(); } } } SolidMechanicsModel::initMaterials(); 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, spatial_dimension); /// add cohesive type connectivity ElementType type = _not_defined; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType type_ghost = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, type_ghost); Mesh::type_iterator last = mesh.lastType(spatial_dimension, type_ghost); for (; it != last; ++it) { const Array<UInt> & connectivity = mesh.getConnectivity(*it, type_ghost); if (connectivity.getSize() != 0) { type = *it; ElementType type_facet = Mesh::getFacetType(type); ElementType 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<MyFEEngineType>("FacetsFEEngine", mesh.getMeshFacets(), spatial_dimension - 1); if (is_extrinsic) { getFEEngine("FacetsFEEngine").initShapeFunctions(_not_ghost); getFEEngine("FacetsFEEngine").initShapeFunctions(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::limitInsertion(BC::Axis axis, Real first_limit, Real second_limit) { AKANTU_DEBUG_IN(); inserter->setLimit(axis, first_limit, second_limit); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::insertIntrinsicElements() { AKANTU_DEBUG_IN(); inserter->insertIntrinsicElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initAutomaticInsertion() { AKANTU_DEBUG_IN(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) if (facet_stress_synchronizer != NULL) { DataAccessor * data_accessor = this; const ElementTypeMapArray<UInt> & rank_to_element = synch_parallel->getPrankToElement(); facet_stress_synchronizer->updateFacetStressSynchronizer(*inserter, rank_to_element, *data_accessor); } #endif inserter->getMeshFacets().initElementTypeMapArray(facet_stress, 2 * spatial_dimension * spatial_dimension, spatial_dimension - 1); resizeFacetStress(); /// compute normals on facets computeNormals(); /// allocate stress_on_facet to store element stress on facets mesh.initElementTypeMapArray(stress_on_facet, spatial_dimension * spatial_dimension, spatial_dimension); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_facet_per_elem = Mesh::getNbFacetsPerElement(type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_quad_per_facet = getFEEngine("FacetsFEEngine").getNbQuadraturePoints(type_facet); stress_on_facet(type).resize(nb_quad_per_facet * nb_facet_per_elem * nb_element); } if (stress_interpolation) initStressInterpolation(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateAutomaticInsertion() { AKANTU_DEBUG_IN(); inserter->limitCheckFacets(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) if (facet_stress_synchronizer != NULL) { DataAccessor * data_accessor = this; const ElementTypeMapArray<UInt> & rank_to_element = synch_parallel->getPrankToElement(); facet_stress_synchronizer->updateFacetStressSynchronizer(*inserter, rank_to_element, *data_accessor); } #endif 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); mesh_facets.initElementTypeMapArray(quad_facets, spatial_dimension, spatial_dimension - 1); getFEEngine("FacetsFEEngine").interpolateOnQuadraturePoints(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); mesh.initElementTypeMapArray(elements_quad_facets, spatial_dimension, spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType elem_gt = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, elem_gt); Mesh::type_iterator last = mesh.lastType(spatial_dimension, elem_gt); for (; it != last; ++it) { ElementType type = *it; 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 = 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").getNbQuadraturePoints(facet_type); 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 < 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 (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat __attribute__((unused)) = dynamic_cast<MaterialCohesive &>(*materials[m]); } catch(std::bad_cast&) { /// initialize the interpolation function materials[m]->initElementalFieldInterpolation(elements_quad_facets); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateResidual(bool need_initialize) { AKANTU_DEBUG_IN(); if (need_initialize) initializeUpdateResidualData(); // f -= fint std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { try { MaterialCohesive & mat = dynamic_cast<MaterialCohesive &>(**mat_it); mat.computeTraction(_not_ghost); } catch (std::bad_cast & bce) { } } SolidMechanicsModel::updateResidual(false); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { try { MaterialCohesive & mat = dynamic_cast<MaterialCohesive &>(**mat_it); mat.computeEnergies(); } catch (std::bad_cast & bce) { } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeNormals() { AKANTU_DEBUG_IN(); Mesh & mesh_facets = inserter->getMeshFacets(); getFEEngine("FacetsFEEngine").computeNormalsOnControlPoints(_not_ghost); /** * @todo store tangents while computing normals instead of * recomputing them as follows: */ /* ------------------------------------------------------------------------ */ UInt tangent_components = spatial_dimension * (spatial_dimension - 1); mesh_facets.initElementTypeMapArray(tangents, tangent_components, spatial_dimension - 1); Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1); for (; it != last; ++it) { ElementType facet_type = *it; const Array<Real> & normals = getFEEngine("FacetsFEEngine").getNormalsOnQuadPoints(facet_type); UInt nb_quad = normals.getSize(); Array<Real> & tang = tangents(facet_type); tang.resize(nb_quad); Real * normal_it = normals.storage(); Real * tangent_it = tang.storage(); /// compute first tangent for (UInt q = 0; q < nb_quad; ++q) { /// if normal is orthogonal to xy plane, arbitrarly define tangent if ( Math::are_float_equal(Math::norm2(normal_it), 0) ) tangent_it[0] = 1; else Math::normal2(normal_it, tangent_it); normal_it += spatial_dimension; tangent_it += tangent_components; } /// compute second tangent (3D case) if (spatial_dimension == 3) { normal_it = normals.storage(); tangent_it = tang.storage(); for (UInt q = 0; q < nb_quad; ++q) { Math::normal3(normal_it, tangent_it, tangent_it + spatial_dimension); normal_it += spatial_dimension; tangent_it += tangent_components; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::averageStressOnFacets(UInt material_index) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); /// loop over element type for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_quad_per_element = getFEEngine().getNbQuadraturePoints(type); const Array<Real> & stress = materials[material_index]->getStress(type); Array<Real> & s_on_facet = stress_on_facet(type); UInt nb_facet_per_elem = Mesh::getNbFacetsPerElement(type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_quad_per_facet = getFEEngine("FacetsFEEngine").getNbQuadraturePoints(type_facet); UInt nb_facet_quad_per_elem = nb_quad_per_facet * nb_facet_per_elem; Array<Real>::const_iterator<Matrix<Real> > stress_it = stress.begin(spatial_dimension, spatial_dimension); Array<Real>::iterator<Matrix<Real> > s_on_facet_it = s_on_facet.begin(spatial_dimension, spatial_dimension); Matrix<Real> average_stress(spatial_dimension, spatial_dimension); for (UInt el = 0; el < nb_element; ++el) { /// compute average stress average_stress.clear(); for (UInt q = 0; q < nb_quad_per_element; ++q, ++stress_it) average_stress += *stress_it; average_stress /= nb_quad_per_element; /// store average stress for (UInt q = 0; q < nb_facet_quad_per_elem; ++q, ++s_on_facet_it) *s_on_facet_it = average_stress; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::fillStressOnFacet() { AKANTU_DEBUG_IN(); Mesh & mesh_facets = inserter->getMeshFacets(); UInt sp2 = spatial_dimension * spatial_dimension; UInt sp4 = sp2 * 2; /// loop over materials for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat __attribute__((unused)) = dynamic_cast<MaterialCohesive &>(*materials[m]); } catch(std::bad_cast&) { if (stress_interpolation) /// interpolate stress on facet quadrature points positions materials[m]->interpolateStress(stress_on_facet); else averageStressOnFacets(m); GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type); /// loop over element type for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, ghost_type); if (nb_element == 0) continue; Array<Real> & stress_on_f = stress_on_facet(type, ghost_type); /// store the interpolated stresses on the facet_stress vector Array<Element> & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); Array<Element>::iterator<Vector<Element> > facet_to_el_it = facet_to_element.begin(nb_facet_per_elem); Array<Real>::iterator< Matrix<Real> > stress_on_f_it = stress_on_f.begin(spatial_dimension, spatial_dimension); ElementType facet_type = _not_defined; GhostType facet_gt = _casper; Array<std::vector<Element> > * element_to_facet = NULL; Array<Real> * f_stress = NULL; Array<bool> * f_check = NULL; UInt nb_quad_per_facet = 0; UInt element_rank = 0; Element current_el(type, 0, ghost_type); for (UInt el = 0; el < nb_element; ++el, ++facet_to_el_it) { current_el.element = el; for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element global_facet_elem = (*facet_to_el_it)(f); UInt global_facet = global_facet_elem.element; if (facet_type != global_facet_elem.type || facet_gt != global_facet_elem.ghost_type) { facet_type = global_facet_elem.type; facet_gt = global_facet_elem.ghost_type; element_to_facet = &( mesh_facets.getElementToSubelement(facet_type, facet_gt) ); f_stress = &( facet_stress(facet_type, facet_gt) ); nb_quad_per_facet = getFEEngine("FacetsFEEngine").getNbQuadraturePoints(facet_type, facet_gt); f_check = &( inserter->getCheckFacets(facet_type, facet_gt) ); } if (!(*f_check)(global_facet)) { stress_on_f_it += nb_quad_per_facet; continue; } for (UInt q = 0; q < nb_quad_per_facet; ++q, ++stress_on_f_it) { element_rank = (*element_to_facet)(global_facet)[0] != current_el; Matrix<Real> facet_stress_local(f_stress->storage() + (global_facet * nb_quad_per_facet + q) * sp4 + element_rank * sp2, spatial_dimension, spatial_dimension); facet_stress_local = *stress_on_f_it; } } } } } } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::reassignMaterial() { - AKANTU_DEBUG_IN(); - - SolidMechanicsModel::reassignMaterial(); - - std::vector< Array<Element> > element_to_add (materials.size()); - std::vector< Array<Element> > element_to_remove(materials.size()); - - 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; - - Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); - Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); - for(; it != end; ++it) { - - ElementType type = *it; - element.type = type; - element.kind = Mesh::getKind(type); - - UInt nb_element = mesh.getNbElement(type, ghost_type); - - Array<UInt> & el_index_by_mat = element_index_by_material(type, ghost_type); - - for (UInt el = 0; el < nb_element; ++el) { - element.element = el; - - UInt old_material = el_index_by_mat(el, 0); - UInt new_material = (*material_selector)(element); - - if(old_material != new_material) { - element_to_add [new_material].push_back(element); - element_to_remove[old_material].push_back(element); - } - } - } - } - - std::vector<Material *>::iterator mat_it; - UInt mat_index = 0; - for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it, ++mat_index) { - (*mat_it)->removeElements(element_to_remove[mat_index]); - (*mat_it)->addElements (element_to_add[mat_index]); - } - - AKANTU_DEBUG_OUT(); -} - /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::checkCohesiveStress() { AKANTU_DEBUG_IN(); fillStressOnFacet(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_model_cohesive, "Interpolated stresses before", facet_stress); #endif synch_registry->synchronize(_gst_smmc_facets_stress); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_model_cohesive, "Interpolated stresses", facet_stress); #endif for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat_cohesive = dynamic_cast<MaterialCohesive &>(*materials[m]); /// check which not ghost cohesive elements are to be created mat_cohesive.checkInsertion(); } catch(std::bad_cast&) { } } /// communicate data among processors synch_registry->synchronize(_gst_smmc_facets); /// insert cohesive elements inserter->insertElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + updateCohesiveSynchronizers(); +#endif + SolidMechanicsModel::onElementsAdded(element_list, event); +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + if (cohesive_distributed_synchronizer != NULL) + cohesive_distributed_synchronizer->computeAllBufferSizes(*this); +#endif + /// update shape functions getFEEngine("CohesiveFEEngine").initShapeFunctions(_not_ghost); getFEEngine("CohesiveFEEngine").initShapeFunctions(_ghost); -#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - updateCohesiveSynchronizers(); -#endif - if (is_extrinsic) resizeFacetStress(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onNodesAdded(const Array<UInt> & doubled_nodes, __attribute__((unused)) const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_new_nodes = doubled_nodes.getSize(); 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(nodes_list, event); for (UInt n = 0; n < nb_new_nodes; ++n) { UInt old_node = doubled_nodes(n, 0); UInt new_node = doubled_nodes(n, 1); for (UInt dim = 0; dim < spatial_dimension; ++dim) { (*displacement)(new_node, dim) = (*displacement)(old_node, dim); (*velocity) (new_node, dim) = (*velocity) (old_node, dim); (*acceleration)(new_node, dim) = (*acceleration)(old_node, dim); (*blocked_dofs)(new_node, dim) = (*blocked_dofs)(old_node, dim); if (current_position) (*current_position)(new_node, dim) = (*current_position)(old_node, dim); if (increment_acceleration) (*increment_acceleration)(new_node, dim) = (*increment_acceleration)(old_node, dim); if (increment) (*increment)(new_node, dim) = (*increment)(old_node, dim); if (previous_displacement) (*previous_displacement)(new_node, dim) = (*previous_displacement)(old_node, dim); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onEndSolveStep(const AnalysisMethod & method) { AKANTU_DEBUG_IN(); /****************************************************************************** This is required because the Cauchy stress is the stress measure that is used to check the insertion of cohesive elements ******************************************************************************/ std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; 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(); Mesh & mesh_facets = inserter->getMeshFacets(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for(; it != end; ++it) { ElementType type = *it; UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); UInt nb_quadrature_points = getFEEngine("FacetsFEEngine").getNbQuadraturePoints(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(); ElementKind _element_kind = element_kind; if (dumper_name == "cohesive elements") { _element_kind = _ek_cohesive; } SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, _element_kind, padding_flag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onDump(){ this->flattenAllRegisteredInternals(_ek_cohesive); SolidMechanicsModel::onDump(); } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh index a8bc4dfe7..9d6ec740e 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh @@ -1,299 +1,295 @@ /** * @file solid_mechanics_model_cohesive.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Tue Sep 02 2014 * * @brief Solid mechanics model for cohesive elements * * @section LICENSE * * Copyright (©) 2014 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_SOLID_MECHANICS_MODEL_COHESIVE_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ #include "solid_mechanics_model.hh" #include "solid_mechanics_model_event_handler.hh" #include "cohesive_element_inserter.hh" #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "facet_synchronizer.hh" # include "facet_stress_synchronizer.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ struct SolidMechanicsModelCohesiveOptions : public SolidMechanicsModelOptions { SolidMechanicsModelCohesiveOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool extrinsic = false, bool no_init_materials = false, bool stress_interpolation = true) : SolidMechanicsModelOptions(analysis_method, no_init_materials), extrinsic(extrinsic), stress_interpolation(stress_interpolation) {} bool extrinsic; bool stress_interpolation; }; extern const SolidMechanicsModelCohesiveOptions default_solid_mechanics_model_cohesive_options; /* -------------------------------------------------------------------------- */ /* Solid Mechanics Model for Cohesive elements */ /* -------------------------------------------------------------------------- */ class SolidMechanicsModelCohesive : public SolidMechanicsModel, public SolidMechanicsModelEventHandler{ /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewCohesiveNodesEvent : public NewNodesEvent { public: AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array<UInt> &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array<UInt> &); protected: Array<UInt> old_nodes; }; typedef FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive> MyFEEngineCohesiveType; SolidMechanicsModelCohesive(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model_cohesive", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModelCohesive(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - - /// reassigns materials depending on the material selector - virtual void reassignMaterial(); - /// set the value of the time step void setTimeStep(Real time_step); /// assemble the residual for the explicit scheme virtual void updateResidual(bool need_initialize = true); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// function to perform a stress check on each facet and insert /// cohesive elements if needed void checkCohesiveStress(); /// initialize the cohesive model void initFull(const ModelOptions & options = default_solid_mechanics_model_cohesive_options); /// initialize the model void initModel(); /// initialize cohesive material void initMaterials(); /// init facet filters for cohesive materials void initFacetFilter(); /// limit the cohesive element insertion to a given area void limitInsertion(BC::Axis axis, Real first_limit, Real second_limit); /// update automatic insertion after a change in the element inserter void updateAutomaticInsertion(); /// insert intrinsic cohesive elements void insertIntrinsicElements(); private: /// initialize completely the model for extrinsic elements void initAutomaticInsertion(); /// initialize stress interpolation void initStressInterpolation(); /// compute facets' normals void computeNormals(); /// resize facet stress void resizeFacetStress(); /// init facets_check array void initFacetsCheck(); /// fill stress_on_facet void fillStressOnFacet(); /// compute average stress on elements void averageStressOnFacets(UInt material_index); /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: virtual void onNodesAdded (const Array<UInt> & nodes_list, const NewNodesEvent & event); virtual void onElementsAdded (const Array<Element> & nodes_list, const NewElementsEvent & event); /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void onEndSolveStep(const AnalysisMethod & method); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: virtual void onDump(); virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get facet mesh AKANTU_GET_MACRO(MeshFacets, mesh.getMeshFacets(), const Mesh &); /// get stress on facets vector AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(StressOnFacets, facet_stress, Real); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO(FacetMaterial, facet_material, const ElementTypeMapArray<UInt> &); /// @todo THIS HAS TO BE CHANGED AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Tangents, tangents, Real); /// get element inserter AKANTU_GET_MACRO_NOT_CONST(ElementInserter, *inserter, CohesiveElementInserter &); /// get is_extrinsic boolean AKANTU_GET_MACRO(IsExtrinsic, is_extrinsic, bool); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// @todo store tangents when normals are computed: ElementTypeMapArray<Real> tangents; /// list of stresses on facet quadrature points for every element ElementTypeMapArray<Real> stress_on_facet; /// stress on facets on the two sides by quadrature point ElementTypeMapArray<Real> facet_stress; /// material to use if a cohesive element is created on a facet ElementTypeMapArray<UInt> facet_material; /// stress interpolation flag bool stress_interpolation; bool is_extrinsic; /// cohesive element inserter CohesiveElementInserter * inserter; #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) #include "solid_mechanics_model_cohesive_parallel.hh" #endif }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "solid_mechanics_model_cohesive_inline_impl.cc" #endif /* -------------------------------------------------------------------------- */ class DefaultMaterialCohesiveSelector : public DefaultMaterialSelector { public: DefaultMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model) : - DefaultMaterialSelector(model.getElementIndexByMaterial()), + DefaultMaterialSelector(model.getMaterialByElement()), facet_material(model.getFacetMaterial()), mesh(model.getMesh()) { } inline virtual UInt operator()(const Element & element) { if(Mesh::getKind(element.type) == _ek_cohesive) { try { const Array<Element> & cohesive_el_to_facet = mesh.getMeshFacets().getSubelementToElement(element.type, element.ghost_type); bool third_dimension = (mesh.getSpatialDimension() == 3); const Element & facet = cohesive_el_to_facet(element.element, third_dimension); if(facet_material.exists(facet.type, facet.ghost_type)) { return facet_material(facet.type, facet.ghost_type)(facet.element); } else { return MaterialSelector::operator()(element); } } catch (...) { return MaterialSelector::operator()(element); } } else if (Mesh::getSpatialDimension(element.type) == mesh.getSpatialDimension() - 1) { return facet_material(element.type, element.ghost_type)(element.element); } else { return DefaultMaterialSelector::operator()(element); } } private: const ElementTypeMapArray<UInt> & facet_material; const Mesh & mesh; }; /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const SolidMechanicsModelCohesive & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc index 15dd25b04..d9f89f870 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc @@ -1,611 +1,613 @@ /** * @file solid_mechanics_model_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 04 2010 * @date last modification: Mon Sep 15 2014 * * @brief Implementation of the inline functions of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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 Material & SolidMechanicsModel::getMaterial(UInt mat_index) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(UInt mat_index) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(const std::string & name) { AKANTU_DEBUG_IN(); std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getMaterialIndex(const std::string & name) const { AKANTU_DEBUG_IN(); std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return it->second; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(const std::string & name) const { AKANTU_DEBUG_IN(); std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::setMaterialSelector(MaterialSelector & selector) { if(is_default_material_selector) delete material_selector; material_selector = &selector; is_default_material_selector = false; } /* -------------------------------------------------------------------------- */ inline FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) { return dynamic_cast<FEEngine &>(getFEEngineClassBoundary<MyFEEngineType>(name)); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::splitElementByMaterial(const Array<Element> & elements, Array<Element> * elements_per_mat) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; - const Array<UInt> * elem_mat = NULL; + const Array<UInt> * mat_indexes = NULL; + const Array<UInt> * mat_loc_num = NULL; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> end = elements.end(); for (; it != end; ++it) { Element el = *it; if(el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; - elem_mat = &element_index_by_material(el.type, el.ghost_type); + mat_indexes = &(this->material_index(el.type, el.ghost_type)); + mat_loc_num = &(this->material_local_numbering(el.type, el.ghost_type)); } UInt old_id = el.element; - el.element = (*elem_mat)(old_id, 1); - elements_per_mat[(*elem_mat)(old_id, 0)].push_back(el); + el.element = (*mat_loc_num)(old_id); + elements_per_mat[(*mat_indexes)(old_id)].push_back(el); } } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes_per_element = 0; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> end = elements.end(); for (; it != end; ++it) { const Element & el = *it; nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch(tag) { case _gst_material_id: { - size += elements.getSize() * 2 * sizeof(UInt); + size += elements.getSize() * sizeof(UInt); break; } case _gst_smm_mass: { size += nb_nodes_per_element * sizeof(Real) * spatial_dimension; // mass vector break; } case _gst_smm_for_gradu: { size += nb_nodes_per_element * spatial_dimension * sizeof(Real); // displacement break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } default: { } } if(tag != _gst_material_id) { Array<Element> * elements_per_mat = new Array<Element>[materials.size()]; this->splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { size += materials[i]->getNbDataForElements(elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); switch(tag) { case _gst_material_id: { - packElementalDataHelper(element_index_by_material, buffer, elements, false, getFEEngine()); + packElementalDataHelper(material_index, buffer, elements, false, getFEEngine()); break; } case _gst_smm_mass: { packNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { packNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_smm_boundary: { packNodalDataHelper(*force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id) { Array<Element> * elements_per_mat = new Array<Element>[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->packElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) { AKANTU_DEBUG_IN(); switch(tag) { case _gst_material_id: { - unpackElementalDataHelper(element_index_by_material, buffer, elements, + unpackElementalDataHelper(material_index, buffer, elements, false, getFEEngine()); break; } case _gst_smm_mass: { unpackNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id) { Array<Element> * elements_per_mat = new Array<Element>[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->unpackElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToPack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } case _gst_for_dump: { size += sizeof(Real) * spatial_dimension * 5; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToUnpack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } case _gst_for_dump: { size += sizeof(Real) * spatial_dimension * 5; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Array<Real>::const_vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::const_vector_iterator it_velo = velocity->begin(spatial_dimension); buffer << it_disp[index]; buffer << it_velo[index]; break; } case _gst_smm_res: { Array<Real>::const_vector_iterator it_res = residual->begin(spatial_dimension); buffer << it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("pack mass of node " << index << " which is " << (*mass)(index,0)); Array<Real>::const_vector_iterator it_mass = mass->begin(spatial_dimension); buffer << it_mass[index]; break; } case _gst_for_dump: { Array<Real>::const_vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::const_vector_iterator it_velo = velocity->begin(spatial_dimension); Array<Real>::const_vector_iterator it_acce = acceleration->begin(spatial_dimension); Array<Real>::const_vector_iterator it_resi = residual->begin(spatial_dimension); Array<Real>::const_vector_iterator it_forc = force->begin(spatial_dimension); buffer << it_disp[index]; buffer << it_velo[index]; buffer << it_acce[index]; buffer << it_resi[index]; buffer << it_forc[index]; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Array<Real>::vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::vector_iterator it_velo = velocity->begin(spatial_dimension); buffer >> it_disp[index]; buffer >> it_velo[index]; break; } case _gst_smm_res: { Array<Real>::vector_iterator it_res = residual->begin(spatial_dimension); buffer >> it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("mass of node " << index << " was " << (*mass)(index,0)); Array<Real>::vector_iterator it_mass = mass->begin(spatial_dimension); buffer >> it_mass[index]; AKANTU_DEBUG_INFO("mass of node " << index << " is now " << (*mass)(index,0)); break; } case _gst_for_dump: { Array<Real>::vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::vector_iterator it_velo = velocity->begin(spatial_dimension); Array<Real>::vector_iterator it_acce = acceleration->begin(spatial_dimension); Array<Real>::vector_iterator it_resi = residual->begin(spatial_dimension); Array<Real>::vector_iterator it_forc = force->begin(spatial_dimension); buffer >> it_disp[index]; buffer >> it_velo[index]; buffer >> it_acce[index]; buffer >> it_resi[index]; buffer >> it_forc[index]; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ #include "sparse_matrix.hh" #include "solver.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template <NewmarkBeta::IntegrationSchemeCorrectorType type> void SolidMechanicsModel::solve(Array<Real> &increment, Real block_val, bool need_factorize, bool has_profile_changed) { if(has_profile_changed) { this->initJacobianMatrix(); need_factorize = true; } updateResidualInternal(); //doesn't do anything for static if(need_factorize) { Real c = 0.,d = 0.,e = 0.; if(method == _static) { AKANTU_DEBUG_INFO("Solving K inc = r"); e = 1.; } else { AKANTU_DEBUG_INFO("Solving (c M + d C + e K) inc = r"); NewmarkBeta * nmb_int = dynamic_cast<NewmarkBeta *>(integrator); c = nmb_int->getAccelerationCoefficient<type>(time_step); d = nmb_int->getVelocityCoefficient<type>(time_step); e = nmb_int->getDisplacementCoefficient<type>(time_step); } jacobian_matrix->clear(); // J = c M + d C + e K if(stiffness_matrix) jacobian_matrix->add(*stiffness_matrix, e); if(mass_matrix) jacobian_matrix->add(*mass_matrix, c); #if !defined(AKANTU_NDEBUG) if(mass_matrix && AKANTU_DEBUG_TEST(dblDump)) mass_matrix->saveMatrix("M.mtx"); #endif if(velocity_damping_matrix) jacobian_matrix->add(*velocity_damping_matrix, d); jacobian_matrix->applyBoundary(*blocked_dofs, block_val); #if !defined(AKANTU_NDEBUG) if(AKANTU_DEBUG_TEST(dblDump)) jacobian_matrix->saveMatrix("J.mtx"); #endif solver->factorize(); } // if (rhs.getSize() != 0) // solver->setRHS(rhs); // else solver->setOperators(); solver->setRHS(*residual); // solve @f[ J \delta w = r @f] solver->solve(increment); UInt nb_nodes = displacement-> getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; bool * blocked_dofs_val = blocked_dofs->storage(); Real * increment_val = increment.storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j,++increment_val, ++blocked_dofs_val) { if ((*blocked_dofs_val)) *increment_val = 0.0; } } /* -------------------------------------------------------------------------- */ template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> bool SolidMechanicsModel::solveStatic(Real tolerance, UInt max_iteration, bool do_not_factorize) { AKANTU_DEBUG_INFO("Solving Ku = f"); AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL, "You should first initialize the implicit solver and assemble the stiffness matrix by calling initImplicit"); AnalysisMethod analysis_method=method; Real error = 0.; method=_static; bool converged = this->template solveStep<cmethod, criteria>(tolerance, error, max_iteration, do_not_factorize); method=analysis_method; return converged; } /* -------------------------------------------------------------------------- */ template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> bool SolidMechanicsModel::solveStep(Real tolerance, UInt max_iteration) { Real error = 0.; return this->template solveStep<cmethod,criteria>(tolerance, error, max_iteration); } /* -------------------------------------------------------------------------- */ template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> bool SolidMechanicsModel::solveStep(Real tolerance, Real & error, UInt max_iteration, bool do_not_factorize) { EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); this->implicitPred(); this->updateResidual(); AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL, "You should first initialize the implicit solver and assemble the stiffness matrix"); bool need_factorize = !do_not_factorize; if (method==_implicit_dynamic) { AKANTU_DEBUG_ASSERT(mass_matrix != NULL, "You should first initialize the implicit solver and assemble the mass matrix"); } switch (cmethod) { case _scm_newton_raphson_tangent: case _scm_newton_raphson_tangent_not_computed: break; case _scm_newton_raphson_tangent_modified: this->assembleStiffnessMatrix(); break; default: AKANTU_DEBUG_ERROR("The resolution method " << cmethod << " has not been implemented!"); } UInt iter = 0; bool converged = false; error = 0.; if(criteria == _scc_residual) { converged = this->testConvergence<criteria> (tolerance, error); if(converged) return converged; } do { if (cmethod == _scm_newton_raphson_tangent) this->assembleStiffnessMatrix(); solve<NewmarkBeta::_displacement_corrector> (*increment, 1., need_factorize); this->implicitCorr(); if(criteria == _scc_residual) this->updateResidual(); converged = this->testConvergence<criteria> (tolerance, error); if(criteria == _scc_increment && !converged) this->updateResidual(); //this->dump(); iter++; AKANTU_DEBUG_INFO("[" << criteria << "] Convergence iteration " << std::setw(std::log10(max_iteration)) << iter << ": error " << error << (converged ? " < " : " > ") << tolerance); switch (cmethod) { case _scm_newton_raphson_tangent: need_factorize = true; break; case _scm_newton_raphson_tangent_not_computed: case _scm_newton_raphson_tangent_modified: need_factorize = false; break; default: AKANTU_DEBUG_ERROR("The resolution method " << cmethod << " has not been implemented!"); } } while (!converged && iter < max_iteration); // this makes sure that you have correct strains and stresses after the solveStep function (e.g., for dumping) if(criteria == _scc_increment) this->updateResidual(); if (converged) { EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); } else if(iter == max_iteration) { AKANTU_DEBUG_WARNING("[" << criteria << "] Convergence not reached after " << std::setw(std::log10(max_iteration)) << iter << " iteration" << (iter == 1 ? "" : "s") << "!" << std::endl); } return converged; } diff --git a/src/model/solid_mechanics/solid_mechanics_model_mass.cc b/src/model/solid_mechanics/solid_mechanics_model_mass.cc index b3602402a..073e44e9c 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_mass.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_mass.cc @@ -1,158 +1,158 @@ /** * @file solid_mechanics_model_mass.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Oct 05 2010 * @date last modification: Thu Jun 05 2014 * * @brief function handling mass computation * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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" #include "material.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMassLumped() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if (!mass) { std::stringstream sstr_mass; sstr_mass << id << ":mass"; mass = &(alloc<Real>(sstr_mass.str(), nb_nodes, spatial_dimension, 0)); } else mass->clear(); assembleMassLumped(_not_ghost); assembleMassLumped(_ghost); /// for not connected nodes put mass to one in order to avoid /// wrong range in paraview Real * mass_values = mass->storage(); for (UInt i = 0; i < nb_nodes; ++i) { if (fabs(mass_values[i]) < std::numeric_limits<Real>::epsilon() || Math::isnan(mass_values[i])) mass_values[i] = 1.; } synch_registry->synchronize(_gst_smm_mass); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMassLumped(GhostType ghost_type) { AKANTU_DEBUG_IN(); FEEngine & fem = getFEEngine(); Array<Real> rho_1(0,1); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { ElementType type = *it; computeRho(rho_1, type, ghost_type); AKANTU_DEBUG_ASSERT(dof_synchronizer, "DOFSynchronizer number must not be initialized"); fem.assembleFieldLumped(rho_1, spatial_dimension,*mass, dof_synchronizer->getLocalDOFEquationNumbers(), type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMass() { AKANTU_DEBUG_IN(); if(!mass_matrix) { std::stringstream sstr; sstr << id << ":mass_matrix"; mass_matrix = new SparseMatrix(*jacobian_matrix, sstr.str(), memory_id); } assembleMass(_not_ghost); // assembleMass(_ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMass(GhostType ghost_type) { AKANTU_DEBUG_IN(); MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); Array<Real> rho_1(0,1); //UInt nb_element; mass_matrix->clear(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { ElementType type = *it; computeRho(rho_1, type, ghost_type); fem.assembleFieldMatrix(rho_1, spatial_dimension, *mass_matrix, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); - Material ** mat_val = &(materials.at(0)); + Material ** mat_val = &(this->materials.at(0)); - FEEngine & fem = getFEEngine(); + FEEngine & fem = this->getFEEngine(); UInt nb_element = fem.getMesh().getNbElement(type,ghost_type); - Array<UInt> & elem_mat_val = element_index_by_material(type, ghost_type); + Array<UInt> & mat_indexes = this->material_index(type, ghost_type); UInt nb_quadrature_points = fem.getNbQuadraturePoints(type, ghost_type); rho.resize(nb_element * nb_quadrature_points); Real * rho_1_val = rho.storage(); /// compute @f$ rho @f$ for each nodes of each element for (UInt el = 0; el < nb_element; ++el) { - Real mat_rho = mat_val[elem_mat_val(el, 0)]->getParam<Real>("rho"); /// here rho is constant in an element + Real mat_rho = mat_val[mat_indexes(el)]->getParam<Real>("rho"); /// here rho is constant in an element for (UInt n = 0; n < nb_quadrature_points; ++n) { *rho_1_val++ = mat_rho; } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_material.cc b/src/model/solid_mechanics/solid_mechanics_model_material.cc index fcd6b6fc8..4a188c53f 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_material.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_material.cc @@ -1,310 +1,311 @@ /** * @file solid_mechanics_model_material.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Nov 26 2010 * @date last modification: Tue Jun 24 2014 * * @brief instatiation of materials * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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" #include "material_list.hh" #include "aka_math.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #define AKANTU_INTANTIATE_MATERIAL_BY_DIM_NO_TMPL(dim, elem) \ registerNewMaterial< BOOST_PP_ARRAY_ELEM(1, elem)< dim > >(section) #define AKANTU_INTANTIATE_MATERIAL_BY_DIM_TMPL_EACH(r, data, i, elem) \ BOOST_PP_EXPR_IF(BOOST_PP_NOT_EQUAL(0, i), else ) \ if(opt_param == BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, elem))) { \ registerNewMaterial< BOOST_PP_ARRAY_ELEM(1, data)< BOOST_PP_ARRAY_ELEM(0, data), \ BOOST_PP_SEQ_ENUM(BOOST_PP_TUPLE_ELEM(2, 1, elem)) > >(section); \ } #define AKANTU_INTANTIATE_MATERIAL_BY_DIM_TMPL(dim, elem) \ BOOST_PP_SEQ_FOR_EACH_I(AKANTU_INTANTIATE_MATERIAL_BY_DIM_TMPL_EACH, \ (2, (dim, BOOST_PP_ARRAY_ELEM(1, elem))), \ BOOST_PP_ARRAY_ELEM(2, elem)) \ else { \ AKANTU_INTANTIATE_MATERIAL_BY_DIM_NO_TMPL(dim, elem); \ } #define AKANTU_INTANTIATE_MATERIAL_BY_DIM(dim, elem) \ BOOST_PP_IF(BOOST_PP_EQUAL(3, BOOST_PP_ARRAY_SIZE(elem) ), \ AKANTU_INTANTIATE_MATERIAL_BY_DIM_TMPL, \ AKANTU_INTANTIATE_MATERIAL_BY_DIM_NO_TMPL)(dim, elem) #define AKANTU_INTANTIATE_MATERIAL(elem) \ switch(spatial_dimension) { \ case 1: { AKANTU_INTANTIATE_MATERIAL_BY_DIM(1, elem); break; } \ case 2: { AKANTU_INTANTIATE_MATERIAL_BY_DIM(2, elem); break; } \ case 3: { AKANTU_INTANTIATE_MATERIAL_BY_DIM(3, elem); break; } \ } #define AKANTU_INTANTIATE_MATERIAL_IF(elem) \ if (mat_type == BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(0, elem))) { \ AKANTU_INTANTIATE_MATERIAL(elem); \ } #define AKANTU_INTANTIATE_OTHER_MATERIAL(r, data, elem) \ else AKANTU_INTANTIATE_MATERIAL_IF(elem) #define AKANTU_INSTANTIATE_MATERIALS() \ do { \ AKANTU_INTANTIATE_MATERIAL_IF(BOOST_PP_SEQ_HEAD(AKANTU_MATERIAL_LIST)) \ BOOST_PP_SEQ_FOR_EACH(AKANTU_INTANTIATE_OTHER_MATERIAL, \ _, \ BOOST_PP_SEQ_TAIL(AKANTU_MATERIAL_LIST)) \ else { \ if(getStaticParser().isPermissive()) \ AKANTU_DEBUG_INFO("Malformed material file " << \ ": unknown material type '" \ << mat_type << "'"); \ else \ AKANTU_DEBUG_WARNING("Malformed material file " \ <<": unknown material type " << mat_type \ << ". This is perhaps a user" \ << " defined material ?"); \ } \ } while(0) /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::instantiateMaterials() { std::pair<Parser::const_section_iterator, Parser::const_section_iterator> sub_sect = this->parser->getSubSections(_st_material); Parser::const_section_iterator it = sub_sect.first; for (; it != sub_sect.second; ++it) { const ParserSection & section = *it; std::string mat_type = section.getName(); std::string opt_param = section.getOption(); AKANTU_INSTANTIATE_MATERIALS(); } are_materials_instantiated = true; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assignMaterialToElements(const ElementTypeMapArray<UInt> * filter) { Material ** mat_val = &(materials.at(0)); Element element; element.ghost_type = _not_ghost; Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, _not_ghost, _ek_not_defined); if(filter != NULL) { it = filter->firstType(spatial_dimension, _not_ghost, _ek_not_defined); end = filter->lastType(spatial_dimension, _not_ghost, _ek_not_defined); } // Fill the element material array from the material selector for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, _not_ghost); const Array<UInt> * filter_array = NULL; if (filter != NULL) { filter_array = &((*filter)(*it, _not_ghost)); nb_element = filter_array->getSize(); } element.type = *it; element.kind = mesh.getKind(element.type); - Array<UInt> & el_id_by_mat = element_index_by_material(*it, _not_ghost); + Array<UInt> & mat_indexes = material_index(*it, _not_ghost); for (UInt el = 0; el < nb_element; ++el) { if (filter != NULL) element.element = (*filter_array)(el); else element.element = el; UInt mat_index = (*material_selector)(element); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The material selector returned an index that does not exists"); - el_id_by_mat(element.element, 0) = mat_index; + mat_indexes(element.element) = mat_index; } } // synchronize the element material arrays synch_registry->synchronize(_gst_material_id); /// fill the element filters of the materials using the element_material arrays for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; it = mesh.firstType(spatial_dimension, gt, _ek_not_defined); end = mesh.lastType(spatial_dimension, gt, _ek_not_defined); if(filter != NULL) { it = filter->firstType(spatial_dimension, gt, _ek_not_defined); end = filter->lastType(spatial_dimension, gt, _ek_not_defined); } for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, gt); const Array<UInt> * filter_array = NULL; if (filter != NULL) { filter_array = &((*filter)(*it, gt)); nb_element = filter_array->getSize(); } - Array<UInt> & el_id_by_mat = element_index_by_material(*it, gt); + Array<UInt> & mat_indexes = material_index(*it, gt); + Array<UInt> & mat_local_num = material_local_numbering(*it, gt); for (UInt el = 0; el < nb_element; ++el) { UInt element; if (filter != NULL) element = (*filter_array)(el); else element = el; - UInt mat_index = el_id_by_mat(element, 0); + UInt mat_index = mat_indexes(element); UInt index = mat_val[mat_index]->addElement(*it, element, gt); - el_id_by_mat(element, 1) = index; + mat_local_num(element) = index; } } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initMaterials() { AKANTU_DEBUG_ASSERT(materials.size() != 0, "No material to initialize !"); if(!are_materials_instantiated) instantiateMaterials(); this->assignMaterialToElements(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { /// init internals properties (*mat_it)->initMaterial(); } synch_registry->synchronize(_gst_smm_init_mat); // initialize mass switch(method) { case _explicit_lumped_mass: assembleMassLumped(); break; case _explicit_consistent_mass: case _implicit_dynamic: assembleMass(); break; case _static: break; default: AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel"); break; } // initialize the previous displacement array if at least on material needs it for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; if (mat.isFiniteDeformation() || mat.isInelasticDeformation()) { initArraysPreviousDisplacment(); break; } } } /* -------------------------------------------------------------------------- */ Int SolidMechanicsModel::getInternalIndexFromID(const ID & id) const { AKANTU_DEBUG_IN(); std::vector<Material *>::const_iterator first = materials.begin(); std::vector<Material *>::const_iterator last = materials.end(); for (; first != last; ++first) if ((*first)->getID() == id) { AKANTU_DEBUG_OUT(); return (first - materials.begin()); } AKANTU_DEBUG_OUT(); return -1; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::reassignMaterial() { AKANTU_DEBUG_IN(); std::vector< Array<Element> > element_to_add (materials.size()); std::vector< Array<Element> > element_to_remove(materials.size()); 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; - Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_regular); - Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type, _ek_regular); + Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_not_defined); + Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type, _ek_not_defined); for(; it != end; ++it) { ElementType type = *it; element.type = type; element.kind = Mesh::getKind(type); UInt nb_element = mesh.getNbElement(type, ghost_type); - Array<UInt> & el_index_by_mat = element_index_by_material(type, ghost_type); + Array<UInt> & mat_indexes = material_index(type, ghost_type); for (UInt el = 0; el < nb_element; ++el) { element.element = el; - UInt old_material = el_index_by_mat(el, 0); + UInt old_material = mat_indexes(el); UInt new_material = (*material_selector)(element); if(old_material != new_material) { element_to_add [new_material].push_back(element); element_to_remove[old_material].push_back(element); } } } } std::vector<Material *>::iterator mat_it; UInt mat_index = 0; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it, ++mat_index) { (*mat_it)->removeElements(element_to_remove[mat_index]); (*mat_it)->addElements (element_to_add[mat_index]); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/synchronizer/distributed_synchronizer.cc b/src/synchronizer/distributed_synchronizer.cc index d698c9fea..ab9b4e10f 100644 --- a/src/synchronizer/distributed_synchronizer.cc +++ b/src/synchronizer/distributed_synchronizer.cc @@ -1,1651 +1,1663 @@ /** * @file distributed_synchronizer.cc * * @author Dana Christen <dana.christen@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jun 16 2011 * @date last modification: Fri Sep 05 2014 * * @brief implementation of a communicator using a static_communicator for real * send/receive * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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 "distributed_synchronizer.hh" #include "static_communicator.hh" #include "mesh_utils.hh" #include "mesh_data.hh" #include "element_group.hh" /* -------------------------------------------------------------------------- */ #include <map> #include <iostream> #include <algorithm> #if defined(AKANTU_DEBUG_TOOLS) # include "aka_debug_tools.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ DistributedSynchronizer::DistributedSynchronizer(Mesh & mesh, SynchronizerID id, MemoryID memory_id) : Synchronizer(id, memory_id), mesh(mesh), prank_to_element("prank_to_element", id) { AKANTU_DEBUG_IN(); nb_proc = static_communicator->getNbProc(); rank = static_communicator->whoAmI(); send_element = new Array<Element>[nb_proc]; recv_element = new Array<Element>[nb_proc]; mesh.registerEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DistributedSynchronizer::~DistributedSynchronizer() { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { send_element[p].clear(); recv_element[p].clear(); } delete [] send_element; delete [] recv_element; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DistributedSynchronizer * DistributedSynchronizer:: createDistributedSynchronizerMesh(Mesh & mesh, const MeshPartition * partition, UInt root, SynchronizerID id, MemoryID memory_id) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); DistributedSynchronizer & communicator = *(new DistributedSynchronizer(mesh, id, memory_id)); if(nb_proc == 1) return &communicator; UInt * local_connectivity = NULL; UInt * local_partitions = NULL; Array<UInt> * old_nodes = mesh.getNodesGlobalIdsPointer(); old_nodes->resize(0); Array<Real> * nodes = mesh.getNodesPointer(); UInt spatial_dimension = nodes->getNbComponent(); mesh.synchronizeGroupNames(); /* ------------------------------------------------------------------------ */ /* Local (rank == root) */ /* ------------------------------------------------------------------------ */ if(my_rank == root) { AKANTU_DEBUG_ASSERT(partition->getNbPartition() == nb_proc, "The number of partition does not match the number of processors: " << partition->getNbPartition() << " != " << nb_proc); /** * connectivity and communications scheme construction */ Mesh::type_iterator it = mesh.firstType(_all_dimensions, _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, _not_ghost, _ek_not_defined); UInt count = 0; /* --- MAIN LOOP ON TYPES --- */ for(; it != end; ++it) { ElementType type = *it; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(*it); UInt nb_local_element[nb_proc]; UInt nb_ghost_element[nb_proc]; UInt nb_element_to_send[nb_proc]; memset(nb_local_element, 0, nb_proc*sizeof(UInt)); memset(nb_ghost_element, 0, nb_proc*sizeof(UInt)); memset(nb_element_to_send, 0, nb_proc*sizeof(UInt)); /// \todo change this ugly way to avoid a problem if an element /// type is present in the mesh but not in the partitions const Array<UInt> * tmp_partition_num = NULL; try { tmp_partition_num = &partition->getPartition(type, _not_ghost); } catch(...) { continue; } const Array<UInt> & partition_num = *tmp_partition_num; const CSR<UInt> & ghost_partition = partition->getGhostPartitionCSR()(type, _not_ghost); /* -------------------------------------------------------------------- */ /// constructing the reordering structures for (UInt el = 0; el < nb_element; ++el) { nb_local_element[partition_num(el)]++; for (CSR<UInt>::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { nb_ghost_element[*part]++; } nb_element_to_send[partition_num(el)] += ghost_partition.getNbCols(el) + 1; } /// allocating buffers UInt * buffers[nb_proc]; UInt * buffers_tmp[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { UInt size = nb_nodes_per_element * (nb_local_element[p] + nb_ghost_element[p]); buffers[p] = new UInt[size]; buffers_tmp[p] = buffers[p]; } /// copying the local connectivity UInt * conn_val = mesh.getConnectivity(type, _not_ghost).storage(); for (UInt el = 0; el < nb_element; ++el) { memcpy(buffers_tmp[partition_num(el)], conn_val + el * nb_nodes_per_element, nb_nodes_per_element * sizeof(UInt)); buffers_tmp[partition_num(el)] += nb_nodes_per_element; } /// copying the connectivity of ghost element for (UInt el = 0; el < nb_element; ++el) { for (CSR<UInt>::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { UInt proc = *part; memcpy(buffers_tmp[proc], conn_val + el * nb_nodes_per_element, nb_nodes_per_element * sizeof(UInt)); buffers_tmp[proc] += nb_nodes_per_element; } } /// tag info std::vector<std::string> tag_names; mesh.getMeshData().getTagNames(tag_names, type); UInt nb_tags = tag_names.size(); /* -------->>>>-SIZE + CONNECTIVITY------------------------------------ */ /// send all connectivity and ghost information to all processors std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { UInt size[5]; size[0] = (UInt) type; size[1] = nb_local_element[p]; size[2] = nb_ghost_element[p]; size[3] = nb_element_to_send[p]; size[4] = nb_tags; AKANTU_DEBUG_INFO("Sending connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")"); comm.send(size, 5, p, Tag::genTag(my_rank, count, TAG_SIZES)); AKANTU_DEBUG_INFO("Sending connectivities to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_CONNECTIVITY) <<")"); requests.push_back(comm.asyncSend(buffers[p], nb_nodes_per_element * (nb_local_element[p] + nb_ghost_element[p]), p, Tag::genTag(my_rank, count, TAG_CONNECTIVITY))); } else { local_connectivity = buffers[p]; } } /// create the renumbered connectivity AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, local_connectivity, nb_local_element[root], nb_ghost_element[root], type, *old_nodes); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { delete [] buffers[p]; } /* -------------------------------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { buffers[p] = new UInt[nb_ghost_element[p] + nb_element_to_send[p]]; buffers_tmp[p] = buffers[p]; } /// splitting the partition information to send them to processors UInt count_by_proc[nb_proc]; memset(count_by_proc, 0, nb_proc*sizeof(UInt)); for (UInt el = 0; el < nb_element; ++el) { *(buffers_tmp[partition_num(el)]++) = ghost_partition.getNbCols(el); UInt i(0); for (CSR<UInt>::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part, ++i) { *(buffers_tmp[partition_num(el)]++) = *part; } } for (UInt el = 0; el < nb_element; ++el) { UInt i(0); for (CSR<UInt>::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part, ++i) { *(buffers_tmp[*part]++) = partition_num(el); } } /* -------->>>>-PARTITIONS--------------------------------------------- */ /// last data to compute the communication scheme for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Sending partition informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_PARTITIONS) <<")"); requests.push_back(comm.asyncSend(buffers[p], nb_element_to_send[p] + nb_ghost_element[p], p, Tag::genTag(my_rank, count, TAG_PARTITIONS))); } else { local_partitions = buffers[p]; } } if(Mesh::getSpatialDimension(type) == mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); communicator.fillCommunicationScheme(local_partitions, nb_local_element[root], nb_ghost_element[root], type); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { delete [] buffers[p]; } /* -------------------------------------------------------------------- */ /// send data assossiated to the mesh /* -------->>>>-TAGS--------------------------------------------------- */ synchronizeTagsSend(communicator, root, mesh, nb_tags, type, partition_num, ghost_partition, nb_local_element[root], nb_ghost_element[root]); /* -------------------------------------------------------------------- */ /// send data assossiated to groups /* -------->>>>-GROUPS------------------------------------------------- */ synchronizeElementGroups(communicator, root, mesh, type, partition_num, ghost_partition, nb_element); ++count; } /* -------->>>>-SIZE----------------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { UInt size[5]; size[0] = (UInt) _not_defined; size[1] = 0; size[2] = 0; size[3] = 0; size[4] = 0; AKANTU_DEBUG_INFO("Sending empty connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")"); comm.send(size, 5, p, Tag::genTag(my_rank, count, TAG_SIZES)); } } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /** * Nodes coordinate construction and synchronization */ std::multimap< UInt, std::pair<UInt, UInt> > nodes_to_proc; /// get the list of nodes to send and send them Real * local_nodes = NULL; UInt nb_nodes_per_proc[nb_proc]; UInt * nodes_per_proc[nb_proc]; comm.broadcast(&(mesh.nb_global_nodes), 1, root); /* --------<<<<-NB_NODES + NODES----------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { UInt nb_nodes = 0; // UInt * buffer; if(p != root) { AKANTU_DEBUG_INFO("Receiving number of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NB_NODES) <<")"); comm.receive(&nb_nodes, 1, p, Tag::genTag(p, 0, TAG_NB_NODES)); nodes_per_proc[p] = new UInt[nb_nodes]; nb_nodes_per_proc[p] = nb_nodes; AKANTU_DEBUG_INFO("Receiving list of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NODES) <<")"); comm.receive(nodes_per_proc[p], nb_nodes, p, Tag::genTag(p, 0, TAG_NODES)); } else { nb_nodes = old_nodes->getSize(); nb_nodes_per_proc[p] = nb_nodes; nodes_per_proc[p] = old_nodes->storage(); } /// get the coordinates for the selected nodes Real * nodes_to_send = new Real[nb_nodes * spatial_dimension]; Real * nodes_to_send_tmp = nodes_to_send; for (UInt n = 0; n < nb_nodes; ++n) { memcpy(nodes_to_send_tmp, nodes->storage() + spatial_dimension * nodes_per_proc[p][n], spatial_dimension * sizeof(Real)); // nodes_to_proc.insert(std::make_pair(buffer[n], std::make_pair(p, n))); nodes_to_send_tmp += spatial_dimension; } /* -------->>>>-COORDINATES-------------------------------------------- */ if(p != root) { /// send them for distant processors AKANTU_DEBUG_INFO("Sending coordinates to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_COORDINATES) <<")"); comm.send(nodes_to_send, nb_nodes * spatial_dimension, p, Tag::genTag(my_rank, 0, TAG_COORDINATES)); delete [] nodes_to_send; } else { /// save them for local processor local_nodes = nodes_to_send; } } /// construct the local nodes coordinates UInt nb_nodes = old_nodes->getSize(); nodes->resize(nb_nodes); memcpy(nodes->storage(), local_nodes, nb_nodes * spatial_dimension * sizeof(Real)); delete [] local_nodes; Array<Int> * nodes_type_per_proc[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { nodes_type_per_proc[p] = new Array<Int>(nb_nodes_per_proc[p]); } communicator.fillNodesType(mesh); /* --------<<<<-NODES_TYPE-1--------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Receiving first nodes types from proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_NODES_TYPE) <<")"); comm.receive(nodes_type_per_proc[p]->storage(), nb_nodes_per_proc[p], p, Tag::genTag(p, 0, TAG_NODES_TYPE)); } else { nodes_type_per_proc[p]->copy(mesh.getNodesType()); } for (UInt n = 0; n < nb_nodes_per_proc[p]; ++n) { if((*nodes_type_per_proc[p])(n) == -2) nodes_to_proc.insert(std::make_pair(nodes_per_proc[p][n], std::make_pair(p, n))); } } std::multimap< UInt, std::pair<UInt, UInt> >::iterator it_node; std::pair< std::multimap< UInt, std::pair<UInt, UInt> >::iterator, std::multimap< UInt, std::pair<UInt, UInt> >::iterator > it_range; for (UInt i = 0; i < mesh.nb_global_nodes; ++i) { it_range = nodes_to_proc.equal_range(i); if(it_range.first == nodes_to_proc.end() || it_range.first->first != i) continue; UInt node_type = (it_range.first)->second.first; for (it_node = it_range.first; it_node != it_range.second; ++it_node) { UInt proc = it_node->second.first; UInt node = it_node->second.second; if(proc != node_type) nodes_type_per_proc[proc]->storage()[node] = node_type; } } /* -------->>>>-NODES_TYPE-2--------------------------------------------- */ std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Sending nodes types to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_NODES_TYPE) <<")"); requests.push_back(comm.asyncSend(nodes_type_per_proc[p]->storage(), nb_nodes_per_proc[p], p, Tag::genTag(my_rank, 0, TAG_NODES_TYPE))); } else { mesh.getNodesTypePointer()->copy(*nodes_type_per_proc[p]); } } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { if(p != root) delete [] nodes_per_proc[p]; delete nodes_type_per_proc[p]; } /* -------->>>>-NODE GROUPS --------------------------------------------- */ synchronizeNodeGroupsMaster(communicator, root, mesh); /* ---------------------------------------------------------------------- */ /* Distant (rank != root) */ /* ---------------------------------------------------------------------- */ } else { /** * connectivity and communications scheme construction on distant processors */ ElementType type = _not_defined; UInt count = 0; do { /* --------<<<<-SIZE--------------------------------------------------- */ UInt size[5] = { 0 }; comm.receive(size, 5, root, Tag::genTag(root, count, TAG_SIZES)); type = (ElementType) size[0]; UInt nb_local_element = size[1]; UInt nb_ghost_element = size[2]; UInt nb_element_to_send = size[3]; UInt nb_tags = size[4]; if(type != _not_defined) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); /* --------<<<<-CONNECTIVITY----------------------------------------- */ local_connectivity = new UInt[(nb_local_element + nb_ghost_element) * nb_nodes_per_element]; AKANTU_DEBUG_INFO("Receiving connectivities from proc " << root); comm.receive(local_connectivity, nb_nodes_per_element * (nb_local_element + nb_ghost_element), root, Tag::genTag(root, count, TAG_CONNECTIVITY)); AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, local_connectivity, nb_local_element, nb_ghost_element, type, *old_nodes); delete [] local_connectivity; /* --------<<<<-PARTITIONS--------------------------------------------- */ local_partitions = new UInt[nb_element_to_send + nb_ghost_element * 2]; AKANTU_DEBUG_INFO("Receiving partition informations from proc " << root); comm.receive(local_partitions, nb_element_to_send + nb_ghost_element * 2, root, Tag::genTag(root, count, TAG_PARTITIONS)); if(Mesh::getSpatialDimension(type) == mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); communicator.fillCommunicationScheme(local_partitions, nb_local_element, nb_ghost_element, type); } delete [] local_partitions; /* --------<<<<-TAGS------------------------------------------------- */ synchronizeTagsRecv(communicator, root, mesh, nb_tags, type, nb_local_element, nb_ghost_element); /* --------<<<<-GROUPS----------------------------------------------- */ synchronizeElementGroups(communicator, root, mesh, type); } ++count; } while(type != _not_defined); /** * Nodes coordinate construction and synchronization on distant processors */ comm.broadcast(&(mesh.nb_global_nodes), 1, root); /* -------->>>>-NB_NODES + NODES----------------------------------------- */ AKANTU_DEBUG_INFO("Sending list of nodes to proc " << root); UInt nb_nodes = old_nodes->getSize(); comm.send(&nb_nodes, 1, root, Tag::genTag(my_rank, 0, TAG_NB_NODES)); comm.send(old_nodes->storage(), nb_nodes, root, Tag::genTag(my_rank, 0, TAG_NODES)); /* --------<<<<-COORDINATES---------------------------------------------- */ nodes->resize(nb_nodes); AKANTU_DEBUG_INFO("Receiving coordinates from proc " << root); comm.receive(nodes->storage(), nb_nodes * spatial_dimension, root, Tag::genTag(root, 0, TAG_COORDINATES)); communicator.fillNodesType(mesh); /* -------->>>>-NODES_TYPE-1--------------------------------------------- */ Int * nodes_types = mesh.getNodesTypePointer()->storage(); AKANTU_DEBUG_INFO("Sending first nodes types to proc " << root); comm.send(nodes_types, nb_nodes, root, Tag::genTag(my_rank, 0, TAG_NODES_TYPE)); /* --------<<<<-NODES_TYPE-2--------------------------------------------- */ AKANTU_DEBUG_INFO("Receiving nodes types from proc " << root); comm.receive(nodes_types, nb_nodes, root, Tag::genTag(root, 0, TAG_NODES_TYPE)); /* --------<<<<-NODE GROUPS --------------------------------------------- */ synchronizeNodeGroupsSlaves(communicator, root, mesh); } MeshUtils::fillElementToSubElementsData(mesh); mesh.is_distributed = true; AKANTU_DEBUG_OUT(); return &communicator; } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::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) { #define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem) : { \ fillTagBufferTemplated<BOOST_PP_TUPLE_ELEM(2, 1, elem)>(mesh_data, buffers, tag_name, el_type, partition_num, ghost_partition); \ break; \ } \ MeshDataTypeCode data_type_code = mesh_data.getTypeCode(tag_name); switch(data_type_code) { BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , AKANTU_MESH_DATA_TYPES) default : AKANTU_DEBUG_ERROR("Could not obtain the type of tag" << tag_name << "!"); break; } #undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::fillNodesType(Mesh & mesh) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); Int * nodes_type = mesh.getNodesTypePointer()->storage(); UInt * nodes_set = new UInt[nb_nodes]; std::fill_n(nodes_set, nb_nodes, 0); const UInt NORMAL_SET = 1; const UInt GHOST_SET = 2; bool * already_seen = new bool[nb_nodes]; for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; UInt set = NORMAL_SET; if (gt == _ghost) set = GHOST_SET; std::fill_n(already_seen, nb_nodes, false); Mesh::type_iterator it = mesh.firstType(_all_dimensions, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, gt, _ek_not_defined); for(; it != end; ++it) { ElementType type = *it; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type, gt); Array<UInt>::iterator< Vector<UInt> > conn_it = mesh.getConnectivity(type, gt).begin(nb_nodes_per_element); for (UInt e = 0; e < nb_element; ++e, ++conn_it) { Vector<UInt> & conn = *conn_it; for (UInt n = 0; n < nb_nodes_per_element; ++n) { AKANTU_DEBUG_ASSERT(conn(n) < nb_nodes, "Node " << conn(n) << " bigger than number of nodes " << nb_nodes); if(!already_seen[conn(n)]) { nodes_set[conn(n)] += set; already_seen[conn(n)] = true; } } } } } delete [] already_seen; for (UInt i = 0; i < nb_nodes; ++i) { if(nodes_set[i] == NORMAL_SET) nodes_type[i] = -1; else if(nodes_set[i] == GHOST_SET) nodes_type[i] = -3; else if(nodes_set[i] == (GHOST_SET + NORMAL_SET)) nodes_type[i] = -2; } delete [] nodes_set; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::fillCommunicationScheme(const UInt * partition, UInt nb_local_element, UInt nb_ghost_element, ElementType type) { AKANTU_DEBUG_IN(); Element element; element.type = type; element.kind = Mesh::getKind(type); const UInt * part = partition; part = partition; for (UInt lel = 0; lel < nb_local_element; ++lel) { UInt nb_send = *part; part++; element.element = lel; element.ghost_type = _not_ghost; for (UInt p = 0; p < nb_send; ++p) { UInt proc = *part; part++; AKANTU_DEBUG(dblAccessory, "Must send : " << element << " to proc " << proc); (send_element[proc]).push_back(element); } } for (UInt gel = 0; gel < nb_ghost_element; ++gel) { UInt proc = *part; part++; element.element = gel; element.ghost_type = _ghost; AKANTU_DEBUG(dblAccessory, "Must recv : " << element << " from proc " << proc); recv_element[proc].push_back(element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::asynchronousSynchronize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); if (communications.find(tag) == communications.end()) computeBufferSize(data_accessor, tag); Communication & communication = communications[tag]; AKANTU_DEBUG_ASSERT(communication.send_requests.size() == 0, "There must be some pending sending communications. Tag is " << tag); std::map<SynchronizationTag, UInt>::iterator t_it = tag_counter.find(tag); UInt counter = 0; if(t_it == tag_counter.end()) { tag_counter[tag] = 0; } else { counter = ++(t_it->second); } for (UInt p = 0; p < nb_proc; ++p) { UInt ssize = communication.size_to_send[p]; if(p == rank || ssize == 0) continue; CommunicationBuffer & buffer = communication.send_buffer[p]; buffer.resize(ssize); #ifndef AKANTU_NDEBUG UInt nb_elements = send_element[p].getSize(); AKANTU_DEBUG_INFO("Packing data for proc " << p << " (" << ssize << "/" << nb_elements <<" data to send/elements)"); /// pack barycenters in debug mode Array<Element>::const_iterator<Element> bit = send_element[p].begin(); Array<Element>::const_iterator<Element> bend = send_element[p].end(); for (; bit != bend; ++bit) { const Element & element = *bit; Vector<Real> barycenter(mesh.getSpatialDimension()); mesh.getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); buffer << barycenter; } #endif data_accessor.packElementData(buffer, send_element[p], tag); AKANTU_DEBUG_ASSERT(buffer.getPackedSize() == ssize, "a problem have been introduced with " << "false sent sizes declaration " << buffer.getPackedSize() << " != " << ssize); AKANTU_DEBUG_INFO("Posting send to proc " << p << " (tag: " << tag << " - " << ssize << " data to send)" << " [" << Tag::genTag(rank, counter, tag) << "]"); communication.send_requests.push_back(static_communicator->asyncSend(buffer.storage(), ssize, p, Tag::genTag(rank, counter, tag))); } AKANTU_DEBUG_ASSERT(communication.recv_requests.size() == 0, "There must be some pending receive communications"); for (UInt p = 0; p < nb_proc; ++p) { UInt rsize = communication.size_to_receive[p]; if(p == rank || rsize == 0) continue; CommunicationBuffer & buffer = communication.recv_buffer[p]; buffer.resize(rsize); AKANTU_DEBUG_INFO("Posting receive from proc " << p << " (tag: " << tag << " - " << rsize << " data to receive) " << " [" << Tag::genTag(p, counter, tag) << "]"); communication.recv_requests.push_back(static_communicator->asyncReceive(buffer.storage(), rsize, p, Tag::genTag(p, counter, tag))); } #if defined(AKANTU_DEBUG_TOOLS) && defined(AKANTU_CORE_CXX11) static std::set<SynchronizationTag> tags; if(tags.find(tag) == tags.end()) { debug::element_manager.print(debug::_dm_synch, [&send_element, rank, nb_proc, tag, id](const Element & el)->std::string { std::stringstream out; UInt elp = 0; for (UInt p = 0; p < nb_proc; ++p) { UInt pos = send_element[p].find(el); if(pos != UInt(-1)) { if(elp > 0) out << std::endl; out << id << " send (" << pos << "/" << send_element[p].getSize() << ") to proc " << p << " tag:" << tag; ++elp; } } return out.str(); }); debug::element_manager.print(debug::_dm_synch, [&recv_element, rank, nb_proc, tag, id](const Element & el)->std::string { std::stringstream out; UInt elp = 0; for (UInt p = 0; p < nb_proc; ++p) { if(p == rank) continue; UInt pos = recv_element[p].find(el); if(pos != UInt(-1)) { if(elp > 0) out << std::endl; out << id << " recv (" << pos << "/" << recv_element[p].getSize() << ") from proc " << p << " tag:" << tag; ++elp; } } return out.str(); }); tags.insert(tag); } #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::waitEndSynchronize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(communications.find(tag) != communications.end(), "No communication with the tag \"" << tag <<"\" started"); Communication & communication = communications[tag]; std::vector<CommunicationRequest *> req_not_finished; std::vector<CommunicationRequest *> * req_not_finished_tmp = &req_not_finished; std::vector<CommunicationRequest *> * recv_requests_tmp = &(communication.recv_requests); // static_communicator->waitAll(recv_requests); while(!recv_requests_tmp->empty()) { for (std::vector<CommunicationRequest *>::iterator req_it = recv_requests_tmp->begin(); req_it != recv_requests_tmp->end() ; ++req_it) { CommunicationRequest * req = *req_it; if(static_communicator->testRequest(req)) { UInt proc = req->getSource(); AKANTU_DEBUG_INFO("Unpacking data coming from proc " << proc); CommunicationBuffer & buffer = communication.recv_buffer[proc]; #ifndef AKANTU_NDEBUG Array<Element>::const_iterator<Element> bit = recv_element[proc].begin(); Array<Element>::const_iterator<Element> bend = recv_element[proc].end(); UInt spatial_dimension = mesh.getSpatialDimension(); for (; bit != bend; ++bit) { const Element & element = *bit; Vector<Real> barycenter_loc(spatial_dimension); mesh.getBarycenter(element.element, element.type, barycenter_loc.storage(), element.ghost_type); Vector<Real> barycenter(spatial_dimension); buffer >> barycenter; Real tolerance = Math::getTolerance(); Real bary_norm = barycenter.norm(); for (UInt i = 0; i < spatial_dimension; ++i) { if((std::abs((barycenter(i) - barycenter_loc(i))/bary_norm) <= tolerance) || (std::abs(barycenter_loc(i)) <= tolerance && std::abs(barycenter(i)) <= tolerance)) continue; AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: " << element << "(barycenter[" << i << "] = " << barycenter_loc(i) << " and buffer[" << i << "] = " << barycenter(i) << ") [" << std::abs((barycenter(i) - barycenter_loc(i))/barycenter_loc(i)) << "] - tag: " << tag); } } #endif data_accessor.unpackElementData(buffer, recv_element[proc], tag); buffer.resize(0); AKANTU_DEBUG_ASSERT(buffer.getLeftToUnpack() == 0, "all data have not been unpacked: " << buffer.getLeftToUnpack() << " bytes left"); static_communicator->freeCommunicationRequest(req); } else { req_not_finished_tmp->push_back(req); } } std::vector<CommunicationRequest *> * swap = req_not_finished_tmp; req_not_finished_tmp = recv_requests_tmp; recv_requests_tmp = swap; req_not_finished_tmp->clear(); } AKANTU_DEBUG_INFO("Waiting that every send requests are received"); static_communicator->waitAll(communication.send_requests); for (std::vector<CommunicationRequest *>::iterator req_it = communication.send_requests.begin(); req_it != communication.send_requests.end() ; ++req_it) { CommunicationRequest & req = *(*req_it); if(static_communicator->testRequest(&req)) { UInt proc = req.getDestination(); CommunicationBuffer & buffer = communication.send_buffer[proc]; buffer.resize(0); static_communicator->freeCommunicationRequest(&req); } } communication.send_requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); communications[tag].resize(nb_proc); for (UInt p = 0; p < nb_proc; ++p) { UInt ssend = 0; UInt sreceive = 0; if(p != rank) { if(send_element[p].getSize() != 0) { #ifndef AKANTU_NDEBUG ssend += send_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real); #endif ssend += data_accessor.getNbDataForElements(send_element[p], tag); AKANTU_DEBUG_INFO("I have " << ssend << "(" << ssend / 1024. << "kB - "<< send_element[p].getSize() <<" element(s)) data to send to " << p << " for tag " << tag); } if(recv_element[p].getSize() != 0) { #ifndef AKANTU_NDEBUG sreceive += recv_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real); #endif sreceive += data_accessor.getNbDataForElements(recv_element[p], tag); AKANTU_DEBUG_INFO("I have " << sreceive << "(" << sreceive / 1024. << "kB - "<< recv_element[p].getSize() <<" element(s)) data to receive for tag " << tag); } } communications[tag].size_to_send [p] = ssend; communications[tag].size_to_receive[p] = sreceive; } AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +void DistributedSynchronizer::computeAllBufferSizes(DataAccessor & data_accessor) { + std::map<SynchronizationTag, Communication>::iterator it = this->communications.begin(); + std::map<SynchronizationTag, Communication>::iterator end = this->communications.end(); + + for (; it != end; ++it) { + SynchronizationTag tag = it->first; + this->computeBufferSize(data_accessor, tag); + } + +} + /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); Int prank = StaticCommunicator::getStaticCommunicator().whoAmI(); Int psize = StaticCommunicator::getStaticCommunicator().getNbProc(); stream << "[" << prank << "/" << psize << "]" << space << "DistributedSynchronizer [" << std::endl; for (UInt p = 0; p < nb_proc; ++p) { if (p == UInt(prank)) continue; stream << "[" << prank << "/" << psize << "]" << space << " + Communication to proc " << p << " [" << std::endl; if(AKANTU_DEBUG_TEST(dblDump)) { stream << "[" << prank << "/" << psize << "]" << space << " - Element to send to proc " << p << " [" << std::endl; Array<Element>::iterator<Element> it_el = send_element[p].begin(); Array<Element>::iterator<Element> end_el = send_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " - Element to recv from proc " << p << " [" << std::endl; it_el = recv_element[p].begin(); end_el = recv_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; } std::map< SynchronizationTag, Communication>::const_iterator it = communications.begin(); std::map< SynchronizationTag, Communication>::const_iterator end = communications.end(); for (; it != end; ++it) { const SynchronizationTag & tag = it->first; const Communication & communication = it->second; UInt ssend = communication.size_to_send[p]; UInt sreceive = communication.size_to_receive[p]; stream << "[" << prank << "/" << psize << "]" << space << " - Tag " << tag << " -> " << ssend << "byte(s) -- <- " << sreceive << "byte(s)" << std::endl; } } } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::onElementsRemoved(const Array<Element> & element_to_remove, const ElementTypeMapArray<UInt> & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt psize = comm.getNbProc(); UInt prank = comm.whoAmI(); std::vector<CommunicationRequest *> isend_requests; Array<UInt> * list_of_el = new Array<UInt>[nb_proc]; // Handling ghost elements for (UInt p = 0; p < psize; ++p) { if (p == prank) continue; Array<Element> & recv = recv_element[p]; if(recv.getSize() == 0) continue; Array<Element>::iterator<Element> recv_begin = recv.begin(); Array<Element>::iterator<Element> recv_end = recv.end(); Array<Element>::const_iterator<Element> er_it = element_to_remove.begin(); Array<Element>::const_iterator<Element> er_end = element_to_remove.end(); Array<UInt> & list = list_of_el[p]; for (UInt i = 0; recv_begin != recv_end; ++i, ++recv_begin) { const Element & el = *recv_begin; Array<Element>::const_iterator<Element> pos = std::find(er_it, er_end, el); if(pos == er_end) { list.push_back(i); } } if(list.getSize() == recv.getSize()) list.push_back(UInt(0)); else list.push_back(UInt(-1)); AKANTU_DEBUG_INFO("Sending a message of size " << list.getSize() << " to proc " << p << " TAG(" << Tag::genTag(prank, 0, 0) << ")"); isend_requests.push_back(comm.asyncSend(list.storage(), list.getSize(), p, Tag::genTag(prank, 0, 0))); list.erase(list.getSize() - 1); if(list.getSize() == recv.getSize()) continue; Array<Element> new_recv; for (UInt nr = 0; nr < list.getSize(); ++nr) { Element & el = recv(list(nr)); el.element = new_numbering(el.type, el.ghost_type)(el.element); new_recv.push_back(el); } AKANTU_DEBUG_INFO("I had " << recv.getSize() << " elements to recv from proc " << p << " and " << list.getSize() << " elements to keep. I have " << new_recv.getSize() << " elements left."); recv.copy(new_recv); } for (UInt p = 0; p < psize; ++p) { if (p == prank) continue; Array<Element> & send = send_element[p]; if(send.getSize() == 0) continue; CommunicationStatus status; AKANTU_DEBUG_INFO("Getting number of elements of proc " << p << " not needed anymore TAG("<< Tag::genTag(p, 0, 0) <<")"); comm.probe<UInt>(p, Tag::genTag(p, 0, 0), status); Array<UInt> list(status.getSize()); AKANTU_DEBUG_INFO("Receiving list of elements (" << status.getSize() - 1 << " elements) no longer needed by proc " << p << " TAG("<< Tag::genTag(p, 0, 0) <<")"); comm.receive(list.storage(), list.getSize(), p, Tag::genTag(p, 0, 0)); if(list.getSize() == 1 && list(0) == 0) continue; list.erase(list.getSize() - 1); Array<Element> new_send; for (UInt ns = 0; ns < list.getSize(); ++ns) { new_send.push_back(send(list(ns))); } AKANTU_DEBUG_INFO("I had " << send.getSize() << " elements to send to proc " << p << " and " << list.getSize() << " elements to keep. I have " << new_send.getSize() << " elements left."); send.copy(new_send); } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); delete [] list_of_el; AKANTU_DEBUG_OUT(); } // void DistributedSynchronizer::checkCommunicationScheme() { // for (UInt p = 0; p < psize; ++p) { // if (p == prank) continue; // for(UInt e(0), e < recv_element.getSize()) // } // } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::buildPrankToElement() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); mesh.initElementTypeMapArray(prank_to_element, 1, spatial_dimension, false, _ek_not_defined, true); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, _not_ghost, _ek_not_defined); /// assign prank to all not ghost elements for (; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); Array<UInt> & prank_to_el = prank_to_element(*it); for (UInt el = 0; el < nb_element; ++el) { prank_to_el(el) = rank; } } /// assign prank to all ghost elements for (UInt p = 0; p < nb_proc; ++p) { UInt nb_ghost_element = recv_element[p].getSize(); for (UInt el = 0; el < nb_ghost_element; ++el) { UInt element = recv_element[p](el).element; ElementType type = recv_element[p](el).type; GhostType ghost_type = recv_element[p](el).ghost_type; Array<UInt> & prank_to_el = prank_to_element(type, ghost_type); prank_to_el(element) = p; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::filterElementsByKind(DistributedSynchronizer * new_synchronizer, ElementKind kind) { AKANTU_DEBUG_IN(); Array<Element> * newsy_send_element = new_synchronizer->send_element; Array<Element> * newsy_recv_element = new_synchronizer->recv_element; Array<Element> * new_send_element = new Array<Element>[nb_proc]; Array<Element> * new_recv_element = new Array<Element>[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { /// send element copying part new_send_element[p].resize(0); for (UInt el = 0; el < send_element[p].getSize(); ++el) { Element & element = send_element[p](el); if (element.kind == kind) newsy_send_element[p].push_back(element); else new_send_element[p].push_back(element); } /// recv element copying part new_recv_element[p].resize(0); for (UInt el = 0; el < recv_element[p].getSize(); ++el) { Element & element = recv_element[p](el); if (element.kind == kind) newsy_recv_element[p].push_back(element); else new_recv_element[p].push_back(element); } } /// deleting and reassigning old pointers delete [] send_element; delete [] recv_element; send_element = new_send_element; recv_element = new_recv_element; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::reset() { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { send_element[p].resize(0); recv_element[p].resize(0); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeTagsSend(DistributedSynchronizer & 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) { AKANTU_DEBUG_IN(); static UInt count = 0; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); if(nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } UInt mesh_data_sizes_buffer_length; MeshData & mesh_data = mesh.getMeshData(); /// tag info std::vector<std::string> tag_names; mesh.getMeshData().getTagNames(tag_names, type); // Make sure the tags are sorted (or at least not in random order), // because they come from a map !! std::sort(tag_names.begin(), tag_names.end()); // Sending information about the tags in mesh_data: name, data type and // number of components of the underlying array associated to the current type DynamicCommunicationBuffer mesh_data_sizes_buffer; std::vector<std::string>::const_iterator names_it = tag_names.begin(); std::vector<std::string>::const_iterator names_end = tag_names.end(); for(;names_it != names_end; ++names_it) { mesh_data_sizes_buffer << *names_it; mesh_data_sizes_buffer << mesh_data.getTypeCode(*names_it); mesh_data_sizes_buffer << mesh_data.getNbComponent(*names_it, type); } mesh_data_sizes_buffer_length = mesh_data_sizes_buffer.getSize(); AKANTU_DEBUG_INFO("Broadcasting the size of the information about the mesh data tags: (" << mesh_data_sizes_buffer_length << ")." ); comm.broadcast(&mesh_data_sizes_buffer_length, 1, root); AKANTU_DEBUG_INFO("Broadcasting the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage()); if(mesh_data_sizes_buffer_length !=0) comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer.getSize(), root); if(mesh_data_sizes_buffer_length !=0) { //Sending the actual data to each processor DynamicCommunicationBuffer buffers[nb_proc]; std::vector<std::string>::const_iterator names_it = tag_names.begin(); std::vector<std::string>::const_iterator names_end = tag_names.end(); // Loop over each tag for the current type for(;names_it != names_end; ++names_it) { // Type code of the current tag (i.e. the tag named *names_it) communicator.fillTagBuffer(mesh_data, buffers, *names_it, type, partition_num, ghost_partition); } std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Sending " << buffers[p].getSize() << " bytes of mesh data to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_MESH_DATA) <<")"); requests.push_back(comm.asyncSend(buffers[p].storage(), buffers[p].getSize(), p, Tag::genTag(my_rank, count, TAG_MESH_DATA))); } } names_it = tag_names.begin(); // Loop over each tag for the current type for(;names_it != names_end; ++names_it) { // Reinitializing the mesh data on the master communicator.populateMeshData(mesh_data, buffers[root], *names_it, type, mesh_data.getTypeCode(*names_it), mesh_data.getNbComponent(*names_it, type), nb_local_element, nb_ghost_element); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); } ++count; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeTagsRecv(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, UInt nb_local_element, UInt nb_ghost_element) { AKANTU_DEBUG_IN(); static UInt count = 0; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); if(nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } /* --------<<<<-TAGS------------------------------------------------- */ UInt mesh_data_sizes_buffer_length = 0; CommunicationBuffer mesh_data_sizes_buffer; MeshData & mesh_data = mesh.getMeshData(); AKANTU_DEBUG_INFO("Receiving the size of the information about the mesh data tags."); comm.broadcast(&mesh_data_sizes_buffer_length, 1, root); if(mesh_data_sizes_buffer_length != 0) { mesh_data_sizes_buffer.resize(mesh_data_sizes_buffer_length); AKANTU_DEBUG_INFO("Receiving the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage()); comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer_length, root); AKANTU_DEBUG_INFO("Size of the information about the mesh data: " << mesh_data_sizes_buffer_length); std::vector<std::string> tag_names; std::vector<MeshDataTypeCode> tag_type_codes; std::vector<UInt> tag_nb_component; tag_names.resize(nb_tags); tag_type_codes.resize(nb_tags); tag_nb_component.resize(nb_tags); CommunicationBuffer mesh_data_buffer; UInt type_code_int; for(UInt i(0); i < nb_tags; ++i) { mesh_data_sizes_buffer >> tag_names[i]; mesh_data_sizes_buffer >> type_code_int; tag_type_codes[i] = static_cast<MeshDataTypeCode>(type_code_int); mesh_data_sizes_buffer >> tag_nb_component[i]; } std::vector<std::string>::const_iterator names_it = tag_names.begin(); std::vector<std::string>::const_iterator names_end = tag_names.end(); CommunicationStatus mesh_data_comm_status; AKANTU_DEBUG_INFO("Checking size of data to receive for mesh data TAG(" << Tag::genTag(root, count, TAG_MESH_DATA) << ")"); comm.probe<char>(root, Tag::genTag(root, count, TAG_MESH_DATA), mesh_data_comm_status); UInt mesh_data_buffer_size(mesh_data_comm_status.getSize()); AKANTU_DEBUG_INFO("Receiving " << mesh_data_buffer_size << " bytes of mesh data TAG(" << Tag::genTag(root, count, TAG_MESH_DATA) << ")"); mesh_data_buffer.resize(mesh_data_buffer_size); comm.receive(mesh_data_buffer.storage(), mesh_data_buffer_size, root, Tag::genTag(root, count, TAG_MESH_DATA)); // Loop over each tag for the current type UInt k(0); for(; names_it != names_end; ++names_it, ++k) { communicator.populateMeshData(mesh_data, mesh_data_buffer, *names_it, type, tag_type_codes[k], tag_nb_component[k], nb_local_element, nb_ghost_element); } } ++count; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<class CommunicationBuffer> void DistributedSynchronizer::fillElementGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, const ElementType & type, CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); Element el; el.type = type; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { UInt nb_element = mesh.getNbElement(type, *gt); el.ghost_type = *gt; for (UInt e = 0; e < nb_element; ++e) { el.element = e; std::vector<std::string> element_to_group; buffer >> element_to_group; AKANTU_DEBUG_ASSERT(e < mesh.getNbElement(type, *gt), "The mesh does not have the element " << e); std::vector<std::string>::iterator it = element_to_group.begin(); std::vector<std::string>::iterator end = element_to_group.end(); for (; it != end; ++it) { mesh.getElementGroup(*it).add(el, false, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeElementGroups(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_element) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); DynamicCommunicationBuffer buffers[nb_proc]; typedef std::vector< std::vector<std::string> > ElementToGroup; ElementToGroup element_to_group; element_to_group.resize(nb_element); GroupManager::const_element_group_iterator egi = mesh.element_group_begin(); GroupManager::const_element_group_iterator ege = mesh.element_group_end(); for (; egi != ege; ++egi) { ElementGroup & eg = *(egi->second); std::string name = egi->first; ElementGroup::const_element_iterator eit = eg.element_begin(type, _not_ghost); ElementGroup::const_element_iterator eend = eg.element_end(type, _not_ghost); for (; eit != eend; ++eit) { element_to_group[*eit].push_back(name); } eit = eg.element_begin(type, _not_ghost); if(eit != eend) const_cast<Array<UInt> &>(eg.getElements(type)).empty(); } /// preparing the buffers const UInt * part = partition_num.storage(); /// copying the data, element by element ElementToGroup::const_iterator data_it = element_to_group.begin(); ElementToGroup::const_iterator data_end = element_to_group.end(); for (; data_it != data_end; ++part, ++data_it) { buffers[*part] << *data_it; } data_it = element_to_group.begin(); /// copying the data for the ghost element for (UInt el(0); data_it != data_end; ++data_it, ++el) { CSR<UInt>::const_iterator it = ghost_partition.begin(el); CSR<UInt>::const_iterator end = ghost_partition.end(el); for (;it != end; ++it) { UInt proc = *it; buffers[proc] << *data_it; } } std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; AKANTU_DEBUG_INFO("Sending element groups to proc " << p << " TAG("<< Tag::genTag(my_rank, p, TAG_ELEMENT_GROUP) <<")"); requests.push_back(comm.asyncSend(buffers[p].storage(), buffers[p].getSize(), p, Tag::genTag(my_rank, p, TAG_ELEMENT_GROUP))); } fillElementGroupsFromBuffer(communicator, mesh, type, buffers[my_rank]); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeElementGroups(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt my_rank = comm.whoAmI(); AKANTU_DEBUG_INFO("Receiving element groups from proc " << root << " TAG("<< Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP) <<")"); CommunicationStatus status; comm.probe<char>(root, Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP), status); CommunicationBuffer buffer(status.getSize()); comm.receive(buffer.storage(), buffer.getSize(), root, Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP)); fillElementGroupsFromBuffer(communicator, mesh, type, buffer); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<class CommunicationBuffer> void DistributedSynchronizer::fillNodeGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); std::vector< std::vector<std::string> > node_to_group; buffer >> node_to_group; AKANTU_DEBUG_ASSERT(node_to_group.size() == mesh.getNbGlobalNodes(), "Not the good amount of nodes where transmitted"); const Array<UInt> & global_nodes = mesh.getGlobalNodesIds(); Array<UInt>::const_scalar_iterator nbegin = global_nodes.begin(); Array<UInt>::const_scalar_iterator nit = global_nodes.begin(); Array<UInt>::const_scalar_iterator nend = global_nodes.end(); for (; nit != nend; ++nit) { std::vector<std::string>::iterator it = node_to_group[*nit].begin(); std::vector<std::string>::iterator end = node_to_group[*nit].end(); for (; it != end; ++it) { mesh.getNodeGroup(*it).add(nit - nbegin, false); } } GroupManager::const_node_group_iterator ngi = mesh.node_group_begin(); GroupManager::const_node_group_iterator nge = mesh.node_group_end(); for (; ngi != nge; ++ngi) { NodeGroup & ng = *(ngi->second); ng.optimize(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeNodeGroupsMaster(DistributedSynchronizer & communicator, UInt root, Mesh & mesh) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); UInt nb_total_nodes = mesh.getNbGlobalNodes(); DynamicCommunicationBuffer buffer; typedef std::vector< std::vector<std::string> > NodeToGroup; NodeToGroup node_to_group; node_to_group.resize(nb_total_nodes); GroupManager::const_node_group_iterator ngi = mesh.node_group_begin(); GroupManager::const_node_group_iterator nge = mesh.node_group_end(); for (; ngi != nge; ++ngi) { NodeGroup & ng = *(ngi->second); std::string name = ngi->first; NodeGroup::const_node_iterator nit = ng.begin(); NodeGroup::const_node_iterator nend = ng.end(); for (; nit != nend; ++nit) { node_to_group[*nit].push_back(name); } nit = ng.begin(); if(nit != nend) ng.empty(); } buffer << node_to_group; std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; AKANTU_DEBUG_INFO("Sending node groups to proc " << p << " TAG("<< Tag::genTag(my_rank, p, TAG_NODE_GROUP) <<")"); requests.push_back(comm.asyncSend(buffer.storage(), buffer.getSize(), p, Tag::genTag(my_rank, p, TAG_NODE_GROUP))); } fillNodeGroupsFromBuffer(communicator, mesh, buffer); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeNodeGroupsSlaves(DistributedSynchronizer & communicator, UInt root, Mesh & mesh) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt my_rank = comm.whoAmI(); AKANTU_DEBUG_INFO("Receiving node groups from proc " << root << " TAG("<< Tag::genTag(root, my_rank, TAG_NODE_GROUP) <<")"); CommunicationStatus status; comm.probe<char>(root, Tag::genTag(root, my_rank, TAG_NODE_GROUP), status); CommunicationBuffer buffer(status.getSize()); comm.receive(buffer.storage(), buffer.getSize(), root, Tag::genTag(root, my_rank, TAG_NODE_GROUP)); fillNodeGroupsFromBuffer(communicator, mesh, buffer); AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/synchronizer/distributed_synchronizer.hh b/src/synchronizer/distributed_synchronizer.hh index 2edd12ab1..3630c7a70 100644 --- a/src/synchronizer/distributed_synchronizer.hh +++ b/src/synchronizer/distributed_synchronizer.hh @@ -1,268 +1,271 @@ /** * @file distributed_synchronizer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jun 16 2011 * @date last modification: Fri Sep 05 2014 * * @brief wrapper to the static communicator * * @section LICENSE * * Copyright (©) 2010-2012, 2014 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_DISTRIBUTED_SYNCHRONIZER_HH__ #define __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_array.hh" #include "synchronizer.hh" #include "mesh.hh" #include "mesh_partition.hh" #include "communication_buffer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class DistributedSynchronizer : public Synchronizer, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DistributedSynchronizer(Mesh & mesh, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); public: virtual ~DistributedSynchronizer(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get a mesh and a partition and create the local mesh and the associated /// DistributedSynchronizer static DistributedSynchronizer * createDistributedSynchronizerMesh(Mesh & mesh, const MeshPartition * partition, UInt root = 0, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); /* ------------------------------------------------------------------------ */ /* Inherited from Synchronizer */ /* ------------------------------------------------------------------------ */ /// asynchronous synchronization of ghosts void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// wait end of asynchronous synchronization of ghosts void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// build processor to element corrispondance void buildPrankToElement(); virtual void printself(std::ostream & stream, int indent = 0) const; /// mesh event handler onRemovedElement virtual void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event); /// filter elements of a certain kind and copy them into a new synchronizer void filterElementsByKind(DistributedSynchronizer * new_synchronizer, ElementKind kind); /// reset send and recv element lists void reset(); /// compute buffer size for a given tag and data accessor void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag); + /// recalculate buffer sizes for all tags + void computeAllBufferSizes(DataAccessor & data_accessor); + protected: /// fill the nodes type vector void fillNodesType(Mesh & mesh); 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); template<typename T, typename BufferType> void populateMeshDataTemplated(MeshData & mesh_data, BufferType & buffer, const std::string & tag_name, const ElementType & el_type, UInt nb_component, UInt nb_local_element, UInt nb_ghost_element); template <typename BufferType> void populateMeshData(MeshData & mesh_data, BufferType & buffer, const std::string & tag_name, const ElementType & el_type, const MeshDataTypeCode & type_code, UInt nb_component, UInt nb_local_element, UInt nb_ghost_element); /// fill the communications array of a distributedSynchronizer based on a partition array void fillCommunicationScheme(const UInt * partition, UInt nb_local_element, UInt nb_ghost_element, ElementType type); /// function that handels the MeshData to be split (root side) static void synchronizeTagsSend(DistributedSynchronizer & 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(DistributedSynchronizer & 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(DistributedSynchronizer & 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(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type); template<class CommunicationBuffer> static void fillElementGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, const ElementType & type, CommunicationBuffer & buffer); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsMaster(DistributedSynchronizer & communicator, UInt root, Mesh & mesh); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsSlaves(DistributedSynchronizer & communicator, UInt root, Mesh & mesh); template<class CommunicationBuffer> static void fillNodeGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, CommunicationBuffer & buffer); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(PrankToElement, prank_to_element, const ElementTypeMapArray<UInt> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: enum CommTags { TAG_SIZES = 0, TAG_CONNECTIVITY = 1, TAG_DATA = 2, TAG_PARTITIONS = 3, TAG_NB_NODES = 4, TAG_NODES = 5, TAG_COORDINATES = 6, TAG_NODES_TYPE = 7, TAG_MESH_DATA = 8, TAG_ELEMENT_GROUP = 9, TAG_NODE_GROUP = 10, }; protected: /// reference to the underlying mesh Mesh & mesh; std::map<SynchronizationTag, Communication> communications; /// list of element to send to proc p Array<Element> * send_element; /// list of element to receive from proc p Array<Element> * recv_element; UInt nb_proc; UInt rank; friend class FilteredSynchronizer; friend class FacetSynchronizer; ElementTypeMapArray<UInt> prank_to_element; }; __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "distributed_synchronizer_tmpl.hh" #endif /* __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/grid_synchronizer.cc b/src/synchronizer/grid_synchronizer.cc index 426117c90..a4da85ce2 100644 --- a/src/synchronizer/grid_synchronizer.cc +++ b/src/synchronizer/grid_synchronizer.cc @@ -1,509 +1,514 @@ /** * @file grid_synchronizer.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Oct 03 2011 * @date last modification: Thu Jun 05 2014 * * @brief implementation of the grid synchronizer * * @section LICENSE * * Copyright (©) 2014 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 "grid_synchronizer.hh" #include "aka_grid_dynamic.hh" #include "mesh.hh" #include "fe_engine.hh" #include "static_communicator.hh" #include "mesh_io.hh" #include <iostream> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ GridSynchronizer::GridSynchronizer(Mesh & mesh, const ID & id, MemoryID memory_id) : DistributedSynchronizer(mesh, id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <class E> GridSynchronizer * GridSynchronizer::createGridSynchronizer(Mesh & mesh, const SpatialGrid<E> & grid, + SynchronizerRegistry & synch_registry, SynchronizerID id, MemoryID memory_id) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); GridSynchronizer & communicator = *(new GridSynchronizer(mesh, id, memory_id)); if(nb_proc == 1) return &communicator; UInt spatial_dimension = mesh.getSpatialDimension(); Real * bounding_boxes = new Real[2 * spatial_dimension * nb_proc]; Real * my_bounding_box = bounding_boxes + 2 * spatial_dimension * my_rank; // mesh.getLocalLowerBounds(my_bounding_box); // mesh.getLocalUpperBounds(my_bounding_box + spatial_dimension); const Vector<Real> & lower = grid.getLowerBounds(); const Vector<Real> & upper = grid.getUpperBounds(); const Vector<Real> & spacing = grid.getSpacing(); for (UInt i = 0; i < spatial_dimension; ++i) { my_bounding_box[i ] = lower(i) - spacing(i); my_bounding_box[spatial_dimension + i] = upper(i) + spacing(i); } AKANTU_DEBUG_INFO("Exchange of bounding box to detect the overlapping regions."); comm.allGather(bounding_boxes, spatial_dimension * 2); bool * intersects_proc = new bool[nb_proc]; std::fill_n(intersects_proc, nb_proc, true); Int * first_cells = new Int[3 * nb_proc]; Int * last_cells = new Int[3 * nb_proc]; std::fill_n(first_cells, 3 * nb_proc, 0); std::fill_n(first_cells, 3 * nb_proc, 0); ElementTypeMapArray<UInt> ** element_per_proc = new ElementTypeMapArray<UInt>* [nb_proc]; for (UInt p = 0; p < nb_proc; ++p) element_per_proc[p] = NULL; // check the overlapping between my box and the one from other processors for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; Real * proc_bounding_box = bounding_boxes + 2 * spatial_dimension * p; bool intersects = false; Int * first_cell_p = first_cells + p * spatial_dimension; Int * last_cell_p = last_cells + p * spatial_dimension; for (UInt s = 0; s < spatial_dimension; ++s) { // check overlapping of grid intersects = Math::intersects(my_bounding_box[s], my_bounding_box[spatial_dimension + s], proc_bounding_box[s], proc_bounding_box[spatial_dimension + s]); intersects_proc[p] &= intersects; if(intersects) { AKANTU_DEBUG_INFO("I intersects with processor " << p << " in direction " << s); // is point 1 of proc p in the dimension s in the range ? bool point1 = Math::is_in_range(proc_bounding_box[s], my_bounding_box[s], my_bounding_box[s+spatial_dimension]); // is point 2 of proc p in the dimension s in the range ? bool point2 = Math::is_in_range(proc_bounding_box[s+spatial_dimension], my_bounding_box[s], my_bounding_box[s+spatial_dimension]); Real start = 0.; Real end = 0.; if(point1 && !point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box[s]; end = my_bounding_box[s+spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 1 in direction " << s << " with processor " << p << " [" << start << ", " << end <<"]"); } else if(point1 && point2) { /* |-----------------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box[s]; end = proc_bounding_box[s+spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 2 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else if(!point1 && point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box[s]; end = proc_bounding_box[s+spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 3 in direction " << s << " with processor " << p << " [" << start << ", " << end <<"]"); } else { /* |-----------| my_bounding_box(i) * |-----------------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box[s]; end = my_bounding_box[s+spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 4 in direction " << s << " with processor " << p << " [" << start << ", " << end <<"]"); } first_cell_p[s] = grid.getCellID(start, s); last_cell_p [s] = grid.getCellID(end, s); } } //create the list of cells in the overlapping typedef typename SpatialGrid<E>::CellID CellID; std::vector<CellID> * cell_ids = new std::vector<CellID>; if(intersects_proc[p]) { AKANTU_DEBUG_INFO("I intersects with processor " << p); CellID cell_id(spatial_dimension); // for (UInt i = 0; i < spatial_dimension; ++i) { // if(first_cell_p[i] != 0) --first_cell_p[i]; // if(last_cell_p[i] != 0) ++last_cell_p[i]; // } for (Int fd = first_cell_p[0]; fd <= last_cell_p[0]; ++fd) { cell_id.setID(0, fd); if(spatial_dimension == 1) { cell_ids->push_back(cell_id); } else { for (Int sd = first_cell_p[1]; sd <= last_cell_p[1] ; ++sd) { cell_id.setID(1, sd); if(spatial_dimension == 2) { cell_ids->push_back(cell_id); } else { for (Int ld = first_cell_p[2]; ld <= last_cell_p[2] ; ++ld) { cell_id.setID(2, ld); cell_ids->push_back(cell_id); } } } } } // get the list of elements in the cells of the overlapping typename std::vector<CellID>::iterator cur_cell_id = cell_ids->begin(); typename std::vector<CellID>::iterator last_cell_id = cell_ids->end(); std::set<Element> * to_send = new std::set<Element>(); for (; cur_cell_id != last_cell_id; ++cur_cell_id) { typename SpatialGrid<E>::Cell::const_iterator cur_elem = grid.beginCell(*cur_cell_id); typename SpatialGrid<E>::Cell::const_iterator last_elem = grid.endCell(*cur_cell_id); for (; cur_elem != last_elem; ++cur_elem) { to_send->insert(*cur_elem); } } AKANTU_DEBUG_INFO("I have prepared " << to_send->size() << " elements to send to processor " << p); std::stringstream sstr; sstr << "element_per_proc_" << p; element_per_proc[p] = new ElementTypeMapArray<UInt>(sstr.str(), id); ElementTypeMapArray<UInt> & elempproc = *(element_per_proc[p]); typename std::set<Element>::iterator elem = to_send->begin(); typename std::set<Element>::iterator last_elem = to_send->end(); for (; elem != last_elem; ++elem) { ElementType type = elem->type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); // /!\ this part must be slow due to the access in the ElementTypeMapArray<UInt> if(!elempproc.exists(type)) elempproc.alloc(0, nb_nodes_per_element, type, _not_ghost); UInt global_connect[nb_nodes_per_element]; UInt * local_connect = mesh.getConnectivity(type).storage() + elem->element * nb_nodes_per_element; for (UInt i = 0; i < nb_nodes_per_element; ++i) { global_connect[i] = mesh.getNodeGlobalId(local_connect[i]); AKANTU_DEBUG_ASSERT(global_connect[i] < mesh.getNbGlobalNodes(), "This global node send in the connectivity does not seem correct " << global_connect[i] << " corresponding to " << local_connect[i] << " from element " << elem->element); } elempproc(type).push_back(global_connect); communicator.send_element[p].push_back(*elem); } delete to_send; } delete cell_ids; } delete [] first_cells; delete [] last_cells; delete [] bounding_boxes; AKANTU_DEBUG_INFO("I have finished to compute intersection," << " no it's time to communicate with my neighbors"); /** * Sending loop, sends the connectivity asynchronously to all concerned proc */ std::vector<CommunicationRequest *> isend_requests; for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; if(intersects_proc[p]) { ElementTypeMapArray<UInt> & elempproc = *(element_per_proc[p]); ElementTypeMapArray<UInt>::type_iterator it_type = elempproc.firstType(_all_dimensions, _not_ghost); ElementTypeMapArray<UInt>::type_iterator last_type = elempproc.lastType (_all_dimensions, _not_ghost); UInt count = 0; for (; it_type != last_type; ++it_type) { Array<UInt> & conn = elempproc(*it_type, _not_ghost); UInt info[2]; info[0] = (UInt) *it_type; info[1] = conn.getSize() * conn.getNbComponent(); AKANTU_DEBUG_INFO("I have " << conn.getSize() << " elements of type " << *it_type << " to send to processor " << p << " (communication tag : " << Tag::genTag(my_rank, count, DATA_TAG) << ")"); isend_requests.push_back(comm.asyncSend(info, 2, p, Tag::genTag(my_rank, count, SIZE_TAG))); if(info[1]) isend_requests.push_back(comm.asyncSend<UInt>(conn.storage(), info[1], p, Tag::genTag(my_rank, count, DATA_TAG))); ++count; } UInt info[2]; info[0] = (UInt) _not_defined; info[1] = 0; isend_requests.push_back(comm.asyncSend(info, 2, p, Tag::genTag(my_rank, count, SIZE_TAG))); } } /** * Receives the connectivity and store them in the ghosts elements */ Array<UInt> & global_nodes_ids = const_cast<Array<UInt> &>(mesh.getGlobalNodesIds()); Array<Int> & nodes_type = const_cast<Array<Int> &>(const_cast<const Mesh &>(mesh).getNodesType()); std::vector<CommunicationRequest *> isend_nodes_requests; UInt nb_nodes_to_recv[nb_proc]; UInt nb_total_nodes_to_recv = 0; UInt nb_current_nodes = global_nodes_ids.getSize(); NewNodesEvent new_nodes; NewElementsEvent new_elements; Array<UInt> * ask_nodes_per_proc = new Array<UInt>[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { nb_nodes_to_recv[p] = 0; if(p == my_rank) continue; Array<UInt> & ask_nodes = ask_nodes_per_proc[p]; UInt count = 0; if(intersects_proc[p]) { ElementType type = _not_defined; do { UInt info[2] = { 0 }; comm.receive(info, 2, p, Tag::genTag(p, count, SIZE_TAG)); type = (ElementType) info[0]; if(type != _not_defined) { UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type);; UInt nb_element = info[1] / nb_nodes_per_element; Array<UInt> tmp_conn(nb_element, nb_nodes_per_element); tmp_conn.clear(); if(info[1]) comm.receive<UInt>(tmp_conn.storage(), info[1], p, Tag::genTag(p, count, DATA_TAG)); AKANTU_DEBUG_INFO("I will receive " << nb_element << " elements of type " << ElementType(info[0]) << " from processor " << p << " (communication tag : " << Tag::genTag(p, count, DATA_TAG) << ")"); Array<UInt> & ghost_connectivity = const_cast<Array<UInt> &>(mesh.getConnectivity(type, _ghost)); UInt nb_ghost_element = ghost_connectivity.getSize(); Element element(type, 0, _ghost); UInt conn[nb_nodes_per_element]; for (UInt el = 0; el < nb_element; ++el) { UInt nb_node_to_ask_for_elem = 0; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt gn = tmp_conn(el, n); UInt ln = global_nodes_ids.find(gn); AKANTU_DEBUG_ASSERT(gn < mesh.getNbGlobalNodes(), "This global node seems not correct " << gn << " from element " << el << " node " << n); if(ln == UInt(-1)) { global_nodes_ids.push_back(gn); nodes_type.push_back(-3); // pure ghost node ln = nb_current_nodes; new_nodes.getList().push_back(ln); ++nb_current_nodes; ask_nodes.push_back(gn); ++nb_node_to_ask_for_elem; } conn[n] = ln; } // all the nodes are already known locally, the element should already exists UInt c = UInt(-1); if(nb_node_to_ask_for_elem == 0) { c = ghost_connectivity.find(conn); element.element = c; } if(c == UInt(-1)) { element.element = nb_ghost_element; ++nb_ghost_element; ghost_connectivity.push_back(conn); new_elements.getList().push_back(element); } communicator.recv_element[p].push_back(element); } } count++; } while(type != _not_defined); AKANTU_DEBUG_INFO("I have " << ask_nodes.getSize() << " missing nodes for elements coming from processor " << p << " (communication tag : " << Tag::genTag(my_rank, 0, ASK_NODES_TAG) << ")"); isend_nodes_requests.push_back(comm.asyncSend(ask_nodes.storage(), ask_nodes.getSize(), p, Tag::genTag(my_rank, 0, ASK_NODES_TAG))); nb_nodes_to_recv[p] = ask_nodes.getSize(); nb_total_nodes_to_recv += ask_nodes.getSize(); } } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); for (UInt p = 0; p < nb_proc; ++p) { if(element_per_proc[p]) delete element_per_proc[p]; } delete [] element_per_proc; /** * Sends requested nodes to proc */ Array<Real> & nodes = const_cast<Array<Real> &>(mesh.getNodes()); UInt nb_nodes = nodes.getSize(); std::vector<CommunicationRequest *> isend_coordinates_requests; Array<Real> * nodes_to_send_per_proc = new Array<Real>[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank || !intersects_proc[p]) continue; Array<UInt> asked_nodes; CommunicationStatus status; AKANTU_DEBUG_INFO("Waiting list of nodes to send to processor " << p << "(communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.probe<UInt>(p, Tag::genTag(p, 0, ASK_NODES_TAG), status); UInt nb_nodes_to_send = status.getSize(); asked_nodes.resize(nb_nodes_to_send); AKANTU_DEBUG_INFO("I have " << nb_nodes_to_send << " nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); AKANTU_DEBUG_INFO("Getting list of nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.receive(asked_nodes.storage(), nb_nodes_to_send, p, Tag::genTag(p, 0, ASK_NODES_TAG)); Array<Real> & nodes_to_send = nodes_to_send_per_proc[p]; nodes_to_send.extendComponentsInterlaced(spatial_dimension, 1); for (UInt n = 0; n < nb_nodes_to_send; ++n) { UInt ln = global_nodes_ids.find(asked_nodes(n)); AKANTU_DEBUG_ASSERT(ln != UInt(-1), "The node [" << asked_nodes(n) << "] requested by proc " << p << " was not found locally!"); nodes_to_send.push_back(nodes.storage() + ln * spatial_dimension); } AKANTU_DEBUG_INFO("Sending the nodes to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); isend_coordinates_requests.push_back(comm.asyncSend(nodes_to_send.storage(), nb_nodes_to_send * spatial_dimension, p, Tag::genTag(my_rank, 0, SEND_NODES_TAG))); } comm.waitAll(isend_nodes_requests); comm.freeCommunicationRequest(isend_nodes_requests); delete [] ask_nodes_per_proc; nodes.resize(nb_total_nodes_to_recv + nb_nodes); for (UInt p = 0; p < nb_proc; ++p) { if((p != my_rank) && (nb_nodes_to_recv[p] > 0)) { AKANTU_DEBUG_INFO("Receiving the nodes from processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.receive(nodes.storage() + nb_nodes * spatial_dimension, nb_nodes_to_recv[p] * spatial_dimension, p, Tag::genTag(p, 0, SEND_NODES_TAG)); nb_nodes += nb_nodes_to_recv[p]; } } comm.waitAll(isend_coordinates_requests); comm.freeCommunicationRequest(isend_coordinates_requests); delete [] nodes_to_send_per_proc; + synch_registry.registerSynchronizer(communicator, _gst_material_id); + mesh.sendEvent(new_nodes); mesh.sendEvent(new_elements); delete [] intersects_proc; AKANTU_DEBUG_OUT(); return &communicator; } /* -------------------------------------------------------------------------- */ template GridSynchronizer * GridSynchronizer::createGridSynchronizer<QuadraturePoint>(Mesh & mesh, const SpatialGrid<QuadraturePoint> & grid, + SynchronizerRegistry & synch_registry, SynchronizerID id, MemoryID memory_id); template GridSynchronizer * GridSynchronizer::createGridSynchronizer<Element>(Mesh & mesh, const SpatialGrid<Element> & grid, + SynchronizerRegistry & synch_registry, SynchronizerID id, MemoryID memory_id); __END_AKANTU__ diff --git a/src/synchronizer/grid_synchronizer.hh b/src/synchronizer/grid_synchronizer.hh index 8f381fd2d..d1062f18f 100644 --- a/src/synchronizer/grid_synchronizer.hh +++ b/src/synchronizer/grid_synchronizer.hh @@ -1,92 +1,94 @@ /** * @file grid_synchronizer.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Oct 03 2011 * @date last modification: Thu Feb 21 2013 * * @brief synchronizer based in RegularGrid * * @section LICENSE * * Copyright (©) 2014 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 "distributed_synchronizer.hh" +#include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GRID_SYNCHRONIZER_HH__ #define __AKANTU_GRID_SYNCHRONIZER_HH__ __BEGIN_AKANTU__ class Mesh; template<class T> class SpatialGrid; class GridSynchronizer : public DistributedSynchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ protected: GridSynchronizer(Mesh & mesh, const ID & id = "grid_synchronizer", MemoryID memory_id = 0); public: virtual ~GridSynchronizer() { }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template <class E> static GridSynchronizer * createGridSynchronizer(Mesh & mesh, const SpatialGrid<E> & grid, + SynchronizerRegistry & synch_registry, SynchronizerID id = "grid_synchronizer", MemoryID memory_id = 0); protected: enum CommTags { SIZE_TAG = 0, DATA_TAG = 1, ASK_NODES_TAG = 2, SEND_NODES_TAG = 3 }; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; __END_AKANTU__ #endif /* __AKANTU_GRID_SYNCHRONIZER_HH__ */ diff --git a/test/test_model/test_solid_mechanics_model/CMakeLists.txt b/test/test_model/test_solid_mechanics_model/CMakeLists.txt index 8a3aca11e..cfc6762bb 100644 --- a/test/test_model/test_solid_mechanics_model/CMakeLists.txt +++ b/test/test_model/test_solid_mechanics_model/CMakeLists.txt @@ -1,214 +1,214 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # # @date creation: Fri Sep 03 2010 # @date last modification: Thu Mar 27 2014 # # @brief configuratio for SolidMechanicsModel tests # # @section LICENSE # # Copyright (©) 2010-2012, 2014 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_materials "test_materials") add_akantu_test(patch_tests "patch_tests") add_akantu_test(test_cohesive "cohesive_test") #=============================================================================== add_mesh(test_solid_mechanics_model_square_mesh square.geo 2 1) add_mesh(test_solid_mechanics_model_circle_mesh1 circle.geo 2 1 OUTPUT circle1.msh) add_mesh(test_solid_mechanics_model_circle_mesh2 circle.geo 2 2 OUTPUT circle2.msh) register_test(test_solid_mechanics_model_square SOURCES test_solid_mechanics_model_square.cc DEPENDENCIES test_solid_mechanics_model_square_mesh FILES_TO_COPY material.dat test_cst_energy.pl DIRECTORIES_TO_CREATE paraview PACKAGE core ) register_test(test_solid_mechanics_model_circle_2 SOURCES test_solid_mechanics_model_circle_2.cc DEPENDENCIES test_solid_mechanics_model_circle_mesh2 FILES_TO_COPY material.dat DIRECTORIES_TO_CREATE paraview PACKAGE core ) #=============================================================================== add_mesh(test_bar_traction_2d_mesh1 bar.geo 2 1 OUTPUT bar1.msh) add_mesh(test_bar_traction_2d_mesh2 bar.geo 2 2 OUTPUT bar2.msh) add_mesh(test_bar_traction_2d_mesh_structured1 bar_structured.geo 2 1 OUTPUT bar_structured1.msh) register_test(test_solid_mechanics_model_bar_traction2d SOURCES test_solid_mechanics_model_bar_traction2d.cc DEPENDENCIES test_bar_traction_2d_mesh1 test_bar_traction_2d_mesh2 FILES_TO_COPY material.dat test_cst_energy.pl DIRECTORIES_TO_CREATE paraview PACKAGE core ) register_test(test_solid_mechanics_model_bar_traction2d_structured SOURCES test_solid_mechanics_model_bar_traction2d_structured.cc DEPENDENCIES test_bar_traction_2d_mesh_structured1 FILES_TO_COPY material.dat test_cst_energy.pl DIRECTORIES_TO_CREATE paraview PACKAGE core ) #=============================================================================== add_mesh(test_solid_mechanics_model_segment_mesh segment.geo 1 2) register_test(test_solid_mechanics_model_bar_traction2d_parallel SOURCES test_solid_mechanics_model_bar_traction2d_parallel.cc DEPENDENCIES test_bar_traction_2d_mesh2 FILES_TO_COPY material.dat test_cst_energy.pl DIRECTORIES_TO_CREATE paraview PACKAGE parallel ) register_test(test_solid_mechanics_model_segment_parallel SOURCES test_solid_mechanics_model_segment_parallel.cc DEPENDENCIES test_solid_mechanics_model_segment_mesh FILES_TO_COPY material.dat test_cst_energy.pl DIRECTORIES_TO_CREATE paraview PACKAGE parallel ) #=============================================================================== #register_test(test_solid_mechanics_model_bar_traction2d_mass_not_lumped # SOURCES test_solid_mechanics_model_bar_traction2d_mass_not_lumped.cc # DEPENDENCIES test_bar_traction_2d_mesh1 test_bar_traction_2d_mesh2 # FILES_TO_COPY material.dat # DIRECTORIES_TO_CREATE paraview # PACKAGE implicit # ) #=============================================================================== add_mesh(test_solid_mechanics_model_segment_mesh1 segment.geo 1 1 OUTPUT segment1.msh) add_mesh(test_implicit_mesh1 square_implicit.geo 2 1 OUTPUT square_implicit1.msh) add_mesh(test_implicit_mesh2 square_implicit.geo 2 2 OUTPUT square_implicit2.msh) register_test(test_solid_mechanics_model_implicit_1d SOURCES test_solid_mechanics_model_implicit_1d.cc DEPENDENCIES test_solid_mechanics_model_segment_mesh1 FILES_TO_COPY material.dat DIRECTORIES_TO_CREATE paraview PACKAGE implicit ) register_test(test_solid_mechanics_model_implicit_2d SOURCES test_solid_mechanics_model_implicit_2d.cc DEPENDENCIES test_implicit_mesh1 test_implicit_mesh2 FILES_TO_COPY material.dat DIRECTORIES_TO_CREATE paraview PACKAGE implicit ) #=============================================================================== add_mesh(test_implicit_beam_2d_1 beam_2d.geo 2 1 OUTPUT beam_2d_lin.msh) add_mesh(test_implicit_beam_2d_2 beam_2d.geo 2 2 OUTPUT beam_2d_quad.msh) add_mesh(test_implicit_beam_3d_2 beam_3d.geo 3 2 OUTPUT beam_3d_quad.msh) add_mesh(test_implicit_beam_3d_1 beam_3d.geo 3 1 OUTPUT beam_3d_lin.msh) register_test(test_solid_mechanics_model_implicit_dynamic_2d SOURCES test_solid_mechanics_model_implicit_dynamic_2d.cc DEPENDENCIES test_implicit_beam_2d_1 test_implicit_beam_2d_2 test_implicit_beam_3d_2 test_implicit_beam_3d_1 FILES_TO_COPY material_implicit_dynamic.dat DIRECTORIES_TO_CREATE paraview PACKAGE implicit ) #=============================================================================== add_mesh(test_pbc_parallel_mesh square_structured.geo 2 1 OUTPUT square_structured.msh) register_test(test_solid_mechanics_model_bar_traction2d_structured_pbc SOURCES test_solid_mechanics_model_bar_traction2d_structured_pbc.cc DEPENDENCIES test_bar_traction_2d_mesh_structured1 FILES_TO_COPY material.dat test_cst_energy.pl DIRECTORIES_TO_CREATE paraview PACKAGE core ) #register_test(test_solid_mechanics_model_pbc_parallel # SOURCES test_solid_mechanics_model_pbc_parallel.cc # DEPENDENCIES test_pbc_parallel_mesh # FILES_TO_COPY material.dat # DIRECTORIES_TO_CREATE paraview # PACKAGE parallel # ) #=============================================================================== add_mesh(test_cube3d_mesh1 cube.geo 3 1 OUTPUT cube1.msh) add_mesh(test_cube3d_mesh2 cube.geo 3 2 OUTPUT cube2.msh) add_mesh(test_cube3d_mesh_structured cube_structured.geo 3 1 OUTPUT cube_structured.msh) register_test(test_solid_mechanics_model_cube3d SOURCES test_solid_mechanics_model_cube3d.cc DEPENDENCIES test_cube3d_mesh1 FILES_TO_COPY material.dat DIRECTORIES_TO_CREATE paraview PACKAGE core ) register_test(test_solid_mechanics_model_cube3d_tetra10 SOURCES test_solid_mechanics_model_cube3d_tetra10.cc DEPENDENCIES test_cube3d_mesh2 FILES_TO_COPY material.dat DIRECTORIES_TO_CREATE paraview PACKAGE core ) register_test(test_solid_mechanics_model_cube3d_pbc SOURCES test_solid_mechanics_model_cube3d_pbc.cc DEPENDENCIES test_cube3d_mesh_structured FILES_TO_COPY material.dat DIRECTORIES_TO_CREATE paraview PACKAGE core ) #add_mesh(test_solid_mechanics_model_boundary_condition_mesh cube_physical_names.geo 3 1) register_test(test_solid_mechanics_model_boundary_condition SOURCES test_solid_mechanics_model_boundary_condition.cc FILES_TO_COPY material.dat cube_physical_names.msh PACKAGE core ) #=============================================================================== add_mesh(test_cube3d_two_mat_mesh cube_two_materials.geo 3 1) register_test(test_solid_mechanics_model_reassign_material SOURCES test_solid_mechanics_model_reassign_material.cc DEPENDENCIES test_cube3d_two_mat_mesh FILES_TO_COPY two_materials.dat - PACKAGE scotch + PACKAGE implicit ) #=============================================================================== register_test(test_solid_mechanics_model_material_eigenstrain SOURCES test_solid_mechanics_model_material_eigenstrain.cc FILES_TO_COPY cube_3d_tet_4.msh; material_elastic_plane_strain.dat PACKAGE core ) diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/CMakeLists.txt b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/CMakeLists.txt index c7b02c9a6..3b120af1d 100644 --- a/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/CMakeLists.txt +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/CMakeLists.txt @@ -1,41 +1,51 @@ #=============================================================================== # @file CMakeLists.txt # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Jan 20 2014 # @date last modification: Mon Jan 20 2014 # # @brief configuration for materials tests # # @section LICENSE # # Copyright (©) 2014 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_mesh(test_material_non_local_mesh mesh.geo 2 2 OUTPUT mesh.msh) +add_mesh(test_two_materials_mesh two_materials.geo 2 1 OUTPUT two_materials.msh) + register_test(test_material_damage_non_local SOURCES test_material_damage_non_local.cc DEPENDENCIES test_material_non_local_mesh FILES_TO_COPY material_damage_non_local.dat DIRECTORIES_TO_CREATE paraview PACKAGE damage_non_local ) +register_test(test_material_damage_non_local_two_materials + SOURCES test_material_damage_non_local_two_materials.cc + DEPENDENCIES test_two_materials_mesh + FILES_TO_COPY two_materials_non_local.dat + DIRECTORIES_TO_CREATE paraview + PACKAGE damage_non_local + ) + diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/test_material_damage_non_local_two_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/test_material_damage_non_local_two_materials.cc new file mode 100644 index 000000000..131d03d3b --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/test_material_damage_non_local_two_materials.cc @@ -0,0 +1,156 @@ +/** + * @file test_material_damage_non_local_two_materials.cc + * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> + * @date Fri Feb 20 15:30:27 2015 + * + * @brief test to check if two non-local materials can be used together + * + * @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 <iostream> +/* -------------------------------------------------------------------------- */ +#include "aka_common.hh" +#include "mesh.hh" +#include "mesh_io.hh" +#include "solid_mechanics_model.hh" +#include "material.hh" +/* -------------------------------------------------------------------------- */ + +using namespace akantu; + +int main(int argc, char *argv[]) { + initialize("two_materials_non_local.dat", argc, argv); + debug::setDebugLevel(akantu::dblWarning); + + const UInt spatial_dimension = 2; + Mesh mesh(spatial_dimension); + akantu::MeshPartition * partition = NULL; + + StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); + Int psize = comm.getNbProc(); + Int prank = comm.whoAmI(); + + if(prank == 0) { + + mesh.read("two_materials.msh"); + + /// partition the mesh + partition = new MeshPartitionScotch(mesh, spatial_dimension); + + partition->partitionate(psize); + } + + SolidMechanicsModel model(mesh); + model.initParallel(partition); + delete partition; + + model.setBaseName("damage_in_ASR_sample"); + model.addDumpField("partitions"); + + model.dump(); + /// assign the materials + MeshDataMaterialSelector<UInt> * mat_selector; + mat_selector = new MeshDataMaterialSelector<UInt>("tag_0", model, 1); + + model.setMaterialSelector(*mat_selector); + model.initFull(SolidMechanicsModelOptions(_static)); + + /// displaying the material data + if (prank == 0) { + for (UInt m = 0; m < model.getNbMaterials(); ++m) + std::cout << model.getMaterial(m) << std::endl; + } + + + // model.getFEEngine().getMesh().initElementTypeMapArray(quadrature_points_volumes, 1, 0); + // const MaterialNonLocal<spatial_dimension, BaseWeightFunction> & mat = + // dynamic_cast<const MaterialNonLocal<spatial_dimension, BaseWeightFunction> &>(model.getMaterial(0)); + // // mat.computeQuadraturePointsNeighborhoudVolumes(quadrature_points_volumes); + // Real radius = mat.getRadius(); + + // UInt nb_element = mesh.getNbElement(TYPE); + // UInt nb_tot_quad = model.getFEEngine().getNbQuadraturePoints(TYPE) * nb_element; + + // std::cout << mat << std::endl; + + // Array<Real> quads(0, spatial_dimension); + // quads.resize(nb_tot_quad); + + // model.getFEEngine().interpolateOnQuadraturePoints(mesh.getNodes(), + // quads, spatial_dimension, + // TYPE); + + // Array<Real>::iterator< Vector<Real> > first_quad_1 = quads.begin(spatial_dimension); + // Array<Real>::iterator< Vector<Real> > last_quad_1 = quads.end(spatial_dimension); + + // std::ofstream pout; + // pout.open("bf_pairs"); + // UInt q1 = 0; + + // Real R = mat.getRadius(); + + // for(;first_quad_1 != last_quad_1; ++first_quad_1, ++q1) { + // Array<Real>::iterator< Vector<Real> > first_quad_2 = quads.begin(spatial_dimension); + // //Array<Real>::iterator< Vector<Real> > last_quad_2 = quads.end(spatial_dimension); + // UInt q2 = 0; + // for(;first_quad_2 != last_quad_1; ++first_quad_2, ++q2) { + // Real d = first_quad_2->distance(*first_quad_1); + // if(d <= radius) { + // Real alpha = (1 - d*d/(R*R)); + // alpha = alpha*alpha; + // pout << q1 << " " << q2 << " " << alpha << std::endl; + // } + // } + // } + // pout.close(); + + // mat.savePairs("cl_pairs"); + + // ElementTypeMapArray<Real> constant("constant_value", "test"); + // mesh.initElementTypeMapArray(constant, 1, 0); + // Mesh::type_iterator it = mesh.firstType(spatial_dimension); + // Mesh::type_iterator last_type = mesh.lastType(spatial_dimension); + // for(; it != last_type; ++it) { + // UInt nb_quadrature_points = model.getFEEngine().getNbQuadraturePoints(*it); + // UInt _nb_element = mesh.getNbElement(*it); + + // Array<Real> & constant_vect = constant(*it); + // constant_vect.resize(_nb_element * nb_quadrature_points); + + // std::fill_n(constant_vect.storage(), nb_quadrature_points * _nb_element, 1.); + // } + + // ElementTypeMapArray<Real> constant_avg("constant_value_avg", "test"); + // mesh.initElementTypeMapArray(constant_avg, 1, 0); + + // mat.weightedAvergageOnNeighbours(constant, constant_avg, 1); + + // debug::setDebugLevel(akantu::dblTest); + // std::cout << constant(TYPE) << std::endl; + // std::cout << constant_avg(TYPE) << std::endl; + // debug::setDebugLevel(akantu::dblWarning); + + finalize(); + + return EXIT_SUCCESS; +} + diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/two_materials.geo b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/two_materials.geo new file mode 100644 index 000000000..c9f459f12 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/two_materials.geo @@ -0,0 +1,49 @@ +// Mesh size +h = 0.25; // Top cube + +// Dimensions of top cube +Lx = 1; +Ly = 1; + + +// ------------------------------------------ +// Geometry +// ------------------------------------------ + +// Base Cube +Point(101) = { 0.0, 0.0, 0.0, h}; // Bottom Face +Point(102) = { Lx/4, 0.0, 0.0, h}; +Point(103) = { Lx, 0.0, 0.0, h}; // Bottom Face +Point(104) = { Lx, Ly, 0.0, h}; // Bottom Face +Point(105) = { Lx/4, Ly, 0.0, h}; +Point(106) = { 0.0, Ly, 0.0, h}; // Bottom Face + +// Base Cube +Line(101) = {101,102}; // Bottom Face +Line(102) = {102,105}; // Bottom Face +Line(103) = {105,106}; // Bottom Face +Line(104) = {106,101}; // Bottom Face + +Line(105) = {102,103}; // Bottom Face +Line(106) = {103,104}; // Bottom Face +Line(107) = {104,105}; // Bottom Face +// Line(108) = {105,102}; // Bottom Face +// +// // Base Cube +// Line Loop(101) = {101:104}; +// Line Loop(102) = {105:108}; +// +// Plane Surface(101) = {101}; +// Plane Surface(102) = {102}; +// Physical Surface(1) = {101}; +// Physical Surface(2) = {102}; + +Line Loop(108) = {105, 106, 107, -102}; +Plane Surface(209) = {108}; +Line Loop(110) = {101, 102, 103, 104}; +Plane Surface(210) = {110}; + +Physical Surface(1) = {209}; +Physical Surface(2) = {210}; + +Transfinite Surface "*"; diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/two_materials_non_local.dat b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/two_materials_non_local.dat new file mode 100644 index 000000000..fc50cb6a5 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_non_local/two_materials_non_local.dat @@ -0,0 +1,21 @@ +seed = 1 + +material elastic [ + name = aggregate + rho = 2.7e-9 # density + E = 60e9 # young's modulus + nu = 0.3 # poisson's ratio +] + +material damage_iterative_non_local base_wf [ + name = mortar + rho = 2.2e-9 # density + E = 12e9 # young's modulus + nu = 0.3 # poisson's ratio + Sc = 9.6e6 weibull [2.4e6, 5.] + prescribed_dam = 0.1 + max_damage = 0.95 + non_local weight_function [ + radius = 1.0 + ] +] \ No newline at end of file diff --git a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_reassign_material.cc b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_reassign_material.cc index 3af8a370c..02480414b 100644 --- a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_reassign_material.cc +++ b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_reassign_material.cc @@ -1,217 +1,217 @@ /** * @file test_solid_mechanics_model_reassign_material.cc * * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Mon Feb 10 2014 * @date last modification: Thu Jun 05 2014 * * @brief test the function reassign material * * @section LICENSE * * Copyright (©) 2014 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 "static_communicator.hh" #include "solid_mechanics_model.hh" #include "material.hh" #include "aka_grid_dynamic.hh" using namespace akantu; class StraightInterfaceMaterialSelector : public MaterialSelector { public: StraightInterfaceMaterialSelector(SolidMechanicsModel & model, const std::string & mat_1_material, const std::string & mat_2_material, bool & horizontal, Real & pos_interface) : model(model), mat_1_material(mat_1_material), mat_2_material(mat_2_material), horizontal(horizontal), pos_interface(pos_interface) { Mesh & mesh = model.getMesh(); UInt spatial_dimension = mesh.getSpatialDimension(); /// store barycenters of all elements mesh.initElementTypeMapArray(barycenters, spatial_dimension, spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Element e; e.ghost_type = ghost_type; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); e.type = *it; Array<Real> & barycenter = barycenters(*it, ghost_type); barycenter.resize(nb_element); Array<Real>::iterator< Vector<Real> > bary_it = barycenter.begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem) { e.element = elem; mesh.getBarycenter(e, *bary_it); ++bary_it; } } } } UInt operator()(const Element & elem) { UInt spatial_dimension = model.getSpatialDimension(); const Vector<Real> & bary = barycenters(elem.type, elem.ghost_type).begin(spatial_dimension)[elem.element]; /// check for a given element on which side of the material interface plane the bary center lies and assign corresponding material if (bary(!horizontal) < pos_interface) { return model.getMaterialIndex(mat_1_material);; } return model.getMaterialIndex(mat_2_material);; } bool isConditonVerified() { /// check if material has been (re)-assigned correctly Mesh & mesh = model.getMesh(); UInt spatial_dimension = mesh.getSpatialDimension(); GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); for(; it != last_type; ++it) { - Array<UInt> & el_idx_by_mat = model.getElementIndexByMaterial(*it, ghost_type); + Array<UInt> & mat_indexes = model.getMaterialByElement(*it, ghost_type); UInt nb_element = mesh.getNbElement(*it, ghost_type); Array<Real>::iterator<Vector<Real> > bary = barycenters(*it, ghost_type).begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem, ++bary) { /// compare element_index_by material to material index that should be assigned due to the geometry of the interface UInt mat_index; if ((*bary)(!horizontal) < pos_interface) mat_index = model.getMaterialIndex(mat_1_material); else mat_index = model.getMaterialIndex(mat_2_material); - if (el_idx_by_mat(elem,0) != mat_index) + if (mat_indexes(elem) != mat_index) /// wrong material index, make test fail return false; } } return true; } void moveInterface(Real & pos_new, bool & horizontal_new) { /// update position and orientation of material interface plane pos_interface = pos_new; horizontal = horizontal_new; model.reassignMaterial(); } protected: SolidMechanicsModel & model; ElementTypeMapArray<Real> barycenters; std::string mat_1_material; std::string mat_2_material; bool horizontal; Real pos_interface; }; /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { bool test_passed; debug::setDebugLevel(dblWarning); initialize("two_materials.dat", argc, argv); /// specify position and orientation of material interface plane bool horizontal = true; Real pos_interface = 0.; UInt spatial_dimension = 3; akantu::StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); akantu::Int psize = comm.getNbProc(); akantu::Int prank = comm.whoAmI(); Mesh mesh(spatial_dimension); akantu::MeshPartition * partition = NULL; if(prank == 0) { /// creation mesh mesh.read("cube_two_materials.msh"); partition = new akantu::MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } /// model creation SolidMechanicsModel model(mesh); model.initParallel(partition); delete partition; /// assign the two different materials using the StraightInterfaceMaterialSelector StraightInterfaceMaterialSelector * mat_selector; mat_selector = new StraightInterfaceMaterialSelector(model, "mat_1", "mat_2", horizontal, pos_interface); model.setMaterialSelector(*mat_selector); model.initFull(SolidMechanicsModelOptions(_static)); MeshUtils::buildFacets(mesh); // model.setBaseName("test_reassign_material"); // model.addDumpField("element_index_by_material"); // model.addDumpField("partitions"); // model.dump(); /// check if different materials have been assigned correctly test_passed = mat_selector->isConditonVerified(); if (!test_passed) { AKANTU_DEBUG_ERROR("materials not correctly assigned"); return EXIT_FAILURE; } /// change orientation of material interface plane horizontal = false; mat_selector->moveInterface(pos_interface, horizontal); // model.dump(); /// test if material has been reassigned correctly test_passed = mat_selector->isConditonVerified(); if (!test_passed) { AKANTU_DEBUG_ERROR("materials not correctly reassigned"); return EXIT_FAILURE; } finalize(); if(prank == 0) std::cout << "OK: test passed!" << std::endl; return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ diff --git a/test/test_synchronizer/test_grid_synchronizer.cc b/test/test_synchronizer/test_grid_synchronizer.cc index 8807881d1..f5e47b010 100644 --- a/test/test_synchronizer/test_grid_synchronizer.cc +++ b/test/test_synchronizer/test_grid_synchronizer.cc @@ -1,296 +1,297 @@ /** * @file test_grid_synchronizer.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Nov 25 2011 * @date last modification: Tue Jun 24 2014 * * @brief test the GridSynchronizer object * * @section LICENSE * * Copyright (©) 2014 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_grid_dynamic.hh" #include "mesh.hh" #include "grid_synchronizer.hh" #include "mesh_partition.hh" #include "synchronizer_registry.hh" #include "test_data_accessor.hh" #ifdef AKANTU_USE_IOHELPER # include "io_helper.hh" #endif //AKANTU_USE_IOHELPER using namespace akantu; const UInt spatial_dimension = 3; typedef std::map<std::pair<Element, Element>, Real> pair_list; #include "test_grid_tools.hh" static void updatePairList(const ElementTypeMapArray<Real> & barycenter, const SpatialGrid<Element> & grid, Real radius, pair_list & neighbors, neighbors_map_t<spatial_dimension>::type & neighbors_map) { AKANTU_DEBUG_IN(); GhostType ghost_type = _not_ghost; Element e; e.ghost_type = ghost_type; // generate the pair of neighbor depending of the cell_list ElementTypeMapArray<Real>::type_iterator it = barycenter.firstType(_all_dimensions, ghost_type); ElementTypeMapArray<Real>::type_iterator last_type = barycenter.lastType(0, ghost_type); for(; it != last_type; ++it) { // loop over quad points e.type = *it; e.element = 0; const Array<Real> & barycenter_vect = barycenter(*it, ghost_type); UInt sp = barycenter_vect.getNbComponent(); Array<Real>::const_iterator< Vector<Real> > bary = barycenter_vect.begin(sp); Array<Real>::const_iterator< Vector<Real> > bary_end = barycenter_vect.end(sp); for(;bary != bary_end; ++bary, e.element++) { #if !defined(AKANTU_NDEBUG) Point<spatial_dimension> pt1(*bary); #endif SpatialGrid<Element>::CellID cell_id = grid.getCellID(*bary); SpatialGrid<Element>::neighbor_cells_iterator first_neigh_cell = grid.beginNeighborCells(cell_id); SpatialGrid<Element>::neighbor_cells_iterator last_neigh_cell = grid.endNeighborCells(cell_id); // loop over neighbors cells of the one containing the current element for (; first_neigh_cell != last_neigh_cell; ++first_neigh_cell) { SpatialGrid<Element>::Cell::const_iterator first_neigh_el = grid.beginCell(*first_neigh_cell); SpatialGrid<Element>::Cell::const_iterator last_neigh_el = grid.endCell(*first_neigh_cell); // loop over the quadrature point in the current cell of the cell list for (;first_neigh_el != last_neigh_el; ++first_neigh_el){ const Element & elem = *first_neigh_el; Array<Real>::const_iterator< Vector<Real> > neigh_it = barycenter(elem.type, elem.ghost_type).begin(sp); const Vector<Real> & neigh_bary = neigh_it[elem.element]; Real distance = bary->distance(neigh_bary); if(distance <= radius) { #if !defined(AKANTU_NDEBUG) Point<spatial_dimension> pt2(neigh_bary); neighbors_map[pt1].push_back(pt2); #endif std::pair<Element, Element> pair = std::make_pair(e, elem); pair_list::iterator p = neighbors.find(pair); if(p != neighbors.end()) { AKANTU_DEBUG_ERROR("Pair already registered [" << e << " " << elem << "] -> " << p->second << " " << distance); } else { neighbors[pair] = distance; } } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Main */ /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { akantu::initialize(argc, argv); Real radius = 0.2; Mesh mesh(spatial_dimension); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); DistributedSynchronizer * dist = NULL; if(prank == 0) { mesh.read("bar3d.msh"); MeshPartition * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); dist = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { dist = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } mesh.computeBoundingBox(); const Vector<Real> & lower_bounds = mesh.getLowerBounds(); const Vector<Real> & upper_bounds = mesh.getUpperBounds(); Vector<Real> center = 0.5 * (upper_bounds + lower_bounds); Vector<Real> spacing(spatial_dimension); for (UInt i = 0; i < spatial_dimension; ++i) { spacing[i] = radius * 1.2; } SpatialGrid<Element> grid(spatial_dimension, spacing, center); GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type); ElementTypeMapArray<Real> barycenters("", ""); mesh.initElementTypeMapArray(barycenters, spatial_dimension, spatial_dimension); Element e; e.ghost_type = ghost_type; for(; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); e.type = *it; Array<Real> & barycenter = barycenters(*it, ghost_type); barycenter.resize(nb_element); Array<Real>::iterator< Vector<Real> > bary_it = barycenter.begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem) { mesh.getBarycenter(elem, *it, bary_it->storage(), ghost_type); e.element = elem; grid.insert(e, *bary_it); ++bary_it; } } std::stringstream sstr; sstr << "mesh_" << prank << ".msh"; mesh.write(sstr.str()); Mesh grid_mesh(spatial_dimension, "grid_mesh", 0); std::stringstream sstr_grid; sstr_grid << "grid_mesh_" << prank << ".msh"; grid.saveAsMesh(grid_mesh); grid_mesh.write(sstr_grid.str()); std::cout << "Pouet 1" << std::endl; - GridSynchronizer * grid_communicator = GridSynchronizer::createGridSynchronizer(mesh, grid); + AKANTU_DEBUG_INFO("Creating TestAccessor"); + TestAccessor test_accessor(mesh, barycenters); + SynchronizerRegistry synch_registry(test_accessor); + + GridSynchronizer * grid_communicator = GridSynchronizer::createGridSynchronizer(mesh, grid, synch_registry); std::cout << "Pouet 2" << std::endl; ghost_type = _ghost; it = mesh.firstType(spatial_dimension, ghost_type); last_type = mesh.lastType(spatial_dimension, ghost_type); e.ghost_type = ghost_type; for(; it != last_type; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); e.type = *it; Array<Real> & barycenter = barycenters(*it, ghost_type); barycenter.resize(nb_element); Array<Real>::iterator< Vector<Real> > bary_it = barycenter.begin(spatial_dimension); for (UInt elem = 0; elem < nb_element; ++elem) { mesh.getBarycenter(elem, *it, bary_it->storage(), ghost_type); e.element = elem; grid.insert(e, *bary_it); ++bary_it; } } Mesh grid_mesh_ghost(spatial_dimension, "grid_mesh_ghost", 0); std::stringstream sstr_gridg; sstr_gridg << "grid_mesh_ghost_" << prank << ".msh"; grid.saveAsMesh(grid_mesh_ghost); grid_mesh_ghost.write(sstr_gridg.str()); std::cout << "Pouet 3" << std::endl; neighbors_map_t<spatial_dimension>::type neighbors_map; pair_list neighbors; updatePairList(barycenters, grid, radius, neighbors, neighbors_map); pair_list::iterator nit = neighbors.begin(); pair_list::iterator nend = neighbors.end(); std::stringstream sstrp; sstrp << "pairs_" << prank; std::ofstream fout(sstrp.str().c_str()); for(;nit != nend; ++nit) { fout << "[" << nit->first.first << "," << nit->first.second << "] -> " << nit->second << std::endl; } std::string file = "neighbors_ref"; std::stringstream sstrf; sstrf << file << "_" << prank; file = sstrf.str(); std::ofstream nout; nout.open(file.c_str()); neighbors_map_t<spatial_dimension>::type::iterator it_n = neighbors_map.begin(); neighbors_map_t<spatial_dimension>::type::iterator end_n = neighbors_map.end(); for(;it_n != end_n; ++it_n) { std::sort(it_n->second.begin(), it_n->second.end()); std::vector< Point<spatial_dimension> >::iterator it_v = it_n->second.begin(); std::vector< Point<spatial_dimension> >::iterator end_v = it_n->second.end(); nout << "####" << std::endl; nout << it_n->second.size() << std::endl; nout << it_n->first << std::endl; nout << "#" << std::endl; for(;it_v != end_v; ++it_v) { nout << *it_v << std::endl; } } fout.close(); - AKANTU_DEBUG_INFO("Creating TestAccessor"); - TestAccessor test_accessor(mesh, barycenters); - SynchronizerRegistry synch_registry(test_accessor); synch_registry.registerSynchronizer(*dist, _gst_smm_mass); synch_registry.registerSynchronizer(*grid_communicator, _gst_test); AKANTU_DEBUG_INFO("Synchronizing tag on Dist"); synch_registry.synchronize(_gst_smm_mass); AKANTU_DEBUG_INFO("Synchronizing tag on Grid"); synch_registry.synchronize(_gst_test); delete grid_communicator; delete dist; akantu::finalize(); return EXIT_SUCCESS; }