diff --git a/CMakeLists.txt b/CMakeLists.txt index 7de70155a..1f6989bd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,186 +1,186 @@ #=============================================================================== # @file CMakeLists.txt # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Jun 14 2010 # @date last modification: Mon Sep 15 2014 # # @brief main configuration file # # @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 #------------------------------------------------------------------------------- # _ _ # | | | | # __ _| | ____ _ _ __ | |_ _ _ # / _` | |/ / _` | '_ \| __| | | | # | (_| | < (_| | | | | |_| |_| | # \__,_|_|\_\__,_|_| |_|\__|\__,_| # #=============================================================================== #=============================================================================== # CMake Project #=============================================================================== cmake_minimum_required(VERSION 2.8) # add this options before PROJECT keyword set(CMAKE_DISABLE_SOURCE_CHANGES ON) set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) project(Akantu) enable_language(CXX) #=============================================================================== # Misc. config for cmake #=============================================================================== set(AKANTU_CMAKE_DIR "${PROJECT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules") set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries.") mark_as_advanced(BUILD_SHARED_LIBS) if(NOT AKANTU_TARGETS_EXPORT) set(AKANTU_TARGETS_EXPORT AkantuLibraryDepends) endif() include(CMakeVersionGenerator) include(CMakePackagesSystem) include(CMakeFlagsHandling) include(AkantuMacros) #cmake_activate_debug_message() #=============================================================================== # Version Number #=============================================================================== # AKANTU version number. An even minor number corresponds to releases. set(AKANTU_MAJOR_VERSION 2) set(AKANTU_MINOR_VERSION 2) set(AKANTU_PATCH_VERSION 0) define_project_version() #=============================================================================== # Options #=============================================================================== # Debug set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DAKANTU_NDEBUG" CACHE STRING "Flags used by the compiler during release builds" FORCE) add_flags(cxx "-Wall") #Profiling set(CMAKE_CXX_FLAGS_PROFILING "-g -pg -DNDEBUG -DAKANTU_NDEBUG -O2" CACHE STRING "Flags used by the compiler during profiling builds") set(CMAKE_C_FLAGS_PROFILING "-g -pg -DNDEBUG -DAKANTU_NDEBUG -O2" CACHE STRING "Flags used by the compiler during profiling builds") set(CMAKE_Fortran_FLAGS_PROFILING "-g -pg -DNDEBUG -DAKANTU_NDEBUG -O2" CACHE STRING "Flags used by the compiler during profiling builds") set(CMAKE_EXE_LINKER_FLAGS_PROFILING "-pg" CACHE STRING "Flags used by the linker during profiling builds") set(CMAKE_SHARED_LINKER_FLAGS_PROFILING "-pg" CACHE STRING "Flags used by the linker during profiling builds") mark_as_advanced( CMAKE_CXX_FLAGS_PROFILING CMAKE_C_FLAGS_PROFILING CMAKE_Fortran_FLAGS_PROFILING CMAKE_EXE_LINKER_FLAGS_PROFILING CMAKE_SHARED_LINKER_FLAGS_PROFILING ) include(CMakeDetermineCCompiler) cmake_deactivate_debug_message(PackagesSystem) #=============================================================================== # Dependencies #=============================================================================== option(AKANTU_PYTHON_INTERFACE "Generates the Akantu Python module" OFF) if(AKANTU_PYTHON_INTERFACE) list(APPEND AKANTU_BOOST_COMPONENTS python) endif() package_list_packages(${PROJECT_SOURCE_DIR}/packages EXTRA_PACKAGES_FOLDER ${PROJECT_SOURCE_DIR}/extra_packages) ## meta option \todo better way to do it when multiple package give enable the ## same feature if(AKANTU_SCOTCH) set(AKANTU_PARTITIONER ON) else() set(AKANTU_PARTITIONER OFF) endif() if(AKANTU_MUMPS) set(AKANTU_SOLVER ON) else() set(AKANTU_SOLVER OFF) endif() #=============================================================================== # Akantu library #=============================================================================== add_subdirectory(src) #=============================================================================== # Documentation #=============================================================================== if(AKANTU_DOCUMENTATION_DOXYGEN OR AKANTU_DOCUMENTATION_MANUAL) add_subdirectory(doc) else() set(AKANTU_DOC_EXCLUDE_FILES "${PROJECT_SOURCE_DIR}/doc/manual" CACHE INTERNAL "") endif() #=============================================================================== # Examples and tests #=============================================================================== option(AKANTU_EXAMPLES "Activate examples" OFF) option(AKANTU_TESTS "Activate tests" OFF) include(AkantuTestAndExamples) if(AKANTU_EXAMPLES OR AKANTU_TESTS) find_package(GMSH REQUIRED) endif() if(AKANTU_EXAMPLES) add_subdirectory(examples) endif() add_test_tree(test) #=============================================================================== # Install and Packaging #=============================================================================== include(AkantuInstall) if(NOT AKANTU_DISABLE_CPACK) include(AkantuCPack) endif() #=============================================================================== # Install and Packaging #=============================================================================== mark_as_advanced(AKANTU_PYTHON_INTERFACE) if(AKANTU_PYTHON_INTERFACE) -# add_subdirectory(python) - add_subdirectory(akantu4py) + add_subdirectory(python) +# add_subdirectory(akantu4py) endif() diff --git a/cmake/AkantuTestAndExamples.cmake b/cmake/AkantuTestAndExamples.cmake index 47430143a..8a6e50b0d 100644 --- a/cmake/AkantuTestAndExamples.cmake +++ b/cmake/AkantuTestAndExamples.cmake @@ -1,318 +1,321 @@ #=============================================================================== # @file AkantuTestAndExamples.cmake # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Oct 25 2010 # @date last modification: Tue Jun 24 2014 # # @brief macros for tests and examples # # @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 # #=============================================================================== set(AKANTU_DIFF_SCRIPT ${AKANTU_CMAKE_DIR}/akantu_diff.sh) #=============================================================================== function(manage_test_and_example et_name desc build_all label) string(TOUPPER ${et_name} upper_name) cmake_parse_arguments(manage_test_and_example "" "PACKAGE" "" ${ARGN} ) set(_activated ON) if(manage_test_and_example_PACKAGE) list(FIND ${_project}_PACKAGE_SYSTEM_PACKAGES_ON ${manage_test_and_example_PACKAGE} _ret) if(_ret EQUAL -1) set(_activated OFF) file(RELATIVE_PATH _dir ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${et_name}) list(APPEND AKANTU_TESTS_EXCLUDE_FILES /${_dir}) set(AKANTU_TESTS_EXCLUDE_FILES ${AKANTU_TESTS_EXCLUDE_FILES} CACHE INTERNAL "") endif() endif() if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${et_name} AND _activated) # message("Example or test ${et_name} not present") return() endif() option(AKANTU_BUILD${label}${upper_name} "${desc}") mark_as_advanced(AKANTU_BUILD_${upper_name}) if(${build_all} OR NOT _activated) set(AKANTU_BUILD${label}${upper_name}_OLD ${AKANTU_BUILD${label}${upper_name}} CACHE INTERNAL "${desc}" FORCE) set(AKANTU_BUILD${label}${upper_name} ${_activated} CACHE INTERNAL "${desc}" FORCE) else() if(DEFINED AKANTU_BUILD${label}${upper_name}_OLD) set(AKANTU_BUILD${label}${upper_name} ${AKANTU_BUILD${label}${upper_name}_OLD} CACHE BOOL "${desc}" FORCE) unset(AKANTU_BUILD${label}${upper_name}_OLD CACHE) endif(DEFINED AKANTU_BUILD${label}${upper_name}_OLD) endif() if(AKANTU_BUILD${label}${upper_name}) add_subdirectory(${et_name}) endif(AKANTU_BUILD${label}${upper_name}) endfunction() #=============================================================================== # Tests #=============================================================================== if(AKANTU_TESTS) option(AKANTU_BUILD_ALL_TESTS "Build all tests" ON) mark_as_advanced(AKANTU_BUILD_ALL_TESTS) endif(AKANTU_TESTS) #=============================================================================== # Examples #=============================================================================== if(AKANTU_EXAMPLES) option(AKANTU_BUILD_ALL_EXAMPLES "Build all examples") # mark_as_advanced(AKANTU_BUILD_ALL_EXAMPLES) endif(AKANTU_EXAMPLES) #=============================================================================== macro(register_example example_name) add_executable(${example_name} ${ARGN}) target_link_libraries(${example_name} akantu ${AKANTU_EXTERNAL_LIBRARIES}) endmacro() #=============================================================================== macro(add_example example_name desc) manage_test_and_example(${example_name} ${desc} AKANTU_BUILD_ALL_EXAMPLES _EXAMPLE_ ${ARGN}) endmacro() # ============================================================================== # this should be a macro due to the enable_testing macro(add_test_tree dir) if(AKANTU_TESTS) enable_testing() include(CTest) mark_as_advanced(BUILD_TESTING) set(AKANTU_TESTS_EXCLUDE_FILES "" CACHE INTERNAL "") set(_akantu_current_parent_test ${dir} CACHE INTERNAL "Current test folder" FORCE) set(_akantu_${dir}_tests_count 0 CACHE INTERNAL "" FORCE) string(TOUPPER ${dir} _u_dir) set(AKANTU_BUILD_${_u_dir} ON CACHE INTERNAL "${desc}" FORCE) package_get_all_test_folders(_test_dirs) foreach(_dir ${_test_dirs}) add_subdirectory(${_dir}) endforeach() else() set(AKANTU_TESTS_EXCLUDE_FILES "${CMAKE_CURRENT_BINARY_DIR}/${dir}" CACHE INTERNAL "") endif() endmacro() # ============================================================================== function(add_akantu_test dir desc) set(_my_parent_dir ${_akantu_current_parent_test}) # initialize variables set(_akantu_current_parent_test ${dir} CACHE INTERNAL "Current test folder" FORCE) set(_akantu_${dir}_tests_count 0 CACHE INTERNAL "" FORCE) # set the option for this directory string(TOUPPER ${dir} _u_dir) option(AKANTU_BUILD_${_u_dir} "${desc}") mark_as_advanced(AKANTU_BUILD_${_u_dir}) # add the sub-directory add_subdirectory(${dir}) # if no test can be activated make the option disappear set(_force_deactivate_count FALSE) if(${_akantu_${dir}_tests_count} EQUAL 0) set(_force_deactivate_count TRUE) endif() # if parent off make the option disappear set(_force_deactivate_parent FALSE) string(TOUPPER ${_my_parent_dir} _u_parent_dir) if(NOT AKANTU_BUILD_${_u_parent_dir}) set(_force_deactivate_parent TRUE) endif() if(_force_deactivate_parent OR _force_deactivate_count OR AKANTU_BUILD_ALL_TESTS) if(NOT DEFINED _AKANTU_BUILD_${_u_dir}_SAVE) set(_AKANTU_BUILD_${_u_dir}_SAVE ${AKANTU_BUILD_${_u_dir}} CACHE INTERNAL "" FORCE) endif() unset(AKANTU_BUILD_${_u_dir} CACHE) if(AKANTU_BUILD_ALL_TESTS AND NOT _force_deactivate_count) set(AKANTU_BUILD_${_u_dir} ON CACHE INTERNAL "${desc}" FORCE) else() set(AKANTU_BUILD_${_u_dir} OFF CACHE INTERNAL "${desc}" FORCE) endif() else() if(DEFINED _AKANTU_BUILD_${_u_dir}_SAVE) unset(AKANTU_BUILD_${_u_dir} CACHE) set(AKANTU_BUILD_${_u_dir} ${_AKANTU_BUILD_${_u_dir}_SAVE} CACHE BOOL "${desc}") unset(_AKANTU_BUILD_${_u_dir}_SAVE CACHE) endif() endif() # adding up to the parent count math(EXPR _tmp_parent_count "${_akantu_${dir}_tests_count} + ${_akantu_${_my_parent_dir}_tests_count}") set(_akantu_${_my_parent_dir}_tests_count ${_tmp_parent_count} CACHE INTERNAL "" FORCE) # restoring the parent current dir set(_akantu_current_parent_test ${_my_parent_dir} CACHE INTERNAL "Current test folder" FORCE) endfunction() # ============================================================================== function(register_test test_name) set(multi_variables SOURCES FILES_TO_COPY DEPENDENCIES DIRECTORIES_TO_CREATE COMPILE_OPTIONS EXTRA_FILES ) cmake_parse_arguments(_register_test "" "PACKAGE" "${multi_variables}" ${ARGN} ) if(NOT _register_test_PACKAGE) message(FATAL_ERROR "No reference package was defined for the test ${test_name} in folder ${CMAKE_CURRENT_SOURCE_DIR}") endif() package_is_activated(${_register_test_PACKAGE} _act) if(_act) math(EXPR _tmp_parent_count "${_akantu_${_akantu_current_parent_test}_tests_count} + 1") set(_akantu_${_akantu_current_parent_test}_tests_count ${_tmp_parent_count} CACHE INTERNAL "" FORCE) string(TOUPPER ${_akantu_current_parent_test} _u_parent) if(AKANTU_BUILD_${_u_parent}) + # get the include directories for sources in activated directories package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) + # get the external packages compilation and linking informations package_get_all_external_informations( AKANTU_EXTERNAL_INCLUDE_DIR AKANTU_EXTERNAL_LIBRARIES ) + # set the proper includes to build most of the tests include_directories( ${AKANTU_INCLUDE_DIRS} ${AKANTU_EXTERNAL_LIB_INCLUDE_DIR} ) # Register the executable to compile add_executable(${test_name} ${_register_test_SOURCES} ${_register_test_UNPARSED_ARGUMENTS}) set_property(TARGET ${test_name} APPEND PROPERTY INCLUDE_DIRECTORIES ${AKANTU_LIBRARY_INCLUDE_DIRS} ${AKANTU_EXTERNAL_INCLUDE_DIR}) target_link_libraries(${test_name} akantu ${AKANTU_EXTERNAL_LIBRARIES}) # add the extra compilation options if(_register_test_COMPILE_OPTIONS) set_target_properties(${test_name} PROPERTIES COMPILE_DEFINITIONS "${_register_test_COMPILE_OPTIONS}") endif() set(_test_all_files) # add the different dependencies (meshes, local libraries, ...) foreach(_dep ${_register_test_DEPENDENCIES}) add_dependencies(${test_name} ${_dep}) get_target_property(_dep_in_ressources ${_dep} RESSOURCES) if(_dep_in_ressources) list(APPEND _test_all_files ${_dep_in_ressources}) endif() endforeach() # copy the needed files to the build folder if(_register_test_FILES_TO_COPY) foreach(_file ${_register_test_FILES_TO_COPY}) file(COPY ${_file} DESTINATION .) list(APPEND _test_all_files ${CMAKE_CURRENT_SOURCE_DIR}/${_file}) endforeach() endif() # create the needed folders in the build folder if(_register_test_DIRECTORIES_TO_CREATE) foreach(_dir ${_register_test_DIRECTORIES_TO_CREATE}) if(IS_ABSOLUTE ${dir}) file(MAKE_DIRECTORY ${_dir}) else() file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_dir}) endif() endforeach() endif() # add the source files in the list of all files foreach(_file ${_register_test_SOURCES} ${_register_test_UNPARSED_ARGUMENTS} ${_register_test_EXTRA_FILES}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_file}) list(APPEND _test_all_files ${CMAKE_CURRENT_SOURCE_DIR}/${_file}) else() message("The file \"${_file}\" registred by the test \"${test_name}\" does not exists") endif() endforeach() # register the test for ctest if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.sh) file(COPY ${test_name}.sh DESTINATION .) list(APPEND _test_all_files ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.sh) add_test(${test_name}_run ${CMAKE_CURRENT_BINARY_DIR}/${test_name}.sh) elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified) list(APPEND _test_all_files ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified) add_test(${test_name}_run ${AKANTU_DIFF_SCRIPT} ${test_name} ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified) else() add_test(${test_name}_run ${CMAKE_CURRENT_BINARY_DIR}/${test_name}) endif() # add the executable as a dependency of the run set_tests_properties(${test_name}_run PROPERTIES DEPENDS ${test_name}) # clean the list of all files for this test and add them in the total list set(_tmp ${AKANTU_TESTS_FILES}) foreach(_file ${_source_file}) get_filename_component(_full ${_file} ABSOLUTE) file(RELATIVE_PATH __file ${PROJECT_SOURCE_DIR} ${_full}) list(APPEND _tmp ${__file}) list(APPEND _pkg_tmp ${__file}) endforeach() set(AKANTU_TESTS_FILES ${_tmp} CACHE INTERNAL "") endif() endif() endfunction() \ No newline at end of file diff --git a/cmake/Modules/CMakePackagesSystem.cmake b/cmake/Modules/CMakePackagesSystem.cmake index 2b92f3d0e..333cc7f1b 100644 --- a/cmake/Modules/CMakePackagesSystem.cmake +++ b/cmake/Modules/CMakePackagesSystem.cmake @@ -1,1635 +1,1637 @@ #=============================================================================== # @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 DESCRIPTION # # This package defines multiple function to handle packages. This packages can # be of two kinds regular ones and extra_packages (ex: in akantu the LGPL part # is regular packages and extra packages are on Propetary license) # # Package are loaded with the help of the command: # package_list_packages(<regular_package_folder> # [ EXTRA_PACKAGE_FOLDER <extra_package_folder> ] # [ SOURCE_FOLDER <source_folder>] # [ TEST_FOLDER <test_folder> ] # [ MANUAL_FOLDER <manual_folder> ] # ) # # This command will look for packages name like # <regular_package_folder>/<package>.cmake # OR <extra_package_folder>/<package>/package.cmake # # A package is a cmake script that should contain at list the declaration of a # package # # package_declare(<package real name> # [EXTERNAL] [META] [ADVANCED] [NOT_OPTIONAL] # [DESCRIPTION <description>] [DEFAULT <default_value>] # [DEPENDS <pkg> ...] # [BOOST_COMPONENTS <pkg> ...] # [EXTRA_PACKAGE_OPTIONS <opt> ...] # [COMPILE_FLAGS <flags>] # [SYSTEM <bool> [ <script_to_compile> ]]) # # It can also declare multiple informations: # source files: # package_declare_sources(<package real name> # <src1> <src2> ... <srcn>) # # a LaTeX documentation: # package_declare_documentation(<package real name> # <line1> <line2> ...<linen>) # # LaTeX documentation files # package_declare_documentation_files(<package real name> # <file1> <file2> ... <filen>) # # Different function can also be retrieved from the package system by using the # different accessors # package_get_name(<pkg> <retval>) # package_get_real_name(<pkg> <retval>) # # package_get_option_name(<pkg> <retval>) # # package_use_system(<pkg> <retval>) # # package_get_nature(<pkg> <retval>) # # package_get_description(<pkg> <retval>) # # package_get_filename(<pkg> <retval>) # # package_get_sources_folder(<pkg> <retval>) # package_get_tests_folder(<pkg> <retval>) # package_get_manual_folder(<pkg> <retval>) # # package_get_find_package_extra_options(<pkg> <retval>) # # package_get_compile_flags(<pkg> <retval>) # # package_get_include_dir(<pkg> <retval>) # package_set_include_dir(<pkg> <inc1> <inc2> ... <incn>) # # package_get_libraries(<pkg> <retval>) # package_set_libraries(<pkg> <lib1> <lib2> ... <libn>) # # package_add_extra_dependency(pkg <dep1> <dep2> ... <depn>) # package_rm_extra_dependency(<pkg> <dep>) # package_get_extra_dependencies(<pkg> <retval>) # # package_is_activated(<pkg> <retval>) # package_is_deactivated(<pkg> <retval>) # # package_get_dependencies(<pkg> <retval>) # package_add_dependencies(<pkg> <dep1> <dep2> ... <depn>) # # package_get_all_source_files(<srcs> <public_headers> <private_headers>) # package_get_all_include_directories(<inc_dirs>) # package_get_all_external_informations(<include_dir> <libraries>) # package_get_all_definitions(<definitions>) # package_get_all_extra_dependencies(<dependencies>) # package_get_all_test_folders(<test_dirs>) # package_get_all_documentation_files(<doc_files>) # package_get_all_activated_packages(<activated_list>) # package_get_all_packages(<packages_list>) # # # @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) # ============================================================================== # "Public" 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 ret) package_get_name(${pkg} _pkg_name) _package_get_real_name(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Option name # ------------------------------------------------------------------------------ function(package_get_option_name pkg ret) package_get_name(${pkg} _pkg_name) _package_get_option_name(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Set if system package or compile external lib # ------------------------------------------------------------------------------ function(package_use_system pkg ret) package_get_name(${pkg} _pkg_name) _package_use_system(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() function(package_add_third_party_script_variable pkg var) package_get_name(${pkg} _pkg_name) _package_add_third_party_script_variable(${_pkg_name} ${var} ${ARGN}) set(${var} ${ARGN} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Nature # ------------------------------------------------------------------------------ function(package_get_nature pkg ret) package_get_name(${pkg} _pkg_name) _package_get_nature(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Description # ------------------------------------------------------------------------------ function(package_get_description pkg ret) package_get_name(${pkg} _pkg_name) _package_get_description(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Package file name # ------------------------------------------------------------------------------ function(package_get_filename pkg ret) package_get_name(${pkg} _pkg_name) _package_get_filename(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Source folder # ------------------------------------------------------------------------------ function(package_get_sources_folder pkg ret) package_get_name(${pkg} _pkg_name) _package_get_sources_folder(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Test folder # ------------------------------------------------------------------------------ function(package_get_tests_folder pkg ret) package_get_name(${pkg} _pkg_name) _package_get_tests_folder(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Manual folder # ------------------------------------------------------------------------------ function(package_get_manual_folder pkg ret) package_get_name(${pkg} _pkg_name) _package_get_manual_folder(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Extra option for the find_package # ------------------------------------------------------------------------------ function(package_get_find_package_extra_options pkg ret) package_get_name(${pkg} _pkg_name) _package_get_find_package_extra_options(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() function(package_set_find_package_extra_options pkg) package_get_name(${pkg} _pkg_name) _package_set_find_package_extra_options(${_pkg_name} ${ARGN}) endfunction() # ------------------------------------------------------------------------------ # Compilation flags # ------------------------------------------------------------------------------ function(package_get_compile_flags pkg ret) package_get_name(${pkg} _pkg_name) _package_get_compile_flags(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Include dir # ------------------------------------------------------------------------------ function(package_get_include_dir pkg ret) package_get_name(${pkg} _pkg_name) _package_get_include_dir(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() function(package_set_include_dir pkg) package_get_name(${pkg} _pkg_name) _package_set_include_dir(${_pkg_name} ${ARGN}) endfunction() # ------------------------------------------------------------------------------ # Libraries # ------------------------------------------------------------------------------ function(package_get_libraries pkg ret) package_get_name(${pkg} _pkg_name) _package_get_libraries(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() function(package_set_libraries pkg) package_get_name(${pkg} _pkg_name) _package_set_libraries(${_pkg_name} ${ARGN}) endfunction() # ------------------------------------------------------------------------------ # Extra dependencies like custom commands of ExternalProject # ------------------------------------------------------------------------------ function(package_add_extra_dependency pkg) package_get_name(${pkg} _pkg_name) set(_tmp_dep ${${_pkg_name}_EXTRA_DEPENDS}) list(APPEND _tmp_dep ${ARGN}) list(REMOVE_DUPLICATES _tmp_dep) set(${_pkg_name}_EXTRA_DEPENDENCY "${_tmp_dep}" CACHE INTERNAL "External dependencies") endfunction() function(package_rm_extra_dependency pkg DEP) package_get_name(${pkg} _pkg_name) if(${_pkg_name}_EXTRA_DEPENDENCY) set(_tmp_dep ${${_pkg_name}_EXTRA_DEPENDENCY}) list(REMOVE_ITEM _tmp_dep ${DEP}) set(${_pkg_name}_EXTRA_DEPENDENCY "${_tmp_dep}" CACHE INTERNAL "External dependencies" FORCE) endif() endfunction() function(package_get_extra_dependencies pkg ret) package_get_name(${pkg} _pkg_name) _package_get_extra_dependencies(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Activate/deactivate # ------------------------------------------------------------------------------ function(package_is_activated pkg ret) package_get_name(${pkg} _pkg_name) _package_is_activated(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() function(package_is_deactivated pkg ret) package_get_name(${pkg} _pkg_name) _package_is_deactivated(${_pkg_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() # ------------------------------------------------------------------------------ # Direct dependencies # ------------------------------------------------------------------------------ function(package_get_dependencies pkg ret) package_get_name(${pkg} _pkg_name) _package_get_dependencies(${_pkg_name} _tmp_name) _package_get_real_name(${_tmp_name} _tmp) set(${ret} ${_tmp} PARENT_SCOPE) endfunction() function(package_add_dependencies pkg) package_get_name(${pkg} _pkg_name) foreach(_dep ${ARGN}) package_get_name(${_dep} _dep_pkg_name) list(APPEND _tmp_deps ${_dep_pkg_name}) endforeach() _package_add_dependencies(${_pkg_name} ${_tmp_deps}) 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_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() # ============================================================================== # Global accessors # ============================================================================== # ------------------------------------------------------------------------------ # 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) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_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) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_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) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_list}) _package_get_nature(${_pkg_name} _nature) if(${_nature} MATCHES "external") _package_get_include_dir(${_pkg_name} _inc) - _package_get_libraries (${_pkg_name} _lib) + _package_get_libraries (${_pkg_name} _libraries) list(APPEND tmp_INCLUDE_DIR ${_inc}) - list(APPEND tmp_LIBRARIES ${_lib}) + list(APPEND tmp_LIBRARIES ${_libraries}) 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) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_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_dependencies DEPS) string(TOUPPER ${PROJECT_NAME} _project) set(_tmp_DEPS) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_list}) _package_get_extra_dependencies(${_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) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_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() # ------------------------------------------------------------------------------ # Documentation informations # ------------------------------------------------------------------------------ function(package_get_all_documentation_files doc_files) string(TOUPPER ${PROJECT_NAME} _project) set(_tmp_DOC_FILES) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_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() # ------------------------------------------------------------------------------ # List packages # ------------------------------------------------------------------------------ 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() # ============================================================================== # 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) # Cleaning some states to start correctly package_get_all_packages(_already_loaded_pkg) foreach(_pkg_name ${_already_loaded_pkg}) _package_unset_extra_dependencies(${_pkg_name}) _package_unset_dependencies(${_pkg_name}) _package_unset_activated(${_pkg_name}) endforeach() 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) if(NOT _basename MATCHES "^\\.#.*") list(APPEND _package_files ${_basename}) endif() 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_is_activated(Boost _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> ...] # [BOOST_COMPONENTS <pkg> ...] # [EXTRA_PACKAGE_OPTIONS <opt> ...] # [COMPILE_FLAGS <flags>] # [SYSTEM <bool> [ <script_to_compile> ]]) # ------------------------------------------------------------------------------ function(package_declare pkg) package_get_name(${pkg} _pkg_name) _package_set_real_name(${_pkg_name} ${pkg}) cmake_parse_arguments(_opt_pkg "EXTERNAL;NOT_OPTIONAL;META;ADVANCED" "DEFAULT;DESCRIPTION" "DEPENDS;EXTRA_PACKAGE_OPTIONS;COMPILE_FLAGS;BOOST_COMPONENTS;SYSTEM" ${ARGN}) if(_opt_pkg_UNPARSED_ARGUMENTS) message("You gave to many arguments while registering the package ${pkg} \"${_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) list(LENGTH _opt_pkg_SYSTEM _length) list(GET _opt_pkg_SYSTEM 0 _bool) _package_set_system_option(${_pkg_name} ${_bool}) if(_length GREATER 1) list(GET _opt_pkg_SYSTEM 1 _script) _package_set_system_script(${_pkg_name} ${_script}) endif() 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_add_dependencies(${_pkg_name} ${_depends}) endif() # keep the extra option for the future find package if(_opt_pkg_EXTRA_PACKAGE_OPTIONS) _package_set_find_package_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() # set the boost dependencies if(_opt_pkg_BOOST_COMPONENTS) _package_set_boost_component_needed(${_pkg_name} "${_opt_pkg_BOOST_COMPONENTS}") 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() # ============================================================================== # "Private" Accessors # ============================================================================== # ------------------------------------------------------------------------------ # 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() function(_package_set_system_script pkg_name script) set(${_pkg_name}_COMPILE_SCRIPT "${script}" CACHE INTERNAL "Script associated to package ${pkg_name}" FORCE) endfunction() function(_package_add_third_party_script_variable pkg var) set(${_pkg_name}_VARIABLE_${var} "${ARGN}" CACHE INTERNAL "Script associated to package ${pkg_name}" FORCE) set(${var} ${ARGN} PARENT_SCOPE) endfunction() function(_package_load_third_party_script pkg_name) if(${pkg_name}_COMPILE_SCRIPT) # set the stored variable get_cmake_property(_all_vars VARIABLES) foreach(_var ${_all_vars}) if(_var MATCHES "^${pkg_name}_VARIABLE_.*") string(REPLACE "${pkg_name}_VARIABLE_" "" _orig_var "${_var}") set(${_orig_var} ${${_var}}) endif() endforeach() _package_get_real_name(${pkg_name} _name) string(TOUPPER "${_name}" _u_name) _package_get_option_name(${pkg_name} _opt_name) if(${_opt_name}_VERSION) set(_version " (version ${${_opt_name}_VERSION})") elseif(${_u_name}_VERSION) set(_version " (version ${${_u_name}_VERSION})") endif() # load the script message(STATUS "${_name}: building as third-party${_version}") include(ExternalProject) include(${${pkg_name}_COMPILE_SCRIPT}) 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}} (${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_find_package_extra_options pkg_name) set(${pkg_name}_FIND_PKG_OPTIONS "${ARGN}" CACHE INTERNAL "Extra option for the fin_package function" FORCE) endfunction() function(_package_get_find_package_extra_options pkg_name options) set(${options} "${${pkg_name}_FIND_PKG_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) + if(${pkg_name}_LIBRARIES) + set(${libraries} ${${pkg_name}_LIBRARIES} PARENT_SCOPE) + else() + set(${libraries} "" PARENT_SCOPE) + endif() endfunction() # ------------------------------------------------------------------------------ # Extra dependencies like custom commands of ExternalProject # ------------------------------------------------------------------------------ function(_package_get_extra_dependencies pkg deps) if(${_pkg_name}_EXTRA_DEPENDENCY) set(${deps} ${${_pkg_name}_EXTRA_DEPENDENCY} PARENT_SCOPE) else() set(${deps} PARENT_SCOPE) endif() endfunction() function(_package_unset_extra_dependencies pkg_name) unset(${pkg_name}_EXTRA_DEPENDENCY 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_add_dependencies pkg_name) set(_tmp_deps ${${pkg_name}_DEPENDENCIES}) list(APPEND _tmp_deps ${ARGN}) list(REMOVE_DUPLICATES _tmp_deps) set(${pkg_name}_DEPENDENCIES "${_tmp_deps}" 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() function(_package_unset_dependencies pkg_name) unset(${pkg_name}_DEPENDENCIES CACHE) 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_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() function(_package_get_documentation pkg_name _doc) # \n replaced by && and \\ by ££ to avoid cache problems 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() # ------------------------------------------------------------------------------ # Special boost thingy # ------------------------------------------------------------------------------ function(_package_set_boost_component_needed pkg_name) set(_tmp ${${pkg_name}_BOOST_COMPONENTS_NEEDED}) list(APPEND _tmp ${ARGN}) list(REMOVE_DUPLICATES _tmp) set(${pkg_name}_BOOST_NEEDED_COMPONENTS ${_tmp} CACHE INTERNAL "List of Boost component needed by package ${${pkg_name}}" FORCE) package_get_name(Boost _boost_pkg_name) _package_add_dependencies(${pkg_name} ${_boost_pkg_name}) endfunction() -function(_package_get_boost_component_needed pkg_name) - set(_tmp ${${_project}_BOOST_COMPONENTS_NEEDED}) - list(APPEND _tmp ${ARGN}) - list(REMOVE_DUPLICATES _tmp) - set(${pkg_name}_BOOST_NEEDED_COMPONENTS ${_tmp} - CACHE INTERNAL "List of Boost component needed by package ${${pkg_name}}" FORCE) +function(_package_get_boost_component_needed pkg_name needed) + if(${pkg_name}_BOOST_NEEDED_COMPONENTS) + set(${needed} ${${pkg_name}_BOOST_NEEDED_COMPONENTS} PARENT_SCOPE) + else() + set(${needed} PARENT_SCOPE) + endif() endfunction() function(_package_load_boost_components) string(TOUPPER ${PROJECT_NAME} _project) package_get_name(Boost _pkg_name) set(_boost_needed_components) package_get_all_activated_packages(_activated_list) foreach(_pkg_name ${_activated_list}) - _package_get_documentation_files(${_pkg_name} _doc_files) + _package_get_boost_component_needed(${_pkg_name} _boost_comp) - foreach(_doc_file ${_doc_files}) - list(APPEND _tmp_DOC_FILES ${_doc_dir}/${_doc_file}) - endforeach() + list(APPEND _boost_needed_components ${_boost_comp}) endforeach() - if(_boost_components_needed) - message(STATUS "Looking for Boost liraries") - foreach(_comp ${_boost_components_needed}) + if(_boost_needed_components) + message(STATUS "Looking for Boost liraries: ${_boost_needed_components}") + foreach(_comp ${_boost_needed_components}) 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() # ------------------------------------------------------------------------------ # get the list of source files for a given package # ------------------------------------------------------------------------------ function(_package_get_source_files pkg_name 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_name}_${_type}}) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" _rel_file "${_file}") list(APPEND tmp_${_type} "${_rel_file}") endforeach() endforeach() set(${SRCS} ${tmp_SRCS} PARENT_SCOPE) set(${PUBLIC_HEADERS} ${tmp_PUBLIC_HEADERS} PARENT_SCOPE) set(${PRIVATE_HEADERS} ${tmp_PRIVATE_HEADERS} PARENT_SCOPE) 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) # 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) else() _package_load_third_party_script(${pkg_name}) 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_find_package_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 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() diff --git a/cmake/Modules/FindPETSc.cmake b/cmake/Modules/FindPETSc.cmake index 191a76fef..3c96349ab 100644 --- a/cmake/Modules/FindPETSc.cmake +++ b/cmake/Modules/FindPETSc.cmake @@ -1,345 +1,345 @@ # - Try to find PETSc # Once done this will define # # PETSC_FOUND - system has PETSc # PETSC_INCLUDES - the PETSc include directories # PETSC_LIBRARIES - Link these to use PETSc # PETSC_COMPILER - Compiler used by PETSc, helpful to find a compatible MPI # PETSC_DEFINITIONS - Compiler switches for using PETSc # PETSC_MPIEXEC - Executable for running MPI programs # PETSC_VERSION - Version string (MAJOR.MINOR.SUBMINOR) # # Usage: # find_package(PETSc COMPONENTS CXX) - required if build --with-clanguage=C++ --with-c-support=0 # find_package(PETSc COMPONENTS C) - standard behavior of checking build using a C compiler # find_package(PETSc) - same as above # # Setting these changes the behavior of the search # PETSC_DIR - directory in which PETSc resides # PETSC_ARCH - build architecture # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # set(PETSC_VALID_COMPONENTS C CXX) if(NOT PETSc_FIND_COMPONENTS) set(PETSC_LANGUAGE_BINDINGS "C") else() # Right now, this is designed for compatability with the --with-clanguage option, so # only allow one item in the components list. list(LENGTH ${PETSc_FIND_COMPONENTS} components_length) if(${components_length} GREATER 1) message(FATAL_ERROR "Only one component for PETSc is allowed to be specified") endif() # This is a stub for allowing multiple components should that time ever come. Perhaps # to also test Fortran bindings? foreach(component ${PETSc_FIND_COMPONENTS}) list(FIND PETSC_VALID_COMPONENTS ${component} component_location) if(${component_location} EQUAL -1) message(FATAL_ERROR "\"${component}\" is not a valid PETSc component.") else() list(APPEND PETSC_LANGUAGE_BINDINGS ${component}) endif() endforeach() endif() function (petsc_get_version) if (EXISTS "${PETSC_DIR}/include/petscversion.h") file (STRINGS "${PETSC_DIR}/include/petscversion.h" vstrings REGEX "#define PETSC_VERSION_(RELEASE|MAJOR|MINOR|SUBMINOR|PATCH) ") foreach (line ${vstrings}) string (REGEX REPLACE " +" ";" fields ${line}) # break line into three fields (the first is always "#define") list (GET fields 1 var) list (GET fields 2 val) set (${var} ${val} PARENT_SCOPE) set (${var} ${val}) # Also in local scope so we have access below endforeach () if (PETSC_VERSION_RELEASE) set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}p${PETSC_VERSION_PATCH}" PARENT_SCOPE) else () # make dev version compare higher than any patch level of a released version set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}.99" PARENT_SCOPE) endif () else () message (SEND_ERROR "PETSC_DIR can not be used, ${PETSC_DIR}/include/petscversion.h does not exist") endif () endfunction () find_path (PETSC_DIR include/petsc.h HINTS ENV PETSC_DIR PATHS # Debian paths /usr/lib/petscdir/3.3 /usr/lib/petscdir/3.2 /usr/lib/petscdir/3.1 /usr/lib/petscdir/3.0.0 /usr/lib/petscdir/2.3.3 /usr/lib/petscdir/2.3.2 $ENV{HOME}/petsc DOC "PETSc Directory") find_program (MAKE_EXECUTABLE NAMES make gmake) if (NOT PETSC_ARCH) if (NOT ENV{PETSC_ARCH}) set(_petsc_arches linux-gnu-c-debug linux-gnu-c-opt # Debian defaults x86_64-unknown-linux-gnu i386-unknown-linux-gnu) else() set(_petsc_arches $ENV{PETSC_ARCH}) # If set, use environment variable first) endif() else() set (_petsc_arches ${PETSC_ARCH}) endif() if (NOT PETSC_DIR) if (NOT ENV{PETSC_DIR}) set(PETSC_DIR /usr/lib/petsc) else() set(PETSC_DIR $ENV{PETSC_DIR}) # If set, use environment variable first) endif() endif() foreach (arch ${_petsc_arches}) set (petscconf "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE) find_path (petscconf petscconf.h HINTS ${PETSC_DIR} PATH_SUFFIXES ${arch}/include bmake/${arch} NO_DEFAULT_PATH) if(petscconf) set (PETSC_ARCH "${arch}" CACHE STRING "PETSc build architecture") set(_petsc_dir ${PETSC_DIR}) set (PETSC_DIR "${_petsc_dir}" CACHE STRING "PETSc build directory") break() endif() endforeach() set (petsc_slaves LIBRARIES_SYS LIBRARIES_VEC LIBRARIES_MAT LIBRARIES_DM LIBRARIES_KSP LIBRARIES_SNES LIBRARIES_TS INCLUDE_DIR INCLUDE_CONF) include (FindPackageMultipass) #find_package_multipass (PETSc petsc_config_current # STATES DIR ARCH # DEPENDENTS INCLUDES LIBRARIES COMPILER MPIEXEC EXECUTABLE_RUNS ${petsc_slaves}) # # Determine whether the PETSc layout is old-style (through 2.3.3) or # new-style (>= 3.0.0) if (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include/petscconf.h") # > 2.3.3 set (petsc_conf_rules "${PETSC_DIR}/conf/rules") set (petsc_conf_variables "${PETSC_DIR}/conf/variables") elseif (EXISTS "${PETSC_DIR}/bmake/${PETSC_ARCH}/petscconf.h") # <= 2.3.3 set (petsc_conf_rules "${PETSC_DIR}/bmake/common/rules") set (petsc_conf_variables "${PETSC_DIR}/bmake/common/variables") elseif (PETSC_DIR) message (SEND_ERROR "The pair PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} do not specify a valid PETSc installation") endif () message(petsc_conf_rules ${petsc_conf_rules}) message(petsc_conf_variables ${petsc_conf_variables}) message(petsc_config_current ${petsc_config_current}) if (petsc_conf_rules AND petsc_conf_variables AND NOT petsc_config_current) petsc_get_version() # Put variables into environment since they are needed to get # configuration (petscvariables) in the PETSc makefile set (ENV{PETSC_DIR} "${PETSC_DIR}") set (ENV{PETSC_ARCH} "${PETSC_ARCH}") # A temporary makefile to probe the PETSc configuration set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc") file (WRITE "${petsc_config_makefile}" "## This file was autogenerated by FindPETSc.cmake # PETSC_DIR = ${PETSC_DIR} # PETSC_ARCH = ${PETSC_ARCH} include ${petsc_conf_rules} include ${petsc_conf_variables} show : -@echo -n \${\${VARIABLE}} ") macro (PETSC_GET_VARIABLE name var) set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} show VARIABLE=${name} OUTPUT_VARIABLE ${var} RESULT_VARIABLE petsc_return) endmacro (PETSC_GET_VARIABLE) petsc_get_variable (PETSC_LIB_DIR petsc_lib_dir) petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC petsc_libs_external) petsc_get_variable (PETSC_CCPPFLAGS petsc_cpp_line) petsc_get_variable (PETSC_INCLUDE petsc_include) petsc_get_variable (PCC petsc_cc) petsc_get_variable (PCC_FLAGS petsc_cc_flags) petsc_get_variable (MPIEXEC petsc_mpiexec) # We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid! file (REMOVE ${petsc_config_makefile}) include (ResolveCompilerPaths) # Extract include paths and libraries from compile command line resolve_includes (petsc_includes_all "${petsc_cpp_line}") #on windows we need to make sure we're linking against the right #runtime library if (WIN32) if (petsc_cc_flags MATCHES "-MT") set(using_md False) foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MD") set(using_md True) endif(${flag_var} MATCHES "/MD") endforeach(flag_var) if(${using_md} MATCHES "True") message(WARNING "PETSc was built with /MT, but /MD is currently set. See http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F") endif(${using_md} MATCHES "True") endif (petsc_cc_flags MATCHES "-MT") endif (WIN32) include (CorrectWindowsPaths) convert_cygwin_path(petsc_lib_dir) message (STATUS "petsc_lib_dir ${petsc_lib_dir}") macro (PETSC_FIND_LIBRARY suffix name) set (PETSC_LIBRARY_${suffix} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # Clear any stale value, if we got here, we need to find it again if (WIN32) set (libname lib${name}) #windows expects "libfoo", linux expects "foo" else (WIN32) set (libname ${name}) endif (WIN32) find_library (PETSC_LIBRARY_${suffix} NAMES ${libname} HINTS ${petsc_lib_dir} NO_DEFAULT_PATH) set (PETSC_LIBRARIES_${suffix} "${PETSC_LIBRARY_${suffix}}") mark_as_advanced (PETSC_LIBRARY_${suffix}) endmacro (PETSC_FIND_LIBRARY suffix name) # Look for petscvec first, if it doesn't exist, we must be using single-library petsc_find_library (VEC petscvec) if (PETSC_LIBRARY_VEC) petsc_find_library (SYS "petscsys;petsc") # libpetscsys is called libpetsc prior to 3.1 (when single-library was introduced) petsc_find_library (MAT petscmat) petsc_find_library (DM petscdm) petsc_find_library (KSP petscksp) petsc_find_library (SNES petscsnes) petsc_find_library (TS petscts) macro (PETSC_JOIN libs deps) list (APPEND PETSC_LIBRARIES_${libs} ${PETSC_LIBRARIES_${deps}}) endmacro (PETSC_JOIN libs deps) petsc_join (VEC SYS) petsc_join (MAT VEC) petsc_join (DM MAT) petsc_join (KSP DM) petsc_join (SNES KSP) petsc_join (TS SNES) petsc_join (ALL TS) else () - set (PETSC_LIBRARY_VEC "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # There is no libpetscvec petsc_find_library (SINGLE petsc) foreach (pkg SYS VEC MAT DM KSP SNES TS ALL) set (PETSC_LIBRARIES_${pkg} "${PETSC_LIBRARY_SINGLE}") endforeach () + set (PETSC_LIBRARY_VEC "${PETSC_LIBRARY_SINGLE}" CACHE INTERNAL "Cleared" FORCE) # There is no libpetscvec endif () if (PETSC_LIBRARY_TS) message (STATUS "Recognized PETSc install with separate libraries for each package") else () message (STATUS "Recognized PETSc install with single library for all packages") endif () include(Check${PETSC_LANGUAGE_BINDINGS}SourceRuns) macro (PETSC_TEST_RUNS includes libraries runs) if(${PETSC_LANGUAGE_BINDINGS} STREQUAL "C") set(_PETSC_ERR_FUNC "CHKERRQ(ierr)") elseif(${PETSC_LANGUAGE_BINDINGS} STREQUAL "CXX") set(_PETSC_ERR_FUNC "CHKERRXX(ierr)") endif() if (PETSC_VERSION VERSION_GREATER 3.1) set (_PETSC_TSDestroy "TSDestroy(&ts)") else () set (_PETSC_TSDestroy "TSDestroy(ts)") endif () set(_PETSC_TEST_SOURCE " static const char help[] = \"PETSc test program.\"; #include <petscts.h> int main(int argc,char *argv[]) { PetscErrorCode ierr; TS ts; ierr = PetscInitialize(&argc,&argv,0,help);${_PETSC_ERR_FUNC}; ierr = TSCreate(PETSC_COMM_WORLD,&ts);${_PETSC_ERR_FUNC}; ierr = TSSetFromOptions(ts);${_PETSC_ERR_FUNC}; ierr = ${_PETSC_TSDestroy};${_PETSC_ERR_FUNC}; ierr = PetscFinalize();${_PETSC_ERR_FUNC}; return 0; } ") multipass_source_runs ("${includes}" "${libraries}" "${_PETSC_TEST_SOURCE}" ${runs} "${PETSC_LANGUAGE_BINDINGS}") if (${${runs}}) set (PETSC_EXECUTABLE_RUNS "YES" CACHE BOOL "Can the system successfully run a PETSc executable? This variable can be manually set to \"YES\" to force CMake to accept a given PETSc configuration, but this will almost always result in a broken build. If you change PETSC_DIR, PETSC_ARCH, or PETSC_CURRENT you would have to reset this variable." FORCE) endif (${${runs}}) endmacro (PETSC_TEST_RUNS) find_path (PETSC_INCLUDE_DIR petscts.h HINTS "${PETSC_DIR}" PATH_SUFFIXES include NO_DEFAULT_PATH) find_path (PETSC_INCLUDE_CONF petscconf.h HINTS "${PETSC_DIR}" PATH_SUFFIXES "${PETSC_ARCH}/include" "bmake/${PETSC_ARCH}" NO_DEFAULT_PATH) mark_as_advanced (PETSC_INCLUDE_DIR PETSC_INCLUDE_CONF) set (petsc_includes_minimal ${PETSC_INCLUDE_CONF} ${PETSC_INCLUDE_DIR}) petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_minimal) if (petsc_works_minimal) message (STATUS "Minimal PETSc includes and libraries work. This probably means we are building with shared libs.") set (petsc_includes_needed "${petsc_includes_minimal}") else (petsc_works_minimal) # Minimal includes fail, see if just adding full includes fixes it petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_allincludes) if (petsc_works_allincludes) # It does, we just need all the includes ( message (STATUS "PETSc requires extra include paths, but links correctly with only interface libraries. This is an unexpected configuration (but it seems to work fine).") set (petsc_includes_needed ${petsc_includes_all}) else (petsc_works_allincludes) # We are going to need to link the external libs explicitly resolve_libraries (petsc_libraries_external "${petsc_libs_external}") foreach (pkg SYS VEC MAT DM KSP SNES TS ALL) list (APPEND PETSC_LIBRARIES_${pkg} ${petsc_libraries_external}) endforeach (pkg) petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_alllibraries) if (petsc_works_alllibraries) message (STATUS "PETSc only need minimal includes, but requires explicit linking to all dependencies. This is expected when PETSc is built with static libraries.") set (petsc_includes_needed ${petsc_includes_minimal}) else (petsc_works_alllibraries) # It looks like we really need everything, should have listened to Matt set (petsc_includes_needed ${petsc_includes_all}) petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_all) if (petsc_works_all) # We fail anyways message (STATUS "PETSc requires extra include paths and explicit linking to all dependencies. This probably means you have static libraries and something unexpected in PETSc headers.") else (petsc_works_all) # We fail anyways message (STATUS "PETSc could not be used, maybe the install is broken.") endif (petsc_works_all) endif (petsc_works_alllibraries) endif (petsc_works_allincludes) endif (petsc_works_minimal) # We do an out-of-source build so __FILE__ will be an absolute path, hence __INSDIR__ is superfluous if (${PETSC_VERSION} VERSION_LESS 3.1) set (PETSC_DEFINITIONS "-D__SDIR__=\"\"" CACHE STRING "PETSc definitions" FORCE) else () set (PETSC_DEFINITIONS "-D__INSDIR__=" CACHE STRING "PETSc definitions" FORCE) endif () # Sometimes this can be used to assist FindMPI.cmake set (PETSC_MPIEXEC ${petsc_mpiexec} CACHE FILEPATH "Executable for running PETSc MPI programs" FORCE) set (PETSC_INCLUDES ${petsc_includes_needed} CACHE STRING "PETSc include path" FORCE) set (PETSC_LIBRARIES ${PETSC_LIBRARIES_ALL} CACHE STRING "PETSc libraries" FORCE) set (PETSC_COMPILER ${petsc_cc} CACHE FILEPATH "PETSc compiler" FORCE) # Note that we have forced values for all these choices. If you # change these, you are telling the system to trust you that they # work. It is likely that you will end up with a broken build. mark_as_advanced (PETSC_INCLUDES PETSC_LIBRARIES PETSC_COMPILER PETSC_DEFINITIONS PETSC_MPIEXEC PETSC_EXECUTABLE_RUNS) endif () include (FindPackageHandleStandardArgs) find_package_handle_standard_args (PETSc "PETSc could not be found. Be sure to set PETSC_DIR and PETSC_ARCH." PETSC_INCLUDES PETSC_LIBRARIES PETSC_EXECUTABLE_RUNS) diff --git a/doc/manual/CMakeLists.txt b/doc/manual/CMakeLists.txt index 83cda0284..5edf520f2 100644 --- a/doc/manual/CMakeLists.txt +++ b/doc/manual/CMakeLists.txt @@ -1,135 +1,152 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Jun 09 2014 # @date last modification: Thu Jul 03 2014 # # @brief Build the documentation # # @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/>. # #=============================================================================== #------------------------------------------------------------------------------# function(get_doc_label pkg_name label) string(REPLACE "_" "-" _pkg_tex_label_dash ${pkg_name}) string(TOLOWER "${_pkg_tex_label_dash}" _pkg_tex_label) set(TOLOWER "${_pkg_tex_label_dash}" _pkg_tex_label) set(${label} "pkg:${_pkg_tex_label}" PARENT_SCOPE) endfunction() function(get_doc_package_name pkg_name pkg_tex) _package_get_option_name(${pkg_name} _opt_name) string(REPLACE "_" "\\_" _pkg_tex "${_opt_name}") set(${pkg_tex} ${_pkg_tex} PARENT_SCOPE) endfunction() #------------------------------------------------------------------------------# function(generate_package_dependency_tex_doc pkg_name FILENAME LEVEL) _package_get_option_name(${pkg_name} _opt_name) string(REPLACE "_" "\\_" _pkg_tex "${_opt_name}") get_doc_label(${pkg_name} _pkg_tex_label) file(APPEND ${FILENAME} "\\AkantuPackageNameWithLabel{${_pkg_tex}}{${_pkg_tex_label}}{${LEVEL}}\\xspace") math(EXPR _sub_level "${LEVEL}+1") _package_get_dependencies(${pkg_name} _dependencies) foreach(_dep_pkg_name ${_dependencies}) generate_package_dependency_tex_doc(${_dep_pkg_name} ${FILENAME} ${_sub_level}) endforeach() endfunction() #------------------------------------------------------------------------------# function(generate_package_tex_doc pkg_name FILENAME) get_doc_package_name(${pkg_name} _pkg_tex) get_doc_label(${pkg_name} _pkg_tex_label) file(APPEND ${FILENAME} "\n\\begin{AkantuPackage}{${_pkg_tex}}{${_pkg_tex_label}}") _package_get_documentation(${pkg_name} _doc) if (_doc) file(APPEND ${FILENAME} "${_doc}") else() _package_get_filename(${pkg_name} _file_path) _package_get_real_name(${pkg_name} _pkg) get_filename_component(_file ${_file_path} NAME) - file(APPEND ${FILENAME} "{\\color{red} TODO}: No Documentation in {\\color{blue} \\href{${_file_path}}{${_file}}}\\\\") - file(APPEND ${FILENAME} "looking for the sequence: \\code{\\\\package\\_declare\\_documentation(${_pkg} \" documentation text \" )}" ) + string(REPLACE "_" "\\_" _escaped_pkg "${_pkg}") + + set(_missing_doc + "{\\color{red} TODO}: No Documentation in {\\color{blue} \\href{${_file_path}}{${_file}}}" + "" + "looking for the sequence: " + "\\begin{cmake}" + "\\package_declare_documentation(" + " ${_escaped_pkg}" + " \"documentation text\"" + " )" + "\\end{cmake}") + + set(_missing_doc_str "") + foreach(_str ${_missing_doc}) + set(_missing_doc_str "${_missing_doc_str}\n${_str}") + endforeach() + + file(APPEND ${FILENAME} "${_missing_doc_str}") endif() _package_get_dependencies(${pkg_name} _dependencies) if(_dependencies) file(APPEND ${FILENAME} "\n\\begin{AkantuPackageDependencies}") foreach(_dep_pkg_name ${_dependencies}) generate_package_dependency_tex_doc(${_dep_pkg_name} ${FILENAME} 1) endforeach() file(APPEND ${FILENAME} "\n\\end{AkantuPackageDependencies}") endif() file(APPEND ${FILENAME} "\n\\end{AkantuPackage} ") endfunction() #------------------------------------------------------------------------------# #------------------------------------------------------------------------------# set(DOC_DEPS_TEX_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/manual-packages-doc.tex") file(WRITE ${DOC_DEPS_TEX_FILENAME} "") find_program(RUBBER_EXECUTABLE rubber) if (NOT RUBBER_EXECUTABLE) message(ERROR "Manual cannot be built without rubber latex compiler") endif() mark_as_advanced(RUBBER_EXECUTABLE) package_get_all_documentation_files(_manual_files) set(AKANTU_MANUAL_FILES_DEPEND) set(AKANTU_MANUAL_FILES_COPY_COMMAND) foreach(_f ${_manual_files}) file(RELATIVE_PATH _rel_f ${CMAKE_CURRENT_SOURCE_DIR} "${_f}") list(APPEND AKANTU_MANUAL_FILES_DEPEND ${_f}) list(APPEND AKANTU_MANUAL_FILES_COPY_COMMAND COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_rel_f} ${_rel_f}) endforeach() set(MANUAL_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/manual.pdf) add_custom_command( OUTPUT ${MANUAL_OUTPUT} DEPENDS ${AKANTU_MANUAL_FILES_DEPEND} ${DOC_DEPS_TEX_FILENAME} ${AKANTU_MANUAL_FILES_COPY_COMMAND} COMMAND ${RUBBER_EXECUTABLE} -dfq -Wall manual WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Compiling the user's manual" ) add_custom_target(manual ALL DEPENDS ${MANUAL_OUTPUT}) install(FILES ${MANUAL_OUTPUT} DESTINATION share/akantu/doc) package_get_all_activated_packages(_package_list) foreach (_pkg_name ${_package_list}) generate_package_tex_doc(${_pkg_name} ${DOC_DEPS_TEX_FILENAME}) endforeach() diff --git a/doc/manual/manual-heattransfermodel.tex b/doc/manual/manual-heattransfermodel.tex index 473878c24..359d8dbcc 100644 --- a/doc/manual/manual-heattransfermodel.tex +++ b/doc/manual/manual-heattransfermodel.tex @@ -1,166 +1,166 @@ \chapter{Heat Transfer Model} The heat transfer model is a specific implementation of the \code{Model} interface dedicated to handle the dynamic heat equation. \section{Theory} The strong form of the dynamic heat equation can be expressed as \begin{equation} \rho c_v \dot{T} + \nabla \cdot \vec{\kappa} \nabla T = b \end{equation} with $T$ the scalar temperature field, $c_v$ the specific heat capacity, $\rho$ the mass density, $\mat{\kappa}$ the conductivity tensor, and $b$ the heat generation per unit of volume. The discretized weak form with a finite number of elements is \begin{equation} \forall i \quad \sum_j \left( \int_\Omega \rho c_v N_j N_i d\Omega \right) \dot{T}_j - \sum_j \left( \int_\Omega \vec{\kappa} \nabla N_j \nabla N_i d\Omega \right) T_j = - \int_{\Gamma} N_i \vec{q} \cdot \vec{n} d\Gamma + \int_\Omega b N_i d\Omega \end{equation} with $i$ and $j$ the node indices, $\vec{n}$ the normal field to the surface $\Gamma = \partial \Omega$. To simplify, we can define the capacity and the conductivity matrices as \begin{equation} C_{ij} = \int_\Omega \rho c_v N_j N_i d\Omega \qquad \textrm{and} \qquad K_{ij} = - \int_\Omega \vec{\kappa} \nabla N_j \nabla N_i d\Omega \end{equation} and the system to solve can be written \begin{equation} \mat{C} \cdot \vec{\dot{T}} = \vec{Q}^{\text{ext}} -\mat{K} \cdot \vec{T}~, \end{equation} with $\vec{Q}^{\text{ext}}$ the consistent heat generated. \section{Using the Heat Transfer Model} Currently, the \code{HeatTransferModel} object uses dynamic analysis with an explicit time integration scheme. It can simply be created like this \begin{cpp} HeatTransferModel model(mesh, spatial_dimension); \end{cpp} while an existing mesh has been used (see \ref{sect:common:mesh}). Then the model object can be initialized with: \begin{cpp} model.initFull() \end{cpp} where a material file name has to be provided. This function will load the material properties, and allocate / initialize the nodes and element \code{Array}s More precisely, the heat transfer model contains 4 \code{Arrays}: \begin{description} \item[temperature] contains the nodal temperature $T$ (zero by default after the initialization). \item[temperature\_rate] contains the variations of temperature $\dot{T}$ (zero by default after the initialization). \item[blocked\_dofs] contains a Boolean value for each degree of freedom specifying whether the degree is blocked or not. A Dirichlet boundary condition can be prescribed by setting the \textbf{blocked\_dofs} value of a degree of freedom to \code{true}. The \textbf{temperature} and the \textbf{temperature\_rate} are computed for all degrees of freedom where the \textbf{blocked\_dofs} value is set to \code{false}. For the remaining degrees of freedom, the imposed values (zero by default after initialization) are kept. \item[residual] contains the difference between external and internal heat generations. The \textbf{residual} contains the supported heat reactions ($\vec{R} = \vec{Q^{ext}} -\mat{K} \cdot \vec{T}$) on the nodes that the temperature imposed. \end{description} Only a single material can be specified on the domain. A material text file (\eg material.dat) provides the material properties as follows: \begin{cpp} heat %\emph{name\_material}% [ capacity = %\emph{XXX}% density = %\emph{XXX}% conductivity = [%\emph{XXX}% ... %\emph{XXX}%] ] \end{cpp} where the \code{capacity} and \code{density} are scalars, and the \code{conductivity} is specified as a $3\times 3$ tensor. \subsection{Explicit Dynamic} The explicit time integration scheme in \akantu uses a lumped capacity matrix $\mat{C}$ (reducing the computational cost, see Chapter \ref{sect:smm}). This matrix is assembled by distributing the capacity of each element onto its nodes. Therefore, the resulting $\mat{C}$ is a diagonal matrix stored in the \code{capacity} \code{Array} of the model. \begin{cpp} model.assembleCapacityLumped(); \end{cpp} \index{HeatTransferModel!assembleCapacityLumped} \note{Currently, only the explicit time integration with lumped capacity matrix -is implemented within \akantu.} \\ +is implemented within \akantu.} The explicit integration scheme is \index{Forward Euler} \emph{Forward Euler} \cite{curnier92a}. \begin{itemize} \item Predictor: $\vec{T}_{n+1} = \vec{T}_{n} + \Delta t \dot{\vec{T}}_{n}$ \item Update residual: $\vec{R}_{n+1} = \left( \vec{Q^{ext}_{n+1}} - \vec{K}\vec{T}_{n+1} \right)$ \item Corrector : $\dot{\vec{T}}_{n+1} = \mat{C}^{-1} \vec{R}_{n+1}$ \end{itemize} The explicit integration scheme is conditionally stable. The time step has to be smaller than the stable time step, and it can be obtained in \akantu as follows: \begin{cpp} time_step = model.getStableTimeStep(); \end{cpp} \index{HeatTransferModel!StableTimeStep} The stable time step is defined as: \begin{equation}\label{eqn:htm:explicit:stabletime} \Delta t_{\st{crit}} = 2 \Delta x^2 \frac{\rho c_v}{\mid\mid \mat{\kappa} \mid\mid^\infty} \end{equation} where $\Delta x$ is the characteristic length (\eg the inradius in the case of linear triangle element), $\rho$ is the density, $\mat{\kappa}$ is the conductivity tensor, and $c_v$ is the specific heat capacity. It is necessary to impose a time step which is smaller than the stable time step, for instance, by multiplying the stable time step by a safety factor smaller than one. \begin{cpp} const Real safety_time_factor = 0.1; Real applied_time_step = time_step * safety_time_factor; model.setTimeStep(applied_time_step); \end{cpp} The following loop allows, for each time step, to update the \code{temperature}, \code{residual} and \code{temperature\_rate} fields following the previously described integration scheme. \begin{cpp} for (UInt s = 1; (s-1)*applied_time_step < total_time; ++s) { model.explicitPred(); model.updateResidual(); model.explicitCorr(); } \end{cpp} \index{HeatTransferModel!explicitPred} \index{HeatTransferModel!explicitCorr} \index{HeatTransferModel!updateResidual} \index{HeatTransferModel!solveExplicitLumped} An example of explicit dynamic heat propagation is presented in \\ \shellcode{\examplesdir/heat\_transfer/explicit\_heat\_transfer.cc}. \\ This example consists of a square 2D plate of \SI{1}{\metre^2} having an initial temperature of \SI{100}{\kelvin} everywhere but a none centered hot point maintained at \SI{300}{\kelvin}. Figure~\ref{fig:htm:explicit:dynamic} presents the geometry of this case. The material used is a linear fictitious elastic material with a density of \SI{8940}{\kilo\gram\per\metre^3}, a conductivity of \SI{401}{\watt\per\metre\per\kelvin} and a specific heat capacity of \SI{385}{\joule\per\kelvin\per\kilogram}. The time step used is \SI{0.12}{\second}. \begin{figure}[!htb] \centering \includegraphics[width=.4\textwidth]{figures/hot-point-1} \hfill \includegraphics[width=.4\textwidth]{figures/hot-point-2} \caption{Initial temperature field (left) and after 15000 time steps = 30 minutes (right). The lines represent iso-surfaces.} \label{fig:htm:explicit:dynamic} \end{figure} diff --git a/doc/manual/manual-parallel.tex b/doc/manual/manual-parallel.tex index 588a6aa49..bfd89a089 100644 --- a/doc/manual/manual-parallel.tex +++ b/doc/manual/manual-parallel.tex @@ -1,113 +1,113 @@ \chapter{Parallel Computation} This section explains how to launch a parallel computation. The strategy adopted by \akantu uses a mesh partitioning where elements are mapped to processors. Mesh partitions are then distributed to available processors by adequate routines as will be described below. The sequence of additional operations to be performed by the user are: \begin{itemize} \item Initializing the parallel context \item Partitioning the mesh \item Distributing mesh partitions \end{itemize} After these steps, the \code{Model} object proceeds with the interprocess communication automatically without the user having to explicitly take care of them. In what follows we show how it works on a \code{SolidMechanics} model. \section{Initializing the Parallel Context} The user must initialize \akantu by forwarding the arguments passed to the program by using the function \code{initialize}, and close \akantu instances -at the end of the program by calling the \code{finalize} function.\\ +at the end of the program by calling the \code{finalize} function. \note{This step does not change from the sequential case as it was stated in -Section \ref{sect:common:main}. It only gives a additional motivation in the parallel/MPI context.}\\ +Section \ref{sect:common:main}. It only gives a additional motivation in the parallel/MPI context.} The \code{initialize} function builds a \code{StaticCommunicator} object responsible for handling the interprocess communications later on. The \code{StaticCommunicator} can, for instance, be used to ask the total number of declared processors available for computations as well as the process rank through the functions \code{getNbProc} and \code{whoAmI} respectively. An example of the initializing sequence and basic usage of the \code{StaticCommunicator} is: \begin{cpp} int main(int argc, char *argv[]) { initialize("material.dat", argc, argv); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); ... finalize(); } \end{cpp} \section{Partitioning the Mesh} The mesh is partitioned after the correct initialization of the processes playing a role in the computation. We assume that a \code{Mesh} object is constructed as presented in Section~\ref{sect:common:mesh}. Then a partition must be computed by using an appropriate mesh partitioner. At present time, the only partitioner available is \code{MeshPartitionScotch} which implements the function \code{partitionate} using the \textbf{Scotch}\cite{scotch} program. This is achieved by the following code \begin{cpp} Mesh mesh(spatial_dimension); MeshPartition * partition = NULL; if(prank == 0) { mesh.read("my_mesh.msh"); partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } \end{cpp} \note{Only the processor of rank $0$ should load the mesh file to partition it. Nevertheless, the \code{Mesh} object must by declared for all processors since the mesh distribution will store mesh pieces to that object.} \section{Distributing Mesh Partitions} The distribution of the mesh is done automatically by the \code{SolidMechanicsModel} through the \code{initParallel} method. Thus, after creating a \code{SolidMechanicsModel} with our mesh as the initial parameter, the \code{initParallel} method must be called receiving the partition as a parameter. \begin{cpp} SolidMechanicsModel model(mesh); model.initParallel(partition); \end{cpp} After that point, everything remains as in the sequential case from the user point of view. This allows the user to care only about his simulation without concern for the parallelism. An example of an explicit dynamic 2D bar in compression in a parallel context can be found in \shellcode{\examplesdir/parallel\_2d}. \section{Launching a Parallel Program} Using \textbf{MPI} a parallel run can be launched from a shell using the command \begin{cpp} mpirun -np #procs program_name parameter1 parameter2 ... \end{cpp} %%% Local Variables: %%% mode: latex %%% TeX-master: "manual" %%% End: diff --git a/doc/manual/manual-solidmechanicsmodel.tex b/doc/manual/manual-solidmechanicsmodel.tex index d265c744d..06ffe06b0 100644 --- a/doc/manual/manual-solidmechanicsmodel.tex +++ b/doc/manual/manual-solidmechanicsmodel.tex @@ -1,1040 +1,1040 @@ \chapter{Solid Mechanics Model\index{SolidMechanicsModel}\label{sect:smm}} The solid mechanics model is a specific implementation of the \code{Model} interface dedicated to handle the equations of motion or equations of equilibrium. The model is created for a given mesh. It will create its own \code{FEEngine} object to compute the interpolation, gradient, integration and assembly operations. A \code{SolidMechanicsModel} object can simply be created like this: \begin{cpp} SolidMechanicsModel model(mesh); \end{cpp} where \code{mesh} is the mesh for which the equations are to be solved. A second parameter called \code{spatial\_dimension} can be added after \code{mesh} if the spatial dimension of the problem is different than that of the mesh. This model contains at least the the following six \code{Arrays}: \begin{description} \item[blocked\_dofs] contains a Boolean value for each degree of freedom specifying whether that degree is blocked or not. A Dirichlet boundary condition can be prescribed by setting the \textbf{blocked\_dofs} value of a degree of freedom to \code{true}. A Neumann boundary condition can be applied by setting the \textbf{blocked\_dofs} value of a degree of freedom to \code{false}. The \textbf{displacement}, \textbf{velocity} and \textbf{acceleration} are computed for all degrees of freedom for which the \textbf{blocked\_dofs} value is set to \code{false}. For the remaining degrees of freedom, the imposed values (zero by default after initialization) are kept. \item[displacement] contains the displacements of all degrees of freedom. It can be either a computed displacement for free degrees of freedom or an imposed displacement in case of blocked ones ($\vec{u}$ in the following). \item[velocity] contains the velocities of all degrees of freedom. As \textbf{displacement}, it contains computed or imposed velocities depending on the nature of the degrees of freedom ($\dot{\vec{u}}$ in the following). \item[acceleration] contains the accelerations of all degrees of freedom. As \textbf{displacement}, it contains computed or imposed accelerations depending on the nature of the degrees of freedom ($\ddot{\vec{u}}$ in the following). \item[force] contains the external forces applied on the nodes ($\vec{f}_{\st{ext}}$ in the following). \item[residual] contains the difference between external and internal forces. On blocked degrees of freedom, \textbf{residual} contains the support reactions. ($\vec{r}$ in the following). It should be mentioned that at equilibrium \textbf{residual} should be zero on free degrees of freedom. \end{description} Some examples to help to understand how to use this model will be presented in the next sections. \section{Model Setup} \subsection{Setting Initial Conditions \label{sect:smm:initial_condition}} For a unique solution of the equations of motion, initial displacements and velocities for all degrees of freedom must be specified: \begin{eqnarray} \vec{u}(t=0) = \vec{u}_0\\ \dot{\vec u}(t=0) =\vec{v}_0 \end{eqnarray} The solid mechanics model can be initialized as follows: \begin{cpp} model.initFull() \end{cpp} This function initializes the internal arrays and sets them to zero. Initial displacements and velocities that are not equal to zero can be prescribed by running a loop over the total number of nodes. Here, the initial displacement in $x$-direction and the initial velocity in $y$-direction for all nodes is set to $0.1$ and $1$, respectively. \begin{cpp} Array<Real> & disp = model.getDisplacement(); Array<Real> & velo = model.getVelocity(); for (UInt i = 0; i < mesh.getNbNodes(); ++i) { disp(i, 0) = 0.1; velo(i, 1) = 1.; } \end{cpp} \subsection{Setting Boundary Conditions\label{sect:smm:boundary}} This section explains how to impose Dirichlet or Neumann boundary conditions. A Dirichlet boundary condition specifies the values that the displacement needs to take for every point $x$ at the boundary ($\Gamma_u$) of the problem domain (Fig.~\ref{fig:smm:boundaries}): \begin{equation} \vec{u} = \bar{\vec u} \quad \forall \vec{x}\in \Gamma_{u} \end{equation} A Neumann boundary condition imposes the value of the gradient of the solution at the boundary $\Gamma_t$ of the problem domain (Fig.~\ref{fig:smm:boundaries}): \begin{equation} \vec{t} = \mat{\sigma} \vec{n} = \bar{\vec t} \quad \forall \vec{x}\in \Gamma_{t} \end{equation} \begin{figure} \centering \def\svgwidth{0.5\columnwidth} \input{figures/problemDomain.pdf_tex} \caption{Problem domain $\Omega$ with boundary in three dimensions. The Dirchelet and the Neumann regions of the boundary are denoted with $\Gamma_u$ and $\Gamma_t$, respecitvely.\label{fig:smm:boundaries}} \label{fig:problemDomain} \end{figure} Different ways of imposing these boundary conditions exist. A basic way is to loop over nodes or elements at the boundary and apply local values. A more advanced method consists of using the notion of the boundary of the mesh. In the following both ways are presented. Starting with the basic approach, as mentioned, the Dirichlet boundary conditions can be applied by looping over the nodes and assigning the required values. Figure~\ref{fig:smm:dirichlet_bc} shows a beam with a fixed support on the left side. On the right end of the beam, a load is applied. At the fixed support, the displacement has a given value. For this example, the displacements in both the $x$ and the $y$-direction are set to zero. Implementing this displacement boundary condition is similar to the implementation of initial displacement conditions described above. However, in order to impose a displacement boundary condition for all time steps, the corresponding nodes need to be marked as boundary nodes as shown in the following code: \begin{cpp} Array<bool> & blocked = model.getBlockedDOFs(); const Array<Real> & pos = mesh.getNodes(); UInt nb_nodes = mesh.getNbNodes(); for (UInt i = 0; i < nb_nodes; ++i) { if(Math::are_float_equal(pos(i, 0), 0)) { blocked(i, 0) = true; //block displacement in x-direction blocked(i, 1) = true; //block displacement in y-direction disp(i, 0) = 0.; //fixed displacement in x-direction disp(i, 1)= 0.; //fixed displacement in y-direction } } \end{cpp} \begin{figure}[!htb] \centering \includegraphics[scale=0.4]{figures/dirichlet} \caption{Beam with fixed support.\label{fig:smm:dirichlet_bc}} \end{figure} For the more advanced approach, one needs the notion of a boundary in the mesh. Therefore, the boundary should be created before boundary condition functors can be applied. Generally the boundary can be specified from the mesh file or the geometry. For the first case, the function \code{createGroupsFromMeshData} is called. This function can read any types of mesh data which are provided in the mesh file. If the mesh file is created with Gmsh, the function takes one input strings which is either \code{tag\_0}, \code{tag\_1} or \code{physical\_names}. The first two tags are assigned by Gmsh to each element which shows the physical group that they belong to. In Gmsh, it is also possible to consider strings for different groups of elements. These elements can be separated by giving a string \code{physical\_names} to the function \code{createGroupsFromMeshData}. Boundary conditions can also be created from the geometry by calling \code{createBoundaryGroupFromGeometry}. This function gathers all the elements on the boundary of the geometry. To apply the required boundary conditions, the function \code{applyBC} needs to be called on a \code{SolidMechanicsModel}. This function gets a Dirichlet or Neumann functor and a string which specifies the desired boundary on which the boundary conditions is to be applied. The functors specify the type of conditions to apply. Three built-in functors for Dirichlet exist: \code{FlagOnly, FixedValue,} and \code{IncrementValue}. The functor \code{FlagOnly} is used if a point is fixed in a given direction. Therefore, the input parameter to this functor is only the fixed direction. The \code{FixedValue} functor is used when a displacement value is applied in a fixed direction. The \code{IncrementValue} applies an increment to the displacement in a given direction. The following code shows the utilization of three functors for the top, bottom and side surface of the mesh which were already defined in the Gmsh file: \begin{cpp} mesh.createGroupsFromMeshData<std::string>("physical_names"); model.applyBC(BC::Dirichlet::FixedValue(13.0, BC::_y), "Top"); model.applyBC(BC::Dirichlet::FlagOnly(BC::_x), "Bottom"); model.applyBC(BC::Dirichlet::IncrementValue(13.0, BC::_x), "Side"); \end{cpp} To apply a Neumann boundary condition, the applied traction or stress should be specified before. In case of specifying the traction on the surface, the functor \code{FromTraction} of Neumann boundary conditions is called. Otherwise, the functor \code{FromStress} should be called which gets the stress tensor as an input parameter. \begin{cpp} Array<Real> surface_traction(3); surface_traction(0)=0.0; surface_traction(1)=0.0; surface_traction(2)=-1.0; -Array<Real> surface_stress(3, 3, 0.0); +Matrix<Real> surface_stress(3, 3, 0.0); surface_stress(0,0)=0.0; surface_stress(1,1)=0.0; surface_stress(2,2)=-1.0; model.applyBC(BC::Neumann::FromTraction(surface_traction), "Bottom"); model.applyBC(BC::Neumann::FromStress(surface_stress), "Top"); \end{cpp} If the boundary conditions need to be removed during the simulation, a functor is called from the Neumann boundary condition to free those boundary conditions from the desired boundary. \begin{cpp} model.applyBC(BC::Neumann::FreeBoundary(), "Side"); \end{cpp} User specified functors can also be implemented. A full example for setting both initial and boundary conditions can be found in \shellcode{\examplesdir/boundary\_conditions.cc}. The problem solved in this example is shown in Fig.~\ref{fig:smm:bc_and_ic}. It consists of a plate that is fixed with movable supports on the left and bottom side. On the right side, a traction, which increases linearly with the number of time steps, is applied. The initial displacement and velocity in $x$-direction at all free nodes is zero and two respectively. \begin{figure}[!htb] \centering \includegraphics[scale=0.8]{figures/bc_and_ic_example} \caption{Plate on movable supports.\label{fig:smm:bc_and_ic}} \end{figure} \subsection{Material Selector\label{sect:smm:materialselector}} If the user wants to assign different materials to the different finite elements of choice in \akantu, a material selector has to be used. By default, \akantu assigns the first valid material in the material file to all elements present in the model (regular continuum materials are assigned to the regular elements and cohesive materials are assigned to cohesive elements or element facets). To assign different materials to specific elements, mesh data information such as tag information or specified pyhsical names can be used. \code{MeshDataMaterialSelector} class uses this information to assign different materials. With the proper physical name or tag name and index, different materials can be assigned as demonstrated in the examples below. \begin{cpp} MeshDataMaterialSelector<std::string> * mat_selector; mat_selector = new MeshDataMaterialSelector<std::string>("physical_names", model); model.setMaterialSelector(*mat_selector); \end{cpp} In this example the physical names specified in a GMSH geometry file will by used to match the material names in the input file. Another example would be: \begin{cpp} MeshDataMaterialSelector<UInt> * mat_selector; mat_selector = new MeshDataMaterialSelector<UInt>("tag_1", model); model.setMaterialSelector(*mat_selector); \end{cpp} where \code{tag\_1} of the mesh file is used as the classifier index and the elements that have index value equal to one will be assigned to the second material in the material file. There are four different material selectors pre-defined in \akantu. \code{MaterialSelector} and \code{DefaultMaterialSelector} is used to assign a material to regular elements by default. For the regular elements, as in the example above, \code{MeshDataMaterialSelector} can be used to assign different materials to different elements. However, for cohesive elements, it is not possible to assign multiple cohesive materials automatically and user has to write a custom class. \akantu has a pre-defined material selector to assign the first cohesive material by default to the cohesive elements which is called \code{DefaultMaterialCohesiveSelector} and it inherits its properties from \code{DefaultMaterialSelector}. This material selector first checks if an element is a cohesive element or a facet. If there is, then the first cohesive material in the material file is assigned to that element. Otherwise, this material is assigned to the element facet, to which, a cohesive element might be inserted later. Hence, this material selector works for the extrinsic cohesive elements which are dynamically inserted throughout the analysis. If the element of interest is not a cohesive element or an element facet, then \code{DefaultMaterialSelector} is used by default. Apart from the \akantu's default material selectors, users can always develop their own classes in the main code to tackle various multi-material assignment situations. % An application of \code{DefaultMaterialCohesiveSelector} and usage in % a customly generated material selector class can be seen in % \shellcode{\examplesdir/cohesive\_element/cohesive\_extrinsic\_IG\_TG/cohesive\_extrinsic\_IG\_TG.cc}. \IfFileExists{manual-cohesive_elements_insertion.tex}{\input{manual-cohesive_elements_insertion}}{} \section{Static Analysis\label{sect:smm:static}} The \code{SolidMechanicsModel} class can handle different analysis methods, the first one being presented is the static case. In this case, the equation to solve is \begin{equation} \label{eqn:smm:static} \mat{K} \vec{u} = \vec{f}_{\st{ext}} \end{equation} where $\mat{K}$ is the global stiffness matrix, $\vec{u}$ the displacement vector and $\vec{f}_{\st{ext}}$ the vector of external forces applied to the system. To solve such a problem, the static solver of the \code{SolidMechanicsModel}\index{SolidMechanicsModel} object is used. First, a model has to be created and initialized. To create the model, a mesh (which can be read from a file) is needed, as explained in Section~\ref{sect:common:mesh}. Once an instance of a \code{SolidMechanicsModel} is obtained, the easiest way to initialize it is to use the \code{initFull}\index{SolidMechanicsModel!initFull} method by giving the \code{SolidMechanicsModelOptions}. These options specify the type of analysis to be performed and whether the materials should be initialized or not. \begin{cpp} SolidMechanicsModel model(mesh); model.initFull(SolidMechanicsModelOptions(_static)); \end{cpp} Here, a static analysis is chosen by passing the argument \code{\_static} to the method. By default, the Boolean for no initialization of the materials is set to false, so that they are initialized during the \code{initFull}. The method \code{initFull} also initializes all appropriate vectors to zero. Once the model is created and initialized, the boundary conditions can be set as explained in Section~\ref{sect:smm:boundary}. Boundary conditions will prescribe the external forces for some free degrees of freedom $\vec{f}_{\st{ext}}$ and displacements for some others. At this point of the analysis, the function \code{solveStep}\index{SolidMechanicsModel!solveStep} can be called: \begin{cpp} model.solveStep<_scm_newton_raphson_tangent_modified, _scc_residual>(1e-4, 1); \end{cpp} This function is templated by the solving method and the convergence criterion and takes two arguments: the tolerance and the maximum number of iterations, which are $\num{1e-4}$ and $1$ for this example. The modified Newton-Raphson method is chosen to solve the system. In this method, the equilibrium equation (\ref{eqn:smm:static}) is modified in order to apply a Newton-Raphson convergence algorithm: \begin{align}\label{eqn:smm:static-newton-raphson} \mat{K}^{i+1}\delta\vec{u}^{i+1} &= \vec{r} \\ &= \vec{f}_{\st{ext}} -\vec{f}_{\st{int}}\\ &= \vec{f}_{\st{ext}} - \mat{K}^{i} \vec{u}^{i}\\ \vec{u}^{i+1} &= \vec{u}^{i} + \delta\vec{u}^{i+1}~,\nonumber \end{align} where $\delta\vec{u}$ is the increment of displacement to be added from one iteration to the other, and $i$ is the Newton-Raphson iteration counter. By invoking the \code{solveStep} method in the first step, the global stiffness matrix $\mat{K}$ from Equation~(\ref{eqn:smm:static}) is automatically assembled. A Newton-Raphson iteration is subsequently started, $\mat{K}$ is updated according to the displacement computed at the previous iteration and one loops until the forces are balanced (\code{\_scc\_residual}), \ie $||\vec{r}|| < \mbox{\code{\_scc\_residual}}$. One can also iterate until the increment of displacement is zero (\code{\_scc\_increment}) which also means that the equilibrium is found. For a linear elastic problem, the solution is obtained in one iteration and therefore the maximum number of iterations can be set to one. But for a non-linear case, one needs to iterate as long as the norm of the residual exceeds the tolerance threshold and therefore the maximum number of iterations has to be higher, e.g. $100$: \begin{cpp} model.solveStep<_scm_newton_raphson_tangent_modified,_scc_residual>(1e-4, 100) \end{cpp} At the end of the analysis, the final solution is stored in the \textbf{displacement} vector. A full example of how to solve a static problem is presented in the code \code{\examplesdir/static/static.cc}. This example is composed of a 2D plate of steel, blocked with rollers on the left and bottom sides as shown in Figure \ref{fig:smm:static}. The nodes from the right side of the sample are displaced by $0.01\%$ of the length of the plate. \begin{figure}[!htb] \centering \includegraphics[scale=1.05]{figures/static} \caption{Numerical setup\label{fig:smm:static}} \end{figure} The results of this analysis is depicted in Figure~\ref{fig:smm:implicit:static_solution}. \begin{figure}[!htb] \centering \includegraphics[width=.7\linewidth]{figures/static_analysis} \caption{Solution of the static analysis. Left: the initial condition, right: the solution (deformation magnified 50 times)} \label{fig:smm:implicit:static_solution} \end{figure} \section{Dynamic Methods} \label{sect:smm:Dynamic_methods} Different ways to solve the equations of motion are implemented in the solid mechanics model. The complete equations that should be solved are: \begin{equation} \label{eqn:equation-motion} \mat{M}\ddot{\vec{u}} + \mat{C}\dot{\vec{u}} + \mat{K}\vec{u} = \vec{f}_{\st{ext}}~, \end{equation} where $\mat{M}$, $\mat{C}$ and $\mat{K}$ are the mass, damping and stiffness matrices, respectively. In the previous section, it has already been discussed how to solve this equation in the static case, where $\ddot{\vec{u}} = \dot{\vec{u}} = 0$. Here the method to solve this equation in the general case will be presented. For this purpose, a time discretization has to be specified. The most common discretization method in solid mechanics is the Newmark-$\beta$ method, which is also the default in \akantu. For the Newmark-$\beta$ method, (\ref{eqn:equation-motion}) becomes a system of three equations (see \cite{curnier92a} \cite{hughes-83a} for more details): \begin{align} \mat{M} \ddot{\vec{u}}_{n+1} + \mat{C}\dot{\vec{u}}_{n+1} + \mat{K} \vec{u}_{n+1} &={\vec{f}_{\st{ext}}}_{\, n+1} \label{eqn:equation-motion-discret} \\ \vec{u}_{n+1} &=\vec{u}_{n} + \left(1 - \alpha\right) \Delta t \dot{\vec{u}}_{n} + \alpha \Delta t \dot{\vec{u}}_{n+1} + \left(\frac{1}{2} - \alpha\right) \Delta t^2 \ddot{\vec{u}}_{n} \label{eqn:finite-difference-1}\\ \dot{\vec{u}}_{n+1} &= \dot{\vec{u}}_{n} + \left(1 - \beta\right) \Delta t \ddot{\vec{u}}_{n} + \beta \Delta t \ddot{\vec{u}}_{n+1} \label{eqn:finite-difference-2} \end{align} In these new equations, $\ddot{\vec{u}}_{n}$, $\dot{\vec{u}}_{n}$ and $\vec{u}_{n}$ are the approximations of $\ddot{\vec{u}}(t_n)$, $\dot{\vec{u}}(t_n)$ and $\vec{u}(t_n)$. Equation~(\ref{eqn:equation-motion-discret}) is the equation of motion discretized in space (finite-element discretization), and equations (\ref{eqn:finite-difference-1}) and (\ref{eqn:finite-difference-2}) are discretized in both space and time (Newmark discretization). The $\alpha$ and $\beta$ parameters determine the stability and the accuracy of the algorithm. Classical values for $\alpha$ and $\beta$ are usually $\beta = 1/2$ for no numerical damping and $0 < \alpha < 1/2$. \begin{center} \begin{tabular}{cll} \toprule $\alpha$ & Method ($\beta = 1/2$) & Type\\ \midrule $0$ & central difference & explicit\\ $1/6$ & Fox-Goodwin (royal road) &implicit\\ $1/3$ & Linear acceleration &implicit\\ $1/2$ & Average acceleration (trapezoidal rule)& implicit\\ \bottomrule \end{tabular} \end{center} The solution of this system of equations, (\ref{eqn:equation-motion-discret})-(\ref{eqn:finite-difference-2}) is split into a predictor and a corrector system of equations. Moreover, in the case of a non-linear equations, an iterative algorithm such as the Newton-Raphson method is applied. The system of equations can be written as: \begin{enumerate} \item \textit{Predictor:} \begin{align} \vec{u}_{n+1}^{0} &= \vec{u}_{n} + \Delta t \dot{\vec{u}}_{n} + \frac{\Delta t^2}{2} \ddot{\vec{u}}_{n} \\ \dot{\vec{u}}_{n+1}^{0} &= \dot{\vec{u}}_{n} + \Delta t \ddot{\vec{u}}_{n} \\ \ddot{\vec{u}}_{n+1}^{0} &= \ddot{\vec{u}}_{n} \end{align} \item \textit{Solve:} \begin{align} \left(c \mat{M} + d \mat{C} + e \mat{K}_{n+1}^i\right) \vec{w} = {\vec{f}_{\st{ext}}}_{\,n+1} - {\vec{f}_{\st{int}}}_{\,n+1}^i - \mat{C} \dot{\vec{u}}_{n+1}^i - \mat{M} \ddot{\vec{u}}_{n+1}^i = \vec{r}_{n+1}^i \end{align} \item \textit{Corrector:} \begin{align} \ddot{\vec{u}}_{n+1}^{i+1} &= \ddot{\vec{u}}_{n+1}^{i} +c \vec{w} \\ \dot{\vec{u}}_{n+1}^{i+1} &= \dot{\vec{u}}_{n+1}^{i} + d\vec{w} \\ \vec{u}_{n+1}^{i+1} &= \vec{u}_{n+1}^{i} + e \vec{w} \end{align} \end{enumerate} where $i$ is the Newton-Raphson iteration counter and $c$, $d$ and $e$ are parameters depending on the method used to solve the equations \begin{center} \begin{tabular}{lcccc} \toprule & $\vec{w}$ & $e$ & $d$ & $c$\\ \midrule in acceleration &$ \delta\ddot{\vec{u}}$ & $\alpha \beta\Delta t^2$ &$\beta \Delta t$ &$1$\\ in velocity & $ \delta\dot{\vec{u}}$& $\frac{1}{\beta} \Delta t$ & $1$ & $\alpha\Delta t$\\ in displacement &$\delta\vec{u}$ & $ 1$ & $\frac{1}{\alpha} \Delta t$ & $\frac{1}{\alpha \beta} \Delta t^2$\\ \bottomrule \end{tabular} \end{center} %\note{If you want to use the implicit solver \akantu should be compiled at least with one sparse matrix solver such as Mumps\cite{mumps}.} \subsection{Implicit Time Integration} To solve a problem with an implicit time integration scheme, first a \code{SolidMechanicsModel} object has to be created and initialized. Then the initial and boundary conditions have to be set. Everything is similar to the example in the static case (Section~\ref{sect:smm:static}), however, in this case the implicit dynamic scheme is selected at the initialization of the model. \begin{cpp} SolidMechanicsModel model(mesh); model.initFull(SolidMechanicsModelOptions(_implicit_dynamic)); /*Boundary conditions see Section~%\ref{sect:smm:boundary}% */ \end{cpp} Because a dynamic simulation is conducted, an integration time step $\Delta t$ has to be specified. In the case of implicit simulations, \akantu implements a trapezoidal rule by default. That is to say $\alpha = 1/2$ and $\beta = 1/2$ which is unconditionally stable. Therefore the value of the time step can be chosen arbitrarily within reason. \index{SolidMechanicsModel!setTimeStep} \begin{cpp} model.setTimeStep(time_step); \end{cpp} Since the system has to be solved for a given amount of time, the method \code{solveStep()}, (which has already been used in the static example in Section~\ref{sect:smm:static}), is called inside a time loop: \begin{cpp} /// time loop Real time = 0.; for (UInt s = 1; time <max_time; ++s, time += time_step) { model.solveStep<_scm_newton_raphson_tangent_modified,_scc_increment>(1e-12, 100); } \end{cpp} An example of solid mechanics with an implicit time integration scheme is presented in \shellcode{\examplesdir/implicit/implicit\_dynamic.cc}. This example consists of a 3D beam of $\SI{10}{\metre}\,\times\,\SI{1}{\metre}\,\times\,\SI{1}{\metre}$ blocked on one side and is on a roller on the other side. A constant force of \SI{5}{\kilo\newton} is applied in its middle. Figure~\ref{fig:smm:implicit:dynamic} presents the geometry of this case. The material used is a fictitious linear elastic material with a density of \SI{1000}{\kilo\gram\per\cubic\metre}, a Young's Modulus of \SI{120}{\mega\pascal} and Poisson's ratio of $0.3$. These values were chosen to simplify the analytical solution. An approximation of the dynamic response of the middle point of the beam is given by: \begin{equation} \label{eqn:smm:implicit} u\left(\frac{L}{2}, t\right) = \frac{1}{\pi^4} \left(1 - cos\left(\pi^2 t\right) + \frac{1}{81}\left(1 - cos\left(3^2 \pi^2 t\right)\right) + \frac{1}{625}\left(1 - cos\left(5^2 \pi^2 t\right)\right)\right) \end{equation} \begin{figure}[!htb] \centering \includegraphics[scale=.6]{figures/implicit_dynamic} \caption{Numerical setup} \label{fig:smm:implicit:dynamic} \end{figure} Figure \ref{fig:smm:implicit:dynamic_solution} presents the deformed beam at 3 different times during the simulation: time steps 0, 1000 and 2000. \begin{figure}[!htb] \centering \setlength{\unitlength}{0.1\textwidth} \begin{tikzpicture} \node[above right] (img) at (0,0) {\includegraphics[width=.6\linewidth]{figures/dynamic_analysis}}; \node[left] at (0pt,20pt) {$0$}; \node[left] at (0pt,60pt) {$1000$}; \node[left] at (0pt,100pt) {$2000$}; \end{tikzpicture} \caption{Deformed beam at 3 different times (displacement are magnified by a factor 10).} \label{fig:smm:implicit:dynamic_solution} \end{figure} \subsection{Explicit Time Integration} \label{ssect:smm:expl-time-integr} The explicit dynamic time integration scheme is based on the Newmark-$\beta$ scheme with $\alpha=0$ (see equations \ref{eqn:equation-motion-discret}-\ref{eqn:finite-difference-2}). In \akantu, $\beta$ is defaults to $\beta=1/2$, see section \ref{sect:smm:Dynamic_methods}. The initialization of the simulation is similar to the static and implicit dynamic version. The model is created from the \code{SolidMechanicsModel} class. In the initialization, the explicit scheme is selected using the \code{\_explicit\_lumped\_mass} constant. \begin{cpp} SolidMechanicsModel model(mesh); model.initFull(SolidMechanicsModelOptions(_explicit_lumped_mass)); \end{cpp} \index{SolidMechanicsModel!initFull} \note{Writing \code{model.initFull()} or \code{model.initFull(SolidMechanicsModelOptions());} is equivalent to use the \code{\_explicit\_lumped\_mass} keyword, as this is the default case.} The explicit time integration scheme implemented in \akantu uses a lumped mass matrix $\mat{M}$ (reducing the computational cost). This matrix is assembled by distributing the mass of each element onto its nodes. The resulting $\mat{M}$ is therefore a diagonal matrix stored in the \textbf{mass} vector of the model. The explicit integration scheme is conditionally stable. The time step has to be smaller than the stable time step which is obtained in \akantu as follows: \begin{cpp} time_step = model.getStableTimeStep(); \end{cpp} \index{SolidMechanicsModel!StableTimeStep} The stable time step is defined as: \begin{equation} \label{eqn:smm:explicit:stabletime} \Delta t_{\st{crit}} = \Delta x \sqrt{\frac{\rho}{2 \mu + \lambda}} \end{equation} where $\Delta x$ is a characteristic length (\eg the inradius in the case of linear triangle element), $\mu$ and $\lambda$ are the first and second Lame's coefficients and $\rho$ is the density. The stable time step corresponds to the time the fastest wave (the compressive wave) needs to travel the characteristic length of the mesh. However, it is recommended to impose a time step that is smaller than the stable time step, for instance, by multiplying the stable time step by a safety factor smaller than one. \begin{cpp} const Real safety_time_factor = 0.8; Real applied_time_step = time_step * safety_time_factor; model.setTimeStep(applied_time_step); \end{cpp} \index{SolidMechanicsModel!setTimeStep} The initial displacement and velocity fields are, by default, equal to zero if not given specifically by the user (see \ref{sect:smm:initial_condition}). Like in implicit dynamics, a time loop is used in which the displacement, velocity and acceleration fields are updated at each time step. The values of these fields are obtained from the Newmark$-\beta$ equations with $\beta=1/2$ and $\alpha=0$. In \akantu these computations at each time step are invoked by calling the function \code{solveStep}: \begin{cpp} for (UInt s = 1; (s-1)*applied_time_step < total_time; ++s) { model.solveStep(); } \end{cpp} \index{SolidMechanicsModel!solveStep} The method \code{solveStep} wraps the four following functions: \begin{itemize} \item \code{model.explicitPred()} allows to compute the displacement field at $t+1$ and a part of the velocity field at $t+1$, denoted by $\vec{\dot{u}^{\st{p}}}_{n+1}$, which will be used later in the method \code{model.explicitCorr()}. The equations are: \begin{align} \vec{u}_{n+1} &= \vec{u}_{n} + \Delta t \vec{\dot{u}}_{n} + \frac{\Delta t^2}{2} \vec{\ddot{u}}_{n}\\ \vec{\dot{u}^{\st{p}}}_{n+1} &= \vec{\dot{u}}_{n} + \Delta t \vec{\ddot{u}}_{n} \label{eqn:smm:explicit:onehalfvelocity} \end{align} \item \code{model.updateResidual()} and \code{model.updateAcceleration()} compute the acceleration increment $\delta \vec{\ddot{u}}$: \begin{equation} \left(\mat{M} + \frac{1}{2} \Delta t \mat{C}\right) \delta \vec{\ddot{u}} = \vec{f_{\st{ext}}} - \vec{f}_{\st{int}\, n+1} - \mat{C} \vec{\dot{u}}_{n} - \mat{M} \vec{\ddot{u}}_{n} \end{equation} \note{The internal force $\vec{f}_{\st{int}\, n+1}$ is computed from the displacement $\vec{u}_{n+1}$ based on the constitutive law.} \item \code{model.explicitCorr()} computes the velocity and acceleration fields at $t+1$: \begin{align} \vec{\dot{u}}_{n+1} &= \vec{\dot{u}^{\st{p}}}_{n+1} + \frac{\Delta t}{2} \delta \vec{\ddot{u}} \\ \vec{\ddot{u}}_{n+1} &= \vec{\ddot{u}}_{n} + \delta \vec{\ddot{u}} \end{align} \end{itemize} The use of an explicit time integration scheme is illustrated by the example:\par \noindent \shellcode{\examplesdir/explicit/explicit\_dynamic.cc}\par \noindent This example models the propagation of a wave in a steel beam. The beam and the applied displacement in the $x$ direction are shown in Figure~\ref{fig:smm:explicit}. \begin{figure}[!htb] \centering \begin{tikzpicture} \coordinate (c) at (0,2); \draw[shift={(c)},thick, color=blue] plot [id=x, domain=-5:5, samples=50] ({\x, {(40 * sin(0.1*pi*3*\x) * exp(- (0.1*pi*3*\x)*(0.1*pi*3*\x) / 4))}}); \draw[shift={(c)},-latex] (-6,0) -- (6,0) node[right, below] {$x$}; \draw[shift={(c)},-latex] (0,-0.7) -- (0,1) node[right] {$u$}; \draw[shift={(c)}] (-0.1,0.6) node[left] {$A$}-- (1.5,0.6); \coordinate (l) at (0,0.6); \draw[shift={(0,-0.7)}] (-5, 0) -- (5,0) -- (5, 1) -- (-5, 1) -- cycle; \draw[shift={(l)}, latex-latex] (-5,0)-- (5,0) node [midway, above] {$L$}; \draw[shift={(l)}] (5,0.2)-- (5,-0.2); \draw[shift={(l)}] (-5,0.2)-- (-5,-0.2); \coordinate (h) at (5.3,-0.7); \draw[shift={(h)}, latex-latex] (0,0)-- (0,1) node [midway, right] {$h$}; \draw[shift={(h)}] (-0.2,1)-- (0.2,1); \draw[shift={(h)}] (-0.2,0)-- (0.2,0); \end{tikzpicture} \caption{Numerical setup \label{fig:smm:explicit}} \end{figure} The length and height of the beam are $L=\SI{10}{\metre}$ and $h = \SI{1}{\metre}$, respectively. The material is linear elastic, homogeneous and isotropic (density: \SI{7800}{\kilo\gram\per\cubic\metre}, Young's modulus: \SI{210}{\giga\pascal} and Poisson's ratio: $0.3$). The imposed displacement follow a Gaussian function with a maximum amplitude of $A = \SI{0.01}{\meter}$. The potential, kinetic and total energies are computed. The safety factor is equal to $0.8$. \input{manual-constitutive-laws} \section{Adding a New Constitutive Law}\index{Material!create a new material} There are several constitutive laws in \akantu as described in the previous Section~\ref{sect:smm:CL}. It is also possible to use a user-defined material for the simulation. These materials are referred to as local materials since they are local to the example of the user and not part of the \akantu library. To define a new local material, two files (\code {material\_XXX.hh} and \code{material\_XXX.cc}) have to be provided where \code{XXX} is the name of the new material. The header file \code {material\_XXX.hh} defines the interface of your custom material. Its implementation is provided in the \code{material\_XXX.cc}. The new law must inherit from the \code{Material} class or any other existing material class. It is therefore necessary to include the interface of the parent material in the header file of your local material and indicate the inheritance in the declaration of the class: \begin{cpp} /* ---------------------------------------------------------------------- */ #include "material.hh" /* ---------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_XXX_HH__ #define __AKANTU_MATERIAL_XXX_HH__ __BEGIN_AKANTU__ class MaterialXXX : public Material { /// declare here the interface of your material }; \end{cpp} In the header file the user also needs to declare all the members of the new material. These include the parameters that a read from the material input file, as well as any other material parameters that will be computed during the simulation and internal variables.\\ In the following the example of adding a new damage material will be presented. In this case the parameters in the material will consist of the Young's modulus, the Poisson coefficient, the resistance to damage and the damage threshold. The material will then from these values compute its Lam\'{e} coefficients and its bulk modulus. Furthermore, the user has to add a new internal variable \code{damage} in order to store the amount of damage at each quadrature point in each step of the simulation. For this specific material the member declaration inside the class will look as follows: \begin{cpp} class LocalMaterialDamage : public Material { /// declare constructors/destructors here /// declare methods and accessors here /* -------------------------------------------------------------------- */ /* Class Members */ /* -------------------------------------------------------------------- */ AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real); private: /// the young modulus Real E; /// Poisson coefficient Real nu; /// First Lame coefficient Real lambda; /// Second Lame coefficient (shear modulus) Real mu; /// resistance to damage Real Yd; /// damage threshold Real Sd; /// Bulk modulus Real kpa; /// damage internal variable InternalField<Real> damage; }; \end{cpp} In order to enable to print the material parameters at any point in the user's example file using the standard output stream by typing: \begin{cpp} for (UInt m = 0; m < model.getNbMaterials(); ++m) std::cout << model.getMaterial(m) << std::endl; \end{cpp} the standard output stream operator has to be redefined. This should be done at the end of the header file: \begin{cpp} class LocalMaterialDamage : public Material { /// declare here the interace of your material }: /* ---------------------------------------------------------------------- */ /* inline functions */ /* ---------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const LocalMaterialDamage & _this) { _this.printself(stream); return stream; } \end{cpp} However, the user still needs to register the material parameters that should be printed out. The registration is done during the call of the constructor. Like all definitions the implementation of the constructor has to be written in the \code{material\_XXX.cc} file. However, the declaration has to be provided in the \code{material\_XXX.hh} file: \begin{cpp} class LocalMaterialDamage : public Material { /* -------------------------------------------------------------------- */ /* Constructors/Destructors */ /* -------------------------------------------------------------------- */ public: LocalMaterialDamage(SolidMechanicsModel & model, const ID & id = ""); }; \end{cpp} The user can now define the implementation of the constructor in the \code{material\_XXX.cc} file: \begin{cpp} /* ---------------------------------------------------------------------- */ #include "local_material_damage.hh" #include "solid_mechanics_model.hh" __BEGIN_AKANTU__ /* ---------------------------------------------------------------------- */ LocalMaterialDamage::LocalMaterialDamage(SolidMechanicsModel & model, const ID & id) : Material(model, id), damage("damage", *this) { AKANTU_DEBUG_IN(); this->registerParam("E", E, 0., _pat_parsable, "Young's modulus"); this->registerParam("nu", nu, 0.5, _pat_parsable, "Poisson's ratio"); this->registerParam("lambda", lambda, _pat_readable, "First Lame coefficient"); this->registerParam("mu", mu, _pat_readable, "Second Lame coefficient"); this->registerParam("kapa", kpa, _pat_readable, "Bulk coefficient"); this->registerParam("Yd", Yd, 50., _pat_parsmod); this->registerParam("Sd", Sd, 5000., _pat_parsmod); damage.initialize(1); AKANTU_DEBUG_OUT(); } \end{cpp} During the intializer list the reference to the model and the material id are assigned and the constructor of the internal field is called. Inside the scope of the constructor the internal values have to be initialized and the parameters, that should be printed out, are registered with the function: \code{registerParam}\index{Material!registerParam}: \begin{cpp} void registerParam(name of the parameter (key in the material file), member variable, default value (optional parameter), access permissions, description); \end{cpp} The available access permissions are as follows: \begin{itemize} \item \code{\_pat\_internal}: Parameter can only be output when the material is printed. \item \code{\_pat\_writable}: User can write into the parameter. The parameter is output when the material is printed. \item \code{\_pat\_readable}: User can read the parameter. The parameter is output when the material is printed. \item \code{\_pat\_modifiable}: Parameter is writable and readable. \item \code{\_pat\_parsable}: Parameter can be parsed, \textit{i.e.} read from the input file. \item \code{\_pat\_parsmod}: Parameter is modifiable and parsable. \end{itemize} In order to implement the new constitutive law the user needs to specify how the additional material parameters, that are not defined in the input material file, should be calculated. Furthermore, it has to be defined how stresses and the stable time step should be computed for the new local material. In the case of implicit simulations, in addition, the computation of the tangent stiffness needs to be defined. Therefore, the user needs to redefine the following functions of the parent material: \begin{cpp} void initMaterial(); // for explicit and implicit simulations void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost); // for implicit simulations void computeTangentStiffness(const ElementType & el_type, Array<Real> & tangent_matrix, GhostType ghost_type = _not_ghost); // for explicit and implicit simulations Real getStableTimeStep(Real h, const Element & element); \end{cpp} In the following a detailed description of these functions is provided: \begin{itemize} \item \code{initMaterial}:~ This method is called after the material file is fully read and the elements corresponding to each material are assigned. Some of the frequently used constant parameters are calculated in this method. For example, the Lam\'{e} constants of elastic materials can be considered as such parameters. \item \code{computeStress}:~ In this method, the stresses are computed based on the constitutive law as a function of the strains of the quadrature points. For example, the stresses for the elastic material are calculated based on the following formula: \begin{equation} \label{eqn:smm:constitutive_elastic} \mat{\sigma } =\lambda\mathrm{tr}(\mat{\varepsilon})\mat{I}+2 \mu \mat{\varepsilon} \end{equation} Therefore, this method contains a loop on all quadrature points assigned to the material using the two macros:\par \code{MATERIAL\_STRESS\_QUADRATURE\_POINT\_LOOP\_BEGIN}\par \code{MATERIAL\_STRESS\_QUADRATURE\_POINT\_LOOP\_END} \begin{cpp} MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(element_type); // sigma <- f(grad_u) MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END; \end{cpp} \note{The strain vector in \akantu contains the values of $\nabla \vec{u}$, i.e. it is really the \emph{displacement gradient},} \item \code{computeTangentStiffness}:~ This method is called when the tangent to the stress-strain curve is desired (see Fig \ref {fig:smm:AL:K}). For example, it is called in the implicit solver when the stiffness matrix for the regular elements is assembled based on the following formula: \begin{equation} \label{eqn:smm:constitutive_elasc} \mat{K } =\int{\mat{B^T}\mat{D(\varepsilon)}\mat{B}} \end{equation} Therefore, in this method, the \code{tangent} matrix (\mat{D}) is computed for a given strain. \note{ The \code{tangent} matrix is a $4^{th}$ order tensor which is stored as a matrix in Voigt notation.} \begin{figure}[!htb] \begin{center} \includegraphics[width=0.4\textwidth,keepaspectratio=true]{figures/tangent.pdf} \caption{Tangent to the stress-strain curve.} \label{fig:smm:AL:K} \end{center} \end{figure} \item \code{getStableTimeStep}:~ The stable time step should be calculated based on \eqref{eqn:smm:explicit:stabletime} for the conditionally stable methods. This function depends on the longitudinal wave speed which changes for different materials and strains. Therefore, the value of this velocity should be defined in this method for each new material. \note {In case of need, the calculation of the longitudinal and shear wave speeds can be done in separate functions (\code{getPushWaveSpeed} and \code{getShearWaveSpeed}). Therefore, the first function can be called for calculation of the stable time step.} \end{itemize} Once the declaration and implementation of the new material has been completed, this material can be used in the user's example by including the header file: \begin{cpp} #include "material_XXX.hh" \end{cpp} For existing materials, as mentioned in Section~\ref{sect:smm:CL}, by default, the materials are initialized inside the method \code{initFull}. If a local material should be used instead, the initialization of the material has to be postponed until the local material is registered in the model. Therefore, the model is initialized with the boolean for skipping the material initialization equal to true: \begin{cpp} /// model initialization model.initFull(SolidMechanicsModelOptions(_explicit_lumped_mass,true)); \end{cpp} Once the model has been initialized, the local material needs to be registered in the model: \begin{cpp} model.registerNewCustomMaterials<XXX>("name_of_local_material"); \end{cpp} Only at this point the material can be initialized: \begin{cpp} model.initMaterials(); \end{cpp} A full example for adding a new damage law can be found in \shellcode{\examplesdir/new\_material}. %%% Local Variables: %%% mode: latex %%% TeX-master: "manual" %%% End: diff --git a/doc/manual/manual-structuralmechanicsmodel.tex b/doc/manual/manual-structuralmechanicsmodel.tex index 1c73c6712..145c28d1a 100644 --- a/doc/manual/manual-structuralmechanicsmodel.tex +++ b/doc/manual/manual-structuralmechanicsmodel.tex @@ -1,251 +1,249 @@ \chapter{Structural Mechanics Model} Static structural mechanics problems can be handled using the -\code{StructuralMechanicsModel}. So far, \akantu\ provides 2D and 3D -Bernoulli beam elements \cite{frey2009}. Just as for the -\code{SolidMechanicsModel}, this model is created for a given -\code{Mesh}. The model will create its own \code{FEEngine} object to +class \code{StructuralMechanicsModel}. So far, \akantu provides 2D and 3D +Bernoulli beam elements \cite{frey2009}. This model is instantiated for a given +\code{Mesh}, as for the \code{SolidMechanicsModel}. The model will create its own \code{FEEngine} object to compute the interpolation, gradient, integration and assembly operations. The \code{StructuralMechanicsModel} constructor is called in the following way: \begin{cpp} StructuralMechanicsModel model(mesh, spatial_dimension); \end{cpp} where \code{mesh} is a \code{Mesh} object defining the structure for which the equations of statics are to be solved, and \code{spatial\_dimension} is the dimensionality of the problem. If \code{spatial\_dimension} is omitted, the problem is assumed to have the same dimensionality as the one specified by the mesh. \note[\ 1]{Dynamic computations are not supported to date.} \note[\ 2]{Structural meshes are created and loaded as described in Section~\ref{sect:common:mesh} with \code{MeshIOMSHStruct} instead of \code{MeshIOMSH}.} \vspace{1cm} This model contains at least the following \code{Arrays}: \begin{description} \item[blocked\_dofs] contains a Boolean value for each degree of freedom specifying whether that degree is blocked or not. A Dirichlet boundary condition can be prescribed by setting the \textbf{blocked\_dofs} value of a degree of freedom to \code{true}. The \textbf{displacement} is computed for all degrees of freedom for which the \textbf{blocked\_dofs} value is set to \code{false}. For the remaining degrees of freedom, the imposed values (zero by default after initialization) are kept. \item[displacement\_rotation] contains the generalized displacements (\textit{i.e.} displacements and rotations) of all degrees of freedom. It can be either a computed displacement for free degrees of freedom or an imposed displacement in case of blocked ones ($\vec{u}$ in the following). \item[force\_moment] contains the generalized external forces (forces and moments) applied to the nodes ($\vec{f_{\st{ext}}}$ in the following). \item[residual] contains the difference between the generalized external and internal forces and moments. On the blocked degrees of freedom, \textbf{residual} contains the support reactions ($\vec{r}$ in the following). It should be mentioned that, at equilibrium, \textbf{residual} should be zero on the free degrees of freedom. \end{description} An example to help understand how to use this model will be presented in the next section. \section{Model Setup} \label{sec:structMechMod:setup} \subsection{Initialization} The easiest way to initialize the structural mechanics model is: \begin{cpp} model.initFull(); \end{cpp} The method \code{initFull} computes the shape functions, initializes the internal vectors mentioned above and allocates the memory for the stiffness matrix. Material properties are defined using the \code{StructuralMaterial} structure described in Table~\ref{tab:structMechMod:strucMaterial}. Such a definition could, for instance, look like \begin{cpp} StructuralMaterial mat1; mat.E=3e10; mat.I=0.0025; mat.A=0.01; \end{cpp} \begin{table}[htb] \centering \begin{tabular}{cl} \toprule Field & Description \\ \midrule \code{E} & Young's modulus \\ \code{A} & Cross section area \\ \code{I} & Second cross sectional moment of inertia (for 2D elements)\\ \code{Iy} & \code{I} around beam $y$--axis (for 3D elements)\\ \code{Iz} & \code{I} around beam $z$--axis (for 3D elements)\\ \code{GJ} & Polar moment of inertia of beam cross section (for 3D elements)\\ \bottomrule \end{tabular} - \caption{Material properties for structural elements as defined by -the structure \code{StructuralMaterial}.} + \caption{Material properties for structural elements defined in +the class \code{StructuralMaterial}.} \label{tab:structMechMod:strucMaterial} \end{table} Materials can be added to the model's \code{element\_material} vector using \begin{cpp} model.addMaterial(mat1); \end{cpp} They are successively numbered and then assigned to specific elements. \begin{cpp} for (UInt i = 0; i < nb_element_mat_1; ++i) { model.getElementMaterial(_bernoulli_beam_2)(i,0) = 1; } \end{cpp} \subsection{Setting Boundary Conditions}\label{sect:structMechMod:boundary} -As explained before, the Dirichlet boundary conditions are applied -through the array \textbf{blocked\_dofs}. Two options exist to define -Neumann conditions. If a nodal force is applied, it has to be -directly set in the array \textbf{force\_momentum}. For loads -distributed along the beam length, the method -\code{computeForcesFromFunction} integrates them into nodal forces. -The method takes as input a function describing the distribution of -loads along the beam and a \code{BoundaryFunctionType} specifing if -the function is expressed in the local coordinates -(\code{\_bft\_traction\_local}) or in the global system of coordinates -(\code{\_bft\_traction}). + +As explained before, the Dirichlet boundary conditions are applied through the +array \textbf{blocked\_dofs}. Two options exist to define Neumann conditions. +If a nodal force is applied, it has to be directly set in the array +\textbf{force\_momentum}. For loads distributed along the beam length, the +method \code{computeForcesFromFunction} integrates them into nodal forces. The +method takes as input a function describing the distribution of loads along the +beam and a functor \code{BoundaryFunctionType} specifing if the function is +expressed in the local coordinates (\code{\_bft\_traction\_local}) or in the +global system of coordinates (\code{\_bft\_traction}). \begin{cpp} static void lin_load(double * position, double * load, Real * normal, UInt surface_id){ memset(load,0,sizeof(Real)*3); load[1] = position[0]*position[0]-250; } int main(int argc, char *argv[]){ ... model.computeForcesFromFunction<_bernoulli_beam_2>(lin_load, _bft_traction_local); ...} \end{cpp} \section{Static Analysis\label{sect:structMechMod:static}} The \code{StructuralMechanicsModel} class can perform static analyses of structures. In this case, the equation to solve is the same as for the \code{SolidMechanicsModel} used for static analyses \begin{equation}\label{eqn:structMechMod:static} \mat{K} \vec{u} = \vec{f_{\st{ext}}}~, \end{equation} where $\mat{K}$ is the global stiffness matrix, $\vec{u}$ the generalized displacement vector and $\vec{f_{\st{ext}}}$ the vector of generalized external forces applied to the system. To solve such a problem, the static solver of the \code{StructuralMechanicsModel}\index{StructuralMechanicsModel} object is used. First a model has to be created and initialized. \begin{cpp} StructuralMechanicsModel model(mesh); model.initFull(); \end{cpp} \begin{itemize} \item \code{model.initFull} initializes all internal vectors to zero. \end{itemize} Once the model is created and initialized, the boundary conditions can be set as explained in Section~\ref{sect:structMechMod:boundary}. Boundary conditions will prescribe the external forces or moments for the free degrees of freedom $\vec{f_{\st{ext}}}$ and displacements or rotations for the others. To completely define the system represented by equation (\ref{eqn:structMechMod:static}), the global stiffness matrix $\mat{K}$ must be assembled. \index{StructuralMechanicsModel!assembleStiffnessMatrix} \begin{cpp} model.assembleStiffnessMatrix(); \end{cpp} The computation of the static equilibrium is performed using the same Newton-Raphson algorithm as described in Section~\ref{sect:smm:static}. \note{To date, \code{StructuralMechanicsModel} handles only constitutively and geometrically linear problems, the algorithm is therefore guaranteed to converge in two iterations.} \begin{cpp} model.updateResidual(); model.solve(); \end{cpp} \index{StructuralMechanicsModel!updateResidual} \index{StructuralMechanicsModel!solve} \begin{itemize} \item \code{model.updateResidual} assembles the internal forces and removes them from the external forces. \item \code{model.solve} solves the Equation (\ref{eqn:structMechMod:static}). The \textbf{increment} vector of the model will contain the new increment of displacements, and the \textbf{displacement\_rotation} vector is also updated to the new displacements. \end{itemize} %At the end of the analysis, the final solution is stored in the %\textbf{displacement} vector. A full example of how to solve a %structural mechanics problem is presented in the code %\shellcode{\examplesdir/structural\_mechanics/test\_structural\_mechanics\_model\_bernoulli\_beam\_2\_exemple\_1\_1.cc}. %This example is composed of a 2D beam, clamped at the left end and %supported by two rollers as shown in Figure %\ref{fig:structMechMod:exem1_1}. The problem is defined by the %applied load $q=\SI{6}{\kilo\newton\per\metre}$, moment $\bar{M} = %\SI{3.6}{\kilo\newton\metre}$, moments of inertia $I_1 = %\SI{250\,000}{\power{\centi\metre}{4}}$ and $I_2 = %\SI{128\,000}{\power{\centi\metre}{4}}$ and lengths $L_1 = %\SI{10}{\metre}$ and $L_2 = \SI{8}{\metre}$. The resulting %rotations at node two and three are $ \varphi_2 = 0.001\,167\ %\mbox{and}\ \varphi_3 = -0.000\,771.$ At the end of the analysis, the final solution is stored in the \textbf{displacement\_rotation} vector. A full example of how to solve a structural mechanics problem is presented in the code \shellcode{\examplesdir/structural\_mechanics/bernoulli\_beam\_2\_example.cc}. This example is composed of a 2D beam, clamped at the left end and supported by two rollers as shown in Figure \ref{fig:structMechMod:exem1_1}. The problem is defined by the applied load $q=\SI{6}{\kilo\newton\per\metre}$, moment $\bar{M} = \SI{3.6}{\kilo\newton\metre}$, moments of inertia $I_1 = \SI{250\,000}{\centi\metre\tothe{4}}$ and $I_2 = \SI{128\,000}{\centi\metre\tothe{4}}$ and lengths $L_1 = \SI{10}{\metre}$ and $L_2 = \SI{8}{\metre}$. The resulting rotations at node two and three are $ \varphi_2 = 0.001\,167\ \mbox{and}\ \varphi_3 = -0.000\,771.$ \begin{figure}[htb] \centering \includegraphics[scale=1.1]{figures/beam_example} \caption{2D beam example} \label{fig:structMechMod:exem1_1} \end{figure} %%% Local Variables: %%% mode: latex %%% TeX-master: "manual" %%% End: diff --git a/doc/manual/manual.sty b/doc/manual/manual.sty index 6855a85ab..36dcb2425 100644 --- a/doc/manual/manual.sty +++ b/doc/manual/manual.sty @@ -1,312 +1,328 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% LaTeX STYLE SHEET for AKANTU DOCUMENTATION %% %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % Geometry \usepackage{a4wide} \usepackage{geometry} \geometry{ pdftex=true, twoside=true, margin=20mm, bottom=20mm, top=20mm, bindingoffset=5.5mm } % Font encoding \usepackage[T1]{fontenc} \usepackage{palatino} % Line spacing \linespread{1.05}\selectfont % Allow spaces to be added at the end of macro \usepackage{xspace} % Mathematics (including correct font encoding, after amsmath) \usepackage{amsmath} \usepackage{amssymb} \usepackage{pxfonts} \setlength\mathindent{2em} % Some unit stuff \usepackage{siunitx} % Easy tables \usepackage{booktabs} \usepackage{longtable} \usepackage{rotating} % For sideways tables \usepackage{multirow} % For larger cells % A special environment for element tables \newcommand\elemline{}%{\noalign{\smallskip}\hline\noalign{\smallskip}} \newcommand\elemcooroned{\ensuremath{\left(\xi\right)}} \newcommand\elemcoortwod{\ensuremath{\left(\xi\;,\;\eta\right)}} \newcommand\elemcoorthreed{\ensuremath{\left(\xi\;,\;\eta\;,\;\zeta\right)}} \newcommand\elemdshapeoned{\ensuremath{\left(\partial N_i/\partial\xi\right)}} \newcommand\elemdshapetwod{\ensuremath{\left(\partial N_i/\partial\xi\;,\;\partial N_i/\partial\eta\right)}} \newcommand\elemdshapethreed{\ensuremath{\left(\partial N_i/\partial\xi\;,\;\partial N_i/\partial\eta\;,\;\partial N_i/\partial\zeta\right)}} \newcommand\inelemone[1]{\ensuremath{#1}} %\newcommand\inelemtwo[2]{\ensuremath{\begin{pmatrix} {\; #1} & \!,\! & {#2 \;} \end{pmatrix}}} %\newcommand\inelemthree[3]{\ensuremath{\begin{pmatrix} {\; #1} & \!,\! & {#2} & \!,\! & {#3 \;} \end{pmatrix}}} \newcommand\inelemtwo[2]{\ensuremath{\left( {\; #1} \; , \; {#2 \;} \right)}} \newcommand\inelemthree[3]{\ensuremath{\left( {\; #1} \; , \; {#2} \; , \; {#3 \;} \right)}} \newcommand\inelemthreecolumn[3]{\ensuremath{\begin{array}{c}( {\; #1} \; ,\\{#2} \; ,\\{#3 \;} )\end{array}}} \newcommand\inquadone[1]{\ensuremath{#1}} \newcommand\inquadtwo[2]{\ensuremath{\left(\, #1 \, , \, #2 \,\right)}} \newcommand\inquadthree[3]{\ensuremath{\left(\, #1 \, , \, #2 \, , \, #3 \,\right)}} %\newcommand\quada{\tfrac{1}{20}\left(5-\sqrt{5}\right)} %\newcommand\quadb{\tfrac{1}{20}\left(5+3\sqrt{5}\right)} \newcommand\quada{\tfrac{\left(5-\sqrt{5}\right)}{20}} \newcommand\quadb{\tfrac{\left(5+3\sqrt{5}\right)}{20}} \newenvironment{Element}[1] {%\begin{table*}[!htbp] \footnotesize \ifthenelse{\equal{#1}{1D}}{\renewcommand{\arraystretch}{1.50}}{} \ifthenelse{\equal{#1}{2D}}{\renewcommand{\arraystretch}{1.60}}{} \ifthenelse{\equal{#1}{3D}}{\renewcommand{\arraystretch}{1.70}}{} \textbf{{\normalsize Element properties}}\\%\vspace*{0.5\baselineskip} \begin{tabular}{cccc}\\[-2ex] \toprule % \multicolumn{4}{l}{\textbf{{\normalsize Element properties}}} \\ Node ($i$) & Coord. \ifthenelse{\equal{#1}{1D}}{\elemcooroned}{} \ifthenelse{\equal{#1}{2D}}{\elemcoortwod}{} \ifthenelse{\equal{#1}{3D}}{\elemcoorthreed}{} & Shape function ($N_{i}$) & {Derivative \ifthenelse{\equal{#1}{1D}}{\elemdshapeoned}{} \ifthenelse{\equal{#1}{2D}}{\elemdshapetwod}{} \ifthenelse{\equal{#1}{3D}}{\elemdshapethreed}{} }\\ \midrule \elemline } {\bottomrule \end{tabular}%\end{table*} } \newenvironment{QuadPoints}[1] {\vspace*{\baselineskip} %\begin{table*}[!htbp] \footnotesize \renewcommand{\arraystretch}{1.50} \noindent\textbf{{\normalsize Gaussian quadrature points}}\newline%\vspace*{0.5\baselineskip} \begin{tabular}{#1}\\[-2ex] \toprule } {\bottomrule\end{tabular}}%\end{table*}} %\usepackage{xparse} \newenvironment{MaterialDesc}[2]{ \label{#2-app} Keyword: \code{#1}\par \noindent Description here: \ref{#2}\par \noindent Parameters:\par \vspace*{-.4cm} \begin{itemize} \setlength{\topsep}{0ex}% \setlength{\parsep}{0cm}% \setlength{\itemsep}{0cm}% \setlength{\parskip}{0cm}% }{\end{itemize}} \newcommand{\matparam}[3]{\item \code{#1}: (\emph{#2}) #3} \newcommand{\matinherit}[1]{\usebox{#1}} \newcommand{\matlabel}[1]{\label{#1}\xspace(\ref{#1-app})} % Nice coloring \usepackage[dvipsnames,usenames,table]{xcolor} \definecolor{RED}{rgb}{1,0,0} \definecolor{cppbg}{HTML}{EBF2F2} \definecolor{shellbg}{HTML}{F5EDE4} +\definecolor{cmakebg}{HTML}{F5EDE4} \definecolor{commentcolor}{HTML}{101280} % Allow for the use of listings \usepackage{listings} % Create an index \usepackage{makeidx} % Figure handling \usepackage{graphics} \usepackage{epsfig} \usepackage[lofdepth,lotdepth]{subfig} \usepackage{tikz} \usetikzlibrary{decorations} \usepackage{wrapfig} \renewcommand{\floatpagefraction}{.6} % default: .5 \renewcommand\topfraction{0.9} % 90% of page top can be a float (Standard 0.7) \renewcommand\bottomfraction{0.1} % 10% of page bottom can be a float (Standard 0.3) \renewcommand\textfraction{0.1} % only 10% of page must to be text (Standard 0.2) % Removes parenthese around subfig number \renewcommand*{\thesubfigure}{\alph{subfigure}} -% Create a new list style for C++ -\lstdefinestyle{C++}{ - language=C++, % the language of the code +% Create new list style for cmake files +\lstdefinelanguage{cmake}{ + morekeywords={project, cmake\_minimum\_required, enable\_language, message, + add\_executable, add\_library, target\_link\_libraries, include\_directories, + find\_package, find\_path, find\_library, include, mark\_as\_advanced, + find\_package\_handle\_standard\_args, + package\_declare, package\_declare\_documentation}, + morecomment=[l]{\#}, + sensitive=false, + morestring=[b]", +} + +\lstdefinestyle{lstDefaultStyle} { basicstyle=\small\ttfamily, % Without beramono, we'd get cmtt, the teletype font. commentstyle=\color{commentcolor}\itshape, - keywordstyle=\color{DarkOrchid}\bfseries, % fontadjust, % numbers=left, % where to put the line-numbers % numberstyle=\tiny, % the size of the fonts that are used for the line-numbers % stepnumber=2, % the step between two line-numbers. If it's 1, each line will % be numbered % numbersep=5pt, % how far the line-numbers are from the code % showspaces=false, % show spaces adding particular underscores showstringspaces=false, % underline spaces within strings % showtabs=false, % show tabs within strings adding particular underscores % frame=llines, % adds a frame around the code % frame=tb, tabsize=2, % sets default tabsize to 2 spaces captionpos=b, % sets the caption-position to bottom breaklines=true, % sets automatic line breaking breakatwhitespace=false, % sets if automatic breaks should only happen at % whitespace % title=\lstname, % show the filename of files included with \lstinputlisting; % also try caption instead of title % escapeinside={\%*}{*)}, % if you want to add a comment within your code xleftmargin=1cm, xrightmargin=1cm, - mathescape=true, escapechar=\%, - morekeywords={Real, UInt, Int}, columns=flexible, keepspaces=true, + mathescape=false +} + +% Create a new list style for C++ +\lstdefinestyle{C++}{ + language=C++, % the language of the code + style=lstDefaultStyle, + keywordstyle=\color{DarkOrchid}\bfseries, + mathescape=true, + morekeywords={Real, UInt, Int}, backgroundcolor=\color{cppbg} } % Create new list style for the shell \lstdefinestyle{shell}{ language=bash, % the language of the code - basicstyle=\scriptsize\ttfamily, % Without beramono, we'd get cmtt, the teletype font. - showstringspaces=false, % underline spaces within strings - tabsize=2, % sets default tabsize to 2 spaces - captionpos=b, % sets the caption-position to bottom - breaklines=true, % sets automatic line breaking - breakatwhitespace=false, - xleftmargin=1cm, - xrightmargin=1cm, - escapechar=\%, + style=lstDefaultStyle, morekeywords={mkdir, make, ccmake, cmake}, - columns=flexible, - keepspaces=true, backgroundcolor=\color{shellbg} } +\lstdefinestyle{mycmake}{ + language=cmake, % the language of the code + style=lstDefaultStyle, + keywordstyle=\color{RoyalBlue}\bfseries, + stringstyle=\color{Bittersweet}, % + backgroundcolor=\color{cmakebg} +} + % Set some derived listing environments \lstnewenvironment{cpp}{\lstset{style=C++}}{} \lstnewenvironment{command}{\lstset{style=shell}}{} +\lstnewenvironment{cmake}{\lstset{style=mycmake}}{} % Make sure outputspace is white \makeatletter \def\lst@outputspace{{\ifx\lst@bkgcolor\empty\color{white}\else\lst@bkgcolor\fi\lst@visiblespace}} \makeatother % Renow a label in the itemized lists \renewcommand{\labelitemi}{$\mathbf{\circ}$} % Don't care so much about overfull h-boxes \sloppy % Penalty adjusments %\widowpenalty=10000 % Single lines/word on beginning of page %\clubpenalty=10000 % Single lines/word at end of page %\hyphenpenalty=2000 % Hyphenate words %\tolerance=250 % To adjust the hyphenation of words, increase the tolerance to discourage hyphenation % the higher the value, the more ugly the gaps between words % default \tolerance=200 %\hfuzz=10000pt % threshold when an overfull hbox is reported, default \hfuzz=0.1pt %\vfuzz=10000pt % threshold to report an overfull vbox, default \vfuzz=0.1pt %\hbadness=10000 % threshold to report an underfull \hbox %\vbadness=10000 % threshold to report an underfull \vbox protokolliert wird. \emergencystretch=0pt % causes a third attempt to fix bad paragraphs and defines a maximum limit to stretch them % Insert an empty or a blank page \newcommand{\insertemptypage}{\newpage\hbox{}\newpage} \newcommand{\insertblankpage}{\newpage\thispagestyle{empty}\hbox{}\newpage} % No page number on an empty page \let\origdoublepage\cleardoublepage \newcommand{\clearemptydoublepage}{% \clearpage {\thispagestyle{empty}\origdoublepage}% } \let\cleardoublepage\clearemptydoublepage % A new ruler for in chapters \newcommand\InChapterRule{\addvspace{\baselineskip}\rule{0.3\linewidth}{0.25pt}} % New footnote style %\def\@fnsymbol#1{\ifcase#1\or *\or \dagger\or \ddagger\or \mathchar "278\or \mathchar "27B\or \|\or **\or \dagger\dagger \or \ddagger\ddagger \else\@ctrerr\fi\relax} \def\@fnsymbol#1{*\xspace\relax} \renewcommand{\thefootnote}{\fnsymbol{footnote}} % Symbols rather than numbers \def\footnoterule{\vspace*{0.5\baselineskip}\InChapterRule\vspace*{0.25\baselineskip}} % Improved look of the Table of Contents \usepackage[nottoc,notbib]{tocbibind} \usepackage[dotinlabels]{titletoc} \titlecontents{chapter}[1.4pc] {\addvspace{0.6pc}\large\bfseries\filright} {\contentslabel[\thecontentslabel.]{1.4pc}} {\hspace{-1.4pc}} {\hfill\contentspage} [\addvspace{2pt}] \titlecontents{section}[3.4pc] {\filright} {\contentslabel[\thecontentslabel]{2pc}} {\hspace{-2pc}} {\titlerule*[6pt]{.}\contentspage} [] \titlecontents{subsection}[5.0pc] {\filright} {\contentslabel[\thecontentslabel]{2.4pc}} {} {\titlerule*[6pt]{.}\contentspage} [] \setcounter{tocdepth}{2} \newcommand\addspaceintoc{\addtocontents{toc}{\protect\addvspace{20pt}}} % Change the appearance of the bibliography \bibliographystyle{manual-bibliographystyle} \renewcommand\bibname{References} \usepackage{cite} % To sort citations: [2,10-14] \let\oldthebibliography=\thebibliography \let\endoldthebibliography=\endthebibliography \renewenvironment{thebibliography}[1] { \begin{oldthebibliography}{#1} % \small \addcontentsline{toc}{chapter}{\bibname} \setlength{\labelsep}{2mm} \setlength{\parskip}{0\baselineskip} \setlength{\itemsep}{0.24\baselineskip} } { \end{oldthebibliography} } % Hyperref \usepackage{url} \usepackage[pdftex, bookmarks=true, bookmarksnumbered=true, % linkbordercolor={1 1 1}, % pdfborder={0 0 0}, pdfpagemode=UseOutlines ]{hyperref} \hypersetup{ pdfauthor={Computational Solid Mechanics Laboratory - EPFL}, pdftitle={Akantu User's Guide}, pdfsubject={Open Source Finite Element Code - Akantu} } \newenvironment{AkantuPackage}[2]{% \paragraph*{#1}\label{#2} }{} \newenvironment{AkantuPackageDependencies}{\emph{Dependencies}: }{} \newcommand\AkantuPackageNameWithLabel[3]{\textit{\index{Packages!#1}\hyperref[#2]{#1}}\xspace} \newcommand\akantuManualAppendix[1]{} \ No newline at end of file diff --git a/doc/manual/manual.tex b/doc/manual/manual.tex index f9cd426e9..d4e9562e6 100644 --- a/doc/manual/manual.tex +++ b/doc/manual/manual.tex @@ -1,47 +1,48 @@ \documentclass[openright,a4paper,11pt,fleqn]{manual} \usepackage{manual} \usepackage{manual-macros} + \newcommand{\version}{} \graphicspath{ {./figures/} } %%% For references \todo check the coherency %% section 3.5 -> Section 3.5 %% figure 3.5 -> Figure 3.5 %% equation 3.5 -> Equation (3.5) % Title pages and Table of Contents (includes \begin{document}) \input{manual-titlepages} % Introduction chapter \input{manual-introduction} % The planning to write the documentation %\input{manual-planning} % The documentation chapter (split in parts) \input{manual-gettingstarted} \input{manual-elements} %\IfFileExists{manual-lumping.tex}{}{\input{manual-lumping}} \input{manual-solidmechanicsmodel} \IfFileExists{manual-structuralmechanicsmodel.tex}{\input{manual-structuralmechanicsmodel}}{} \IfFileExists{manual-heattransfermodel.tex}{\input{manual-heattransfermodel}}{} \input{manual-io} \IfFileExists{manual-parallel.tex}{\input{manual-parallel}}{} \IfFileExists{manual-contact.tex}{\input{manual-contact}}{} % The appendices \appendix \input{manual-appendix-elements} \input{manual-appendix-materials} \input{manual-appendix-packages} % The backmatter material (index/bibliography, included \end{document}) \input{manual-backmatter} diff --git a/extra_packages/extra-materials b/extra_packages/extra-materials index 27835edcf..ce1204216 160000 --- a/extra_packages/extra-materials +++ b/extra_packages/extra-materials @@ -1 +1 @@ -Subproject commit 27835edcf205dedb552ddb9d82d3bc9e39b0156a +Subproject commit ce1204216c5b64a145c011b619d9ceedc89eb2b4 diff --git a/extra_packages/traction-at-split-node-contact b/extra_packages/traction-at-split-node-contact index ef51588f2..d72a71d49 160000 --- a/extra_packages/traction-at-split-node-contact +++ b/extra_packages/traction-at-split-node-contact @@ -1 +1 @@ -Subproject commit ef51588f2c24f3a1307085941eda060408d1d3d5 +Subproject commit d72a71d4913205050dee2a871e9a9a9fa452bccf diff --git a/packages/cgal.cmake b/packages/cgal.cmake index 68e7c13fd..bbc128aa9 100644 --- a/packages/cgal.cmake +++ b/packages/cgal.cmake @@ -1,62 +1,57 @@ #=============================================================================== # @file cgal.cmake # # @author Lucas Frérot <lucas.frerot@epfl.ch> # # @date creation: Thu Feb 19 2015 # @date last modification: Mon Mar 2 2015 # # @brief package description for CGAL # # @section LICENSE # # Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see <http://www.gnu.org/licenses/>. # #=============================================================================== package_declare(CGAL EXTERNAL DESCRIPTION "Add CGAL support in akantu" COMPILE_FLAGS "-frounding-math" BOOST_COMPONENTS system ) package_declare_sources(CGAL geometry/mesh_geom_abstract.hh geometry/mesh_geom_abstract.cc + geometry/mesh_geom_factory.hh geometry/mesh_geom_factory_tmpl.hh - geometry/mesh_geom_container.hh - geometry/mesh_geom_container.cc + + geometry/mesh_geom_intersector.hh + geometry/mesh_geom_intersector_tmpl.hh + + geometry/mesh_segment_intersector.hh + geometry/mesh_segment_intersector_tmpl.hh geometry/tree_type_helper.hh geometry/geom_helper_functions.hh geometry/aabb_primitives/triangle.hh - geometry/aabb_primitives/triangle_tmpl.hh geometry/aabb_primitives/tetrahedron.hh - geometry/aabb_primitives/tetrahedron_tmpl.hh geometry/aabb_primitives/aabb_primitive.hh ) - - -## Adding CGAL library -#find_package(CGAL COMPONENTS Core) -#if (NOT CGAL_FOUND) -#message(STATUS "This project requires the CGAL library, and will not be compiled.") -#return() -#endif() diff --git a/packages/cohesive_element.cmake b/packages/cohesive_element.cmake index 2853335df..246c77c10 100644 --- a/packages/cohesive_element.cmake +++ b/packages/cohesive_element.cmake @@ -1,92 +1,93 @@ #=============================================================================== # @file 20_cohesive_element.cmake # # @author Marco Vocialta <marco.vocialta@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Tue Oct 16 2012 # @date last modification: Tue Sep 02 2014 # # @brief package description 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/>. # #=============================================================================== package_declare(cohesive_element DESCRIPTION "Use cohesive_element package of Akantu" DEPENDS lapack) package_declare_sources(cohesive_element model/solid_mechanics/materials/material_cohesive_includes.hh mesh_utils/cohesive_element_inserter.hh mesh_utils/cohesive_element_inserter.cc fe_engine/cohesive_element.cc fe_engine/shape_cohesive.hh fe_engine/cohesive_element.hh fe_engine/fe_engine_template_cohesive.cc fe_engine/shape_cohesive_inline_impl.cc model/solid_mechanics/materials/material_cohesive/cohesive_internal_field_tmpl.hh model/solid_mechanics/materials/material_cohesive/cohesive_internal_field.hh model/solid_mechanics/materials/material_cohesive/material_cohesive_inline_impl.cc model/solid_mechanics/solid_mechanics_model_cohesive.cc model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc model/solid_mechanics/fragment_manager.cc model/solid_mechanics/materials/material_cohesive/material_cohesive.cc model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc + model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear_inline_impl.cc model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear_fatigue.cc model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_bilinear.cc model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_exponential.cc model/solid_mechanics/solid_mechanics_model_cohesive.hh model/solid_mechanics/fragment_manager.hh model/solid_mechanics/materials/material_cohesive/material_cohesive.hh model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_bilinear.hh model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear_fatigue.hh model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_exponential.hh ) package_declare_documentation_files(cohesive_element manual-cohesive_elements.tex manual-cohesive_elements_insertion.tex manual-cohesive_laws.tex manual-appendix-materials-cohesive.tex figures/cohesive2d.pdf figures/cohesive_exponential.pdf figures/linear_cohesive_law.pdf figures/bilinear_cohesive_law.pdf ) package_declare_documentation(cohesive_element "This package activates the cohesive elements engine within Akantu." "It depends on:" "\\begin{itemize}" " \\item A fortran compiler." " \\item An implementation of BLAS/LAPACK." "\\end{itemize}" ) diff --git a/packages/embedded.cmake b/packages/embedded.cmake index aeb711a3c..aefb0fdfe 100644 --- a/packages/embedded.cmake +++ b/packages/embedded.cmake @@ -1,51 +1,51 @@ #=============================================================================== # @file embedded.cmake # # @author Lucas Frérot <lucas.frerot@epfl.ch> # # @date creation: Tue Oct 16 2012 # @date last modification: Thu Jun 12 2014 # # @brief package descrition for embedded model use # # @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/>. # #=============================================================================== package_declare(embedded DESCRIPTION "Add support for the embedded solid mechanics model" DEPENDS CGAL) package_declare_sources(embedded model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh - model/solid_mechanics/embedded_interface.hh - model/solid_mechanics/embedded_interface.cc + model/solid_mechanics/embedded_interface_intersector.hh + model/solid_mechanics/embedded_interface_intersector.cc model/solid_mechanics/embedded_interface_model.hh model/solid_mechanics/embedded_interface_model.cc model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh model/solid_mechanics/materials/material_embedded/material_reinforcement.hh model/solid_mechanics/materials/material_embedded/material_reinforcement.cc model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc ) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 215a96a2c..c723c34e4 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,204 +1,205 @@ #=============================================================================== # @file CMakeLists.txt # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date Wed Jul 9 17:22:12 2014 # # @brief CMake file for the python wrapping of akantu # # @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/>. # #=============================================================================== #=============================================================================== # Configuration #=============================================================================== set(AKANTU_SWIG_FLAGS -w309,325,401) set(AKANTU_SWIG_OUTDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(AKANTU_SWIG_MODULES swig/akantu.i) #=============================================================================== # Swig wrapper #=============================================================================== find_package(SWIG REQUIRED) find_package(PythonLibs) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/swig ${PYTHON_INCLUDE_PATH} ${AKANTU_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ) include(CMakeParseArguments) function(swig_generate_dependencies _module _depedencies) set(_dependencies_script "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_generate_dependencies.cmake") file(WRITE ${_dependencies_script} " set(_include_directories ${_include_directories}) list(APPEND _include_directories \"./\") set(_dep) set(_files_to_process \${_module}) while(_files_to_process) list(GET _files_to_process 0 _file) list(REMOVE_AT _files_to_process 0) file(STRINGS \${_file} _file_content REGEX \"^%include *\\\"(.*)\\\"\") set(_includes) foreach(_line \${_file_content}) string(REGEX REPLACE \"^%include *\\\"(.*)\\\"\" \"\\\\1\" _inc \${_line}) if(_inc) list(APPEND _includes \${_inc}) endif() endforeach() foreach(_include \${_includes}) unset(_found) foreach(_inc_dir \${_include_directories}) if(EXISTS \${_inc_dir}/\${_include}) set(_found \${_inc_dir}/\${_include}) break() endif() endforeach() if(_found) list(APPEND _files_to_process \${_found}) list(APPEND _dep \${_found}) endif() endforeach() endwhile() get_filename_component(_module_we \"\${_module}\" NAME_WE) set(_dependencies_file \${CMAKE_CURRENT_BINARY_DIR}\${CMAKE_FILES_DIRECTORY}/_swig_\${_module_we}_depends.cmake) file(WRITE \"\${_dependencies_file}\" \"set(_swig_\${_module_we}_depends\") foreach(_d \${_dep}) file(APPEND \"\${_dependencies_file}\" \" \${_d}\") endforeach() file(APPEND \"\${_dependencies_file}\" \" )\") ") get_directory_property(_include_directories INCLUDE_DIRECTORIES) get_filename_component(_module_absolute "${_module}" ABSOLUTE) get_filename_component(_module_we "${_module}" NAME_WE) set(_dependencies_file ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_${_module_we}_depends.cmake) if(EXISTS ${_dependencies_file}) include(${_dependencies_file}) else() execute_process(COMMAND ${CMAKE_COMMAND} -D_module=${_module_absolute} -P ${_dependencies_script} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) include(${_dependencies_file}) endif() add_custom_command(OUTPUT ${_dependencies_file} COMMAND ${CMAKE_COMMAND} -D_module=${_module_absolute} -P ${_dependencies_script} COMMENT "Scannong dependencies for swig module ${_module_we}" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} MAIN_DEPENDENCY ${_module_absolute} DEPENDS ${_swig_${_module_we}_depends} ) set(${_depedencies} ${_dependencies_file} PARENT_SCOPE) endfunction() function(swig_generate_wrappers project _wrappers) cmake_parse_arguments(_swig_opt "" "OUTPUT_DIR" "EXTRA_FLAGS" ${ARGN}) if(_swig_opt_OUTPUT_DIR) set(_output_dir ${_swig_opt_OUTPUT_DIR}) else() set(_output_dir ${CMAKE_CURRENT_BINARY_DIR}) endif() set(_swig_wrappers) get_directory_property(_include_directories INCLUDE_DIRECTORIES) if(_include_directories) string(REPLACE ";" ";-I" _swig_include_directories "${_include_directories}") endif() foreach(_module ${_swig_opt_UNPARSED_ARGUMENTS}) swig_generate_dependencies(${_module} _module_dependencies) get_filename_component(_module_absolute "${_module}" ABSOLUTE) get_filename_component(_module_path "${_module_absolute}" PATH) get_filename_component(_module_name "${_module}" NAME) get_filename_component(_module_we "${_module}" NAME_WE) set(_wrapper "${_output_dir}/${_module_we}_wrapper.cc") set(_extra_wrapper "${_output_dir}/${_module_we}.py") set(_extra_wrapper_bin "${CMAKE_CURRENT_BINARY_DIR}/${_module_we}.py") + if(SWIG_FOUND) set_source_files_properties("${_wrapper}" PROPERTIES GENERATED 1) set_source_files_properties("${_extra_wrapper}" PROPERTIES GENERATED 1) set(_dependencies_file ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/_swig_${_module_we}_depends.cmake) + set(_ouput "${_wrapper}" "${_extra_wrapper}" "${_extra_wrapper_bin}") add_custom_command( - OUTPUT "${_wrapper}" "${_extra_wrapper}" "${_extra_wrapper_bin}" + OUTPUT ${_ouput} COMMAND "${SWIG_EXECUTABLE}" ARGS -python -c++ ${_swig_opt_EXTRA_FLAGS} -outdir ${_output_dir} -I${_swig_include_directories} -I${_module_path} -o "${_wrapper}" "${_module_absolute}" COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_extra_wrapper} ${_extra_wrapper_bin} # MAIN_DEPENDENCY "${_module_absolute}" DEPENDS ${_module_dependencies} COMMENT "Generating swig wrapper ${_module} -> ${_wrapper}" ) list(APPEND _swig_wrappers ${_wrapper}) else() if(NOT EXISTS ${_wrapper} OR NOT EXISTS "${_extra_wrapper}") message(FATAL_ERROR "The file ${_wrapper} and/or ${_extra_wrapper} does not exists and they cannot be generated. Install swig in order to generate them") else() list(APPEND _swig_wrappers ${_wrapper}) endif() endif() endforeach() add_custom_target(${project}_generate_swig_wrappers DEPENDS ${_swig_wrappers}) set(${_wrappers} ${_swig_wrappers} PARENT_SCOPE) endfunction() swig_generate_wrappers(akantu AKANTU_SWIG_WRAPPERS ${AKANTU_SWIG_MODULES} - OUTPUT_DIR ${AKANTU_SWIG_OUTDIR} EXTRA_FLAGS ${AKANTU_SWIG_FLAGS}) if(AKANTU_SWIG_WRAPPERS) add_library(_akantu MODULE ${AKANTU_SWIG_WRAPPERS}) target_link_libraries(_akantu akantu ${PYTHON_LIBRARIES}) set_target_properties(_akantu PROPERTIES PREFIX "") endif() diff --git a/src/common/aka_array.hh b/src/common/aka_array.hh index a77eaf50e..5d5fce77e 100644 --- a/src/common/aka_array.hh +++ b/src/common/aka_array.hh @@ -1,373 +1,375 @@ /** * @file aka_array.hh * * @author Till Junge <till.junge@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Jun 24 2014 * * @brief Array container for Akantu * This container differs from the std::vector from the fact it as 2 dimensions * a main dimension and the size stored per entries * * @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_VECTOR_HH__ #define __AKANTU_VECTOR_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include <typeinfo> //#include <cstring> #include <vector> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /// class that afford to store vectors in static memory class ArrayBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ArrayBase(const ID & id = ""); virtual ~ArrayBase(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get the amount of space allocated in bytes inline UInt getMemorySize() const; /// set the size to zero without freeing the allocated space inline void empty(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get the real size allocated in memory AKANTU_GET_MACRO(AllocatedSize, allocated_size, UInt); /// Get the Size of the Array AKANTU_GET_MACRO(Size, size, UInt); /// Get the number of components AKANTU_GET_MACRO(NbComponent, nb_component, UInt); /// Get the name of th array AKANTU_GET_MACRO(ID, id, const ID &); + /// Set the name of th array + AKANTU_SET_MACRO(ID, id, const ID &); // AKANTU_GET_MACRO(Tag, tag, const std::string &); // AKANTU_SET_MACRO(Tag, tag, const std::string &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the vector ID id; /// the size allocated UInt allocated_size; /// the size used UInt size; /// number of components UInt nb_component; /// size of the stored type UInt size_of_type; // /// User defined tag // std::string tag; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template<typename T, bool is_scal> class Array : public ArrayBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef T value_type; typedef value_type & reference; typedef value_type * pointer_type; typedef const value_type & const_reference; /// Allocation of a new vector inline Array(UInt size = 0, UInt nb_component = 1, const ID & id = ""); /// Allocation of a new vector with a default value Array(UInt size, UInt nb_component, const value_type def_values[], const ID & id = ""); /// Allocation of a new vector with a default value Array(UInt size, UInt nb_component, const_reference value, const ID & id = ""); /// Copy constructor (deep copy if deep=true) Array(const Array<value_type, is_scal>& vect, bool deep = true, const ID & id = ""); #ifndef SWIG /// Copy constructor (deep copy) Array(const std::vector<value_type> & vect); #endif virtual inline ~Array(); Array & operator=(const Array & a) { /// this is to let STL allocate and copy arrays in the case of std::vector::resize AKANTU_DEBUG_ASSERT(this->size == 0,"Cannot copy akantu::Array"); return const_cast<Array&>(a); } /* ------------------------------------------------------------------------ */ /* Iterator */ /* ------------------------------------------------------------------------ */ /// \todo protected: does not compile with intel check why public: template <class R, class IR = R, bool issame = is_same<IR, T>::value > class iterator_internal; public: /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ template<typename R = T> class const_iterator; template<typename R = T> class iterator; /* ------------------------------------------------------------------------ */ /// iterator for Array of nb_component = 1 typedef iterator< T > scalar_iterator; /// const_iterator for Array of nb_component = 1 typedef const_iterator< T > const_scalar_iterator; /// iterator rerturning Vectors of size n on entries of Array with nb_component = n typedef iterator< Vector<T> > vector_iterator; /// const_iterator rerturning Vectors of n size on entries of Array with nb_component = n typedef const_iterator< Vector<T> > const_vector_iterator; /// iterator rerturning Matrices of size (m, n) on entries of Array with nb_component = m*n typedef iterator< Matrix<T> > matrix_iterator; /// const iterator rerturning Matrices of size (m, n) on entries of Array with nb_component = m*n typedef const_iterator< Matrix<T> > const_matrix_iterator; /* ------------------------------------------------------------------------ */ /// Get an iterator that behaves like a pointer T * to the first entry inline iterator<T> begin(); /// Get an iterator that behaves like a pointer T * to the end of the Array inline iterator<T> end(); /// Get a const_iterator to the beginging of an Array of scalar inline const_iterator<T> begin() const; /// Get a const_iterator to the end of an Array of scalar inline const_iterator<T> end() const; /* ------------------------------------------------------------------------ */ /// Get a vector_iterator on the begining of the Array inline vector_iterator begin(UInt n); /// Get a vector_iterator on the end of the Array inline vector_iterator end(UInt n); /// Get a vector_iterator on the begining of the Array inline const_vector_iterator begin(UInt n) const; /// Get a vector_iterator on the end of the Array inline const_vector_iterator end(UInt n) const; /// Get a vector_iterator on the begining of the Array considered of shape (new_size, n) inline vector_iterator begin_reinterpret(UInt n, UInt new_size); /// Get a vector_iterator on the end of the Array considered of shape (new_size, n) inline vector_iterator end_reinterpret(UInt n, UInt new_size); /// Get a const_vector_iterator on the begining of the Array considered of shape (new_size, n) inline const_vector_iterator begin_reinterpret(UInt n, UInt new_size) const; /// Get a const_vector_iterator on the end of the Array considered of shape (new_size, n) inline const_vector_iterator end_reinterpret(UInt n, UInt new_size) const; /* ------------------------------------------------------------------------ */ /// Get a matrix_iterator on the begining of the Array (Matrices of size (m, n)) inline matrix_iterator begin(UInt m, UInt n); /// Get a matrix_iterator on the end of the Array (Matrices of size (m, n)) inline matrix_iterator end(UInt m, UInt n); /// Get a const_matrix_iterator on the begining of the Array (Matrices of size (m, n)) inline const_matrix_iterator begin(UInt m, UInt n) const; /// Get a const_matrix_iterator on the end of the Array (Matrices of size (m, n)) inline const_matrix_iterator end(UInt m, UInt n) const; /// Get a matrix_iterator on the begining of the Array considered of shape (new_size, m*n) inline matrix_iterator begin_reinterpret(UInt m, UInt n, UInt size); /// Get a matrix_iterator on the end of the Array considered of shape (new_size, m*n) inline matrix_iterator end_reinterpret(UInt m, UInt n, UInt size); /// Get a const_matrix_iterator on the begining of the Array considered of shape (new_size, m*n) inline const_matrix_iterator begin_reinterpret(UInt m, UInt n, UInt size) const; /// Get a const_matrix_iterator on the end of the Array considered of shape (new_size, m*n) inline const_matrix_iterator end_reinterpret(UInt m, UInt n, UInt size) const; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// append a tuple of size nb_component containing value inline void push_back(const_reference value); /// append a vector inline void push_back(const value_type new_elem[]); /// append a Vector or a Matrix template<template<typename> class C> inline void push_back(const C<T> & new_elem); /// append the value of the iterator template<typename Ret> inline void push_back(const iterator<Ret> & it); /// erase the value at position i inline void erase(UInt i); /// ask Nico, clarify template<typename R> inline iterator<R> erase(const iterator<R> & it); /// change the size of the Array void resize(UInt size); /// change the number of components by interlacing data void extendComponentsInterlaced(UInt multiplicator, UInt stride); /// search elem in the vector, return the position of the first occurrence or -1 if not found Int find(const_reference elem) const;\ /// @see Array::find(const_reference elem) const Int find(T elem[]) const; /// set all entries of the array to 0 inline void clear() { std::fill_n(values, size*nb_component, T()); } /// set all entries of the array to the value t /// @param t value to fill the array with inline void set(T t) { std::fill_n(values, size*nb_component, t); } /// set all tuples of the array to a given vector or matrix /// @param vm Matrix or Vector to fill the array with template<template<typename> class C> inline void set(const C<T> & vm); /// copy another Array in the current Array, the no_sanity_check allows you to /// force the copy in cases where you know what you do with two non matching /// Arrays in terms of n void copy(const Array<T, is_scal> & other, bool no_sanity_check = false); /// give the address of the memory allocated for this vector T * storage() const { return values; }; /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; protected: /// perform the allocation for the constructors void allocate(UInt size, UInt nb_component = 1); /// resize without initializing the memory void resizeUnitialized(UInt new_size); /* ------------------------------------------------------------------------ */ /* Operators */ /* ------------------------------------------------------------------------ */ public: /// substraction entry-wise Array<T, is_scal> & operator-=(const Array<T, is_scal> & other); /// addition entry-wise Array<T, is_scal> & operator+=(const Array<T, is_scal> & other); /// multiply evry entry by alpha Array<T, is_scal> & operator*=(const T & alpha); /// check if the array are identical entry-wise bool operator==(const Array<T, is_scal> & other) const; /// @see Array::operator==(const Array<T, is_scal> & other) const bool operator!=(const Array<T, is_scal> & other) const; /// return a reference to the j-th entry of the i-th tuple inline reference operator()(UInt i, UInt j = 0); /// return a const reference to the j-th entry of the i-th tuple inline const_reference operator()(UInt i, UInt j = 0) const; /// return a reference to the ith component of the 1D array inline reference operator[](UInt i); /// return a const reference to the ith component of the 1D array inline const_reference operator[](UInt i) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the number of tuples contained in the array UInt getSize() const{ return this->size; }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// array of values T * values; // /!\ very dangerous }; __END_AKANTU__ #include "aka_types.hh" __BEGIN_AKANTU__ #include "aka_array_tmpl.hh" /* -------------------------------------------------------------------------- */ /* Inline Functions Array<T, is_scal> */ /* -------------------------------------------------------------------------- */ template <typename T, bool is_scal> inline std::ostream & operator<<(std::ostream & stream, const Array<T, is_scal> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ /* Inline Functions ArrayBase */ /* -------------------------------------------------------------------------- */ inline std::ostream & operator<<(std::ostream & stream, const ArrayBase & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_VECTOR_HH__ */ diff --git a/src/common/aka_common_inline_impl.cc b/src/common/aka_common_inline_impl.cc index 6eb33206b..dedf81ea0 100644 --- a/src/common/aka_common_inline_impl.cc +++ b/src/common/aka_common_inline_impl.cc @@ -1,238 +1,238 @@ /** * @file aka_common_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Dec 01 2011 * @date last modification: Wed Jul 23 2014 * * @brief inline implementations of common akantu type descriptions * * @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 * * All common things to be included in the projects files * */ #include <algorithm> #include <iomanip> #include <cctype> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ //! standard output stream operator for ElementType inline std::ostream & operator <<(std::ostream & stream, ElementType type) { #define STRINGIFY(type) \ stream << BOOST_PP_STRINGIZE(type) switch(type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, \ STRINGIFY, \ AKANTU_ALL_ELEMENT_TYPE) case _not_defined: stream << "_not_defined"; break; case _max_element_type: stream << "_max_element_type"; break; } #undef STRINGIFY return stream; } /* -------------------------------------------------------------------------- */ //! standard output stream operator for ElementType inline std::ostream & operator <<(std::ostream & stream, ElementKind kind ) { #define STRINGIFY(kind) \ stream << BOOST_PP_STRINGIZE(kind) AKANTU_BOOST_ALL_KIND_SWITCH(STRINGIFY); #undef STRINGIFY return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for InterpolationType inline std::ostream & operator <<(std::ostream & stream, InterpolationType type) { switch(type) { case _itp_lagrange_point_1 : stream << "_itp_lagrange_point_1" ; break; case _itp_lagrange_segment_2 : stream << "_itp_lagrange_segment_2" ; break; case _itp_lagrange_segment_3 : stream << "_itp_lagrange_segment_3" ; break; case _itp_lagrange_triangle_3 : stream << "_itp_lagrange_triangle_3" ; break; case _itp_lagrange_triangle_6 : stream << "_itp_lagrange_triangle_6" ; break; case _itp_lagrange_quadrangle_4 : stream << "_itp_lagrange_quadrangle_4" ; break; case _itp_serendip_quadrangle_8 : stream << "_itp_serendip_quadrangle_8" ; break; case _itp_lagrange_tetrahedron_4 : stream << "_itp_lagrange_tetrahedron_4" ; break; case _itp_lagrange_tetrahedron_10 : stream << "_itp_lagrange_tetrahedron_10"; break; case _itp_lagrange_hexahedron_8 : stream << "_itp_lagrange_hexahedron_8" ; break; case _itp_lagrange_pentahedron_6 : stream << "_itp_lagrange_pentahedron_6" ; break; case _itp_serendip_hexahedron_20 : stream << "_itp_serendip_hexahedron_20" ; break; case _itp_lagrange_pentahedron_15 : stream << "_itp_lagrange_pentahedron_15"; break; #if defined(AKANTU_STRUCTURAL_MECHANICS) case _itp_bernoulli_beam : stream << "_itp_bernoulli_beam" ; break; case _itp_kirchhoff_shell : stream << "_itp_kirchhoff_shell" ; break; #endif case _itp_not_defined : stream << "_itp_not_defined" ; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for GhostType inline std::ostream & operator <<(std::ostream & stream, GhostType type) { switch(type) { case _not_ghost : stream << "not_ghost"; break; case _ghost : stream << "ghost" ; break; case _casper : stream << "Casper the friendly ghost"; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for SynchronizationTag inline std::ostream & operator <<(std::ostream & stream, SynchronizationTag type) { switch(type) { case _gst_smm_mass : stream << "_gst_smm_mass" ; break; case _gst_smm_for_gradu : stream << "_gst_smm_for_gradu" ; break; case _gst_smm_boundary : stream << "_gst_smm_boundary" ; break; case _gst_smm_uv : stream << "_gst_smm_uv" ; break; case _gst_smm_res : stream << "_gst_smm_res" ; break; case _gst_smm_init_mat : stream << "_gst_smm_init_mat" ; break; case _gst_smm_stress : stream << "_gst_smm_stress" ; break; case _gst_smmc_facets : stream << "_gst_smmc_facets" ; break; case _gst_smmc_facets_conn : stream << "_gst_smmc_facets_conn" ; break; case _gst_smmc_facets_stress : stream << "_gst_smmc_facets_stress" ; break; case _gst_smmc_damage : stream << "_gst_smmc_damage" ; break; case _gst_ce_inserter : stream << "_gst_ce_inserter" ; break; case _gst_gm_clusters : stream << "_gst_gm_clusters" ; break; case _gst_htm_capacity : stream << "_gst_htm_capacity" ; break; case _gst_htm_temperature : stream << "_gst_htm_temperature" ; break; case _gst_htm_gradient_temperature : stream << "_gst_htm_gradient_temperature"; break; case _gst_htm_phi : stream << "_gst_htm_phi" ; break; case _gst_htm_gradient_phi : stream << "_gst_htm_gradient_phi" ; break; case _gst_mnl_for_average : stream << "_gst_mnl_for_average" ; break; case _gst_mnl_weight : stream << "_gst_mnl_weight" ; break; case _gst_test : stream << "_gst_test" ; break; - case _gst_user_1 : stream << "_gst_user_1" ; break; - case _gst_user_2 : stream << "_gst_user_2" ; break; + case _gst_user_1 : stream << "_gst_user_1" ; break; + case _gst_user_2 : stream << "_gst_user_2" ; break; case _gst_material_id : stream << "_gst_material_id" ; break; case _gst_for_dump : stream << "_gst_for_dump" ; break; case _gst_cf_nodal : stream << "_gst_cf_nodal" ; break; case _gst_cf_incr : stream << "_gst_cf_incr" ; break; case _gst_solver_solution : stream << "_gst_solver_solution" ; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for SolveConvergenceCriteria inline std::ostream & operator <<(std::ostream & stream, SolveConvergenceCriteria criteria) { switch(criteria) { case _scc_residual : stream << "_scc_residual" ; break; case _scc_increment: stream << "_scc_increment"; break; case _scc_residual_mass_wgh: stream << "_scc_residual_mass_wgh"; break; } return stream; } /* -------------------------------------------------------------------------- */ inline std::string to_lower(const std::string & str) { std::string lstr = str; std::transform(lstr.begin(), lstr.end(), lstr.begin(), (int(*)(int))tolower); return lstr; } /* -------------------------------------------------------------------------- */ inline std::string trim(const std::string & to_trim) { std::string trimed = to_trim; //left trim trimed.erase(trimed.begin(), std::find_if(trimed.begin(), trimed.end(), std::not1(std::ptr_fun<int, int>(isspace)))); // right trim trimed.erase(std::find_if(trimed.rbegin(), trimed.rend(), std::not1(std::ptr_fun<int, int>(isspace))).base(), trimed.end()); return trimed; } __END_AKANTU__ #include <cmath> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<typename T> std::string printMemorySize(UInt size) { Real real_size = size * sizeof(T); UInt mult = (std::log(real_size) / std::log(2)) / 10; std::stringstream sstr; real_size /= Real(1 << (10 * mult)); sstr << std::setprecision(2) << std::fixed << real_size; std::string size_prefix; switch(mult) { case 0: sstr << ""; break; case 1: sstr << "Ki"; break; case 2: sstr << "Mi"; break; case 3: sstr << "Gi"; break; // I started on this type of machines // (32bit computers) (Nicolas) case 4: sstr << "Ti"; break; case 5: sstr << "Pi"; break; case 6: sstr << "Ei"; break; // theoritical limit of RAM of the current // computers in 2014 (64bit computers) (Nicolas) case 7: sstr << "Zi"; break; case 8: sstr << "Yi"; break; default: AKANTU_DEBUG_ERROR("The programmer in 2014 didn't thought so far (even wikipedia does not go further)." << " You have at least 1024 times more than a yobibit of RAM!!!" << " Just add the prefix corresponding in this switch case."); } sstr << "Byte"; return sstr.str(); } __END_AKANTU__ diff --git a/src/common/aka_types.hh b/src/common/aka_types.hh index 4ccfd7517..d92deb104 100644 --- a/src/common/aka_types.hh +++ b/src/common/aka_types.hh @@ -1,991 +1,1012 @@ /** * @file aka_types.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Feb 17 2011 * @date last modification: Tue Aug 19 2014 * * @brief description of the "simple" types * * @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_error.hh" #include "aka_fwd.hh" #include "aka_math.hh" #include "aka_array.hh" /* -------------------------------------------------------------------------- */ #include <iomanip> #ifndef __INTEL_COMPILER #include <tr1/unordered_map> #else #include <map> #endif /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_TYPES_HH__ #define __AKANTU_AKA_TYPES_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* maps */ /* -------------------------------------------------------------------------- */ #ifndef __INTEL_COMPILER template<class Key, class Ty> struct unordered_map { typedef typename std::tr1::unordered_map<Key, Ty> type; }; #else template<class Key, class Ty> struct unordered_map { typedef typename std::map<Key, Ty> type; }; #endif enum NormType { L_1 = 1, L_2 = 2, L_inf = UInt(-1) }; template<UInt dim> struct DimHelper { static inline void setDims(UInt m, UInt n, UInt p, UInt dims[dim]); }; template<> struct DimHelper<1> { static inline void setDims(UInt m, __attribute__((unused)) UInt n, __attribute__((unused)) UInt p, UInt dims[1]) { dims[0] = m; } }; template<> struct DimHelper<2> { static inline void setDims(UInt m, UInt n, __attribute__((unused)) UInt p, UInt dims[2]) { dims[0] = m; dims[1] = n; } }; template<> struct DimHelper<3> { static inline void setDims(UInt m, UInt n, UInt p, UInt dims[3]) { dims[0] = m; dims[1] = n; dims[2] = p; } }; /* -------------------------------------------------------------------------- */ template<typename T, UInt ndim, class RetType> class TensorStorage; /* -------------------------------------------------------------------------- */ template<typename T, UInt ndim, class RetType> class TensorProxy { protected: TensorProxy(T * data, UInt m, UInt n, UInt p) { DimHelper<ndim>::setDims(m, n, p, this->n); this->values = data; } TensorProxy(const TensorProxy & other) { this->values = other.storage(); for (UInt i = 0; i < ndim; ++i) this->n[i] = other.n[i]; } inline TensorProxy(const TensorStorage<T, ndim, RetType> & other); public: UInt size(UInt i) const { AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim << " dimensions, not " << (i + 1)); return n[i]; } inline UInt size() const{ UInt _size = 1; for (UInt d = 0; d < ndim; ++d) _size *= this->n[d]; return _size; } T * storage() const { return values; } + void copyExternalMemory(T * data, UInt nb_values) { + AKANTU_DEBUG_ASSERT(nb_values == this->size(), + "You are trying to copy two tensors with differents sizes"); + memcpy(this->values, data, nb_values * sizeof(T)); + } + protected: T * values; UInt n[ndim]; }; /* -------------------------------------------------------------------------- */ template<typename T> class VectorProxy : public TensorProxy<T, 1, Vector<T> > { typedef TensorProxy<T, 1, Vector<T> > parent; public: VectorProxy(T * data = NULL, UInt n = 0) : parent(data, n, 0, 0) { } VectorProxy(const VectorProxy & src) : parent(src) { } VectorProxy(const Vector<T> & src) : parent(src) { } + + VectorProxy & operator=(const Vector<T> & src) { + this->copyExternalMemory(src.storage(), src.size()); + return *this; + } }; template<typename T> class MatrixProxy : public TensorProxy<T, 2, Matrix<T> > { typedef TensorProxy<T, 2, Matrix<T> > parent; public: MatrixProxy(T * data = NULL, UInt m = 0, UInt n = 0) : parent(data, m, n, 0) { } MatrixProxy(const MatrixProxy & src) : parent(src) { } MatrixProxy(const Matrix<T> & src) : parent(src) { } + + MatrixProxy & operator=(const Matrix<T> & src) { + this->copyExternalMemory(src.storage(), src.size()); + return *this; + } }; template<typename T> class Tensor3Proxy : public TensorProxy<T, 3, Tensor3<T> > { typedef TensorProxy<T, 3, Tensor3<T> > parent; public: Tensor3Proxy(T * data = NULL, UInt m = 0, UInt n = 0, UInt k = 0) : parent(data, m, n, k) { } Tensor3Proxy(const Tensor3Proxy & src) : parent(src) { } Tensor3Proxy(const Tensor3<T> & src) : parent(src) { } + + Tensor3Proxy & operator=(const Tensor3<T> & src) { + this->copyExternalMemory(src.storage(), src.size()); + return *this; + } }; /* -------------------------------------------------------------------------- */ /* Tensor base class */ /* -------------------------------------------------------------------------- */ template<typename T, UInt ndim, class RetType> class TensorStorage { public: typedef T value_type; protected: template<class TensorType> void copySize(const TensorType & src) { for (UInt d = 0; d < ndim; ++d) this->n[d] = src.size(d); this->_size = src.size(); } TensorStorage() : values(NULL), wrapped(false) { for (UInt d = 0; d < ndim; ++d) this->n[d] = 0; _size = 0; } TensorStorage(const TensorProxy<T, ndim, RetType> & proxy) { this->copySize(proxy); this->values = proxy.storage(); this->wrapped = true; } protected: TensorStorage(const TensorStorage & src) { } public: TensorStorage(const TensorStorage & src, bool deep_copy) : values(NULL), wrapped(false) { if(deep_copy) this->deepCopy(src); else this->shallowCopy(src); } protected: TensorStorage(UInt m, UInt n, UInt p, const T & def) { DimHelper<ndim>::setDims(m, n, p, this->n); this->computeSize(); this->values = new T[this->_size]; this->set(def); this->wrapped = false; } TensorStorage(T * data, UInt m, UInt n, UInt p) { DimHelper<ndim>::setDims(m, n, p, this->n); this->computeSize(); this->values = data; this->wrapped = true; } public: /* ------------------------------------------------------------------------ */ template<class TensorType> inline void shallowCopy(const TensorType & src) { this->copySize(src); if(!this->wrapped) delete[] this->values; this->values = src.storage(); this->wrapped = true; } /* ------------------------------------------------------------------------ */ template<class TensorType> inline void deepCopy(const TensorType & src) { this->copySize(src); if(!this->wrapped) delete [] this->values; this->values = new T[this->_size]; memcpy(this->values, src.storage(), this->_size * sizeof(T)); this->wrapped = false; } virtual ~TensorStorage() { if(!this->wrapped) delete [] this->values; } inline TensorStorage & operator=(const RetType & src) { if(this != &src) { if (this->wrapped) { AKANTU_DEBUG_ASSERT(this->_size == src.size(), "vectors of different size"); memcpy(this->values, src.storage(), this->_size * sizeof(T)); } else { deepCopy(src); } } return *this; } /* ------------------------------------------------------------------------ */ template<class R> inline RetType & operator+=(const TensorStorage<T, ndim, R> & other) { T * a = this->storage(); T * b = other.storage(); AKANTU_DEBUG_ASSERT(_size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); for (UInt i = 0; i < _size; ++i) *(a++) += *(b++); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ template<class R> inline RetType & operator-=(const TensorStorage<T, ndim, R> & other) { T * a = this->storage(); T * b = other.storage(); AKANTU_DEBUG_ASSERT(_size == other.size(), "The two tensors do not have the same size, they cannot be subtracted"); for (UInt i = 0; i < _size; ++i) *(a++) -= *(b++); return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator+=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) += x; return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator-=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) -= x; return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ inline RetType & operator*=(const T & x) { T * a = this->storage(); for (UInt i = 0; i < _size; ++i) *(a++) *= x; return *(static_cast<RetType *>(this)); } /* ---------------------------------------------------------------------- */ inline RetType & operator/=(const T & x) { T * a = this->values; for (UInt i = 0; i < _size; ++i) *(a++) /= x; return *(static_cast<RetType *>(this)); } /* ------------------------------------------------------------------------ */ T * storage() const { return values; } UInt size() const { return _size; } UInt size(UInt i) const { AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim << " dimensions, not " << (i + 1)); return n[i]; }; /* ------------------------------------------------------------------------ */ inline void clear() { memset(values, 0, _size * sizeof(T)); }; inline void set(const T & t) { std::fill_n(values, _size, t); }; template<class TensorType> inline void copy(const TensorType & other) { AKANTU_DEBUG_ASSERT(_size == other.size(), "The two tensors do not have the same size, they cannot be copied"); memcpy(values, other.storage(), _size * sizeof(T)); } protected: friend class Array<T>; inline void computeSize() { _size = 1; for (UInt d = 0; d < ndim; ++d) _size *= this->n[d]; } protected: template<typename R, NormType norm_type> struct NormHelper { template<class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += std::pow(std::abs(*it), norm_type); return std::pow(_norm, 1./norm_type); } }; template<typename R> struct NormHelper<R, L_1> { template<class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += std::abs(*it); return _norm; } }; template<typename R> struct NormHelper<R, L_2> { template<class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm += *it * *it; return sqrt(_norm); } }; template<typename R> struct NormHelper<R, L_inf> { template<class Ten> static R norm(const Ten & ten) { R _norm = 0.; R * it = ten.storage(); R * end = ten.storage() + ten.size(); for (; it < end; ++it) _norm = std::max(std::abs(*it), _norm); return _norm; } }; public: /*----------------------------------------------------------------------- */ /// "Entrywise" norm norm<L_p> @f[ \|\boldsymbol{T}\|_p = \left( /// \sum_i^{n[0]}\sum_j^{n[1]}\sum_k^{n[2]} |T_{ijk}|^p \right)^{\frac{1}{p}} /// @f] template<NormType norm_type> inline T norm() const { return NormHelper<T, norm_type>::norm(*this); } protected: UInt n[ndim]; UInt _size; T * values; bool wrapped; }; template<typename T, UInt ndim, class RetType> inline TensorProxy<T, ndim, RetType>::TensorProxy(const TensorStorage<T, ndim, RetType> & other) { this->values = other.storage(); for (UInt i = 0; i < ndim; ++i) this->n[i] = other.size(i); } /* -------------------------------------------------------------------------- */ /* Vector */ /* -------------------------------------------------------------------------- */ template<typename T> class Vector : public TensorStorage< T, 1, Vector<T> > { typedef TensorStorage< T, 1, Vector<T> > parent; public: typedef typename parent::value_type value_type; typedef VectorProxy<T> proxy; public: Vector() : parent() {} Vector(UInt n, const T & def = T()) : parent(n, 0, 0, def) { } Vector(T * data, UInt n) : parent(data, n, 0, 0) { } Vector(const Vector & src, bool deep_copy = true) : parent(src, deep_copy) { } Vector(const VectorProxy<T> & src) : parent(src) { } public: virtual ~Vector() { }; /* ------------------------------------------------------------------------ */ inline Vector & operator=(const Vector & src) { parent::operator=(src); return *this; } /* ------------------------------------------------------------------------ */ inline T& operator()(UInt i) { return *(this->values + i); }; inline const T& operator()(UInt i) const { return *(this->values + i); }; inline T& operator[](UInt i) { return *(this->values + i); }; inline const T& operator[](UInt i) const { return *(this->values + i); }; /* ------------------------------------------------------------------------ */ inline Vector<T> & operator*=(Real x) { return parent::operator*=(x); } inline Vector<T> & operator/=(Real x) { return parent::operator/=(x); } /* ------------------------------------------------------------------------ */ inline Vector<T> & operator*=(const Vector<T> & vect) { T * a = this->storage(); T * b = vect.storage(); for (UInt i = 0; i < this->_size; ++i) *(a++) *= *(b++); return *this; } /* ------------------------------------------------------------------------ */ inline Real dot(const Vector<T> & vect) const { return Math::vectorDot(this->values, vect.storage(), this->_size); } /* ------------------------------------------------------------------------ */ inline Real mean() const { Real mean = 0; T * a = this->storage(); for (UInt i = 0; i < this->_size; ++i) mean += *(a++); return mean / this->_size; } /* ------------------------------------------------------------------------ */ inline Vector & crossProduct(const Vector<T> & v1, const Vector<T> & v2) { AKANTU_DEBUG_ASSERT(this->size() == 3, "crossProduct is only defined in 3D (n=" << this->size() << ")"); AKANTU_DEBUG_ASSERT(this->size() == v1.size() && this->size() == v2.size(), "crossProduct is not a valid operation non matching size vectors"); Math::vectorProduct3(v1.storage(), v2.storage(), this->values); return *this; } /* ------------------------------------------------------------------------ */ inline void solve(Matrix<T> & A, const Vector<T> & b) { AKANTU_DEBUG_ASSERT(this->size() == A.rows() && this->_size = A.cols(), "The solution vector as a mismatch in size with the matrix"); AKANTU_DEBUG_ASSERT(this->_size == b._size, "The rhs vector as a mismatch in size with the matrix"); Math::solve(this->_size, A.storage(), this->values, b.storage()); } /* ------------------------------------------------------------------------ */ template<bool tr_A> inline void mul(const Matrix<T> & A, const Vector<T> & x, Real alpha = 1.0); /* ------------------------------------------------------------------------ */ inline Real norm() const { return parent::template norm<L_2>(); } template<NormType nt> inline Real norm() const { return parent::template norm<nt>(); } /* ------------------------------------------------------------------------ */ inline void normalize() { Real n = norm(); operator/=(n); } /* ------------------------------------------------------------------------ */ /// norm of (*this - x) inline Real distance(const Vector<T> & y) const { Real * vx = this->values; Real * vy = y.storage(); Real sum_2 = 0; for (UInt i = 0; i < this->_size; ++i, ++vx, ++vy) sum_2 += (*vx - *vy)*(*vx - *vy); return sqrt(sum_2); } /* ------------------------------------------------------------------------ */ inline bool equal(const Vector<T> & v, Real tolerance = Math::getTolerance()) const { T * a = this->storage(); T * b = v.storage(); UInt i = 0; while (i < this->_size && (std::abs(*(a++) - *(b++)) < tolerance)) ++i; return i == this->_size; } /* ------------------------------------------------------------------------ */ inline short compare(const Vector<T> & v, Real tolerance = Math::getTolerance()) const { T * a = this->storage(); T * b = v.storage(); for (UInt i(0); i < this->_size; ++i, ++a, ++b) { if(std::abs(*a - *b) > tolerance) return (((*a - *b) > tolerance) ? 1 : -1); } return 0; } /* ------------------------------------------------------------------------ */ inline bool operator==(const Vector<T> & v) const { return equal(v); } inline bool operator<(const Vector<T> & v) const { return compare(v) == -1; } inline bool operator>(const Vector<T> & v) const { return compare(v) == 1; } /* ------------------------------------------------------------------------ */ /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Vector<" << debug::demangle(typeid(T).name()) << ">(" << this->_size <<") : ["; for (UInt i = 0; i < this->_size; ++i) { if(i != 0) stream << ", "; stream << this->values[i]; } stream << "]"; } friend class ::akantu::Array<T>; }; typedef Vector<Real> RVector; /* -------------------------------------------------------------------------- */ // support operations for the creation of other vectors template <typename T> Vector<T> operator*(T scalar, const Vector<T> & a); template <typename T> Vector<T> operator+(const Vector<T> & a, const Vector<T> & b); template <typename T> Vector<T> operator-(const Vector<T> & a, const Vector<T> & b); /* -------------------------------------------------------------------------- */ template <typename T> Vector<T> operator*(T scalar, const Vector<T> & a) { Vector<T> r(a.size()); r = a; r *= scalar; return r; } template <typename T> Vector<T> operator+(const Vector<T> & a, const Vector<T> & b) { Vector<T> r(a.size()); r = a; r += b; return r; } template <typename T> Vector<T> operator-(const Vector<T>& a, const Vector<T>& b) { Vector<T> r(a.size()); r = a; r -= b; return r; } template <typename T> Matrix<T> operator*(T scalar, const Matrix<T>& a) { Matrix<T> r(a.rows(), a.cols()); r = a; r *= scalar; return r; } template <typename T> Matrix<T> operator+(const Matrix<T>& a, const Matrix<T>& b) { Matrix<T> r(a.rows(), a.cols()); r = a; r += b; return r; } template <typename T> Matrix<T> operator-(const Matrix<T>& a, const Matrix<T>& b) { Matrix<T> r(a.rows(), a.cols()); r = a; r -= b; return r; } /* ------------------------------------------------------------------------ */ template<> inline bool Vector<UInt>::equal(const Vector<UInt> & v, __attribute__((unused)) Real tolerance) const { UInt * a = this->storage(); UInt * b = v.storage(); UInt i = 0; while (i < this->_size && (*(a++) == *(b++))) ++i; return i == this->_size; } /* ------------------------------------------------------------------------ */ /* Matrix */ /* ------------------------------------------------------------------------ */ template<typename T> class Matrix : public TensorStorage< T, 2, Matrix<T> > { typedef TensorStorage< T, 2, Matrix<T> > parent; public: typedef typename parent::value_type value_type; typedef MatrixProxy<T> proxy; public: Matrix() : parent() {} Matrix(UInt m, UInt n, const T & def = T()) : parent(m, n, 0, def) { } Matrix(T * data, UInt m, UInt n) : parent(data, m, n, 0) { } Matrix(const Matrix & src, bool deep_copy = true) : parent(src, deep_copy) { } Matrix(const MatrixProxy<T> & src) : parent(src) { } virtual ~Matrix() { } /* ------------------------------------------------------------------------ */ inline Matrix & operator=(const Matrix & src) { parent::operator=(src); return *this; } public: /* ---------------------------------------------------------------------- */ UInt rows() const { return this->n[0]; } UInt cols() const { return this->n[1]; } /* ---------------------------------------------------------------------- */ inline T& operator()(UInt i, UInt j) { return this->at(i,j); } inline T& at(UInt i, UInt j) { return *(this->values + i + j*this->n[0]); } inline const T& operator()(UInt i, UInt j) const { return this->at(i,j); } inline T& at(UInt i, UInt j) const { return *(this->values + i + j*this->n[0]); } /// give a line vector wrapped on the column i inline VectorProxy<T> operator()(UInt j) { return VectorProxy<T>(this->values + j*this->n[0], this->n[0]); } inline const VectorProxy<T> operator()(UInt j) const { return VectorProxy<T>(this->values + j*this->n[0], this->n[0]); } inline T& operator[](UInt idx) { return *(this->values + idx); }; inline const T& operator[](UInt idx) const { return *(this->values + idx); }; /* ---------------------------------------------------------------------- */ inline Matrix operator* (const Matrix & B) { Matrix C(this->rows(), B.cols()); C.mul<false, false>(*this, B); return C; } /* ----------------------------------------------------------------------- */ inline Matrix & operator*= (const T & x) { return parent::operator*= (x); } inline Matrix & operator*= (const Matrix & B) { Matrix C(*this); this->mul<false, false>(C, B); return *this; } /* ---------------------------------------------------------------------- */ template<bool tr_A, bool tr_B> inline void mul(const Matrix & A, const Matrix & B, T alpha = 1.0) { UInt k = A.cols(); if(tr_A) k = A.rows(); #ifndef AKANTU_NDEBUG if (tr_B){ AKANTU_DEBUG_ASSERT(k == B.cols(), "matrices to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->cols() == B.rows(), "matrices to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(k == B.rows(), "matrices to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->cols() == B.cols(), "matrices to multiply have no fit dimensions"); } if (tr_A){ AKANTU_DEBUG_ASSERT(this->rows() == A.cols(), "matrices to multiply have no fit dimensions"); } else{ AKANTU_DEBUG_ASSERT(this->rows() == A.rows(), "matrices to multiply have no fit dimensions"); } #endif //AKANTU_NDEBUG Math::matMul<tr_A, tr_B>(this->rows(), this->cols(), k, alpha, A.storage(), B.storage(), 0., this->storage()); } /* ---------------------------------------------------------------------- */ inline void outerProduct(const Vector<T> & A, const Vector<T> & B) { AKANTU_DEBUG_ASSERT(A.size() == this->rows() && B.size() == this->cols(), "A and B are not compatible with the size of the matrix"); for (UInt i = 0; i < this->rows(); ++i) { for (UInt j = 0; j < this->cols(); ++j) { this->values[i + j * this->rows()] += A[i] * B[j]; } } } private: class EigenSorter { public: EigenSorter(const Vector<T> & eigs) : eigs(eigs) { } bool operator()(const UInt & a, const UInt & b) const { return (eigs(a) > eigs(b)); } private: const Vector<T> & eigs; }; public: /* ---------------------------------------------------------------------- */ inline void eig(Vector<T> & eigenvalues, Matrix<T> & eigenvectors) const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "eig is not a valid operation on a rectangular matrix"); AKANTU_DEBUG_ASSERT(eigenvalues.size() == this->cols(), "eigenvalues should be of size " << this->cols() << "."); #ifndef AKANTU_NDEBUG if(eigenvectors.storage() != NULL) AKANTU_DEBUG_ASSERT((eigenvectors.rows() == eigenvectors.cols()) && (eigenvectors.rows() == this->cols()), "Eigenvectors needs to be a square matrix of size " << this->cols() << " x " << this->cols() << "."); #endif Matrix<T> tmp = *this; Vector<T> tmp_eigs(eigenvalues.size()); Matrix<T> tmp_eig_vects(eigenvectors.rows(), eigenvectors.cols()); if(tmp_eig_vects.rows() == 0 || tmp_eig_vects.cols() == 0) Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage()); else Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage(), tmp_eig_vects.storage()); Vector<UInt> perm(eigenvalues.size()); for (UInt i = 0; i < perm.size(); ++i) perm(i) = i; std::sort(perm.storage(), perm.storage() + perm.size(), EigenSorter(tmp_eigs)); for (UInt i = 0; i < perm.size(); ++i) eigenvalues(i) = tmp_eigs(perm(i)); if(tmp_eig_vects.rows() != 0 && tmp_eig_vects.cols() != 0) for (UInt i = 0; i < perm.size(); ++i) { for (UInt j = 0; j < eigenvectors.rows(); ++j) { eigenvectors(j, i) = tmp_eig_vects(j, perm(i)); } } } /* ---------------------------------------------------------------------- */ inline void eig(Vector<T> & eigenvalues) const { Matrix<T> empty; eig(eigenvalues, empty); } /* ---------------------------------------------------------------------- */ inline void eye(T alpha = 1.) { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "eye is not a valid operation on a rectangular matrix"); this->clear(); for (UInt i = 0; i < this->cols(); ++i) { this->values[i + i * this->rows()] = alpha; } } /* ---------------------------------------------------------------------- */ static inline Matrix<T> eye(UInt m, T alpha = 1.) { Matrix<T> tmp(m, m); tmp.eye(alpha); return tmp; } /* ---------------------------------------------------------------------- */ inline T trace() const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "trace is not a valid operation on a rectangular matrix"); T trace = 0.; for (UInt i = 0; i < this->rows(); ++i) { trace += this->values[i + i * this->rows()]; } return trace; } /* ---------------------------------------------------------------------- */ inline Matrix transpose() const { Matrix tmp(this->cols(), this->rows()); for (UInt i = 0; i < this->rows(); ++i) { for (UInt j = 0; j < this->cols(); ++j) { tmp(j,i) = operator()(i, j); } } return tmp; } /* ---------------------------------------------------------------------- */ inline void inverse(const Matrix & A) { AKANTU_DEBUG_ASSERT(A.cols() == A.rows(), "inv is not a valid operation on a rectangular matrix"); AKANTU_DEBUG_ASSERT(this->cols() == A.cols(), "the matrix should have the same size as its inverse"); if(this->cols() == 1) *this->values = 1./ *A.storage(); else if(this->cols() == 2) Math::inv2(A.storage(), this->values); else if(this->cols() == 3) Math::inv3(A.storage(), this->values); else Math::inv(this->cols(), A.storage(), this->values); } /* --------------------------------------------------------------------- */ inline T det() const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "inv is not a valid operation on a rectangular matrix"); if(this->cols() == 1) return *(this->values); else if(this->cols() == 2) return Math::det2(this->values); else if(this->cols() == 3) return Math::det3(this->values); else return Math::det(this->cols(), this->values); } /* --------------------------------------------------------------------- */ inline T doubleDot(const Matrix<T> & other) const { AKANTU_DEBUG_ASSERT(this->cols() == this->rows(), "doubleDot is not a valid operation on a rectangular matrix"); if(this->cols() == 1) return *(this->values) * *(other.storage()); else if(this->cols() == 2) return Math::matrixDoubleDot22(this->values, other.storage()); else if(this->cols() == 3) return Math::matrixDoubleDot33(this->values, other.storage()); else AKANTU_DEBUG_ERROR("doubleDot is not defined for other spatial dimensions" << " than 1, 2 or 3."); return T(); } /* ---------------------------------------------------------------------- */ /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Matrix<" << debug::demangle(typeid(T).name()) << ">(" << this->n[0] << "," << this->n[1] <<") :" << "["; for (UInt i = 0; i < this->n[0]; ++i) { if(i != 0) stream << ", "; stream << "["; for (UInt j = 0; j < this->n[1]; ++j) { if(j != 0) stream << ", "; stream << operator()(i, j); } stream << "]"; } stream << "]"; }; }; /* ------------------------------------------------------------------------ */ template<typename T> template<bool tr_A> inline void Vector<T>::mul(const Matrix<T> & A, const Vector<T> & x, Real alpha) { #ifndef AKANTU_NDEBUG UInt n = x.size(); if (tr_A){ AKANTU_DEBUG_ASSERT(n == A.rows(), "matrix and vector to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->size() == A.cols(), "matrix and vector to multiply have no fit dimensions"); } else { AKANTU_DEBUG_ASSERT(n == A.cols(), "matrix and vector to multiply have no fit dimensions"); AKANTU_DEBUG_ASSERT(this->size() == A.rows(), "matrix and vector to multiply have no fit dimensions"); } #endif Math::matVectMul<tr_A>(A.rows(), A.cols(), alpha, A.storage(), x.storage(), 0., this->storage()); } /* -------------------------------------------------------------------------- */ template<typename T> inline std::ostream & operator<<(std::ostream & stream, const Matrix<T> & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ template<typename T> inline std::ostream & operator<<(std::ostream & stream, const Vector<T> & _this) { _this.printself(stream); return stream; } /* ------------------------------------------------------------------------ */ /* Tensor3 */ /* ------------------------------------------------------------------------ */ template<typename T> class Tensor3 : public TensorStorage< T, 3, Tensor3<T> > { typedef TensorStorage< T, 3, Tensor3<T> > parent; public: typedef typename parent::value_type value_type; typedef Tensor3Proxy<T> proxy; public: Tensor3() : parent() { }; Tensor3(UInt m, UInt n, UInt p, const T & def = T()) : parent(m, n, p, def) { } Tensor3(T * data, UInt m, UInt n, UInt p) : parent(data, m, n, p) { } Tensor3(const Tensor3 & src, bool deep_copy = true) : parent(src, deep_copy) { } public: /* ------------------------------------------------------------------------ */ inline Tensor3 & operator=(const Tensor3 & src) { parent::operator=(src); return *this; } /* ---------------------------------------------------------------------- */ inline T& operator()(UInt i, UInt j, UInt k) { return *(this->values + (k*this->n[0] + i)*this->n[1] + j); }; inline const T& operator()(UInt i, UInt j, UInt k) const { return *(this->values + (k*this->n[0] + i)*this->n[1] + j); }; inline MatrixProxy<T> operator()(UInt k) { return MatrixProxy<T>(this->values + k*this->n[0]*this->n[1], this->n[0], this->n[1]); } inline const MatrixProxy<T> operator()(UInt k) const { return MatrixProxy<T>(this->values + k*this->n[0]*this->n[1], this->n[0], this->n[1]); } inline MatrixProxy<T> operator[](UInt k) { return Matrix<T>(this->values + k*this->n[0]*this->n[1], this->n[0], this->n[1]); } inline const MatrixProxy<T> operator[](UInt k) const { return MatrixProxy<T>(this->values + k*this->n[0]*this->n[1], this->n[0], this->n[1]); } }; __END_AKANTU__ #endif /* __AKANTU_AKA_TYPES_HH__ */ diff --git a/src/fe_engine/fe_engine.cc b/src/fe_engine/fe_engine.cc index 753c477cf..66b8dd754 100644 --- a/src/fe_engine/fe_engine.cc +++ b/src/fe_engine/fe_engine.cc @@ -1,241 +1,275 @@ /** * @file fe_engine.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 20 2010 * @date last modification: Fri Jun 13 2014 * * @brief Implementation of the FEEngine 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 "fe_engine.hh" #include "mesh.hh" #include "element_class.hh" #include "static_communicator.hh" #include "aka_math.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ FEEngine::FEEngine(Mesh & mesh, UInt element_dimension, ID id, MemoryID memory_id) : Memory(id, memory_id), mesh(mesh), normals_on_quad_points("normals_on_quad_points", id) { AKANTU_DEBUG_IN(); this->element_dimension = (element_dimension != _all_dimensions) ? element_dimension : mesh.getSpatialDimension(); init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FEEngine::init() { } /* -------------------------------------------------------------------------- */ FEEngine::~FEEngine() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FEEngine::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, - const Array<UInt> & filter_elements, - Real scale_factor) const { + Array<Real> & nodal_values, + const Array<Int> & equation_number, + UInt nb_degree_of_freedom, + const ElementType & type, + const GhostType & ghost_type, + const Array<UInt> & filter_elements, + Real scale_factor) const { AKANTU_DEBUG_IN(); UInt nb_element; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); Array<UInt>::const_iterator< Vector<UInt> > conn_it; Array<UInt> * filtered_connectivity = NULL; if(filter_elements != empty_filter) { nb_element = filter_elements.getSize(); filtered_connectivity = new Array<UInt>(0, nb_nodes_per_element); FEEngine::filterElementalData(mesh, - mesh.getConnectivity(type, ghost_type), - *filtered_connectivity, - type, ghost_type, - filter_elements); + mesh.getConnectivity(type, ghost_type), + *filtered_connectivity, + type, ghost_type, + filter_elements); const Array<UInt> & cfiltered = *filtered_connectivity; // \todo temporary patch conn_it = cfiltered.begin(nb_nodes_per_element); } else { nb_element = mesh.getNbElement(type, ghost_type); conn_it = mesh.getConnectivity(type, ghost_type).begin(nb_nodes_per_element); } AKANTU_DEBUG_ASSERT(elementary_vect.getSize() == nb_element, - "The vector elementary_vect(" << elementary_vect.getID() - << ") has not the good size."); + "The vector elementary_vect(" << elementary_vect.getID() + << ") has not the good size."); AKANTU_DEBUG_ASSERT(elementary_vect.getNbComponent() - == nb_degree_of_freedom*nb_nodes_per_element, - "The vector elementary_vect(" << elementary_vect.getID() - << ") has not the good number of component." - << "(" << elementary_vect.getNbComponent() - << " != " << nb_degree_of_freedom*nb_nodes_per_element << ")"); + == nb_degree_of_freedom*nb_nodes_per_element, + "The vector elementary_vect(" << elementary_vect.getID() + << ") has not the good number of component." + << "(" << elementary_vect.getNbComponent() + << " != " << nb_degree_of_freedom*nb_nodes_per_element << ")"); AKANTU_DEBUG_ASSERT(nodal_values.getNbComponent() == nb_degree_of_freedom, - "The vector nodal_values(" << nodal_values.getID() - << ") has not the good number of component." - << "(" << nodal_values.getNbComponent() - << " != " << nb_degree_of_freedom << ")"); + "The vector nodal_values(" << nodal_values.getID() + << ") has not the good number of component." + << "(" << nodal_values.getNbComponent() + << " != " << nb_degree_of_freedom << ")"); nodal_values.resize(mesh.getNbNodes()); Real * nodal_it = nodal_values.storage(); Array<Real>::const_matrix_iterator elem_it = elementary_vect.begin(nb_degree_of_freedom, - nb_nodes_per_element); + nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++elem_it, ++conn_it) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = (*conn_it)(n); UInt offset_node = node * nb_degree_of_freedom; const Vector<Real> & elem_data = (*elem_it)(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { nodal_it[equation_number(offset_node + d)] += scale_factor * elem_data(d); } } } delete filtered_connectivity; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FEEngine::assembleMatrix(const Array<Real> & elementary_mat, - SparseMatrix & matrix, - UInt nb_degree_of_freedom, - const ElementType & type, - const GhostType & ghost_type, - const Array<UInt> & filter_elements) const { + SparseMatrix & matrix, + UInt nb_degree_of_freedom, + const ElementType & type, + const GhostType & ghost_type, + const Array<UInt> & filter_elements) const { AKANTU_DEBUG_IN(); UInt nb_element; if(ghost_type == _not_ghost) { nb_element = mesh.getNbElement(type); } else { AKANTU_DEBUG_TO_IMPLEMENT(); } UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); if(filter_elements != empty_filter) { nb_element = filter_elements.getSize(); } AKANTU_DEBUG_ASSERT(elementary_mat.getSize() == nb_element, - "The vector elementary_mat(" << elementary_mat.getID() - << ") has not the good size."); + "The vector elementary_mat(" << elementary_mat.getID() + << ") has not the good size."); AKANTU_DEBUG_ASSERT(elementary_mat.getNbComponent() - == nb_degree_of_freedom * nb_nodes_per_element * nb_degree_of_freedom * nb_nodes_per_element, - "The vector elementary_mat(" << elementary_mat.getID() - << ") has not the good number of component."); + == nb_degree_of_freedom * nb_nodes_per_element * nb_degree_of_freedom * nb_nodes_per_element, + "The vector elementary_mat(" << elementary_mat.getID() + << ") has not the good number of component."); Real * elementary_mat_val = elementary_mat.storage(); UInt offset_elementary_mat = elementary_mat.getNbComponent(); UInt * connectivity_val = mesh.getConnectivity(type, ghost_type).storage(); UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom; UInt size = mesh.getNbGlobalNodes() * nb_degree_of_freedom; Int * eq_nb_val = matrix.getDOFSynchronizer().getGlobalDOFEquationNumbers().storage(); Int * local_eq_nb_val = new Int[size_mat]; for (UInt e = 0; e < nb_element; ++e) { UInt el = e; if(filter_elements != empty_filter) el = filter_elements(e); Int * tmp_local_eq_nb_val = local_eq_nb_val; UInt * conn_val = connectivity_val + el * nb_nodes_per_element; for (UInt i = 0; i < nb_nodes_per_element; ++i) { UInt n = conn_val[i]; for (UInt d = 0; d < nb_degree_of_freedom; ++d) { *tmp_local_eq_nb_val++ = eq_nb_val[n * nb_degree_of_freedom + d]; } // memcpy(tmp_local_eq_nb_val, eq_nb_val + n * nb_degree_of_freedom, nb_degree_of_freedom * sizeof(Int)); // tmp_local_eq_nb_val += nb_degree_of_freedom; } - for (UInt i = 0; i < size_mat; ++i) { - UInt c_irn = local_eq_nb_val[i]; - if(c_irn < size) { - UInt j_start = (matrix.getSparseMatrixType() == _symmetric) ? i : 0; - for (UInt j = j_start; j < size_mat; ++j) { - UInt c_jcn = local_eq_nb_val[j]; - if(c_jcn < size) { - matrix(c_irn, c_jcn) += elementary_mat_val[j * size_mat + i]; + /// The matrix assembling for cohesive elements with degenerated nodes + /// (i.e. elements in correspondence of the crack tips) has to be done + /// without considering symmetry + + +#if defined(AKANTU_COHESIVE_ELEMENT) + if (mesh.getKind(type) == _ek_cohesive){ + + /// matrix assembling procedure for cohesive elements + for (UInt i = 0; i < size_mat; ++i) { + UInt c_irn = local_eq_nb_val[i]; + if(c_irn < size) { + for (UInt j = 0; j < size_mat; ++j) { + UInt c_jcn = local_eq_nb_val[j]; + if(c_jcn < size) { + if (matrix.getSparseMatrixType() == _symmetric){ + if (c_jcn >= c_irn){ + matrix(c_irn, c_jcn) += elementary_mat_val[j * size_mat + i]; + } + }else{ + matrix(c_irn, c_jcn) += elementary_mat_val[j * size_mat + i]; + } + } } } } + elementary_mat_val += offset_elementary_mat; + + }else{ +#endif + /// matrix assembling procedure for all the elements except cohesive ones + for (UInt i = 0; i < size_mat; ++i) { + UInt c_irn = local_eq_nb_val[i]; + if(c_irn < size) { + UInt j_start = (matrix.getSparseMatrixType() == _symmetric) ? i : 0; + for (UInt j = j_start; j < size_mat; ++j) { + UInt c_jcn = local_eq_nb_val[j]; + if(c_jcn < size) { + matrix(c_irn, c_jcn) += elementary_mat_val[j * size_mat + i]; + } + } + } + } + elementary_mat_val += offset_elementary_mat; } - elementary_mat_val += offset_elementary_mat; +#if defined(AKANTU_COHESIVE_ELEMENT) } +#endif delete [] local_eq_nb_val; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FEEngine::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "FEEngine [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + element dimension : " << element_dimension << std::endl; stream << space << " + mesh [" << std::endl; mesh.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/geometry/aabb_primitives/aabb_primitive.hh b/src/geometry/aabb_primitives/aabb_primitive.hh index 98f6d85fc..e603bf47e 100644 --- a/src/geometry/aabb_primitives/aabb_primitive.hh +++ b/src/geometry/aabb_primitives/aabb_primitive.hh @@ -1,77 +1,85 @@ /** * @file aabb_primitive.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Fri Mar 13 2015 * @date last modification: Fri Mar 13 2015 * * @brief Macro classe (primitive) for AABB CGAL algos * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AABB_PRIMITIVE_HH__ #define __AKANTU_AABB_PRIMITIVE_HH__ #include "aka_common.hh" #include "triangle.hh" #include "tetrahedron.hh" __BEGIN_AKANTU__ -typedef CGAL::Cartesian<Real> Kernel; - -#define AKANTU_AABB_CLASS(name) \ +/** + * This macro defines a class that is used in the CGAL AABB tree algorithm. + * All the `typedef`s and methods are required by the AABB module. + * + * The member variables are + * - the id of the element associated to the primitive + * - the geometric primitive of the element + * + * @param name the name of the primitive type + * @param kernel the name of the kernel used + */ +#define AKANTU_AABB_CLASS(name, kernel) \ class name##_primitive { \ - typedef std::list< name<Kernel> >::iterator Iterator; \ + typedef std::list< name<kernel> >::iterator Iterator; \ \ public: \ typedef UInt Id; \ - typedef Kernel::Point_3 Point; \ - typedef Kernel::name##_3 Datum; \ + typedef kernel::Point_3 Point; \ + typedef kernel::name##_3 Datum; \ \ public: \ name##_primitive() : meshId(0), primitive() {} \ name##_primitive(Iterator it) : meshId(it->id()), primitive(*it) {} \ \ public: \ const Datum & datum() const { return primitive; } \ const Point & reference_point() const { return primitive.vertex(0); } \ const Id & id() const { return meshId; } \ \ protected: \ Id meshId; \ - name<Kernel> primitive; \ + name<kernel> primitive; \ \ } // If the primitive is supported by CGAL::intersection() then the // implementation process is really easy with this macro -AKANTU_AABB_CLASS(Triangle); -AKANTU_AABB_CLASS(Tetrahedron); +AKANTU_AABB_CLASS(Triangle, CGAL::Cartesian<Real>); #undef AKANTU_AABB_CLASS __END_AKANTU__ #endif // __AKANTU_AABB_PRIMITIVE_HH__ diff --git a/src/geometry/aabb_primitives/tetrahedron.hh b/src/geometry/aabb_primitives/tetrahedron.hh index e7006ad78..6609fd40b 100644 --- a/src/geometry/aabb_primitives/tetrahedron.hh +++ b/src/geometry/aabb_primitives/tetrahedron.hh @@ -1,71 +1,74 @@ /** * @file tetrahedron.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Tue Mar 10 2015 * @date last modification: Tue Mar 10 2015 * * @brief Tetrahedron classe (geometry) for AABB CGAL algos * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TETRAHEDRON_HH__ #define __AKANTU_TETRAHEDRON_HH__ #include "aka_common.hh" #include <CGAL/Cartesian.h> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ +/// Class used for substitution of CGAL::Tetrahedron_3 primitive template<typename K> class Tetrahedron : public CGAL::Tetrahedron_3<K> { public: /// Default constructor - Tetrahedron(); + Tetrahedron() : + CGAL::Tetrahedron_3<K>(), meshId(0) {} /// Copy constructor - Tetrahedron(const Tetrahedron & other); + Tetrahedron(const Tetrahedron & other) : + CGAL::Tetrahedron_3<K>(other), meshId(other.meshId) {} /// Construct from 4 points Tetrahedron(const CGAL::Point_3<K> & a, const CGAL::Point_3<K> & b, const CGAL::Point_3<K> & c, - const CGAL::Point_3<K> & d); + const CGAL::Point_3<K> & d) : + CGAL::Tetrahedron_3<K>(a, b, c, d), meshId(0) {} public: - UInt id() const; - void setId(UInt newId); + UInt id() const { return meshId; } + void setId(UInt newId) { meshId = newId; } protected: + /// Id of the element represented by the primitive UInt meshId; }; __END_AKANTU__ -#include "tetrahedron_tmpl.hh" - #endif diff --git a/src/geometry/aabb_primitives/tetrahedron_tmpl.hh b/src/geometry/aabb_primitives/tetrahedron_tmpl.hh deleted file mode 100644 index d686cda02..000000000 --- a/src/geometry/aabb_primitives/tetrahedron_tmpl.hh +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file tetrahedron_tmpl.hh - * - * @author Lucas Frérot <lucas.frerot@epfl.ch> - * - * @date creation: Tue Mar 10 2015 - * @date last modification: Tue Mar 10 2015 - * - * @brief Tetrahedron class (geometry) for AABB CGAL algos, template impl - * - * @section LICENSE - * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) - * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#ifndef __AKANTU_TETRAHEDRON_TMPL_HH__ -#define __AKANTU_TETRAHEDRON_TMPL_HH__ - -#include "tetrahedron.hh" -#include <CGAL/Cartesian.h> - -__BEGIN_AKANTU__ - -template<typename K> -Tetrahedron<K>::Tetrahedron() : - CGAL::Tetrahedron_3<K>(), - meshId(0) -{} - -template<typename K> -Tetrahedron<K>::Tetrahedron(const CGAL::Point_3<K> & a, - const CGAL::Point_3<K> & b, - const CGAL::Point_3<K> & c, - const CGAL::Point_3<K> & d) : - CGAL::Tetrahedron_3<K>(a, b, c, d), - meshId(0) -{} - -template<typename K> -Tetrahedron<K>::Tetrahedron(const Tetrahedron & other) : - CGAL::Tetrahedron_3<K>(other), - meshId(other.meshId) -{} - -template<typename K> -UInt Tetrahedron<K>::id() const { - return meshId; -} - -template<typename K> -void Tetrahedron<K>::setId(UInt newId) { - meshId = newId; -} - -__END_AKANTU__ - -#endif diff --git a/src/geometry/aabb_primitives/triangle.hh b/src/geometry/aabb_primitives/triangle.hh index 4b4112a65..30c6104d1 100644 --- a/src/geometry/aabb_primitives/triangle.hh +++ b/src/geometry/aabb_primitives/triangle.hh @@ -1,68 +1,71 @@ /** * @file triangle.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Tue Mar 3 2015 * @date last modification: Tue Mar 3 2015 * * @brief Triangle classe (geometry) for AABB CGAL algos * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TRIANGLE_HH__ #define __AKANTU_TRIANGLE_HH__ #include "aka_common.hh" #include <CGAL/Cartesian.h> __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ +/// Class used for substitution of CGAL::Triangle_3 primitive template<typename K> class Triangle : public CGAL::Triangle_3<K> { public: /// Default constructor - Triangle(); + Triangle() : + CGAL::Triangle_3<K>(), meshId(0) {} /// Copy constructor - Triangle(const Triangle & other); + Triangle(const Triangle & other) : + CGAL::Triangle_3<K>(other), meshId(other.meshId) {} /// Construct from 3 points - Triangle(const CGAL::Point_3<K> & a, const CGAL::Point_3<K> & b, const CGAL::Point_3<K> & c); + Triangle(const CGAL::Point_3<K> & a, const CGAL::Point_3<K> & b, const CGAL::Point_3<K> & c): + CGAL::Triangle_3<K>(a, b, c), meshId(0) {} public: - UInt id() const; - void setId(UInt newId); + UInt id() const { return meshId; } + void setId(UInt newId) { meshId = newId; } protected: + /// Id of the element represented by the primitive UInt meshId; }; __END_AKANTU__ -#include "triangle_tmpl.hh" - #endif // __AKANTU_TRIANGLE_HH__ diff --git a/src/geometry/aabb_primitives/triangle_tmpl.hh b/src/geometry/aabb_primitives/triangle_tmpl.hh deleted file mode 100644 index acd15ed8f..000000000 --- a/src/geometry/aabb_primitives/triangle_tmpl.hh +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file triangle_tmpl.hh - * - * @author Lucas Frérot <lucas.frerot@epfl.ch> - * - * @date creation: Tue Mar 3 2015 - * @date last modification: Tue Mar 3 2015 - * - * @brief Triangle classe (geometry) for AABB CGAL algos, template impl - * - * @section LICENSE - * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) - * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#ifndef __AKANTU_TRIANGLE_TMPL_HH__ -#define __AKANTU_TRIANGLE_TMPL_HH__ - -#include "triangle.hh" -#include <CGAL/Cartesian.h> - -__BEGIN_AKANTU__ - -template<typename K> -Triangle<K>::Triangle() : - CGAL::Triangle_3<K>(), - meshId(0) -{} - -template<typename K> -Triangle<K>::Triangle(const CGAL::Point_3<K> & a, const CGAL::Point_3<K> & b, const CGAL::Point_3<K> & c) : - CGAL::Triangle_3<K>(a, b, c), - meshId(0) -{} - -template<typename K> -Triangle<K>::Triangle(const Triangle & other) : - CGAL::Triangle_3<K>(other), - meshId(other.meshId) -{} - -template<typename K> -UInt Triangle<K>::id() const { - return meshId; -} - -template<typename K> -void Triangle<K>::setId(UInt newId) { - meshId = newId; -} - -__END_AKANTU__ - -#endif // __AKANTU_TRIANGLE_TMPL_HH__ diff --git a/src/geometry/geom_helper_functions.hh b/src/geometry/geom_helper_functions.hh index 8ab38bf3f..63337084c 100644 --- a/src/geometry/geom_helper_functions.hh +++ b/src/geometry/geom_helper_functions.hh @@ -1,125 +1,114 @@ /** * @file geom_helper_functions.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Wed Mar 4 2015 * @date last modification: Thu Mar 5 2015 * * @brief Helper functions for the computational geometry algorithms * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef _AKANTU_GEOM_HELPER_FUNCTIONS_HH__ #define _AKANTU_GEOM_HELPER_FUNCTIONS_HH__ #include "aka_common.hh" #include "aka_math.hh" #include "tree_type_helper.hh" #include <CGAL/Cartesian.h> __BEGIN_AKANTU__ typedef CGAL::Cartesian<Real> K; #define EPS 1e-10 +/// Fuzzy compare of two points inline bool comparePoints(const K::Point_3 & a, const K::Point_3 & b) { Math::setTolerance(EPS); return Math::are_float_equal(a.x(), b.x()) && Math::are_float_equal(a.y(), b.y()); } +/// Fuzzy compare of two segments inline bool compareSegments(const K::Segment_3 & a, const K::Segment_3 & b) { return (comparePoints(a.source(), b.source()) && comparePoints(a.target(), b.target())) || (comparePoints(a.source(), b.target()) && comparePoints(a.target(), b.source())); } +/// Compare segment pairs inline bool compareSegmentPairs(const std::pair<K::Segment_3, UInt> & a, const std::pair<K::Segment_3, UInt> & b) { return compareSegments(a.first, b.first); } +/// Pair ordering operator based on second member inline bool comparePairElement(const std::pair<K::Segment_3, UInt> & a, const std::pair<K::Segment_3, UInt> & b) { return a.second < b.second; } +/// Pair ordering operator based on first member inline bool lessSegmentPair(const std::pair<K::Segment_3, UInt> & a, const std::pair<K::Segment_3, UInt> & b) { return CGAL::compare_lexicographically(a.first.min(), b.first.min()) || CGAL::compare_lexicographically(a.first.max(), b.first.max()); } /* -------------------------------------------------------------------------- */ /* Predicates */ /* -------------------------------------------------------------------------- */ -// Predicate used to eliminate faces of mesh not belonging to a specific element -template <UInt dim, ElementType el_type> +/// Predicate used to eliminate faces of mesh not belonging to a specific element +template <class Primitive, class Kernel> class BelongsNotToElement { public: BelongsNotToElement(UInt el): el(el) {} - bool operator()(const typename TreeTypeHelper<dim, el_type>::primitive_type & primitive) { + bool operator()(const typename TreeTypeHelper<Primitive, Kernel>::primitive_type & primitive) { return primitive.id() != el; } protected: const UInt el; }; -// Predicate used to determine if point is on edge of faces of mesh -template <UInt dim, ElementType el_type> -class HasOnEdge { - -public: - HasOnEdge(const K::Point_3 & point): - point(point) - {} - - bool operator()(const typename TreeTypeHelper<dim, el_type>::primitive_type & primitive) { - return primitive.has_on(point); - } - -protected: - const K::Point_3 & point; -}; - +/// Predicate used to determine if two segments are equal class IsSameSegment { public: IsSameSegment(const K::Segment_3 & segment): segment(segment) {} bool operator()(const std::pair<K::Segment_3, UInt> & test_pair) { return compareSegments(segment, test_pair.first); } protected: const K::Segment_3 segment; }; __END_AKANTU__ #endif // _AKANTU_GEOM_HELPER_FUNCTIONS_HH__ diff --git a/src/geometry/mesh_geom_abstract.hh b/src/geometry/mesh_geom_abstract.hh index 0b89f05a4..b116ab725 100644 --- a/src/geometry/mesh_geom_abstract.hh +++ b/src/geometry/mesh_geom_abstract.hh @@ -1,76 +1,64 @@ /** * @file mesh_geom_abstract.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Feb 26 2015 * @date last modification: Fri Mar 6 2015 * * @brief Class for constructing the CGAL primitives of a mesh * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_GEOM_ABSTRACT_HH__ #define __AKANTU_MESH_GEOM_ABSTRACT_HH__ #include "aka_common.hh" #include "mesh.hh" -#include <CGAL/Cartesian.h> - /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ -typedef CGAL::Cartesian<Real> K; - +/// Abstract class for mesh geometry operations class MeshGeomAbstract { -protected: - typedef std::pair<K::Segment_3, std::string> Interface; - public: /// Construct from mesh explicit MeshGeomAbstract(const Mesh & mesh); /// Destructor virtual ~MeshGeomAbstract(); public: /// Construct geometric data for computational geometry algorithms virtual void constructData() = 0; - /// Compute number of intersections with geometric interface - virtual UInt numberOfIntersectionsWithInterface(const K::Segment_3 & interface) const = 0; - - /// Compute the mesh created by a linear interface - virtual void meshOfLinearInterface(const Interface & interface, Mesh & interface_mesh) = 0; - protected: /// Mesh used to construct the primitives const Mesh & mesh; }; __END_AKANTU__ #endif // __AKANTU_MESH_GEOM_ABSTRACT_HH__ diff --git a/src/geometry/mesh_geom_container.cc b/src/geometry/mesh_geom_container.cc deleted file mode 100644 index 84925c1b5..000000000 --- a/src/geometry/mesh_geom_container.cc +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file mesh_geom_container.cc - * - * @author Lucas Frérot <lucas.frerot@epfl.ch> - * - * @date creation: Fri Feb 27 2015 - * @date last modification: Fri Mar 6 2015 - * - * @brief Contains the CGAL representation of a mesh - * - * @section LICENSE - * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) - * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#include "aka_common.hh" - -#include "mesh_geom_container.hh" -#include "mesh_geom_factory.hh" -#include "mesh.hh" - -#include <CGAL/Cartesian.h> - -/* -------------------------------------------------------------------------- */ - -#define MESH_GEOM_CASE(d, type) \ - MeshGeomFactory<d, type> * factory = new MeshGeomFactory<d, type>(mesh); \ - factory_map(factory, type); \ - factory->constructData(); - -#define MESH_GEOM_CASE_2D(type) MESH_GEOM_CASE(2, type) -#define MESH_GEOM_CASE_3D(type) MESH_GEOM_CASE(3, type) - -/* -------------------------------------------------------------------------- */ - -__BEGIN_AKANTU__ - -typedef CGAL::Cartesian<Real> K; - - -MeshGeomContainer::MeshGeomContainer(const Mesh & mesh): - MeshGeomAbstract(mesh), - factory_map(), - interface_mesh(mesh.getSpatialDimension(), "mesh_geom") -{ - interface_mesh.addConnectivityType(_segment_2, _not_ghost); - interface_mesh.addConnectivityType(_segment_2, _ghost); - interface_mesh.registerData<Element>("associated_element").alloc(0, 1, _segment_2); - interface_mesh.registerData<std::string>("material").alloc(0, 1, _segment_2); -} - -MeshGeomContainer::~MeshGeomContainer() -{} - -void MeshGeomContainer::constructData() { - AKANTU_DEBUG_IN(); - - const UInt spatial_dim = mesh.getSpatialDimension(); - - Mesh::type_iterator it = mesh.firstType(spatial_dim, _not_ghost); - Mesh::type_iterator end = mesh.lastType(spatial_dim, _not_ghost); - - /// Loop over the element types of the mesh and construct the primitive trees - for (; it != end ; ++it) { - ElementType type = *it; // for AKANTU_BOOST_ELEMENT_SWITCH macro - switch(spatial_dim) { - case 1: - AKANTU_DEBUG_WARNING("Geometry in 1D is undefined"); - break; - - case 2: - // Expand the list of elements when they are implemented - AKANTU_BOOST_ELEMENT_SWITCH(MESH_GEOM_CASE_2D, (_triangle_3)); - break; - - case 3: - AKANTU_BOOST_ELEMENT_SWITCH(MESH_GEOM_CASE_3D, (_tetrahedron_4)); - break; - } - } - - AKANTU_DEBUG_OUT(); -} - -UInt MeshGeomContainer::numberOfIntersectionsWithInterface(const K::Segment_3 & interface) const { - AKANTU_DEBUG_IN(); - - UInt total = 0; - - GeomMap::type_iterator it = factory_map.firstType(); - GeomMap::type_iterator end = factory_map.lastType(); - - for (; it != end ; ++it) { - total += factory_map(*it)->numberOfIntersectionsWithInterface(interface); - } - - AKANTU_DEBUG_OUT(); - - return total; -} - -void MeshGeomContainer::meshOfLinearInterface(const Interface & interface, Mesh & interface_mesh) { - AKANTU_DEBUG_IN(); - - GeomMap::type_iterator it = factory_map.firstType(); - GeomMap::type_iterator end = factory_map.lastType(); - - for (; it != end ; ++it) { - factory_map(*it)->meshOfLinearInterface(interface, interface_mesh); - } - - AKANTU_DEBUG_OUT(); -} - -Mesh & MeshGeomContainer::meshOfLinearInterfaces(const std::list<Interface> & interfaces) { - std::list<Interface>::const_iterator interfaces_it = interfaces.begin(); - std::list<Interface>::const_iterator interfaces_end = interfaces.end(); - - for (; interfaces_it != interfaces_end ; ++interfaces_it) { - meshOfLinearInterface(*interfaces_it, interface_mesh); - } - - return interface_mesh; -} - -const MeshGeomAbstract * MeshGeomContainer::getFactoryForElementType(ElementType el_type) const { - return factory_map(el_type); -} - -/* -------------------------------------------------------------------------- */ - -#undef MESH_GEOM_CASE_2D -#undef MESH_GEOM_CASE_3D -#undef MESH_GEOM_CASE - -__END_AKANTU__ diff --git a/src/geometry/mesh_geom_container.hh b/src/geometry/mesh_geom_container.hh deleted file mode 100644 index bb8fb2fd2..000000000 --- a/src/geometry/mesh_geom_container.hh +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file mesh_geom_container.hh - * - * @author Lucas Frérot <lucas.frerot@epfl.ch> - * - * @date creation: Fri Feb 27 2015 - * @date last modification: Fri Mar 6 2015 - * - * @brief Contains the CGAL representation of a mesh - * - * @section LICENSE - * - * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) - * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#ifndef __AKANTU_MESH_GEOM_CONTAINER__ -#define __AKANTU_MESH_GEOM_CONTAINER__ - -#include "aka_common.hh" -#include "mesh.hh" -#include "mesh_geom_abstract.hh" - -#include <CGAL/Cartesian.h> - -/* -------------------------------------------------------------------------- */ - -__BEGIN_AKANTU__ - -typedef CGAL::Cartesian<Real> K; - -class MeshGeomContainer : MeshGeomAbstract { - typedef ElementTypeMap<MeshGeomAbstract *> GeomMap; - -public: - /// Construct from mesh - explicit MeshGeomContainer(const Mesh & mesh); - - /// Destructor - virtual ~MeshGeomContainer(); - -public: - /// Constructs the geometric data from the mesh - virtual void constructData(); - - /// Compute the number of intersections with geometric interface - virtual UInt numberOfIntersectionsWithInterface(const K::Segment_3 & interface) const; - - /// Compute the intersection mesh with linear interface - virtual void meshOfLinearInterface(const Interface & interface, Mesh & interface_mesh); - - /// Construct the interface mesh from several segments - Mesh & meshOfLinearInterfaces(const std::list<Interface> & interfaces); - - /// Get the factory object for an element type - const MeshGeomAbstract * getFactoryForElementType(ElementType el_type) const; - -protected: - GeomMap factory_map; - - Mesh interface_mesh; -}; - -__END_AKANTU__ - -#endif // __AKANTU_MESH_GEOM_CONTAINER__ diff --git a/src/geometry/mesh_geom_factory.hh b/src/geometry/mesh_geom_factory.hh index 143a49b2b..43387d45b 100644 --- a/src/geometry/mesh_geom_factory.hh +++ b/src/geometry/mesh_geom_factory.hh @@ -1,90 +1,109 @@ /** * @file mesh_geom_factory.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Feb 26 2015 * @date last modification: Fri Mar 6 2015 * * @brief Class for constructing the CGAL primitives of a mesh * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_GEOM_FACTORY_HH__ #define __AKANTU_MESH_GEOM_FACTORY_HH__ #include "aka_common.hh" #include "mesh.hh" #include "mesh_geom_abstract.hh" #include "tree_type_helper.hh" +#include "geom_helper_functions.hh" + +#include <algorithm> #include <CGAL/Cartesian.h> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ -typedef CGAL::Cartesian<Real> K; - -template<UInt dim, ElementType el_type> +/** + * @brief Class used to construct AABB tree for intersection computations + * + * This class constructs a CGAL AABB tree of one type of element in a mesh + * for fast intersection computations. + */ +template<UInt dim, ElementType el_type, class Primitive, class Kernel> class MeshGeomFactory : public MeshGeomAbstract { public: /// Construct from mesh explicit MeshGeomFactory(const Mesh & mesh); /// Desctructor virtual ~MeshGeomFactory(); public: /// Construct AABB tree for fast intersection computing virtual void constructData(); - /// Compute the number of intersections with primitive - virtual UInt numberOfIntersectionsWithInterface(const K::Segment_3 & interface) const; - - /// Create a mesh of the intersection with a linear interface - virtual void meshOfLinearInterface(const Interface & interface, Mesh & interface_mesh); - - /// Construct a primitive and add it to the list - void addPrimitive(const Matrix<Real> & node_coordinates, UInt id); - - /// Construct segment list from intersections and remove duplicates - void constructSegments( - const std::list<typename TreeTypeHelper<dim, el_type>::linear_intersection> & intersections, - std::list<std::pair<K::Segment_3, UInt> > & segments, - const K::Segment_3 & interface); - - const typename TreeTypeHelper<dim, el_type>::tree & getTree() const { return *data_tree; } + /** + * @brief Construct a primitive and add it to a list of primitives + * + * This function needs to be specialized for every type that is wished to be supported. + * @param node_coordinates coordinates of the nodes making up the element + * @param id element number + * @param list the primitive list (not used inside MeshGeomFactory) + */ + inline void addPrimitive( + const Matrix<Real> & node_coordinates, + UInt id, + typename TreeTypeHelper<Primitive, Kernel>::container_type & list + ); + + inline void addPrimitive( + const Matrix<Real> & node_coordinates, + UInt id + ); + + /// Getter for the AABB tree + const typename TreeTypeHelper<Primitive, Kernel>::tree & getTree() const { return *data_tree; } + + /// Getter for primitive list + const typename TreeTypeHelper<Primitive, Kernel>::container_type & getPrimitiveList() const + { return primitive_list; } protected: - typename TreeTypeHelper<dim, el_type>::tree * data_tree; - typename TreeTypeHelper<dim, el_type>::container_type primitive_list; -}; + /// AABB data tree + typename TreeTypeHelper<Primitive, Kernel>::tree * data_tree; + /// Primitive list + typename TreeTypeHelper<Primitive, Kernel>::container_type primitive_list; +}; __END_AKANTU__ #include "mesh_geom_factory_tmpl.hh" + #endif // __AKANTU_MESH_GEOM_FACTORY_HH__ diff --git a/src/geometry/mesh_geom_factory_tmpl.hh b/src/geometry/mesh_geom_factory_tmpl.hh index 545884d0e..889e379f5 100644 --- a/src/geometry/mesh_geom_factory_tmpl.hh +++ b/src/geometry/mesh_geom_factory_tmpl.hh @@ -1,271 +1,153 @@ /** * @file mesh_geom_factory_tmpl.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Feb 26 2015 * @date last modification: Fri Mar 6 2015 * * @brief Class for constructing the CGAL primitives of a mesh * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ -/* -------------------------------------------------------------------------- */ - -#ifndef _AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ -#define _AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ +#ifndef __AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ +#define __AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ -#include "mesh_geom_factory.hh" +/* -------------------------------------------------------------------------- */ #include "aka_common.hh" -#include "tree_type_helper.hh" -#include "triangle.hh" -#include "geom_helper_functions.hh" - -#include <algorithm> +#include "mesh_geom_factory.hh" #include <CGAL/Cartesian.h> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ -typedef CGAL::Cartesian<Real> K; +typedef CGAL::Cartesian<Real> Cartesian; -template<UInt dim, ElementType type> -MeshGeomFactory<dim, type>::MeshGeomFactory(const Mesh & mesh) : +template<UInt dim, ElementType type, class Primitive, class Kernel> +MeshGeomFactory<dim, type, Primitive, Kernel>::MeshGeomFactory(const Mesh & mesh) : MeshGeomAbstract(mesh), data_tree(NULL), primitive_list() {} -template<UInt dim, ElementType type> -MeshGeomFactory<dim, type>::~MeshGeomFactory() { +template<UInt dim, ElementType type, class Primitive, class Kernel> +MeshGeomFactory<dim, type, Primitive, Kernel>::~MeshGeomFactory() { delete data_tree; } -template<UInt dim, ElementType type> -void MeshGeomFactory<dim, type>::constructData() { +/** + * This function loops over the elements of `type` in the mesh and creates the + * AABB tree of geometrical primitves (`data_tree`). + */ +template<UInt dim, ElementType type, class Primitive, class Kernel> +void MeshGeomFactory<dim, type, Primitive, Kernel>::constructData() { AKANTU_DEBUG_IN(); const GhostType ghost_type = _not_ghost; primitive_list.clear(); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); const Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type); const Array<Real> & nodes = mesh.getNodes(); Array<UInt>::const_vector_iterator begin = connectivity.begin(nb_nodes_per_element); Array<UInt>::const_vector_iterator it = connectivity.begin(nb_nodes_per_element); Array<UInt>::const_vector_iterator end = connectivity.end(nb_nodes_per_element); - /// This loop builds the list of primitives + // This loop builds the list of primitives for (; it != end ; ++it) { const Vector<UInt> & el_connectivity = *it; Matrix<Real> node_coordinates(dim, nb_nodes_per_element); for (UInt i = 0 ; i < nb_nodes_per_element ; i++) for (UInt j = 0 ; j < dim ; j++) node_coordinates(j, i) = nodes(el_connectivity(i), j); addPrimitive(node_coordinates, it - begin); } delete data_tree; - data_tree = new typename TreeTypeHelper<dim, type>::tree(primitive_list.begin(), primitive_list.end()); + data_tree = new typename TreeTypeHelper<Primitive, Kernel>::tree(primitive_list.begin(), primitive_list.end()); AKANTU_DEBUG_OUT(); } +template<UInt dim, ElementType type, class Primitive, class Kernel> +void MeshGeomFactory<dim, type, Primitive, Kernel>::addPrimitive(const Matrix<Real> & node_coordinates, + UInt id) { + this->addPrimitive(node_coordinates, id, this->primitive_list); +} + // 2D and _triangle_3 implementation template<> -void MeshGeomFactory<2, _triangle_3>::addPrimitive(const Matrix<Real> & node_coordinates, UInt id) { - TreeTypeHelper<2, _triangle_3>::point_type a(node_coordinates(0, 0), node_coordinates(1, 0), 0.); - TreeTypeHelper<2, _triangle_3>::point_type b(node_coordinates(0, 1), node_coordinates(1, 1), 0.); - TreeTypeHelper<2, _triangle_3>::point_type c(node_coordinates(0, 2), node_coordinates(1, 2), 0.); +inline void MeshGeomFactory<2, _triangle_3, Triangle<Cartesian>, Cartesian>::addPrimitive( + const Matrix<Real> & node_coordinates, + UInt id, + TreeTypeHelper<Triangle<Cartesian>, Cartesian>::container_type & list) { + + TreeTypeHelper<Triangle<Cartesian>, Cartesian>::point_type + a(node_coordinates(0, 0), node_coordinates(1, 0), 0.), + b(node_coordinates(0, 1), node_coordinates(1, 1), 0.), + c(node_coordinates(0, 2), node_coordinates(1, 2), 0.); - Triangle<K> t(a, b, c); + Triangle<Cartesian> t(a, b, c); t.setId(id); - primitive_list.push_back(t); + list.push_back(t); } -// 3D and _tetrahedron_4 implementation +// 3D and _tetrahedron_4 with triangles implementation template<> -void MeshGeomFactory<3, _tetrahedron_4>::addPrimitive(const Matrix<Real> & node_coordinates, UInt id) { - TreeTypeHelper<3, _tetrahedron_4>::point_type +inline void MeshGeomFactory<3, _tetrahedron_4, Triangle<Cartesian>, Cartesian>::addPrimitive( + const Matrix<Real> & node_coordinates, + UInt id, + TreeTypeHelper<Triangle<Cartesian>, Cartesian>::container_type & list) { + + TreeTypeHelper<Triangle<Cartesian>, Cartesian>::point_type a(node_coordinates(0, 0), node_coordinates(1, 0), node_coordinates(2, 0)), b(node_coordinates(0, 1), node_coordinates(1, 1), node_coordinates(2, 1)), c(node_coordinates(0, 2), node_coordinates(1, 2), node_coordinates(2, 2)), d(node_coordinates(0, 3), node_coordinates(1, 3), node_coordinates(2, 3)); - Triangle<K> + Triangle<Cartesian> t1(a, b, c), t2(b, c, d), t3(c, d, a), t4(d, a, b); t1.setId(id); t2.setId(id); t3.setId(id); t4.setId(id); - primitive_list.push_back(t1); - primitive_list.push_back(t2); - primitive_list.push_back(t3); - primitive_list.push_back(t4); -} - -template<UInt dim, ElementType el_type> -UInt MeshGeomFactory<dim, el_type>::numberOfIntersectionsWithInterface(const K::Segment_3 & interface) const { - return data_tree->number_of_intersected_primitives(interface); + list.push_back(t1); + list.push_back(t2); + list.push_back(t3); + list.push_back(t4); } -template<UInt dim, ElementType el_type> -void MeshGeomFactory<dim, el_type>::meshOfLinearInterface(const Interface & interface_pair, Mesh & interface_mesh) { - AKANTU_DEBUG_IN(); - - const K::Segment_3 & interface = interface_pair.first; - - UInt number_of_intersections = this->numberOfIntersectionsWithInterface(interface); - - if (!number_of_intersections) { - AKANTU_DEBUG_WARNING("No intersection with interface"); - return; - } - - std::list<typename TreeTypeHelper<dim, el_type>::linear_intersection> list_of_intersections; - /// TODO change this list to a set using lessSegmentPair for optimization - std::list< std::pair<K::Segment_3, UInt> > list_of_segments; // Contains no duplicate elements - - /// Compute all the intersection pairs (segment + element id) and remove duplicates - data_tree->all_intersections(interface, std::back_inserter(list_of_intersections)); - this->constructSegments(list_of_intersections, list_of_segments, interface); - - /// Arrays for storing nodes and connectivity - Array<Real> & nodes = interface_mesh.getNodes(); - Array<UInt> & connectivity = interface_mesh.getConnectivity(_segment_2); - - /// Arrays for storing associated element id and type - Array<Element> & associated_element = interface_mesh.getData<Element>("associated_element", _segment_2); - Array<std::string> & associated_material = interface_mesh.getData<std::string>("material", _segment_2); - - std::list<std::pair<K::Segment_3, UInt> >::iterator it = list_of_segments.begin(); - std::list<std::pair<K::Segment_3, UInt> >::iterator end = list_of_segments.end(); - - /// Loop over the intersections pairs (segment, id) - for (; it != end ; ++it) { - Vector<UInt> segment_connectivity(2); - segment_connectivity(0) = interface_mesh.getNbNodes(); - segment_connectivity(1) = interface_mesh.getNbNodes() + 1; - connectivity.push_back(segment_connectivity); - - /// Copy nodes - Vector<Real> source(dim), target(dim); - for (UInt j = 0 ; j < dim ; j++) { - source(j) = it->first.source()[j]; - target(j) = it->first.target()[j]; - } - - nodes.push_back(source); - nodes.push_back(target); - - /// Copy associated element info - associated_element.push_back(Element(el_type, it->second)); - associated_material.push_back(interface_pair.second); - } - - AKANTU_DEBUG_OUT(); -} - -template<UInt dim, ElementType el_type> -void MeshGeomFactory<dim, el_type>::constructSegments( - const std::list< typename TreeTypeHelper<dim, el_type>::linear_intersection > & intersections, - std::list<std::pair<K::Segment_3, UInt> > & segments, - const K::Segment_3 & interface) -{ - AKANTU_DEBUG_IN(); - - typename std::list<typename TreeTypeHelper<dim, el_type>::linear_intersection>::const_iterator - int_it = intersections.begin(), - int_end = intersections.end(); - - for (; int_it != int_end ; ++int_it) { - UInt el = (*int_it)->second; - - if (const K::Segment_3 * segment = boost::get<K::Segment_3>(&((*int_it)->first))) { - if (std::find_if(segments.begin(), segments.end(), IsSameSegment(*segment)) == segments.end()) { - // Use min() and max() for ordering - K::Segment_3 seg_ord(segment->min(), segment->max()); - segments.push_back(std::make_pair(seg_ord, (*int_it)->second)); - } - } - - else if (const K::Point_3 * point = boost::get<K::Point_3>(&((*int_it)->first))) { - // We only want to treat points differently if we're in 3D with Tetra4 elements - // This should be optimized by compilator - if (dim == 3 && el_type == _tetrahedron_4) { - UInt nb_facets = Mesh::getNbFacetsPerElement(el_type); - typename TreeTypeHelper<dim, el_type>::container_type facets(nb_facets); - - // TODO Use mesh facets instead of this (should make O(n²) go to O(n)) - std::remove_copy_if(primitive_list.begin(), - primitive_list.end(), - facets.begin(), - BelongsNotToElement<dim, el_type>(el)); - - typename TreeTypeHelper<dim, el_type>::tree * local_tree = - new typename TreeTypeHelper<dim, el_type>::tree(facets.begin(), facets.end()); - - std::list< typename TreeTypeHelper<dim, el_type>::linear_intersection> - local_intersections; - - local_tree->all_intersections(interface, std::back_inserter(local_intersections)); - - typename std::list<typename TreeTypeHelper<dim, el_type>::linear_intersection>::const_iterator - local_it = local_intersections.begin(), - local_end = local_intersections.end(); - - for (; local_it != local_end ; ++local_it) { - if (const K::Point_3 * local_point = boost::get<K::Point_3>(&((*local_it)->first))) { - if (!comparePoints(*point, *local_point)) { - K::Segment_3 seg(*point, *local_point); - K::Segment_3 seg_ord(seg.min(), seg.max()); - if (std::find_if(segments.begin(), segments.end(), IsSameSegment(seg_ord)) == segments.end()) - segments.push_back(std::make_pair(seg_ord, el)); - } - } - } - - delete local_tree; - } - } - } - - AKANTU_DEBUG_OUT(); -} - - - __END_AKANTU__ -#endif // _AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ +#endif // __AKANTU_MESH_GEOM_FACTORY_TMPL_HH__ diff --git a/src/geometry/mesh_geom_intersector.hh b/src/geometry/mesh_geom_intersector.hh new file mode 100644 index 000000000..5475e6869 --- /dev/null +++ b/src/geometry/mesh_geom_intersector.hh @@ -0,0 +1,87 @@ +/** + * @file mesh_geom_intersector.hh + * + * @author Lucas Frerot <lucas.frerot@epfl.ch> + * + * @date creation: Wed Apr 29 2015 + * @date last modification: Wed Apr 29 2015 + * + * @brief General class for intersection computations + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_MESH_GEOM_INTERSECTOR_HH__ +#define __AKANTU_MESH_GEOM_INTERSECTOR_HH__ + +#include "aka_common.hh" +#include "mesh_geom_abstract.hh" +#include "mesh_geom_factory.hh" + +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +/** + * @brief Class used to perform intersections on a mesh and construct output data + */ +template<UInt dim, ElementType type, class Primitive, class Query, class Kernel> +class MeshGeomIntersector : public MeshGeomAbstract { + +protected: + /// Result of intersection function type + typedef typename IntersectionTypeHelper<TreeTypeHelper<Primitive, Kernel>, Query>::intersection_type result_type; + +public: + /// Construct from mesh + explicit MeshGeomIntersector(const Mesh & mesh); + + /// Destructor + virtual ~MeshGeomIntersector(); + +public: + /// Construct the primitive tree object + virtual void constructData(); + + /** + * @brief Compute the intersection with a query object + * + * This function needs to be implemented for every subclass. It computes the intersections + * with the tree of primitives and creates the data for the user. + * + * @param query the CGAL primitive of the query object + */ + virtual void computeIntersectionQuery(const Query & query) = 0; + + /// Compute list of queries + virtual void computeIntersectionQueryList(const std::list<Query> & query_list); + +protected: + /// Factory object containing the primitive tree + MeshGeomFactory<dim, type, Primitive, Kernel> factory; +}; + +__END_AKANTU__ + +#include "mesh_geom_intersector_tmpl.hh" + +#endif // __AKANTU_MESH_GEOM_INTERSECTOR_HH__ diff --git a/src/geometry/mesh_geom_intersector_tmpl.hh b/src/geometry/mesh_geom_intersector_tmpl.hh new file mode 100644 index 000000000..63f36933b --- /dev/null +++ b/src/geometry/mesh_geom_intersector_tmpl.hh @@ -0,0 +1,76 @@ +/** + * @file mesh_geom_intersector_tmpl.hh + * + * @author Lucas Frerot <lucas.frerot@epfl.ch> + * + * @date creation: Wed Apr 29 2015 + * @date last modification: Wed Apr 29 2015 + * + * @brief General class for intersection computations + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_MESH_GEOM_INTERSECTOR_TMPL_HH__ +#define __AKANTU_MESH_GEOM_INTERSECTOR_TMPL_HH__ + +#include "aka_common.hh" +#include "mesh_geom_intersector.hh" + +__BEGIN_AKANTU__ + +template<UInt dim, ElementType type, class Primitive, class Query, class Kernel> +MeshGeomIntersector<dim, type, Primitive, Query, Kernel>::MeshGeomIntersector(const Mesh & mesh) : + MeshGeomAbstract(mesh), + factory(mesh) +{} + +template<UInt dim, ElementType type, class Primitive, class Query, class Kernel> +MeshGeomIntersector<dim, type, Primitive, Query, Kernel>::~MeshGeomIntersector() +{} + +template<UInt dim, ElementType type, class Primitive, class Query, class Kernel> +void MeshGeomIntersector<dim, type, Primitive, Query, Kernel>::constructData() { + factory.constructData(); +} + +template<UInt dim, ElementType type, class Primitive, class Query, class Kernel> +void MeshGeomIntersector<dim, type, Primitive, Query, Kernel>::computeIntersectionQueryList( + const std::list<Query> & query_list) { + AKANTU_DEBUG_IN(); + + typename std::list<Query>::const_iterator + query_it = query_list.begin(), + query_end = query_list.end(); + + for (; query_it != query_end ; ++query_it) { + computeIntersectionQuery(*query_it); + } + + AKANTU_DEBUG_OUT(); +} + + +__END_AKANTU__ + +#endif // __AKANTU_MESH_GEOM_INTERSECTOR_TMPL_HH__ + diff --git a/src/geometry/mesh_segment_intersector.hh b/src/geometry/mesh_segment_intersector.hh new file mode 100644 index 000000000..88ce3fadb --- /dev/null +++ b/src/geometry/mesh_segment_intersector.hh @@ -0,0 +1,99 @@ +/** + * @file mesh_segment_intersector.hh + * + * @author Lucas Frerot + * + * @date creation: Wed Apr 29 2015 + * @date last modification: Wed Apr 29 2015 + * + * @brief Computation of mesh intersection with segments + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_MESH_SEGMENT_INTERSECTOR_HH__ +#define __AKANTU_MESH_SEGMENT_INTERSECTOR_HH__ + +#include "aka_common.hh" +#include "mesh_geom_intersector.hh" + +#include <CGAL/Cartesian.h> + +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +/// Here, we know what kernel we have to use +typedef CGAL::Cartesian<Real> K; + +template<UInt dim, ElementType type> +class MeshSegmentIntersector : public MeshGeomIntersector<dim, type, Triangle<K>, K::Segment_3, K> { + /// Parent class type + typedef MeshGeomIntersector<dim, type, Triangle<K>, K::Segment_3, K> parent_type; + + /// Result of intersection type + typedef typename parent_type::result_type result_type; + + /// Pair of segments and element id + typedef std::pair<K::Segment_3, UInt> pair_type; + +public: + /// Construct from mesh + explicit MeshSegmentIntersector(const Mesh & mesh, Mesh & result_mesh); + + /// Destructor + virtual ~MeshSegmentIntersector(); + +public: + /** + * @brief Computes the intersection of the mesh with a segment + * + * @param query the segment to compute the intersections with the mesh + */ + virtual void computeIntersectionQuery(const K::Segment_3 & query); + + /// Compute the list of queries + virtual void computeIntersectionQueryList(const std::list<K::Segment_3> & query_list); + + /// Compute the list of queries and adds sets the physical name of the elements created + virtual void computeIntersectionQueryList(const std::list<K::Segment_3> & query_list, + const std::string & physical_name); + +protected: + /// Compute segments from intersection list + void computeSegments(const std::list<result_type> & intersections, + std::list<pair_type> & segments, + const K::Segment_3 & query); + +protected: + /// Result mesh + Mesh & result_mesh; + + /// Physical name of the current batch of queries + std::string current_physical_name; +}; + +__END_AKANTU__ + +#include "mesh_segment_intersector_tmpl.hh" + +#endif // __AKANTU_MESH_SEGMENT_INTERSECTOR_HH__ diff --git a/src/geometry/mesh_segment_intersector_tmpl.hh b/src/geometry/mesh_segment_intersector_tmpl.hh new file mode 100644 index 000000000..15469b7a5 --- /dev/null +++ b/src/geometry/mesh_segment_intersector_tmpl.hh @@ -0,0 +1,276 @@ +/** + * @file mesh_segment_intersector_tmpl.hh + * + * @author Lucas Frerot + * + * @date creation: Wed Apr 29 2015 + * @date last modification: Wed Apr 29 2015 + * + * @brief Computation of mesh intersection with segments + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_MESH_SEGMENT_INTERSECTOR_TMPL_HH__ +#define __AKANTU_MESH_SEGMENT_INTERSECTOR_TMPL_HH__ + +#include "aka_common.hh" +#include "tree_type_helper.hh" + +#include <CGAL/Cartesian.h> + +__BEGIN_AKANTU__ + +typedef CGAL::Cartesian<Real> K; + +template<UInt dim, ElementType type> +MeshSegmentIntersector<dim, type>::MeshSegmentIntersector(const Mesh & mesh, Mesh & result_mesh): + parent_type(mesh), + result_mesh(result_mesh), + current_physical_name() +{ + this->constructData(); +} + +template<UInt dim, ElementType type> +MeshSegmentIntersector<dim, type>::~MeshSegmentIntersector() +{} + +template<UInt dim, ElementType type> +void MeshSegmentIntersector<dim, type>::computeIntersectionQuery(const K::Segment_3 & query) { + AKANTU_DEBUG_IN(); + + result_mesh.addConnectivityType(_segment_2, _not_ghost); + result_mesh.addConnectivityType(_segment_2, _ghost); + + std::list<result_type> result_list; + std::list<std::pair<K::Segment_3, UInt> > segment_list; + + this->factory.getTree().all_intersections(query, std::back_inserter(result_list)); + this->computeSegments(result_list, segment_list, query); + + // Arrays for storing nodes and connectivity + Array<Real> & nodes = result_mesh.getNodes(); + Array<UInt> & connectivity = result_mesh.getConnectivity(_segment_2); + + // Arrays for storing associated element and physical name + bool valid_elemental_data = true; + Array<Element> * associated_element = NULL; + Array<std::string> * associated_physical_name = NULL; + + try { + associated_element = &result_mesh.getData<Element>("associated_element", _segment_2); + associated_physical_name = &result_mesh.getData<std::string>("physical_names", _segment_2); + } catch (debug::Exception & e) { + valid_elemental_data = false; + } + + std::list<pair_type>::iterator + it = segment_list.begin(), + end = segment_list.end(); + + // Loop over the segment pairs + for (; it != end ; ++it) { + Vector<UInt> segment_connectivity(2); + segment_connectivity(0) = result_mesh.getNbNodes(); + segment_connectivity(1) = result_mesh.getNbNodes() + 1; + connectivity.push_back(segment_connectivity); + + // Copy nodes + Vector<Real> source(dim), target(dim); + for (UInt j = 0 ; j < dim ; j++) { + source(j) = it->first.source()[j]; + target(j) = it->first.target()[j]; + } + + nodes.push_back(source); + nodes.push_back(target); + + // Copy associated element info + if (valid_elemental_data) { + associated_element->push_back(Element(type, it->second)); + associated_physical_name->push_back(current_physical_name); + } + } + + AKANTU_DEBUG_OUT(); +} + +template<UInt dim, ElementType type> +void MeshSegmentIntersector<dim, type>::computeIntersectionQueryList(const std::list<K::Segment_3> & query_list, + const std::string & physical_name) { + AKANTU_DEBUG_IN(); + + current_physical_name = physical_name; + parent_type::computeIntersectionQueryList(query_list); + + AKANTU_DEBUG_OUT(); +} + +template<UInt dim, ElementType type> +void MeshSegmentIntersector<dim, type>::computeIntersectionQueryList(const std::list<K::Segment_3> & query_list) { + AKANTU_DEBUG_IN(); + + parent_type::computeIntersectionQueryList(query_list); + + AKANTU_DEBUG_OUT(); +} + +template<UInt dim, ElementType type> +void MeshSegmentIntersector<dim, type>::computeSegments(const std::list<result_type> & intersections, + std::list<pair_type> & segments, + const K::Segment_3 & query) { + AKANTU_DEBUG_IN(); + + /* + * Number of intersections = 0 means + * + * - query is completely outside mesh + * - query is completely inside primitive + * + * We try to determine the case and still construct the segment list + */ + if (intersections.size() == 0) { + // We look at all the primitives intersected by two rays + // If there is one primitive in common, then query is inside + // that primitive + K::Ray_3 ray1(query.source(), query.target()); + K::Ray_3 ray2(query.target(), query.source()); + + std::list<UInt> ray1_results, ray2_results; + + this->factory.getTree().all_intersected_primitives(ray1, std::back_inserter(ray1_results)); + this->factory.getTree().all_intersected_primitives(ray2, std::back_inserter(ray2_results)); + + std::set<UInt> id_set; + bool inside_primitive = false; + UInt primitive_id = 0; + + std::list<UInt>::iterator + ray1_it = ray1_results.begin(), + ray2_it = ray2_results.begin(), + ray1_end = ray1_results.end(), + ray2_end = ray2_results.end(); + + // Populate the set with elements of first list + for (; ray1_it != ray1_end ; ++ray1_it) + id_set.insert(id_set.begin(), *ray1_it); + + // Test if first list contains an element of second list + for (; ray2_it != ray2_end && !inside_primitive ; ++ray2_it) { + if (id_set.find(*ray2_it) != id_set.end()) { + inside_primitive = true; + primitive_id = *ray2_it; + } + } + + if (inside_primitive) { + segments.push_back(std::make_pair(query, primitive_id)); + } + } + + else { + typename std::list<result_type>::const_iterator + it = intersections.begin(), + end = intersections.end(); + + for(; it != end ; ++it) { + UInt el = (*it)->second; + + // Result of intersection is a segment + if (const K::Segment_3 * segment = boost::get<K::Segment_3>(&((*it)->first))) { + // Check if the segment was alread created + if (std::find_if(segments.begin(), segments.end(), IsSameSegment(*segment)) == segments.end()) { + segments.push_back(std::make_pair(*segment, el)); + } + } + + // Result of intersection is a point + else if (const K::Point_3 * point = boost::get<K::Point_3>(&((*it)->first))) { + // We only want to treat points differently if we're in 3D with Tetra4 elements + // This should be optimized by compilator + if (dim == 3 && type == _tetrahedron_4) { + UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + TreeTypeHelper<Triangle<K>, K>::container_type facets; + + const Array<Real> & nodes = this->mesh.getNodes(); + Array<UInt>::const_vector_iterator + connectivity_vec = this->mesh.getConnectivity(type).begin(nb_nodes_per_element); + + const Vector<UInt> & el_connectivity = connectivity_vec[el]; + + Matrix<Real> node_coordinates(dim, nb_nodes_per_element); + for (UInt i = 0 ; i < nb_nodes_per_element ; i++) + for (UInt j = 0 ; j < dim ; j++) + node_coordinates(j, i) = nodes(el_connectivity(i), j); + + this->factory.addPrimitive(node_coordinates, el, facets); + + // Local tree + TreeTypeHelper<Triangle<K>, K>::tree * local_tree = + new TreeTypeHelper<Triangle<K>, K>::tree(facets.begin(), facets.end()); + + // Compute local intersections (with current element) + std::list<result_type> local_intersections; + local_tree->all_intersections(query, std::back_inserter(local_intersections)); + + if (local_intersections.size() == 1) { + TreeTypeHelper<Triangle<K>, K>::point_type + a(node_coordinates(0, 0), node_coordinates(1, 0), node_coordinates(2, 0)), + b(node_coordinates(0, 1), node_coordinates(1, 1), node_coordinates(2, 1)), + c(node_coordinates(0, 2), node_coordinates(1, 2), node_coordinates(2, 2)), + d(node_coordinates(0, 3), node_coordinates(1, 3), node_coordinates(2, 3)); + K::Tetrahedron_3 tetra(a, b, c, d); + K::Point_3 inside_point = + (tetra.has_on_bounded_side(query.source())) ? query.source() : query.target(); + K::Segment_3 seg(inside_point, *point); + segments.push_back(std::make_pair(seg, el)); + } + + else { + typename std::list<result_type>::const_iterator + local_it = local_intersections.begin(), + local_end = local_intersections.end(); + + for (; local_it != local_end ; ++local_it) { + if (const K::Point_3 * local_point = boost::get<K::Point_3>(&((*local_it)->first))) { + if (!comparePoints(*point, *local_point)) { + K::Segment_3 seg(*point, *local_point); + if(std::find_if(segments.begin(), segments.end(), IsSameSegment(seg)) == segments.end()) + segments.push_back(std::make_pair(seg, el)); + } + } + } + } + + delete local_tree; + } + } + } + } + AKANTU_DEBUG_OUT(); +} + +__END_AKANTU__ + +#endif // __AKANTU_MESH_SEGMENT_INTERSECTOR_TMPL_HH__ + diff --git a/src/geometry/tree_type_helper.hh b/src/geometry/tree_type_helper.hh index e79f6f28f..d372306df 100644 --- a/src/geometry/tree_type_helper.hh +++ b/src/geometry/tree_type_helper.hh @@ -1,81 +1,95 @@ /** * @file tree_type_helper.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Fri Feb 27 2015 * @date last modification: Thu Mar 5 2015 * * @brief Converts element types of a mesh to CGAL primitive types * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_TREE_TYPE_HELPER_HH__ #define __AKANTU_TREE_TYPE_HELPER_HH__ #include "aka_common.hh" #include "triangle.hh" #include "tetrahedron.hh" #include "aabb_primitive.hh" #include <CGAL/Cartesian.h> #include <CGAL/AABB_traits.h> #include <CGAL/AABB_tree.h> __BEGIN_AKANTU__ -typedef CGAL::Cartesian<Real> Kernel; - /* -------------------------------------------------------------------------- */ -template<UInt dim, ElementType el_type> +typedef CGAL::Cartesian<Real> CartKern; + +/// Helper class used to ease the use of CGAL AABB tree algorithm +template<class Primitive, class Kernel> struct TreeTypeHelper; -#define TREE_TYPE_HELPER_MACRO(dim, el_type, my_primitive) \ - template<> \ - struct TreeTypeHelper<dim, el_type> { \ - typedef my_primitive<Kernel> primitive_type; \ - typedef my_primitive##_primitive aabb_primitive_type; \ - typedef Kernel::Point_3 point_type; \ - \ - typedef std::list<primitive_type> container_type; \ - typedef container_type::iterator iterator; \ - typedef CGAL::AABB_traits<Kernel, aabb_primitive_type> aabb_traits_type; \ - typedef CGAL::AABB_tree<aabb_traits_type> tree; \ +/// Helper class used to ease the use of intersections +template<class TTHelper, class Query> +struct IntersectionTypeHelper; + + +/** + * Macro used to specialize TreeTypeHelper + * @param my_primitive associated primitive type + * @param my_query query_type + * @param my_kernel kernel type + */ +#define TREE_TYPE_HELPER_MACRO(my_primitive, my_query, my_kernel) \ + template<> \ + struct TreeTypeHelper<my_primitive<my_kernel>, my_kernel> { \ + typedef my_primitive<my_kernel> primitive_type; \ + typedef my_primitive##_primitive aabb_primitive_type; \ + typedef CGAL::Point_3<my_kernel> point_type; \ \ - typedef boost::optional< \ - tree::Intersection_and_primitive_id< \ - CGAL::Segment_3<Kernel> \ - >::Type > linear_intersection; \ + typedef std::list<primitive_type> container_type; \ + typedef container_type::iterator iterator; \ + typedef CGAL::AABB_traits<my_kernel, aabb_primitive_type> aabb_traits_type; \ + typedef CGAL::AABB_tree<aabb_traits_type> tree; \ + typedef tree::Primitive_id id_type; \ + }; \ + \ + template<> \ + struct IntersectionTypeHelper<TreeTypeHelper<my_primitive<my_kernel>, my_kernel>, my_query> { \ + typedef boost::optional< \ + TreeTypeHelper<my_primitive<my_kernel>, my_kernel>::tree::Intersection_and_primitive_id<my_query>::Type \ + > intersection_type; \ } -TREE_TYPE_HELPER_MACRO(2, _triangle_3, Triangle); -TREE_TYPE_HELPER_MACRO(3, _tetrahedron_4, Triangle); +TREE_TYPE_HELPER_MACRO(Triangle, CartKern::Segment_3, CartKern); #undef TREE_TYPE_HELPER_MACRO __END_AKANTU__ #endif // __AKANTU_TREE_TYPE_HELPER_HH__ diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc index 032b42b07..20246f4d4 100644 --- a/src/mesh_utils/cohesive_element_inserter.cc +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -1,350 +1,348 @@ /** * @file cohesive_element_inserter.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 * @date last modification: Tue Jul 29 2014 * * @brief Cohesive element inserter functions * * @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 <limits> #include "cohesive_element_inserter.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, bool is_extrinsic, DistributedSynchronizer * synchronizer, const ID & id) : id(id), mesh(mesh), mesh_facets(mesh.initMeshFacets()), insertion_facets("insertion_facets", id), insertion_limits(mesh.getSpatialDimension(), 2), check_facets("check_facets", id) { MeshUtils::buildAllFacets(mesh, mesh_facets, 0, synchronizer); init(is_extrinsic); } /* -------------------------------------------------------------------------- */ CohesiveElementInserter::~CohesiveElementInserter() { #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) delete distributed_synchronizer; #endif } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::init(bool is_extrinsic) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); MeshUtils::resetFacetToDouble(mesh_facets); /// initialize facet insertion array mesh_facets.initElementTypeMapArray(insertion_facets, 1, spatial_dimension - 1, false, _ek_regular, true); /// init insertion limits for (UInt dim = 0; dim < spatial_dimension; ++dim) { insertion_limits(dim, 0) = std::numeric_limits<Real>::max() * (-1.); insertion_limits(dim, 1) = std::numeric_limits<Real>::max(); } if (is_extrinsic) { mesh_facets.initElementTypeMapArray(check_facets, 1, spatial_dimension - 1); initFacetsCheck(); } #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) facet_synchronizer = NULL; distributed_synchronizer = NULL; #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::initFacetsCheck() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType facet_gt = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); for (; it != last; ++it) { ElementType facet_type = *it; Array<bool> & f_check = check_facets(facet_type, facet_gt); const Array< std::vector<Element> > & element_to_facet = mesh_facets.getElementToSubelement(facet_type, facet_gt); UInt nb_facet = element_to_facet.getSize(); f_check.resize(nb_facet); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull || (element_to_facet(f)[0].ghost_type == _ghost && element_to_facet(f)[1].ghost_type == _ghost)) { f_check(f) = false; } else f_check(f) = true; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector<Real> bary_facet(spatial_dimension); 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; Array<bool> & f_check = check_facets(type, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (f_check(f)) { mesh_facets.getBarycenter(f, type, bary_facet.storage(), ghost_type); UInt coord_in_limit = 0; while (coord_in_limit < spatial_dimension && bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) ++coord_in_limit; if (coord_in_limit != spatial_dimension) f_check(f) = false; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::setLimit(SpacialDirection axis, Real first_limit, Real second_limit) { AKANTU_DEBUG_ASSERT(axis < mesh.getSpatialDimension(), "You are trying to limit insertion in a direction that doesn't exist"); insertion_limits(axis, 0) = std::min(first_limit, second_limit); insertion_limits(axis, 1) = std::max(first_limit, second_limit); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::insertIntrinsicElements() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector<Real> bary_facet(spatial_dimension); 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) { const ElementType type_facet = *it; Array<bool> & f_insertion = insertion_facets(type_facet, ghost_type); Array<std::vector<Element> > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type_facet, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull) continue; mesh_facets.getBarycenter(f, type_facet, bary_facet.storage(), ghost_type); UInt coord_in_limit = 0; while (coord_in_limit < spatial_dimension && bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) ++coord_in_limit; if (coord_in_limit == spatial_dimension) f_insertion(f) = true; } } } insertElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -void CohesiveElementInserter::insertElements() { - AKANTU_DEBUG_IN(); - +UInt CohesiveElementInserter::insertElements() { NewNodesEvent node_event; node_event.getList().extendComponentsInterlaced(2, 1); NewElementsEvent element_event; MeshUtils::insertCohesiveElements(mesh, mesh_facets, insertion_facets, node_event.getList(), element_event.getList()); UInt nb_new_nodes = node_event.getList().getSize(); UInt nb_new_elements = element_event.getList().getSize(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) if (mesh.getNodesType().getSize()) { /// update nodes type updateNodesType(mesh, node_event); updateNodesType(mesh_facets, node_event); /// update global ids nb_new_nodes = updateGlobalIDs(node_event); /// compute total number of new elements StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); comm.allReduce(&nb_new_elements, 1, _so_sum); } #endif if (nb_new_nodes > 0) { mesh.nb_global_nodes += nb_new_nodes; mesh_facets.nb_global_nodes += nb_new_nodes; mesh.sendEvent(node_event); } if (nb_new_elements > 0) { updateInsertionFacets(); mesh.updateTypesOffsets(_not_ghost); mesh.sendEvent(element_event); MeshUtils::resetFacetToDouble(mesh_facets); } - AKANTU_DEBUG_OUT(); + return nb_new_elements; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::updateInsertionFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType facet_gt = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); for (; it != last; ++it) { ElementType facet_type = *it; Array<bool> & ins_facets = insertion_facets(facet_type, facet_gt); // this is the extrinsic case if (check_facets.exists(facet_type, facet_gt)) { Array<bool> & f_check = check_facets(facet_type, facet_gt); UInt nb_facets = f_check.getSize(); for (UInt f = 0; f < ins_facets.getSize(); ++f) { if (ins_facets(f)) { ++nb_facets; ins_facets(f) = false; f_check(f) = false; } } f_check.resize(nb_facets); } // and this the intrinsic one else { ins_facets.resize(mesh_facets.getNbElement(facet_type, facet_gt)); ins_facets.set(false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "CohesiveElementInserter [" << std::endl; stream << space << " + mesh [" << std::endl; mesh.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + mesh_facets [" << std::endl; mesh_facets.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } __END_AKANTU__ diff --git a/src/mesh_utils/cohesive_element_inserter.hh b/src/mesh_utils/cohesive_element_inserter.hh index b5b5fe5d1..03232e486 100644 --- a/src/mesh_utils/cohesive_element_inserter.hh +++ b/src/mesh_utils/cohesive_element_inserter.hh @@ -1,192 +1,193 @@ /** * @file cohesive_element_inserter.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 * @date last modification: Tue Jul 29 2014 * * @brief Cohesive element inserter * * @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_COHESIVE_ELEMENT_INSERTER_HH__ #define __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ /* -------------------------------------------------------------------------- */ #include <numeric> #include "data_accessor.hh" #include "mesh_utils.hh" #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "facet_synchronizer.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class CohesiveElementInserter : public DataAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: CohesiveElementInserter(Mesh & mesh, bool is_extrinsic = false, DistributedSynchronizer * synchronizer = NULL, const ID & id = "cohesive_element_inserter"); virtual ~CohesiveElementInserter(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// init function void init(bool is_extrinsic); /// set range limitation for intrinsic cohesive element insertion void setLimit(SpacialDirection axis, Real first_limit, Real second_limit); /// insert intrinsic cohesive elements in a predefined range void insertIntrinsicElements(); - /// insert extrinsic cohesive elements - void insertElements(); + /// insert extrinsic cohesive elements (returns the number of new + /// cohesive elements) + UInt insertElements(); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// limit check facets to match given insertion limits void limitCheckFacets(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) /// init parallel variables void initParallel(FacetSynchronizer * facet_synchronizer); #endif protected: /// init facets check void initFacetsCheck(); /// update facet insertion arrays after facets doubling void updateInsertionFacets(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) /// update nodes type and global ids for parallel simulations UInt updateGlobalIDs(NewNodesEvent & node_event); /// update nodes type void updateNodesType(Mesh & mesh, NewNodesEvent & node_event); /// functions for parallel communications inline UInt getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const; inline void packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const; inline void unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag); template<bool pack_mode> inline void packUnpackGlobalConnectivity(CommunicationBuffer & buffer, const Array<Element> & elements) const; #endif /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO_NOT_CONST(InsertionFacetsByElement, insertion_facets, ElementTypeMapArray<bool> &); AKANTU_GET_MACRO(InsertionFacetsByElement, insertion_facets, const ElementTypeMapArray<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(InsertionFacets, insertion_facets, bool); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(CheckFacets, check_facets, bool); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(CheckFacets, check_facets, bool); AKANTU_GET_MACRO(MeshFacets, mesh_facets, const Mesh &); AKANTU_GET_MACRO_NOT_CONST(MeshFacets, mesh_facets, Mesh &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// object id ID id; /// main mesh where to insert cohesive elements Mesh & mesh; /// mesh containing facets Mesh & mesh_facets; /// list of facets where to insert elements ElementTypeMapArray<bool> insertion_facets; /// limits for element insertion Array<Real> insertion_limits; /// vector containing facets in which extrinsic cohesive elements can be inserted ElementTypeMapArray<bool> check_facets; #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) /// facet synchronizer FacetSynchronizer * facet_synchronizer; /// distributed synchronizer DistributedSynchronizer * distributed_synchronizer; #endif }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "cohesive_element_inserter_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const CohesiveElementInserter & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ */ diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index ddbf2615f..1464591d5 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2051 +1,2048 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Aug 20 2010 * @date last modification: Mon Jun 09 2014 * * @brief All mesh utils necessary for various tasks * * @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 "mesh_utils.hh" #include "aka_safe_enum.hh" #include "fe_engine.hh" /* -------------------------------------------------------------------------- */ #include <numeric> #include <queue> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<Element> & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); /// count number of occurrence of each node UInt nb_nodes = mesh.getNbNodes(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); AKANTU_DEBUG_ASSERT(mesh.firstType(spatial_dimension) != mesh.lastType(spatial_dimension), "Some elements must be found in right dimension to compute facets!"); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); for (; first != last; ++first) { ElementType type = *first; UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator< Vector<UInt> > conn_it = mesh.getConnectivity(type, *gt).begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) for (UInt n = 0; n < conn_it->size(); ++n) ++node_to_elem.rowOffset((*conn_it)(n)); } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); /// rearrange element to get the node-element list Element e; node_to_elem.beginInsertions(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); e.ghost_type = *gt; for (; first != last; ++first) { ElementType type = *first; e.type = type; e.kind = Mesh::getKind(type); UInt nb_element = mesh.getNbElement(type, *gt); Array<UInt>::const_iterator< Vector<UInt> > conn_it = mesh.getConnectivity(type, *gt).begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; for (UInt n = 0; n < conn_it->size(); ++n) node_to_elem.insertInRow((*conn_it)(n), e); } } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This function should disappear in the future (used in mesh partitioning) */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<UInt> & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes = mesh.getNbNodes(); const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; UInt nb_types = type_list.size(); UInt nb_good_types = 0; UInt nb_nodes_per_element[nb_types]; UInt * conn_val[nb_types]; UInt nb_element[nb_types]; for(it = type_list.begin(); it != type_list.end(); ++it) { ElementType type = *it; if(Mesh::getSpatialDimension(type) != spatial_dimension) continue; nb_nodes_per_element[nb_good_types] = Mesh::getNbNodesPerElement(type); conn_val[nb_good_types] = mesh.getConnectivity(type, _not_ghost).storage(); nb_element[nb_good_types] = mesh.getConnectivity(type, _not_ghost).getSize(); nb_good_types++; } AKANTU_DEBUG_ASSERT(nb_good_types != 0, "Some elements must be found in right dimension to compute facets!"); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt t = 0; t < nb_good_types; ++t) { for (UInt el = 0; el < nb_element[t]; ++el) { UInt el_offset = el*nb_nodes_per_element[t]; for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) { ++node_to_elem.rowOffset(conn_val[t][el_offset + n]); } } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// rearrange element to get the node-element list for (UInt t = 0, linearized_el = 0; t < nb_good_types; ++t) for (UInt el = 0; el < nb_element[t]; ++el, ++linearized_el) { UInt el_offset = el*nb_nodes_per_element[t]; for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) node_to_elem.insertInRow(conn_val[t][el_offset + n], linearized_el); } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR<UInt> & node_to_elem, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, ghost_type).getSize(); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el*nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) ++node_to_elem.rowOffset(conn_val[el_offset + n]); } /// convert the occurrence array in a csr one node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el*nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { node_to_elem.insertInRow(conn_val[el_offset + n], el); } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh){ AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { mesh.getConnectivity(*it, *gt).resize(0); // \todo inform the mesh event handler } } buildFacetsDimension(mesh, mesh, true, spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension, DistributedSynchronizer * synchronizer) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension, synchronizer); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension, DistributedSynchronizer * synchronizer) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mesh_facets.isMeshFacets(), "The mesh_facets should be initialized with initMeshFacets"); const ElementTypeMapArray<UInt> * prank_to_element = NULL; if (synchronizer) { synchronizer->buildPrankToElement(); prank_to_element = &synchronizer->getPrankToElement(); } /// generate facets buildFacetsDimension(mesh, mesh_facets, false, from_dimension, prank_to_element); /// copy nodes type mesh_facets.nodes_type.resize(mesh.nodes_type.getSize()); mesh_facets.nodes_type.copy(mesh.nodes_type); /// sort facets and generate subfacets for (UInt i = from_dimension - 1; i > to_dimension; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i, prank_to_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, const ElementTypeMapArray<UInt> * prank_to_element){ AKANTU_DEBUG_IN(); // save the current parent of mesh_facets and set it temporarly to mesh since // mesh is the one containing the elements for which mesh_facets has the subelements // example: if the function is called with mesh = mesh_facets const Mesh & mesh_facets_parent = mesh_facets.getMeshParent(); mesh_facets.defineMeshParent(mesh); UInt spatial_dimension = mesh.getSpatialDimension(); const Array<Real> & mesh_facets_nodes = mesh_facets.getNodes(); const Array<Real>::const_vector_iterator mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); CSR<Element> node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array<UInt> counter; std::vector<Element> connected_elements; // init the SubelementToElement data to improve performance for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator first = mesh.firstType(dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(dimension, ghost_type); for(; first != last; ++first) { ElementType type = *first; ElementType facet_type = mesh.getFacetType(type); mesh_facets.getSubelementToElementPointer(type, ghost_type); mesh_facets.getElementToSubelementPointer(facet_type, ghost_type); mesh_facets.getConnectivityPointer(facet_type, ghost_type); } } Element current_element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; GhostType facet_ghost_type = ghost_type; current_element.ghost_type = ghost_type; Mesh::type_iterator first = mesh.firstType(dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(dimension, ghost_type); for(; first != last; ++first) { ElementType type = *first; ElementType facet_type = mesh.getFacetType(type); current_element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array< std::vector<Element> > * element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, ghost_type); Array<UInt> * connectivity_facets = &mesh_facets.getConnectivity(facet_type, ghost_type); UInt nb_facet_per_element = mesh.getNbFacetsPerElement(type); const Array<UInt> & element_connectivity = mesh.getConnectivity(type, ghost_type); const Matrix<UInt> facet_local_connectivity = mesh.getFacetLocalConnectivity(type); UInt nb_nodes_per_facet = connectivity_facets->getNbComponent(); Vector<UInt> facet(nb_nodes_per_facet); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; for (UInt f = 0; f < nb_facet_per_element; ++f) { for (UInt n = 0; n < nb_nodes_per_facet; ++n) facet(n) = element_connectivity(el, facet_local_connectivity(f, n)); UInt first_node_nb_elements = node_to_elem.getNbCols(facet(0)); counter.resize(first_node_nb_elements); counter.clear(); //loop over the other nodes to search intersecting elements, //which are the elements that share another node with the //starting element after first_node CSR<Element>::iterator first_node_elements = node_to_elem.begin(facet(0)); CSR<Element>::iterator first_node_elements_end = node_to_elem.end(facet(0)); UInt local_el = 0; for (; first_node_elements != first_node_elements_end; ++first_node_elements, ++local_el) { for (UInt n = 1; n < nb_nodes_per_facet; ++n) { CSR<Element>::iterator node_elements_begin = node_to_elem.begin(facet(n)); CSR<Element>::iterator node_elements_end = node_to_elem.end (facet(n)); counter(local_el) += std::count(node_elements_begin, node_elements_end, *first_node_elements); } } // counting the number of elements connected to the facets and // taking the minimum element number, because the facet should // be inserted just once UInt nb_element_connected_to_facet = 0; Element minimum_el = ElementNull; connected_elements.clear(); for (UInt el_f = 0; el_f < first_node_nb_elements; el_f++) { Element real_el = node_to_elem(facet(0), el_f); if (counter(el_f) == nb_nodes_per_facet - 1) { ++nb_element_connected_to_facet; minimum_el = std::min(minimum_el, real_el); connected_elements.push_back(real_el); } } if (minimum_el == current_element) { bool full_ghost_facet = false; UInt n = 0; while (n < nb_nodes_per_facet && mesh.isPureGhostNode(facet(n))) ++n; if (n == nb_nodes_per_facet) full_ghost_facet = true; if (!full_ghost_facet) { if (!boundary_only || (boundary_only && nb_element_connected_to_facet == 1)) { std::vector<Element> elements; // build elements_on_facets: linearized_el must come first // in order to store the facet in the correct direction // and avoid to invert the sign in the normal computation elements.push_back(current_element); /// boundary facet if (nb_element_connected_to_facet == 1) elements.push_back(ElementNull); /// internal facet else if (nb_element_connected_to_facet == 2) { elements.push_back(connected_elements[1]); /// check if facet is in between ghost and normal /// elements: if it's the case, the facet is either /// ghost or not ghost. The criterion to decide this /// is arbitrary. It was chosen to check the processor /// id (prank) of the two neighboring elements. If /// prank of the ghost element is lower than prank of /// the normal one, the facet is not ghost, otherwise /// it's ghost GhostType gt[2] = { _not_ghost, _not_ghost }; for (UInt el = 0; el < connected_elements.size(); ++el) gt[el] = connected_elements[el].ghost_type; if (gt[0] + gt[1] == 1) { if (prank_to_element) { UInt prank[2]; for (UInt el = 0; el < 2; ++el) { UInt current_el = connected_elements[el].element; ElementType current_type = connected_elements[el].type; GhostType current_gt = connected_elements[el].ghost_type; const Array<UInt> & prank_to_el = (*prank_to_element)(current_type, current_gt); prank[el] = prank_to_el(current_el); } bool ghost_one = (gt[0] != _ghost); if (prank[ghost_one] > prank[!ghost_one]) facet_ghost_type = _not_ghost; else facet_ghost_type = _ghost; connectivity_facets = &mesh_facets.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, facet_ghost_type); } } } /// facet of facet else { for (UInt i = 1; i < nb_element_connected_to_facet; ++i) { elements.push_back(connected_elements[i]); } } element_to_subelement->push_back(elements); connectivity_facets->push_back(facet); /// current facet index UInt current_facet = connectivity_facets->getSize() - 1; /// loop on every element connected to current facet and /// insert current facet in the first free spot of the /// subelement_to_element vector for (UInt elem = 0; elem < elements.size(); ++elem) { Element loc_el = elements[elem]; if (loc_el.type != _not_defined) { Array<Element> & subelement_to_element = mesh_facets.getSubelementToElement(type, loc_el.ghost_type); for (UInt f_in = 0; f_in < nb_facet_per_element; ++f_in) { if (subelement_to_element(loc_el.element, f_in).type == _not_defined) { subelement_to_element(loc_el.element, f_in).type = facet_type; subelement_to_element(loc_el.element, f_in).element = current_facet; subelement_to_element(loc_el.element, f_in).ghost_type = facet_ghost_type; break; } } } } /// reset connectivity in case a facet was found in /// between ghost and normal elements if (facet_ghost_type != ghost_type) { facet_ghost_type = ghost_type; connectivity_facets = mesh_facets.getConnectivityPointer(facet_type, facet_ghost_type); element_to_subelement = mesh_facets.getElementToSubelementPointer(facet_type, facet_ghost_type); } } } } } } } } // restore the parent of mesh_facet mesh_facets.defineMeshParent(mesh_facets_parent); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, UInt * local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array<UInt> & old_nodes_numbers) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map<UInt, UInt> renumbering_map; for (UInt i = 0; i < old_nodes_numbers.getSize(); ++i) { renumbering_map[old_nodes_numbers(i)] = i; } /// renumber the nodes renumberNodesInConnectivity(local_connectivities, (nb_local_element + nb_ghost_element)*nb_nodes_per_element, renumbering_map); std::map<UInt, UInt>::iterator it = renumbering_map.begin(); std::map<UInt, UInt>::iterator end = renumbering_map.end(); old_nodes_numbers.resize(renumbering_map.size()); for (;it != end; ++it) { old_nodes_numbers(it->second) = it->first; } renumbering_map.clear(); /// copy the renumbered connectivity to the right place Array<UInt> * local_conn = mesh.getConnectivityPointer(type); local_conn->resize(nb_local_element); memcpy(local_conn->storage(), local_connectivities, nb_local_element * nb_nodes_per_element * sizeof(UInt)); Array<UInt> * ghost_conn = mesh.getConnectivityPointer(type, _ghost); ghost_conn->resize(nb_ghost_element); memcpy(ghost_conn->storage(), local_connectivities + nb_local_element * nb_nodes_per_element, nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity(UInt * list_nodes, UInt nb_nodes, std::map<UInt, UInt> & renumbering_map) { AKANTU_DEBUG_IN(); UInt * connectivity = list_nodes; UInt new_node_num = renumbering_map.size(); for (UInt n = 0; n < nb_nodes; ++n, ++connectivity) { UInt & node = *connectivity; std::map<UInt, UInt>::iterator it = renumbering_map.find(node); if(it == renumbering_map.end()) { UInt old_node = node; renumbering_map[old_node] = new_node_num; node = new_node_num; ++new_node_num; } else { node = it->second; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::purifyMesh(Mesh & mesh) { AKANTU_DEBUG_IN(); std::map<UInt, UInt> renumbering_map; RemovedNodesEvent remove_nodes(mesh); Array<UInt> & nodes_removed = remove_nodes.getList(); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; Mesh::type_iterator it = mesh.firstType(_all_dimensions, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, ghost_type, _ek_not_defined); for(; it != end; ++it) { ElementType type(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array<UInt> & connectivity_vect = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity_vect.getSize()); UInt * connectivity = connectivity_vect.storage(); renumberNodesInConnectivity (connectivity, nb_element*nb_nodes_per_element, renumbering_map); } } Array<UInt> & new_numbering = remove_nodes.getNewNumbering(); std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); std::map<UInt, UInt>::iterator it = renumbering_map.begin(); std::map<UInt, UInt>::iterator end = renumbering_map.end(); for (; it != end; ++it) { new_numbering(it->first) = it->second; } for (UInt i = 0; i < new_numbering.getSize(); ++i) { if(new_numbering(i) == UInt(-1)) nodes_removed.push_back(i); } mesh.sendEvent(remove_nodes); AKANTU_DEBUG_OUT(); } #if defined(AKANTU_COHESIVE_ELEMENT) /* -------------------------------------------------------------------------- */ void MeshUtils::insertCohesiveElements(Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion, Array<UInt> & doubled_nodes, Array<Element> & new_elements) { - AKANTU_DEBUG_IN(); - UInt spatial_dimension = mesh.getSpatialDimension(); + UInt elements_to_insert = updateFacetToDouble(mesh_facets, facet_insertion); - if (updateFacetToDouble(mesh_facets, facet_insertion)) { + if (elements_to_insert > 0) { if (spatial_dimension == 1) { doublePointFacet(mesh, mesh_facets, doubled_nodes); } else { doubleFacet(mesh, mesh_facets, spatial_dimension - 1, doubled_nodes, true); findSubfacetToDouble<false>(mesh, mesh_facets); if (spatial_dimension == 2) { doubleSubfacet<2>(mesh, mesh_facets, doubled_nodes); } else if (spatial_dimension == 3) { doubleFacet(mesh, mesh_facets, 1, doubled_nodes, false); findSubfacetToDouble<true>(mesh, mesh_facets); doubleSubfacet<3>(mesh, mesh_facets, doubled_nodes); } } updateCohesiveData(mesh, mesh_facets, new_elements); } - - AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doubleNodes(Mesh & mesh, const std::vector<UInt> & old_nodes, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); Array<Real> & position = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt old_nb_nodes = position.getSize(); UInt new_nb_nodes = old_nb_nodes + old_nodes.size(); UInt old_nb_doubled_nodes = doubled_nodes.getSize(); UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.size(); position.resize(new_nb_nodes); doubled_nodes.resize(new_nb_doubled_nodes); Array<Real>::iterator<Vector<Real> > position_begin = position.begin(spatial_dimension); for (UInt n = 0; n < old_nodes.size(); ++n) { UInt new_node = old_nb_nodes + n; /// store doubled nodes doubled_nodes(old_nb_doubled_nodes + n, 0) = old_nodes[n]; doubled_nodes(old_nb_doubled_nodes + n, 1) = new_node; /// update position std::copy(position_begin + old_nodes[n], position_begin + old_nodes[n] + 1, position_begin + new_node); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array<UInt> & doubled_nodes, bool facet_mode) { AKANTU_DEBUG_IN(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(facet_dimension, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(facet_dimension, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); const UInt nb_subfacet_per_facet = Mesh::getNbFacetsPerElement(type_facet); GhostType gt_subfacet = _casper; Array<std::vector<Element> > * f_to_subfacet = NULL; Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); UInt nb_nodes_per_facet = conn_facet.getNbComponent(); UInt old_nb_facet = conn_facet.getSize(); UInt new_nb_facet = old_nb_facet + nb_facet_to_double; conn_facet.resize(new_nb_facet); subfacet_to_facet.resize(new_nb_facet); UInt new_facet = old_nb_facet - 1; Element new_facet_el(type_facet, 0, gt_facet); Array<Element>::iterator<Vector<Element> > subfacet_to_facet_begin = subfacet_to_facet.begin(nb_subfacet_per_facet); Array<UInt>::iterator<Vector<UInt> > conn_facet_begin = conn_facet.begin(nb_nodes_per_facet); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); ++new_facet; /// adding a new facet by copying original one /// copy connectivity in new facet std::copy(conn_facet_begin + old_facet, conn_facet_begin + old_facet + 1, conn_facet_begin + new_facet); /// update subfacet_to_facet std::copy(subfacet_to_facet_begin + old_facet, subfacet_to_facet_begin + old_facet + 1, subfacet_to_facet_begin + new_facet); new_facet_el.element = new_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet_per_facet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; f_to_subfacet = & mesh_facets.getElementToSubelement(type_subfacet, subfacet.ghost_type); } /// update facet_to_subfacet array (*f_to_subfacet)(subfacet.element).push_back(new_facet_el); } } /// update facet_to_subfacet and _segment_3 facets if any if (!facet_mode) { updateSubfacetToFacet(mesh_facets, type_facet, gt_facet, true); updateFacetToSubfacet(mesh_facets, type_facet, gt_facet, true); updateQuadraticSegments<true>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } else updateQuadraticSegments<false>(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -bool MeshUtils::updateFacetToDouble(Mesh & mesh_facets, +UInt MeshUtils::updateFacetToDouble(Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); - bool facets_to_double = false; + UInt nb_facets_to_double = 0.; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; const Array<bool> & f_insertion = facet_insertion(type_facet, gt_facet); Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); Array< std::vector<Element> > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); ElementType el_type = _not_defined; GhostType el_gt = _casper; UInt nb_facet_per_element = 0; Element old_facet_el(type_facet, 0, gt_facet); Array<Element> * facet_to_element = NULL; for (UInt f = 0; f < f_insertion.getSize(); ++f) { if (f_insertion(f) == false) continue; - facets_to_double = true; + ++nb_facets_to_double; if (element_to_facet(f)[1].type == _not_defined #if defined(AKANTU_COHESIVE_ELEMENT) || element_to_facet(f)[1].kind == _ek_cohesive #endif ) { AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary"); continue; } f_to_double.push_back(f); UInt new_facet = mesh_facets.getNbElement(type_facet, gt_facet) + f_to_double.getSize() - 1; old_facet_el.element = f; /// update facet_to_element vector Element & elem_to_update = element_to_facet(f)[1]; UInt el = elem_to_update.element; if (elem_to_update.ghost_type != el_gt || elem_to_update.type != el_type) { el_type = elem_to_update.type; el_gt = elem_to_update.ghost_type; facet_to_element = & mesh_facets.getSubelementToElement(el_type, el_gt); nb_facet_per_element = facet_to_element->getNbComponent(); } Element * f_update = std::find(facet_to_element->storage() + el * nb_facet_per_element, facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, old_facet_el); AKANTU_DEBUG_ASSERT(facet_to_element->storage() + el * nb_facet_per_element != facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, "Facet not found"); f_update->element = new_facet; /// update elements connected to facet std::vector<Element> first_facet_list = element_to_facet(f); element_to_facet.push_back(first_facet_list); /// set new and original facets as boundary facets element_to_facet(new_facet)[0] = element_to_facet(new_facet)[1]; element_to_facet(f)[1] = ElementNull; element_to_facet(new_facet)[1] = ElementNull; } } } AKANTU_DEBUG_OUT(); - return facets_to_double; + return nb_facets_to_double; } /* -------------------------------------------------------------------------- */ void MeshUtils::resetFacetToDouble(Mesh & mesh_facets) { AKANTU_DEBUG_IN(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh_facets.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh_facets.lastType(_all_dimensions, gt); for(; it != end; ++it) { ElementType type = *it; mesh_facets.getDataPointer<UInt>("facet_to_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element> > ("facets_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element> > ("elements_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer<std::vector<Element> > ("subfacets_to_subsubfacet_double", type, gt, 1, false); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool subsubfacet_mode> void MeshUtils::findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); GhostType gt_subfacet = _casper; ElementType type_subsubfacet = Mesh::getFacetType(type_subfacet); GhostType gt_subsubfacet = _casper; Array<UInt> * conn_subfacet = NULL; Array<UInt> * sf_to_double = NULL; Array<std::vector<Element> > * sf_to_subfacet_double = NULL; Array<std::vector<Element> > * f_to_subfacet_double = NULL; Array<std::vector<Element> > * el_to_subfacet_double = NULL; UInt nb_subfacet = Mesh::getNbFacetsPerElement(type_facet); UInt nb_subsubfacet; UInt nb_nodes_per_sf_el; if (subsubfacet_mode) { nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subsubfacet); nb_subsubfacet = Mesh::getNbFacetsPerElement(type_subfacet); } else nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subfacet); Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array< std::vector<Element> > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array<Element> * subsubfacet_to_subfacet = NULL; UInt old_nb_facet = subfacet_to_facet.getSize() - nb_facet_to_double; Element current_facet(type_facet, 0, gt_facet); std::vector<Element> element_list; std::vector<Element> facet_list; std::vector<Element> * subfacet_list; if (subsubfacet_mode) subfacet_list = new std::vector<Element>; /// map to filter subfacets Array< std::vector<Element> > * facet_to_subfacet = NULL; /// this is used to make sure that both new and old facets are /// checked UInt facets[2]; /// loop on every facet for (UInt f_index = 0; f_index < 2; ++f_index) { for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { facets[bool(f_index)] = f_to_double(facet); facets[!bool(f_index)] = old_nb_facet + facet; UInt old_facet = facets[0]; UInt new_facet = facets[1]; Element & starting_element = element_to_facet(new_facet)[0]; current_facet.element = old_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; if (subsubfacet_mode) { subsubfacet_to_subfacet = & mesh_facets.getSubelementToElement(type_subfacet, gt_subfacet); } else { conn_subfacet = & mesh_facets.getConnectivity(type_subfacet, gt_subfacet); sf_to_double = & mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); f_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("facets_to_subfacet_double", type_subfacet, gt_subfacet); el_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("elements_to_subfacet_double", type_subfacet, gt_subfacet); facet_to_subfacet = & mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); } } if (subsubfacet_mode) { /// loop on every subsubfacet for (UInt ssf = 0; ssf < nb_subsubfacet; ++ssf) { Element & subsubfacet = (*subsubfacet_to_subfacet)(subfacet.element, ssf); if (subsubfacet == ElementNull) continue; if (gt_subsubfacet != subsubfacet.ghost_type) { gt_subsubfacet = subsubfacet.ghost_type; conn_subfacet = & mesh_facets.getConnectivity(type_subsubfacet, gt_subsubfacet); sf_to_double = & mesh_facets.getData<UInt>("facet_to_double", type_subsubfacet, gt_subsubfacet); sf_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("subfacets_to_subsubfacet_double", type_subsubfacet, gt_subsubfacet); f_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("facets_to_subfacet_double", type_subsubfacet, gt_subsubfacet); el_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("elements_to_subfacet_double", type_subsubfacet, gt_subsubfacet); facet_to_subfacet = & mesh_facets.getElementToSubelement(type_subsubfacet, gt_subsubfacet); } UInt global_ssf = subsubfacet.element; Vector<UInt> subsubfacet_connectivity(conn_subfacet->storage() + global_ssf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subsubfacet is to be doubled if (findElementsAroundSubfacet<true>(mesh, mesh_facets, starting_element, current_facet, subsubfacet_connectivity, element_list, facet_list, subfacet_list) == false && removeElementsInVector(*subfacet_list, (*facet_to_subfacet)(global_ssf)) == false) { sf_to_double->push_back(global_ssf); sf_to_subfacet_double->push_back(*subfacet_list); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } else { const UInt global_sf = subfacet.element; Vector<UInt> subfacet_connectivity(conn_subfacet->storage() + global_sf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subfacet is to be doubled if (findElementsAroundSubfacet<false>(mesh, mesh_facets, starting_element, current_facet, subfacet_connectivity, element_list, facet_list) == false && removeElementsInVector(facet_list, (*facet_to_subfacet)(global_sf)) == false) { sf_to_double->push_back(global_sf); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } } } if (subsubfacet_mode) delete subfacet_list; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array<Element> & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); Array<Element> * facet_to_coh_element = mesh_facets.getSubelementToElementPointer(type_cohesive, gt_facet); Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array<UInt> * conn_cohesive = mesh.getConnectivityPointer(type_cohesive, gt_facet); UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet); Array< std::vector<Element> > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); UInt old_nb_cohesive_elements = conn_cohesive->getSize(); UInt new_nb_cohesive_elements = conn_cohesive->getSize() + nb_facet_to_double; UInt old_nb_facet = element_to_facet.getSize() - nb_facet_to_double; facet_to_coh_element->resize(new_nb_cohesive_elements); conn_cohesive->resize(new_nb_cohesive_elements); UInt new_elements_old_size = new_elements.getSize(); new_elements.resize(new_elements_old_size + nb_facet_to_double); Element c_element(type_cohesive, 0, gt_facet, _ek_cohesive); Element f_element(type_facet, 0, gt_facet); UInt facets[2]; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { /// (in 3D cohesive elements connectivity is inverted) facets[third_dimension] = f_to_double(facet); facets[!third_dimension] = old_nb_facet + facet; UInt cohesive_element = old_nb_cohesive_elements + facet; /// store doubled facets f_element.element = facets[0]; (*facet_to_coh_element)(cohesive_element, 0) = f_element; f_element.element = facets[1]; (*facet_to_coh_element)(cohesive_element, 1) = f_element; /// modify cohesive elements' connectivity for (UInt n = 0; n < nb_nodes_per_facet; ++n) { (*conn_cohesive)(cohesive_element, n) = conn_facet(facets[0], n); (*conn_cohesive)(cohesive_element, n + nb_nodes_per_facet) = conn_facet(facets[1], n); } /// update element_to_facet vectors c_element.element = cohesive_element; element_to_facet(facets[0])[1] = c_element; element_to_facet(facets[1])[1] = c_element; /// add cohesive element to the element event list new_elements(new_elements_old_size + facet) = c_element; } } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); if (spatial_dimension != 1) return; Array<Real> & position = mesh.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array< std::vector<Element> > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); const Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); UInt old_nb_facet = element_to_facet.getSize() - nb_facet_to_double; UInt new_nb_facet = element_to_facet.getSize(); UInt old_nb_nodes = position.getSize(); UInt new_nb_nodes = old_nb_nodes + nb_facet_to_double; position.resize(new_nb_nodes); conn_facet.resize(new_nb_facet); UInt old_nb_doubled_nodes = doubled_nodes.getSize(); doubled_nodes.resize(old_nb_doubled_nodes + nb_facet_to_double); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt new_facet = old_nb_facet + facet; ElementType type = element_to_facet(new_facet)[0].type; UInt el = element_to_facet(new_facet)[0].element; GhostType gt = element_to_facet(new_facet)[0].ghost_type; UInt old_node = conn_facet(old_facet); UInt new_node = old_nb_nodes + facet; /// update position position(new_node) = position(old_node); conn_facet(new_facet) = new_node; Array<UInt> & conn_segment = mesh.getConnectivity(type, gt); UInt nb_nodes_per_segment = conn_segment.getNbComponent(); /// update facet connectivity UInt i; for (i = 0; conn_segment(el, i) != old_node && i <= nb_nodes_per_segment; ++i); conn_segment(el, i) = new_node; doubled_nodes(old_nb_doubled_nodes + facet, 0) = old_node; doubled_nodes(old_nb_doubled_nodes + facet, 1) = new_node; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_segments> void MeshUtils::updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (type_facet != _segment_3) return; Array<UInt> & f_to_double = mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); UInt old_nb_facet = mesh_facets.getNbElement(type_facet, gt_facet) - nb_facet_to_double; Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array< std::vector<Element> > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); /// this ones matter only for segments in 3D Array< std::vector<Element> > * el_to_subfacet_double = NULL; Array< std::vector<Element> > * f_to_subfacet_double = NULL; if (third_dim_segments) { el_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("elements_to_subfacet_double", type_facet, gt_facet); f_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("facets_to_subfacet_double", type_facet, gt_facet); } std::vector<UInt> middle_nodes; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt node = conn_facet(old_facet, 2); if (!mesh.isPureGhostNode(node)) middle_nodes.push_back(node); } UInt n = doubled_nodes.getSize(); doubleNodes(mesh, middle_nodes, doubled_nodes); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt old_node = conn_facet(old_facet, 2); if (mesh.isPureGhostNode(old_node)) continue; UInt new_node = doubled_nodes(n, 1); UInt new_facet = old_nb_facet + facet; conn_facet(new_facet, 2) = new_node; if (third_dim_segments) { updateElementalConnectivity(mesh_facets, old_node, new_node, element_to_facet(new_facet)); updateElementalConnectivity(mesh, old_node, new_node, (*el_to_subfacet_double)(facet), &(*f_to_subfacet_double)(facet)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_facet(new_facet)); } ++n; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); /// update subfacet_to_facet vector ElementType type_facet = _not_defined; GhostType gt_facet = _casper; Array<Element> * subfacet_to_facet = NULL; UInt nb_subfacet_per_facet = 0; UInt old_nb_subfacet = mesh_facets.getNbElement(type_subfacet, gt_subfacet) - nb_subfacet_to_double; Array<std::vector<Element> > * facet_list = NULL; if (facet_mode) facet_list = & mesh_facets.getData<std::vector<Element> >("facets_to_subfacet_double", type_subfacet, gt_subfacet); else facet_list = & mesh_facets.getData<std::vector<Element> >("subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); Element old_subfacet_el(type_subfacet, 0, gt_subfacet); Element new_subfacet_el(type_subfacet, 0, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { old_subfacet_el.element = sf_to_double(sf); new_subfacet_el.element = old_nb_subfacet + sf; for (UInt f = 0; f < (*facet_list)(sf).size(); ++f) { Element & facet = (*facet_list)(sf)[f]; if (facet.type != type_facet || facet.ghost_type != gt_facet) { type_facet = facet.type; gt_facet = facet.ghost_type; subfacet_to_facet = & mesh_facets.getSubelementToElement(type_facet, gt_facet); nb_subfacet_per_facet = subfacet_to_facet->getNbComponent(); } Element * sf_update = std::find(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet, subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, old_subfacet_el); AKANTU_DEBUG_ASSERT(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet != subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, "Subfacet not found"); *sf_update = new_subfacet_el; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); Array< std::vector<Element> > & facet_to_subfacet = mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); Array< std::vector<Element> > * facet_to_subfacet_double = NULL; if (facet_mode) { facet_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("facets_to_subfacet_double", type_subfacet, gt_subfacet); } else { facet_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); } UInt old_nb_subfacet = facet_to_subfacet.getSize(); facet_to_subfacet.resize(old_nb_subfacet + nb_subfacet_to_double); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) facet_to_subfacet(old_nb_subfacet + sf) = (*facet_to_subfacet_double)(sf); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <UInt spatial_dimension> void MeshUtils::doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes) { AKANTU_DEBUG_IN(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_subfacet = *gt; Mesh::type_iterator it = mesh_facets.firstType(0, gt_subfacet); Mesh::type_iterator end = mesh_facets.lastType(0, gt_subfacet); for(; it != end; ++it) { ElementType type_subfacet = *it; Array<UInt> & sf_to_double = mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); if (nb_subfacet_to_double == 0) continue; AKANTU_DEBUG_ASSERT(type_subfacet == _point_1, "Only _point_1 subfacet doubling is supported at the moment"); Array<UInt> & conn_subfacet = mesh_facets.getConnectivity(type_subfacet, gt_subfacet); UInt old_nb_subfacet = conn_subfacet.getSize(); UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double; conn_subfacet.resize(new_nb_subfacet); std::vector<UInt> nodes_to_double; UInt old_nb_doubled_nodes = doubled_nodes.getSize(); /// double nodes for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_subfacet = sf_to_double(sf); nodes_to_double.push_back(conn_subfacet(old_subfacet)); } doubleNodes(mesh, nodes_to_double, doubled_nodes); /// add new nodes in connectivity for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt new_subfacet = old_nb_subfacet + sf; UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); conn_subfacet(new_subfacet) = new_node; } /// update facet and element connectivity Array<std::vector<Element> > & f_to_subfacet_double = mesh_facets.getData<std::vector<Element> >("facets_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element> > & el_to_subfacet_double = mesh_facets.getData<std::vector<Element> >("elements_to_subfacet_double", type_subfacet, gt_subfacet); Array<std::vector<Element> > * sf_to_subfacet_double = NULL; if (spatial_dimension == 3) sf_to_subfacet_double = & mesh_facets.getData<std::vector<Element> >("subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_node = doubled_nodes(old_nb_doubled_nodes + sf, 0); UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); updateElementalConnectivity(mesh, old_node, new_node, el_to_subfacet_double(sf), &f_to_subfacet_double(sf)); updateElementalConnectivity(mesh_facets, old_node, new_node, f_to_subfacet_double(sf)); if (spatial_dimension == 3) updateElementalConnectivity(mesh_facets, old_node, new_node, (*sf_to_subfacet_double)(sf)); } if (spatial_dimension == 2) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, true); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, true); } else if (spatial_dimension == 3) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, false); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::flipFacets(Mesh & mesh_facets, const ElementTypeMapArray<UInt> & global_connectivity, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); /// get global connectivity for local mesh ElementTypeMapArray<UInt> global_connectivity_tmp; mesh_facets.initElementTypeMapArray(global_connectivity_tmp, 1, spatial_dimension - 1, gt_facet, true, _ek_regular, true); mesh_facets.getGlobalConnectivity(global_connectivity_tmp, spatial_dimension - 1, gt_facet); Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); /// loop on every facet for(; it != end; ++it) { ElementType type_facet = *it; Array<UInt> & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet); const Array<UInt> & g_connectivity = global_connectivity(type_facet, gt_facet); Array<std::vector<Element> > & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array<Element> & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); UInt nb_subfacet_per_facet = subfacet_to_facet.getNbComponent(); UInt nb_nodes_per_facet = connectivity.getNbComponent(); UInt nb_facet = connectivity.getSize(); UInt nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); Array<UInt> & global_conn_tmp = global_connectivity_tmp(type_facet, gt_facet); Array<UInt>::iterator<Vector<UInt> > conn_it = connectivity.begin(nb_nodes_per_facet); Array<UInt>::iterator<Vector<UInt> > gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet); Array<UInt>::const_iterator<Vector<UInt> > conn_glob_it = g_connectivity.begin(nb_nodes_per_facet); Array<Element>::iterator<Vector<Element> > subf_to_f = subfacet_to_facet.begin(nb_subfacet_per_facet); UInt * conn_tmp_pointer = new UInt[nb_nodes_per_facet]; Vector<UInt> conn_tmp(conn_tmp_pointer, nb_nodes_per_facet); Element el_tmp; Element * subf_tmp_pointer = new Element[nb_subfacet_per_facet]; Vector<Element> subf_tmp(subf_tmp_pointer, nb_subfacet_per_facet); for (UInt f = 0; f < nb_facet; ++f, ++conn_it, ++gconn_tmp_it, ++subf_to_f, ++conn_glob_it) { Vector<UInt> & gconn_tmp = *gconn_tmp_it; const Vector<UInt> & conn_glob = *conn_glob_it; Vector<UInt> & conn_local = *conn_it; /// skip facet if connectivities are the same if (gconn_tmp == conn_glob) continue; /// re-arrange connectivity conn_tmp = conn_local; UInt * begin = conn_glob.storage(); UInt * end = conn_glob.storage() + nb_nodes_per_facet; for (UInt n = 0; n < nb_nodes_per_facet; ++n) { UInt * new_node = std::find(begin, end, gconn_tmp(n)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; conn_local(new_position) = conn_tmp(n); } /// if 3D, check if facets are just rotated if (spatial_dimension == 3) { /// find first node UInt * new_node = std::find(begin, end, gconn_tmp(0)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; UInt n = 1; /// count how many nodes in the received connectivity follow /// the same order of those in the local connectivity for (; n < nb_nodes_per_P1_facet && gconn_tmp(n) == conn_glob((new_position + n) % nb_nodes_per_P1_facet); ++n); /// skip the facet inversion if facet is just rotated if (n == nb_nodes_per_P1_facet) continue; } /// update data to invert facet el_tmp = el_to_f(f)[0]; el_to_f(f)[0] = el_to_f(f)[1]; el_to_f(f)[1] = el_tmp; subf_tmp = (*subf_to_f); (*subf_to_f)(0) = subf_tmp(1); (*subf_to_f)(1) = subf_tmp(0); } delete [] subf_tmp_pointer; delete [] conn_tmp_pointer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::fillElementToSubElementsData(Mesh & mesh) { AKANTU_DEBUG_IN(); if(mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) { AKANTU_DEBUG_INFO("There are not facets, add them in the mesh file or call the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray<Real> barycenters("barycenter_tmp", mesh.getID()); mesh.initElementTypeMapArray(barycenters, spatial_dimension, _all_dimensions); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator it = mesh.firstType(_all_dimensions, *gt); Mesh::type_iterator end = mesh.lastType(_all_dimensions, *gt); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, *gt); Array<Real> & barycenters_arr = barycenters(*it, *gt); barycenters_arr.resize(nb_element); Array<Real>::vector_iterator bary = barycenters_arr.begin(spatial_dimension); Array<Real>::vector_iterator bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { mesh.getBarycenter(el, *it, bary->storage(), *gt); } } } for(Int sp(spatial_dimension); sp >= 1; --sp) { if(mesh.getNbElement(sp) == 0) continue; for (ghost_type_t::iterator git = ghost_type_t::begin(); git != ghost_type_t::end(); ++git) { Mesh::type_iterator tit = mesh.firstType(sp, *git); Mesh::type_iterator tend = mesh.lastType(sp, *git); for (;tit != tend; ++tit) { mesh.getSubelementToElementPointer(*tit, *git)->resize(mesh.getNbElement(*tit, *git)); mesh.getSubelementToElement(*tit, *git).clear(); } tit = mesh.firstType(sp - 1, *git); tend = mesh.lastType(sp - 1, *git); for (;tit != tend; ++tit) { mesh.getElementToSubelementPointer(*tit, *git)->resize(mesh.getNbElement(*tit, *git)); mesh.getElementToSubelement(*tit, *git).clear(); } } CSR<Element> nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (ghost_type_t::iterator git = ghost_type_t::begin(); git != ghost_type_t::end(); ++git) { Mesh::type_iterator tit = mesh.firstType(sp - 1, *git); Mesh::type_iterator tend = mesh.lastType(sp - 1, *git); facet_element.ghost_type = *git; for (;tit != tend; ++tit) { facet_element.type = *tit; Array< std::vector<Element> > & element_to_subelement = mesh.getElementToSubelement(*tit, *git); const Array<UInt> & connectivity = mesh.getConnectivity(*tit, *git); Array<UInt>::const_iterator< Vector<UInt> > fit = connectivity.begin(mesh.getNbNodesPerElement(*tit)); Array<UInt>::const_iterator< Vector<UInt> > fend = connectivity.end(mesh.getNbNodesPerElement(*tit)); UInt fid = 0; for (;fit != fend; ++fit, ++fid) { const Vector<UInt> & facet = *fit; facet_element.element = fid; std::map<Element, UInt> element_seen_counter; UInt nb_nodes_per_facet = mesh.getNbNodesPerElement(Mesh::getP1ElementType(*tit)); for (UInt n(0); n < nb_nodes_per_facet; ++n) { CSR<Element>::iterator eit = nodes_to_elements.begin(facet(n)); CSR<Element>::iterator eend = nodes_to_elements.end(facet(n)); for(;eit != eend; ++eit) { Element & elem = *eit; std::map<Element, UInt>::iterator cit = element_seen_counter.find(elem); if(cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } std::vector<Element> connected_elements; std::map<Element, UInt>::iterator cit = element_seen_counter.begin(); std::map<Element, UInt>::iterator cend = element_seen_counter.end(); for(;cit != cend; ++cit) { if(cit->second == nb_nodes_per_facet) connected_elements.push_back(cit->first); } std::vector<Element>::iterator ceit = connected_elements.begin(); std::vector<Element>::iterator ceend = connected_elements.end(); for(;ceit != ceend; ++ceit) element_to_subelement(fid).push_back(*ceit); for (UInt ce = 0; ce < connected_elements.size(); ++ce) { Element & elem = connected_elements[ce]; Array<Element> & subelement_to_element = *(mesh.getSubelementToElementPointer(elem.type, elem.ghost_type)); UInt f(0); for(; f < mesh.getNbFacetsPerElement(elem.type) && subelement_to_element(elem.element, f) != ElementNull; ++f); AKANTU_DEBUG_ASSERT(f < mesh.getNbFacetsPerElement(elem.type), "The element " << elem << " seems to have too many facets!! (" << f << " < " << mesh.getNbFacetsPerElement(elem.type) << ")"); subelement_to_element(elem.element, f) = facet_element; } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template <bool third_dim_points> bool MeshUtils::findElementsAroundSubfacet(const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector<UInt> & subfacet_connectivity, std::vector<Element> & elem_list, std::vector<Element> & facet_list, std::vector<Element> * subfacet_list) { AKANTU_DEBUG_IN(); /// preallocated stuff before starting bool facet_matched = false; elem_list.clear(); facet_list.clear(); if (third_dim_points) subfacet_list->clear(); elem_list.push_back(starting_element); const Array<UInt> * facet_connectivity = NULL; const Array<UInt> * sf_connectivity = NULL; const Array<Element> * facet_to_element = NULL; const Array<Element> * subfacet_to_facet = NULL; ElementType current_type = _not_defined; GhostType current_ghost_type = _casper; ElementType current_facet_type = _not_defined; GhostType current_facet_ghost_type = _casper; ElementType current_subfacet_type = _not_defined; GhostType current_subfacet_ghost_type = _casper; const Array< std::vector<Element> > * element_to_facet = NULL; const Element * opposing_el = NULL; std::queue<Element> elements_to_check; elements_to_check.push(starting_element); /// keep going until there are elements to check while (!elements_to_check.empty()) { /// check current element Element & current_el = elements_to_check.front(); if (current_el.type != current_type || current_el.ghost_type != current_ghost_type) { current_type = current_el.type; current_ghost_type = current_el.ghost_type; facet_to_element = & mesh_facets.getSubelementToElement(current_type, current_ghost_type); } /// loop over each facet of the element for (UInt f = 0; f < facet_to_element->getNbComponent(); ++f) { const Element & current_facet = (*facet_to_element)(current_el.element, f); if (current_facet == ElementNull) continue; if (current_facet_type != current_facet.type || current_facet_ghost_type != current_facet.ghost_type) { current_facet_type = current_facet.type; current_facet_ghost_type = current_facet.ghost_type; element_to_facet = & mesh_facets.getElementToSubelement(current_facet_type, current_facet_ghost_type); facet_connectivity = & mesh_facets.getConnectivity(current_facet_type, current_facet_ghost_type); if (third_dim_points) subfacet_to_facet = & mesh_facets.getSubelementToElement(current_facet_type, current_facet_ghost_type); } /// check if end facet is reached if (current_facet == end_facet) facet_matched = true; /// add this facet if not already passed if (std::find(facet_list.begin(), facet_list.end(), current_facet) == facet_list.end() && hasElement(*facet_connectivity, current_facet, subfacet_connectivity)) { facet_list.push_back(current_facet); if (third_dim_points) { /// check subfacets for (UInt sf = 0; sf < subfacet_to_facet->getNbComponent(); ++sf) { const Element & current_subfacet = (*subfacet_to_facet)(current_facet.element, sf); if (current_subfacet == ElementNull) continue; if (current_subfacet_type != current_subfacet.type || current_subfacet_ghost_type != current_subfacet.ghost_type) { current_subfacet_type = current_subfacet.type; current_subfacet_ghost_type = current_subfacet.ghost_type; sf_connectivity = & mesh_facets.getConnectivity(current_subfacet_type, current_subfacet_ghost_type); } if (std::find(subfacet_list->begin(), subfacet_list->end(), current_subfacet) == subfacet_list->end() && hasElement(*sf_connectivity, current_subfacet, subfacet_connectivity)) subfacet_list->push_back(current_subfacet); } } } else continue; /// consider opposing element if ( (*element_to_facet)(current_facet.element)[0] == current_el) opposing_el = & (*element_to_facet)(current_facet.element)[1]; else opposing_el = & (*element_to_facet)(current_facet.element)[0]; /// skip null elements since they are on a boundary if (*opposing_el == ElementNull) continue; /// skip this element if already added if ( std::find(elem_list.begin(), elem_list.end(), *opposing_el) != elem_list.end() ) continue; /// only regular elements have to be checked if (opposing_el->kind == _ek_regular) elements_to_check.push(*opposing_el); elem_list.push_back(*opposing_el); #ifndef AKANTU_NDEBUG const Array<UInt> & conn_elem = mesh.getConnectivity(opposing_el->type, opposing_el->ghost_type); AKANTU_DEBUG_ASSERT(hasElement(conn_elem, *opposing_el, subfacet_connectivity), "Subfacet doesn't belong to this element"); #endif } /// erased checked element from the list elements_to_check.pop(); } AKANTU_DEBUG_OUT(); return facet_matched; } __END_AKANTU__ // LocalWords: ElementType diff --git a/src/mesh_utils/mesh_utils.hh b/src/mesh_utils/mesh_utils.hh index 48a1a1100..7848bd139 100644 --- a/src/mesh_utils/mesh_utils.hh +++ b/src/mesh_utils/mesh_utils.hh @@ -1,277 +1,278 @@ /** * @file mesh_utils.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Aug 20 2010 * @date last modification: Mon Jun 23 2014 * * @brief All mesh utils necessary for various tasks * * @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 "mesh.hh" #include "aka_csr.hh" #include "distributed_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include <vector> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_UTILS_HH__ #define __AKANTU_MESH_UTILS_HH__ /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class MeshUtils { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshUtils(); virtual ~MeshUtils(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// build a CSR<UInt> that contains for each node the linearized number of /// the connected elements of a given spatial dimension static void buildNode2Elements(const Mesh & mesh, CSR<UInt> & node_to_elem, UInt spatial_dimension = _all_dimensions); /// build a CSR<Element> that contains for each node the list of connected /// elements ofr a given spatial dimension static void buildNode2Elements(const Mesh & mesh, CSR<Element> & node_to_elem, UInt spatial_dimension = _all_dimensions); /// build a CSR<UInt> that contains for each node the number of /// the connected elements of a given ElementType static void buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR<UInt> & node_to_elem, const ElementType & type, const GhostType & ghost_type = _not_ghost); /// build the facets elements on the boundaries of a mesh static void buildFacets(Mesh & mesh); /// build all the facets elements: boundary and internals and store them in /// the mesh_facets for element of dimension from_dimension to to_dimension static void buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension, DistributedSynchronizer * synchronizer = NULL); /// build all the facets elements: boundary and internals and store them in /// the mesh_facets static void buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension = 0, DistributedSynchronizer * synchronizer = NULL); /// build facets for a given spatial dimension static void buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, const ElementTypeMapArray<UInt> * prank_to_element = NULL); /// take the local_connectivity array as the array of local and ghost /// connectivity, renumber the nodes and set the connectivity of the mesh static void renumberMeshNodes(Mesh & mesh, UInt * local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array<UInt> & old_nodes); /// compute pbc pair for on given a direction static void computePBCMap(const Mesh & mymesh, const UInt dir, std::map<UInt,UInt> & pbc_pair); /// compute pbc pair for a surface pair static void computePBCMap(const Mesh & mymesh, const std::pair<Surface, Surface> & surface_pair, std::map<UInt,UInt> & pbc_pair); /// create a multimap of nodes per surfaces static void buildNodesPerSurface(const Mesh & mesh, CSR<UInt> & nodes_per_surface); /// remove not connected nodes /!\ this functions renumbers the nodes. static void purifyMesh(Mesh & mesh); #if defined(AKANTU_COHESIVE_ELEMENT) /// function to insert cohesive elements on the selected facets static void insertCohesiveElements(Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion, Array<UInt> & doubled_nodes, Array<Element> & new_elements); #endif /// fill the subelement to element and the elements to subelements data static void fillElementToSubElementsData(Mesh & mesh); /// flip facets based on global connectivity static void flipFacets(Mesh & mesh_facets, const ElementTypeMapArray<UInt> & global_connectivity, GhostType gt_facet); /// provide list of elements around a node and check if a given /// facet is reached template <bool third_dim_points> static bool findElementsAroundSubfacet(const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector<UInt> & subfacet_connectivity, std::vector<Element> & elem_list, std::vector<Element> & facet_list, std::vector<Element> * subfacet_list = NULL); /// function to check if a node belongs to a given element static inline bool hasElement(const Array<UInt> & connectivity, const Element & el, const Vector<UInt> & nodes); /// reset facet_to_double arrays in the Mesh static void resetFacetToDouble(Mesh & mesh_facets); private: /// match pairs that are on the associated pbc's static void matchPBCPairs(const Mesh & mymesh, const UInt dir, Array<UInt> & selected_left, Array<UInt> & selected_right, std::map<UInt,UInt> & pbc_pair); /// function used by all the renumbering functions static void renumberNodesInConnectivity(UInt * list_nodes, UInt nb_nodes, std::map<UInt, UInt> & renumbering_map); /// update facet_to_subfacet static void updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// update subfacet_to_facet static void updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// function to double a given facet and update the list of doubled /// nodes static void doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array<UInt> & doubled_nodes, bool facet_mode); /// function to double a subfacet given start and end index for /// local facet_to_subfacet vector, and update the list of doubled /// nodes template <UInt spatial_dimension> static void doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes); /// double a node static void doubleNodes(Mesh & mesh, const std::vector<UInt> & old_nodes, Array<UInt> & doubled_nodes); /// fill facet_to_double array in the mesh - static bool updateFacetToDouble(Mesh & mesh_facets, + /// returns the number of facets to be doubled + static UInt updateFacetToDouble(Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion); /// find subfacets to be doubled template <bool subsubfacet_mode> static void findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets); /// double facets (points) in 1D static void doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array<UInt> & doubled_nodes); #if defined(AKANTU_COHESIVE_ELEMENT) /// update cohesive element data static void updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array<Element> & new_elements); #endif /// update elemental connectivity after doubling a node inline static void updateElementalConnectivity(Mesh & mesh, UInt old_node, UInt new_node, const std::vector<Element> & element_list, const std::vector<Element> * facet_list = NULL); /// double middle nodes if facets are _segment_3 template <bool third_dim_segments> static void updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array<UInt> & doubled_nodes); /// remove elements on a vector inline static bool removeElementsInVector(const std::vector<Element> & elem_to_remove, std::vector<Element> & elem_list); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "mesh_utils_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MESH_UTILS_HH__ */ diff --git a/src/model/boundary_condition_functor.hh b/src/model/boundary_condition_functor.hh index e1e300106..279dc72a2 100644 --- a/src/model/boundary_condition_functor.hh +++ b/src/model/boundary_condition_functor.hh @@ -1,205 +1,202 @@ /** * @file boundary_condition_functor.hh * * @author Dana Christen <dana.christen@gmail.com> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * * @date creation: Fri May 03 2013 * @date last modification: Fri Sep 19 2014 * * @brief XXX * * @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_BOUNDARY_CONDITION_FUNCTOR_HH__ #define __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ #include "aka_common.hh" #include "fe_engine.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ namespace BC { typedef ::akantu::SpacialDirection Axis; struct Functor { enum Type { _dirichlet, _neumann }; }; /* ------------------------------------------------------------------------ */ /* Dirichlet */ /* ------------------------------------------------------------------------ */ namespace Dirichlet { /* ---------------------------------------------------------------------- */ class DirichletFunctor : public Functor { protected: DirichletFunctor() : axis(_x) {} DirichletFunctor(Axis ax) : axis(ax) {} public: void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const { AKANTU_DEBUG_TO_IMPLEMENT(); } public: static const Type type = _dirichlet; protected: Axis axis; }; /* ---------------------------------------------------------------------- */ class FlagOnly : public DirichletFunctor { public: FlagOnly(Axis ax = _x) : DirichletFunctor(ax) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; }; /* ---------------------------------------------------------------------- */ class FreeBoundary : public DirichletFunctor { public: FreeBoundary(Axis ax = _x) : DirichletFunctor(ax) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; }; /* ---------------------------------------------------------------------- */ class FixedValue : public DirichletFunctor { public: FixedValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; protected: Real value; }; /* ---------------------------------------------------------------------- */ class IncrementValue : public DirichletFunctor { public: IncrementValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {} public: inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal, const Vector<Real> & coord) const; inline void setIncrement(Real val) { this->value = val; } protected: Real value; }; } //end namespace Dirichlet /* ------------------------------------------------------------------------ */ /* Neumann */ /* ------------------------------------------------------------------------ */ namespace Neumann { /* ---------------------------------------------------------------------- */ class NeumannFunctor : public Functor { protected: NeumannFunctor() {} public: - void operator()(UInt node, - Vector<bool> & flags, - Vector<Real> & primal, - const Vector<Real> & coord) const { - AKANTU_DEBUG_TO_IMPLEMENT(); - } - + virtual void operator()(const QuadraturePoint & quad_point, + Vector<Real> & dual, + const Vector<Real> & coord, + const Vector<Real> & normals) const = 0; public: static const Type type = _neumann; }; /* ---------------------------------------------------------------------- */ class FromHigherDim : public NeumannFunctor { public: FromHigherDim(const Matrix<Real> & mat) : bc_data(mat) {} public: inline void operator()(const QuadraturePoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const; protected: Matrix<Real> bc_data; }; /* ---------------------------------------------------------------------- */ class FromSameDim : public NeumannFunctor { public: FromSameDim(const Vector<Real> & vec) : bc_data(vec) {} public: inline void operator()(const QuadraturePoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const; protected: Vector<Real> bc_data; }; /* ---------------------------------------------------------------------- */ class FreeBoundary : public NeumannFunctor { public: inline void operator()(const QuadraturePoint & quad_point, Vector<Real> & dual, const Vector<Real> & coord, const Vector<Real> & normals) const; }; } //end namespace Neumann } //end namespace BC __END_AKANTU__ #include "boundary_condition_functor_inline_impl.cc" #endif /* __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ */ diff --git a/src/model/model.cc b/src/model/model.cc index 3c0388268..2d7a9c7d8 100644 --- a/src/model/model.cc +++ b/src/model/model.cc @@ -1,373 +1,373 @@ /** * @file model.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Oct 03 2011 * @date last modification: Fri Sep 05 2014 * * @brief implementation of model common parts * * @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 "model.hh" #include "element_group.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ Model::Model(Mesh& m, UInt dim, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), mesh(m), spatial_dimension(dim == _all_dimensions ? m.getSpatialDimension() : dim), synch_registry(NULL),is_pbc_slave_node(0,1,"is_pbc_slave_node") , parser(&getStaticParser()) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Model::~Model() { AKANTU_DEBUG_IN(); FEEngineMap::iterator it; for (it = fems.begin(); it != fems.end(); ++it) { if(it->second) delete it->second; } for (it = fems_boundary.begin(); it != fems_boundary.end(); ++it) { if(it->second) delete it->second; } delete synch_registry; delete dof_synchronizer; dof_synchronizer = NULL; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Model::setParser(Parser & parser){ this->parser = &parser; } /* -------------------------------------------------------------------------- */ void Model::initFull(const ModelOptions & options) { AKANTU_DEBUG_IN(); initModel(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Model::createSynchronizerRegistry(DataAccessor * data_accessor){ synch_registry = new SynchronizerRegistry(*data_accessor); } /* -------------------------------------------------------------------------- */ void Model::setPBC(UInt x, UInt y, UInt z){ mesh.computeBoundingBox(); if (x) MeshUtils::computePBCMap(this->mesh, 0, this->pbc_pair); if (y) MeshUtils::computePBCMap(this->mesh, 1, this->pbc_pair); if (z) MeshUtils::computePBCMap(this->mesh, 2, this->pbc_pair); } /* -------------------------------------------------------------------------- */ void Model::setPBC(SurfacePairList & surface_pairs){ SurfacePairList::iterator s_it; for(s_it = surface_pairs.begin(); s_it != surface_pairs.end(); ++s_it) { MeshUtils::computePBCMap(this->mesh, *s_it, this->pbc_pair); } } /* -------------------------------------------------------------------------- */ void Model::initPBC() { std::map<UInt,UInt>::iterator it = pbc_pair.begin(); std::map<UInt,UInt>::iterator end = pbc_pair.end(); is_pbc_slave_node.resize(mesh.getNbNodes()); #ifndef AKANTU_NDEBUG Real * coords = mesh.getNodes().storage(); UInt dim = mesh.getSpatialDimension(); #endif while(it != end){ UInt i1 = (*it).first; is_pbc_slave_node(i1) = true; #ifndef AKANTU_NDEBUG UInt i2 = (*it).second; AKANTU_DEBUG_INFO("pairing " << i1 << " (" << coords[dim*i1] << "," << coords[dim*i1+1] << "," << coords[dim*i1+2] << ") with " << i2 << " (" << coords[dim*i2] << "," << coords[dim*i2+1] << "," << coords[dim*i2+2] << ")"); #endif ++it; } } /* -------------------------------------------------------------------------- */ DistributedSynchronizer & Model::createParallelSynch(MeshPartition * partition, __attribute__((unused)) DataAccessor * data_accessor){ AKANTU_DEBUG_IN(); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); DistributedSynchronizer * synch = NULL; if(prank == 0) synch = DistributedSynchronizer::createDistributedSynchronizerMesh(getFEEngine().getMesh(), partition); else synch = DistributedSynchronizer::createDistributedSynchronizerMesh(getFEEngine().getMesh(), NULL); AKANTU_DEBUG_OUT(); return *synch; } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name, const std::string & dumper_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup() { GroupManager::element_group_iterator bit = mesh.element_group_begin(); GroupManager::element_group_iterator bend = mesh.element_group_end(); for(; bit != bend; ++bit) { bit->second->dump(); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory) { GroupManager::element_group_iterator bit = mesh.element_group_begin(); GroupManager::element_group_iterator bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->setDirectory(directory); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setGroupBaseName(const std::string & basename, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setBaseName(basename); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Model::getGroupDumper(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); return group.getDumper(); } /* -------------------------------------------------------------------------- */ // DUMPER stuff /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & field_id, dumper::Field * field, DumperIOHelper & dumper) { #ifdef AKANTU_USE_IOHELPER dumper.registerField(field_id,field); #endif } /* -------------------------------------------------------------------------- */ void Model::addDumpField(const std::string & field_id) { this->addDumpFieldToDumper(mesh.getDefaultDumperName(),field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVector(const std::string & field_id) { this->addDumpFieldVectorToDumper(mesh.getDefaultDumperName(),field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensor(const std::string & field_id) { this->addDumpFieldTensorToDumper(mesh.getDefaultDumperName(),field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseName(const std::string & field_id) { mesh.setBaseName(field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseNameToDumper(const std::string & dumper_name, const std::string & basename) { mesh.setBaseNameToDumper(dumper_name,basename); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name,field_id,"all",_ek_regular,false); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldToDumper(group.getDefaultDumperName(), field_id, group_name,_ek_regular,false); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->removeDumpGroupFieldFromDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.removeDumpFieldFromDumper(dumper_name, field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name,field_id,"all",_ek_regular,3); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldVectorToDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { this->addDumpGroupFieldToDumper(dumper_name,field_id,group_name,_ek_regular,true); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name,field_id,"all",_ek_regular,true); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & dumper_name, - const std::string & field_id, - const std::string & group_name, - const ElementKind & element_kind, - bool padding_flag) { + const std::string & field_id, + const std::string & group_name, + const ElementKind & element_kind, + bool padding_flag) { #ifdef AKANTU_USE_IOHELPER dumper::Field * field = NULL; if (!field) field = this->createNodalFieldReal(field_id,group_name,padding_flag); if (!field) field = this->createNodalFieldUInt(field_id,group_name,padding_flag); if (!field) field = this->createNodalFieldBool(field_id,group_name,padding_flag); - if (!field) field = this->createElementalField(field_id,group_name,padding_flag,element_kind); + if (!field) field = this->createElementalField(field_id,group_name,padding_flag,this->spatial_dimension,element_kind); if (!field) field = this->mesh.createFieldFromAttachedData<UInt>(field_id,group_name, element_kind); if (!field) field = this->mesh.createFieldFromAttachedData<Real>(field_id,group_name, element_kind); if (!field) AKANTU_DEBUG_WARNING("No field could be found based on name: " << field_id); if (field) { DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name,group_name); this->addDumpGroupFieldToDumper(field_id,field,dumper); } #endif } /* -------------------------------------------------------------------------- */ void Model::dump() { mesh.dump(); } /* -------------------------------------------------------------------------- */ void Model::setDirectory(const std::string & directory) { mesh.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setDirectoryToDumper(const std::string & dumper_name, const std::string & directory) { mesh.setDirectoryToDumper(dumper_name,directory); } __END_AKANTU__ diff --git a/src/model/model.hh b/src/model/model.hh index ee38ae66e..86d658102 100644 --- a/src/model/model.hh +++ b/src/model/model.hh @@ -1,316 +1,317 @@ /** * @file model.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Fri Sep 05 2014 * * @brief Interface of a model * * @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_MODEL_HH__ #define __AKANTU_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "mesh.hh" #include "fe_engine.hh" #include "mesh_utils.hh" #include "synchronizer_registry.hh" #include "distributed_synchronizer.hh" #include "static_communicator.hh" #include "mesh_partition.hh" #include "dof_synchronizer.hh" #include "pbc_synchronizer.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ struct ModelOptions { virtual ~ModelOptions() {} }; class DumperIOHelper; class Model : public Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef Mesh mesh_type; Model(Mesh& mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "model", const MemoryID & memory_id = 0); virtual ~Model(); typedef std::map<std::string, FEEngine *> FEEngineMap; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: virtual void initFull(const ModelOptions & options); virtual void initModel() = 0; /// create the synchronizer registry object void createSynchronizerRegistry(DataAccessor * data_accessor); /// create a parallel synchronizer and distribute the mesh DistributedSynchronizer & createParallelSynch(MeshPartition * partition, DataAccessor * data_accessor); /// change local equation number so that PBC is assembled properly void changeLocalEquationNumberForPBC(std::map<UInt,UInt> & pbc_pair,UInt dimension); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const = 0; /// initialize the model for PBC void setPBC(UInt x, UInt y, UInt z); void setPBC(SurfacePairList & surface_pairs); virtual void initPBC(); /// set the parser to use void setParser(Parser & parser); /* ------------------------------------------------------------------------ */ /* Access to the dumpable interface of the boundaries */ /* ------------------------------------------------------------------------ */ /// Dump the data for a given group void dumpGroup(const std::string & group_name); void dumpGroup(const std::string & group_name, const std::string & dumper_name); /// Dump the data for all boundaries void dumpGroup(); /// Set the directory for a given group void setGroupDirectory(const std::string & directory, const std::string & group_name); /// Set the directory for all boundaries void setGroupDirectory(const std::string & directory); /// Set the base name for a given group void setGroupBaseName(const std::string & basename, const std::string & group_name); /// Get the internal dumper of a given group DumperIOHelper & getGroupDumper(const std::string & group_name); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get id of model AKANTU_GET_MACRO(ID, id, const ID) /// get the number of surfaces AKANTU_GET_MACRO(Mesh, mesh, Mesh&); /// return the object handling equation numbers AKANTU_GET_MACRO(DOFSynchronizer, *dof_synchronizer, const DOFSynchronizer &) /// return the object handling synchronizers AKANTU_GET_MACRO(SynchronizerRegistry, *synch_registry, SynchronizerRegistry &) /// synchronize the boundary in case of parallel run virtual void synchronizeBoundaries() {}; /// return the fem object associated with a provided name inline FEEngine & getFEEngine(const ID & name = "") const; /// return the fem boundary object associated with a provided name virtual FEEngine & getFEEngineBoundary(const ID & name = ""); /// register a fem object associated with name template <typename FEEngineClass> inline void registerFEEngineObject(const std::string & name, Mesh & mesh, UInt spatial_dimension); /// unregister a fem object associated with name inline void unRegisterFEEngineObject(const std::string & name); /// return the synchronizer registry SynchronizerRegistry & getSynchronizerRegistry(); /// return the fem object associated with a provided name template <typename FEEngineClass> inline FEEngineClass & getFEEngineClass(std::string name = "") const; /// return the fem boundary object associated with a provided name template <typename FEEngineClass> inline FEEngineClass & getFEEngineClassBoundary(std::string name = ""); /// get the pbc pairs std::map<UInt,UInt> & getPBCPairs(){return pbc_pair;}; /// returns if node is slave in pbc inline bool isPBCSlaveNode(const UInt node) const; /// returns the array of pbc slave nodes (boolean information) AKANTU_GET_MACRO(IsPBCSlaveNode, is_pbc_slave_node, const Array<bool> &) /* ------------------------------------------------------------------------ */ /* Pack and unpack helper functions */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbQuadraturePoints(const Array<Element> & elements, const ID & fem_id = ID()) const; /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ virtual void addDumpGroupFieldToDumper(const std::string & field_id, dumper::Field * field, DumperIOHelper & dumper); virtual void addDumpField(const std::string & field_id); virtual void addDumpFieldVector(const std::string & field_id); virtual void addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpFieldTensor(const std::string & field_id); virtual void setBaseName(const std::string & basename); virtual void setBaseNameToDumper(const std::string & dumper_name, const std::string & basename); virtual void addDumpGroupField(const std::string & field_id, const std::string & group_name); 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); virtual void removeDumpGroupField(const std::string & field_id, const std::string & group_name); virtual void removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag){return NULL;} virtual dumper::Field * createNodalFieldUInt(const std::string & field_name, const std::string & group_name, bool padding_flag){return NULL;} virtual dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag){return NULL;} virtual dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, + const UInt & spatial_dimension, const ElementKind & kind){return NULL;} void setDirectory(const std::string & directory); void setDirectoryToDumper(const std::string & dumper_name, const std::string & directory); virtual void dump(); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Mesh Mesh & mesh; /// Spatial dimension of the problem UInt spatial_dimension; /// the main fem object present in all models FEEngineMap fems; /// the fem object present in all models for boundaries FEEngineMap fems_boundary; /// default fem object std::string default_fem; /// synchronizer registry SynchronizerRegistry * synch_registry; /// handle the equation number things DOFSynchronizer * dof_synchronizer; /// pbc pairs std::map<UInt,UInt> pbc_pair; /// flag per node to know is pbc slave Array<bool> is_pbc_slave_node; /// parser to the pointer to use Parser * parser; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "model_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Model & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_MODEL_HH__ */ diff --git a/src/model/solid_mechanics/embedded_interface.cc b/src/model/solid_mechanics/embedded_interface.cc deleted file mode 100644 index 812bfff4a..000000000 --- a/src/model/solid_mechanics/embedded_interface.cc +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file embedded_interface.cc - * - * @author Lucas Frerot <lucas.frerot@epfl.ch> - * - * @date creation: Mon Mar 23 2015 - * @date last modification: Mon Mar 23 2015 - * - * @brief Class used to represent embedded interfaces - * - * @section LICENSE - * - * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) - * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#include "aka_common.hh" -#include "embedded_interface.hh" - -#include <CGAL/Cartesian.h> - -__BEGIN_AKANTU__ - -typedef CGAL::Cartesian<Real> K; - -EmbeddedInterface::EmbeddedInterface(UInt dim, const ID & id) : - Parsable(_st_embedded_interface, id), - points(2, dim) -{ - registerParam<std::string>("name", name, _pat_parsable | _pat_readable, "ID"); - registerParam<std::string>("material", mat_name, _pat_parsable | _pat_readable, "Material Name"); - registerParam< Matrix<Real> >("points", points, _pat_parsable | _pat_readable, "Interface Points"); -} - -EmbeddedInterface::~EmbeddedInterface() -{} - -K::Segment_3 EmbeddedInterface::getPrimitive() const { - AKANTU_DEBUG_INFO("Creating interface " << points); - - if (points.cols() == 2) { - K::Point_3 a(points(0, 0), points(0, 1), 0.); - K::Point_3 b(points(1, 0), points(1, 1), 0.); - return K::Segment_3(a, b); - } else if (points.cols() == 3) { - K::Point_3 a(points(0, 0), points(0, 1), points(0, 2)); - K::Point_3 b(points(1, 0), points(1, 1), points(1, 2)); - return K::Segment_3(a, b); - } else { - AKANTU_DEBUG_ERROR("Error in reading embedded interface : wrong number of components"); - return K::Segment_3(CGAL::ORIGIN, CGAL::ORIGIN); - } -} - -__END_AKANTU__ diff --git a/src/model/solid_mechanics/embedded_interface.hh b/src/model/solid_mechanics/embedded_interface.hh deleted file mode 100644 index b9edbeb5e..000000000 --- a/src/model/solid_mechanics/embedded_interface.hh +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @file embedded_interface.hh - * - * @author Lucas Frerot <lucas.frerot@epfl.ch> - * - * @date creation: Mon Mar 23 2015 - * @date last modification: Mon Mar 23 2015 - * - * @brief Class used to represent embedded interfaces - * - * @section LICENSE - * - * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) - * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) - * - * Akantu is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Akantu. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* -------------------------------------------------------------------------- */ - -#ifndef __AKANTU_EMBEDDED_INTERFACE_HH__ -#define __AKANTU_EMBEDDED_INTERFACE_HH__ - -#include "aka_common.hh" -#include "parsable.hh" - -#include <CGAL/Cartesian.h> - -/* -------------------------------------------------------------------------- */ - -__BEGIN_AKANTU__ - -class EmbeddedInterface : public Parsable { - - typedef CGAL::Cartesian<Real> K; - - /* ------------------------------------------------------------------------ */ - /* Constructors/Destructors */ - /* ------------------------------------------------------------------------ */ -public: - EmbeddedInterface(UInt dim, const ID & id = ""); - - virtual ~EmbeddedInterface(); - - /* ------------------------------------------------------------------------ */ - /* Methods */ - /* ------------------------------------------------------------------------ */ -public: - K::Segment_3 getPrimitive() const; - - /* ------------------------------------------------------------------------ */ - /* Accessors */ - /* ------------------------------------------------------------------------ */ -public: - AKANTU_GET_MACRO(Name, name, const std::string &); - AKANTU_GET_MACRO(MaterialName, mat_name, const std::string &); - - /* ------------------------------------------------------------------------ */ - /* Class Members */ - /* ------------------------------------------------------------------------ */ -protected: - std::string name; - std::string mat_name; - Matrix<Real> points; - - -}; - -__END_AKANTU__ - -#endif // __AKANTU_EMBEDDED_INTERFACE_HH__ diff --git a/src/model/solid_mechanics/embedded_interface_intersector.cc b/src/model/solid_mechanics/embedded_interface_intersector.cc new file mode 100644 index 000000000..38b7e7eef --- /dev/null +++ b/src/model/solid_mechanics/embedded_interface_intersector.cc @@ -0,0 +1,151 @@ +/** + * @file embedded_interface_intersector.cc + * + * @author Lucas Frerot <lucas.frerot@epfl.ch> + * + * @date creation: Wed Apr 29 2015 + * @date last modification: Wed Apr 29 2015 + * + * @brief Class that loads the interface from mesh and computes intersections + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +#include "embedded_interface_intersector.hh" +#include "mesh_segment_intersector.hh" + +#define INTERFACE_INTERSECTOR_CASE(dim, type) do { \ + MeshSegmentIntersector<dim, type> intersector(this->mesh, interface_mesh); \ + name_to_primitives_it = name_to_primitives_map.begin(); \ + for (; name_to_primitives_it != name_to_primitives_end ; ++name_to_primitives_it) { \ + intersector.computeIntersectionQueryList( \ + name_to_primitives_it->second, \ + name_to_primitives_it->first); \ + } } while(0) + +#define INTERFACE_INTERSECTOR_CASE_2D(type) INTERFACE_INTERSECTOR_CASE(2, type) +#define INTERFACE_INTERSECTOR_CASE_3D(type) INTERFACE_INTERSECTOR_CASE(3, type) + +__BEGIN_AKANTU__ + +EmbeddedInterfaceIntersector::EmbeddedInterfaceIntersector(const Mesh & mesh, const Mesh & primitive_mesh) : + MeshGeomAbstract(mesh), + interface_mesh(mesh.getSpatialDimension(), "interface_mesh"), + primitive_mesh(primitive_mesh) +{ + interface_mesh.addConnectivityType(_segment_2, _not_ghost); + interface_mesh.addConnectivityType(_segment_2, _ghost); + interface_mesh.registerData<Element>("associated_element").alloc(0, 1, _segment_2); + interface_mesh.registerData<std::string>("physical_names").alloc(0, 1, _segment_2); +} + +EmbeddedInterfaceIntersector::~EmbeddedInterfaceIntersector() +{} + +void EmbeddedInterfaceIntersector::constructData() { + AKANTU_DEBUG_IN(); + + const UInt dim = this->mesh.getSpatialDimension(); + + Array<std::string> * physical_names = NULL; + + try { + physical_names = &const_cast<Array<std::string> &>(this->primitive_mesh.getData<std::string>("physical_names", _segment_2)); + } catch (debug::Exception & e) { + AKANTU_DEBUG_ERROR("You must define physical names to reinforcements in order to use the embedded model"); + throw e; + } + + const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_segment_2); + Array<UInt>::const_vector_iterator connectivity = primitive_mesh.getConnectivity(_segment_2).begin(nb_nodes_per_element); + + Array<std::string>::scalar_iterator + names_it = physical_names->begin(), + names_end = physical_names->end(); + + std::map<std::string, std::list<K::Segment_3> > name_to_primitives_map; + + for (; names_it != names_end ; ++names_it) { + UInt element_id = names_it - physical_names->begin(); + const Vector<UInt> el_connectivity = connectivity[element_id]; + + K::Segment_3 segment = this->createSegment(el_connectivity); + name_to_primitives_map[*names_it].push_back(segment); + } + + // Loop over the background types of the mesh + Mesh::type_iterator + type_it = this->mesh.firstType(dim, _not_ghost), + type_end = this->mesh.lastType(dim, _not_ghost); + + std::map<std::string, std::list<K::Segment_3> >::iterator + name_to_primitives_it, + name_to_primitives_end = name_to_primitives_map.end(); + + for (; type_it != type_end ; ++type_it) { + ElementType type = *type_it; + + switch(dim) { + case 1: + AKANTU_DEBUG_ERROR("No embedded model in 1D"); + break; + + case 2: + AKANTU_BOOST_ELEMENT_SWITCH(INTERFACE_INTERSECTOR_CASE_2D, (_triangle_3)); + break; + + case 3: + AKANTU_BOOST_ELEMENT_SWITCH(INTERFACE_INTERSECTOR_CASE_3D, (_tetrahedron_4)); + break; + } + } + + AKANTU_DEBUG_OUT(); +} + +K::Segment_3 EmbeddedInterfaceIntersector::createSegment(const Vector<UInt> & connectivity) { + AKANTU_DEBUG_IN(); + + K::Point_3 * source = NULL, * target = NULL; + const Array<Real> & nodes = this->primitive_mesh.getNodes(); + + if (this->mesh.getSpatialDimension() == 2) { + source = new K::Point_3(nodes(connectivity(0), 0), nodes(connectivity(0), 1), 0.); + target = new K::Point_3(nodes(connectivity(1), 0), nodes(connectivity(1), 1), 0.); + } else if (this->mesh.getSpatialDimension() == 3) { + source = new K::Point_3(nodes(connectivity(0), 0), nodes(connectivity(0), 1), nodes(connectivity(0), 2)); + target = new K::Point_3(nodes(connectivity(1), 0), nodes(connectivity(1), 1), nodes(connectivity(1), 2)); + } + + K::Segment_3 segment(*source, *target); + delete source; + delete target; + + AKANTU_DEBUG_OUT(); + return segment; +} + +__END_AKANTU__ + +#undef INTERFACE_INTERSECTOR_CASE +#undef INTERFACE_INTERSECTOR_CASE_2D +#undef INTERFACE_INTERSECTOR_CASE_3D diff --git a/src/model/solid_mechanics/embedded_interface_intersector.hh b/src/model/solid_mechanics/embedded_interface_intersector.hh new file mode 100644 index 000000000..b12e2443b --- /dev/null +++ b/src/model/solid_mechanics/embedded_interface_intersector.hh @@ -0,0 +1,92 @@ +/** + * @file embedded_interface_intersector.hh + * + * @author Lucas Frerot <lucas.frerot@epfl.ch> + * + * @date creation: Wed Apr 29 2015 + * @date last modification: Wed Apr 29 2015 + * + * @brief Class that loads the interface from mesh and computes intersections + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_EMBEDDED_INTERFACE_INTERSECTOR_HH__ +#define __AKANTU_EMBEDDED_INTERFACE_INTERSECTOR_HH__ + +#include "aka_common.hh" +#include "mesh_geom_abstract.hh" +#include "mesh_segment_intersector.hh" + +#include <CGAL/Cartesian.h> + +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +typedef CGAL::Cartesian<Real> K; + +/** + * @brief Computes the intersections of the reinforcements defined in the primitive mesh + * + * The purpose of this class is to look for reinforcements in the primitive mesh, which + * should be defined by physical groups with the same names as the reinforcement materials + * in the model. + * + * It then constructs the CGAL primitives from the elements of those reinforcements + * and computes the intersections with the background mesh, to create an `interface_mesh`, + * which is in turn used by the EmbeddedInterfaceModel. + * + * @see MeshSegmentIntersector, MeshGeomAbstract + * @see EmbeddedInterfaceModel + */ +class EmbeddedInterfaceIntersector : public MeshGeomAbstract { + +public: + /// Construct from mesh and a reinforcement mesh + explicit EmbeddedInterfaceIntersector(const Mesh & mesh, const Mesh & primitive_mesh); + + /// Destructor + virtual ~EmbeddedInterfaceIntersector(); + +public: + /// Generate the interface mesh + virtual void constructData(); + + /// Create a segment with an element connectivity + K::Segment_3 createSegment(const Vector<UInt> & connectivity); + + /// Getter for interface mesh + AKANTU_GET_MACRO_NOT_CONST(InterfaceMesh, interface_mesh, Mesh &); + +protected: + /// Resulting mesh of intersection + Mesh interface_mesh; + + /// Mesh used for primitive construction + const Mesh & primitive_mesh; + +}; + +__END_AKANTU__ + +#endif // __AKANTU_EMBEDDED_INTERFACE_INTERSECTOR_HH__ diff --git a/src/model/solid_mechanics/embedded_interface_model.cc b/src/model/solid_mechanics/embedded_interface_model.cc index 945b80f1d..ad82a8875 100644 --- a/src/model/solid_mechanics/embedded_interface_model.cc +++ b/src/model/solid_mechanics/embedded_interface_model.cc @@ -1,171 +1,186 @@ /** * @file embedded_interface_model.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Mon Mar 9 2015 * @date last modification: Mon Mar 9 2015 * * @brief Model of Solid Mechanics with embedded interfaces * * @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 "embedded_interface_model.hh" #include "material_reinforcement.hh" #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" # include "dumpable_inline_impl.hh" #endif #include <CGAL/Cartesian.h> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ typedef CGAL::Cartesian<Real> K; EmbeddedInterfaceModel::EmbeddedInterfaceModel(Mesh & mesh, + Mesh & primitive_mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, spatial_dimension, id, memory_id), interface_mesh(NULL), + primitive_mesh(primitive_mesh), interface_material_selector(NULL), - interface_container(mesh) -{} + intersector(mesh, primitive_mesh) +{ + // This pointer should be deleted by ~SolidMechanicsModel() + MaterialSelector * mat_sel_pointer = new MeshDataMaterialSelector<std::string>("physical_names", *this); + this->setMaterialSelector(*mat_sel_pointer); +} EmbeddedInterfaceModel::~EmbeddedInterfaceModel() { delete interface_material_selector; } -void EmbeddedInterfaceModel::initModel() { - interface_container.constructData(); - instanciateInterfaces(); +void EmbeddedInterfaceModel::initFull(const ModelOptions & options) { + const SolidMechanicsModelOptions & smm_options = + dynamic_cast<const SolidMechanicsModelOptions &>(options); + + // We don't want to initiate materials before shape functions are initialized + SolidMechanicsModelOptions dummy_options(smm_options.analysis_method, true); + + interface_mesh = &(intersector.getInterfaceMesh()); + registerFEEngineObject<MyFEEngineType>("EmbeddedInterfaceFEEngine", *interface_mesh, 1); + + SolidMechanicsModel::initFull(dummy_options); + + intersector.constructData(); + + FEEngine & engine = getFEEngine("EmbeddedInterfaceFEEngine"); + engine.initShapeFunctions(_not_ghost); + engine.initShapeFunctions(_ghost); + + this->initMaterials(); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("reinforcement", id); this->mesh.addDumpMeshToDumper("reinforcement", *interface_mesh, - spatial_dimension, _not_ghost, _ek_regular); + 1, _not_ghost, _ek_regular); #endif - - SolidMechanicsModel::initModel(); } void EmbeddedInterfaceModel::initMaterials() { - delete interface_material_selector; - interface_material_selector = new EmbeddedInterfaceMaterialSelector<std::string>("material", *this); - this->setMaterialSelector(*interface_material_selector); - Element element; - //Material ** mat_val = &(materials.at(0)); + + delete interface_material_selector; + interface_material_selector = new InterfaceMeshDataMaterialSelector<std::string>("physical_names", *this); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { element.ghost_type = *gt; Mesh::type_iterator it = interface_mesh->firstType(1, *gt); Mesh::type_iterator end = interface_mesh->lastType(1, *gt); for (; it != end ; ++it) { UInt nb_element = interface_mesh->getNbElement(*it, *gt); element.type = *it; Array<UInt> & mat_indexes = material_index.alloc(nb_element, 1, *it, *gt); for (UInt el = 0 ; el < nb_element ; el++) { element.element = el; UInt mat_index = (*interface_material_selector)(element); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The material selector returned an index that does not exist"); mat_indexes(element.element) = mat_index; materials.at(mat_index)->addElement(*it, el, *gt); } } } SolidMechanicsModel::initMaterials(); } -void EmbeddedInterfaceModel::instanciateInterfaces() { - const std::pair<Parser::const_section_iterator, Parser::const_section_iterator> & - sub_sect = this->parser->getSubSections(_st_embedded_interface); +ElementTypeMap<UInt> EmbeddedInterfaceModel::getInternalDataPerElem(const std::string & field_name, + const ElementKind & kind) { + if (!(this->isInternal(field_name,kind))) AKANTU_EXCEPTION("unknown internal " << field_name); - Parser::const_section_iterator section_it = sub_sect.first; + for (UInt m = 0; m < materials.size() ; ++m) { + if (materials[m]->isInternal(field_name, kind)) { + Material * mat = NULL; - std::list<std::pair<K::Segment_3, std::string> > interface_list; + switch(this->spatial_dimension) { + case 1: + mat = dynamic_cast<MaterialReinforcement<1> *>(materials[m]); + break; - for (; section_it != sub_sect.second ; ++section_it) { - EmbeddedInterface interface(this->spatial_dimension); - interface.parseSection(*section_it); + case 2: + mat = dynamic_cast<MaterialReinforcement<2> *>(materials[m]); + break; - interface_list.push_back(std::make_pair(interface.getPrimitive(), interface.getMaterialName())); + case 3: + mat = dynamic_cast<MaterialReinforcement<3> *>(materials[m]); + break; + } + + if (mat == NULL && field_name != "stress_embedded") + return materials[m]->getInternalDataPerElem(field_name,kind); + else if (mat != NULL && field_name == "stress_embedded") + return mat->getInternalDataPerElem(field_name, kind, "EmbeddedInterfaceFEEngine"); + } } - initInterface(interface_list); + return ElementTypeMap<UInt>(); } -void EmbeddedInterfaceModel::initInterface(const std::list<std::pair<K::Segment_3, std::string> > & interface_list) { - AKANTU_DEBUG_IN(); - - interface_mesh = &(interface_container.meshOfLinearInterfaces(interface_list)); - - registerFEEngineObject<MyFEEngineType>("EmbeddedInterfaceFEEngine", *interface_mesh, 1); - FEEngine & engine = getFEEngine("EmbeddedInterfaceFEEngine"); - engine.initShapeFunctions(_not_ghost); - engine.initShapeFunctions(_ghost); +void EmbeddedInterfaceModel::addDumpGroupFieldToDumper(const std::string & dumper_name, + const std::string & field_id, + const std::string & group_name, + const ElementKind & element_kind, + bool padding_flag) { +#ifdef AKANTU_USE_IOHELPER + dumper::Field * field = NULL; - AKANTU_DEBUG_OUT(); -} + if (field_id == "stress_embedded") + field = this->createElementalField(field_id, group_name, padding_flag, 1, element_kind); + else + SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, element_kind, padding_flag); -void EmbeddedInterfaceModel::assembleStiffnessMatrix() { - SolidMechanicsModel::assembleStiffnessMatrix(); -} - -dumper::Field * EmbeddedInterfaceModel::createElementalField(const std::string & field_name, - const std::string & group_name, - bool padding_flag, - const ElementKind & kind, - const std::string & fe_engine_id) { - - if (field_name == "stress_embedded") { - return SolidMechanicsModel::createElementalField(field_name, - group_name, - padding_flag, - kind, - "EmbeddedInterfaceFEEngine"); - } else { - return SolidMechanicsModel::createElementalField(field_name, - group_name, - padding_flag, - kind, - fe_engine_id); + if (field) { + DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name,group_name); + Model::addDumpGroupFieldToDumper(field_id,field,dumper); } + +#endif } __END_AKANTU__ diff --git a/src/model/solid_mechanics/embedded_interface_model.hh b/src/model/solid_mechanics/embedded_interface_model.hh index d1e233c5c..11eab4f80 100644 --- a/src/model/solid_mechanics/embedded_interface_model.hh +++ b/src/model/solid_mechanics/embedded_interface_model.hh @@ -1,162 +1,150 @@ /** * @file embedded_interface_model.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Mon Mar 9 2015 * @date last modification: Mon Mar 9 2015 * * @brief Model of Solid Mechanics with embedded interfaces * * @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_EMBEDDED_INTERFACE_MODEL_HH__ #define __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "mesh.hh" -#include "parsable.hh" -#include "embedded_interface.hh" -#include "mesh_geom_container.hh" +#include "embedded_interface_intersector.hh" #include <CGAL/Cartesian.h> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ typedef CGAL::Cartesian<Real> K; +/** + * @brief Solid mechanics model using the embedded model. + * + * This SolidMechanicsModel subclass implements the embedded model, + * a method used to represent 1D elements in a finite elements model + * (eg. reinforcements in concrete). + * + * In addition to the SolidMechanicsModel properties, this model has + * a mesh of the 1D elements embedded in the model, and an instance of the + * EmbeddedInterfaceIntersector class for the computation of the intersections of the + * 1D elements with the background (bulk) mesh. + * + * @see MaterialReinforcement + */ class EmbeddedInterfaceModel : public SolidMechanicsModel { typedef FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_regular> MyFEEngineType; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - /// Constructor + /** + * @brief Constructor + * + * @param mesh main mesh (concrete) + * @param primitive_mesh mesh of the embedded reinforcement + */ EmbeddedInterfaceModel(Mesh & mesh, + Mesh & primitive_mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "embedded_interface_model", const MemoryID & memory_id = 0); /// Destructor virtual ~EmbeddedInterfaceModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Initialise the model - virtual void initModel(); + virtual void initFull(const ModelOptions & options = default_solid_mechanics_model_options); /// Initialise the materials virtual void initMaterials(); - /// Instanciate the interfaces - virtual void instanciateInterfaces(); - - /// Initialise the interface mesh - void initInterface(const std::list<std::pair<K::Segment_3, std::string> > & interface_list); - - /// Assemble the stiffness matrix of the model - virtual void assembleStiffnessMatrix(); - - /// Dump - virtual dumper::Field * createElementalField(const std::string & field_name, - const std::string & group_name, - bool padding_flag, - const ElementKind & kind, - const std::string & fe_engine_id = ""); - - +#ifndef SWIG + /// give the amount of data per element + ElementTypeMap<UInt> getInternalDataPerElem(const std::string & field_name, + const ElementKind & kind); +#endif + + 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 interface mesh AKANTU_GET_MACRO(InterfaceMesh, *interface_mesh, Mesh &); /// get associated elements AKANTU_GET_MACRO_BY_ELEMENT_TYPE(InterfaceAssociatedElements, interface_mesh->getData<Element>("associated_element"), Element); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Interface mesh (weak reference) Mesh * interface_mesh; + /// Mesh used to create the CGAL primitives for intersections + Mesh & primitive_mesh; + /// Material selector for interface MaterialSelector * interface_material_selector; - /// Geom object to build the interface mesh - MeshGeomContainer interface_container; + /// Intersector object to build the interface mesh + EmbeddedInterfaceIntersector intersector; }; -/// Material selector for EmbeddedInterfaceModel -template <typename T> class EmbeddedInterfaceMaterialSelector : public DefaultMaterialSelector {}; - -/// Material selector based on associated material name -template<> -class EmbeddedInterfaceMaterialSelector<std::string> : public DefaultMaterialSelector { - +template<typename T> +class InterfaceMeshDataMaterialSelector : public ElementDataMaterialSelector<T> { public: - EmbeddedInterfaceMaterialSelector(const std::string & name, const EmbeddedInterfaceModel & model): - DefaultMaterialSelector(model.getMaterialByElement()), - names(model.getInterfaceMesh().getData<std::string>(name)), - model(model) + InterfaceMeshDataMaterialSelector(const std::string & name, const EmbeddedInterfaceModel & model, UInt first_index = 1) : + ElementDataMaterialSelector<T>(model.getInterfaceMesh().getData<T>(name), model, first_index) {} - - UInt operator() (const Element & element) { - try { - DebugLevel dbl = debug::getDebugLevel(); - debug::setDebugLevel(dblError); - - std::string material_name = names(element.type, element.ghost_type)(element.element); - - debug::setDebugLevel(dbl); - - return model.getMaterialIndex(material_name); - } catch (debug::Exception& e) { - /// TODO this returns the last material, which should be a bulk material. Try to find cleaner way - return model.getNbMaterials() - 1; - } - } - -protected: - const ElementTypeMapArray<std::string> & names; - const EmbeddedInterfaceModel & model; }; __END_AKANTU__ #endif // __AKANTU_EMBEDDED_INTERFACE_MODEL_HH__ diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 3b8ae9092..2a3041210 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1663 +1,1667 @@ /** * @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(); for (std::map<ID, InternalField<UInt> *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.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); 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> * 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); /// 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); 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->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, \ nb_interpolation_points_per_elem, \ 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 UInt nb_interpolation_points_per_elem, 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); if(!interpolation_inverse_coordinates.exists(type, ghost_type)) interpolation_inverse_coordinates.alloc(nb_element, nb_quad_per_element*nb_quad_per_element, type, ghost_type); + else + interpolation_inverse_coordinates(type, ghost_type).resize(nb_element); if(!interpolation_points_matrices.exists(type, ghost_type)) interpolation_points_matrices.alloc(nb_element, nb_interpolation_points_per_elem * nb_quad_per_element, type, ghost_type); + else + interpolation_points_matrices(type, ghost_type).resize(nb_element); 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(nb_quad_per_element, nb_quad_per_element); Array<Real>::const_matrix_iterator quad_coords_it = quad_coordinates.begin_reinterpret(spatial_dimension, 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); Array<Real>::matrix_iterator inv_quad_coord_it = interp_inv_coord.begin(nb_quad_per_element, nb_quad_per_element); Array<Real>::matrix_iterator inv_points_mat_it = interp_points_mat.begin(nb_interpolation_points_per_elem, nb_quad_per_element); /// 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); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(ElementTypeMapArray<Real> & result, const GhostType ghost_type) { interpolateElementalField(stress, result, ghost_type); } /* -------------------------------------------------------------------------- */ void Material::interpolateElementalField(const ElementTypeMapArray<Real> & field, ElementTypeMapArray<Real> & result, const GhostType ghost_type) { AKANTU_DEBUG_IN(); 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; 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); const Array<Real> & field_vec = field(type, ghost_type); Array<Real> & result_vec = result(type, ghost_type); Matrix<Real> coefficients(nb_quad_per_element, field_vec.getNbComponent()); const Array<Real> & interp_inv_coord = interpolation_inverse_coordinates(type, ghost_type); const Array<Real> & interp_points_coord = interpolation_points_matrices(type, ghost_type); UInt nb_interpolation_points_per_elem = interp_points_coord.getNbComponent() / nb_quad_per_element; Array<Real>::const_matrix_iterator field_it = field_vec.begin_reinterpret(field_vec.getNbComponent(), nb_quad_per_element, nb_element); Array<Real>::const_matrix_iterator interpolation_points_coordinates_it = interp_points_coord.begin(nb_interpolation_points_per_elem, nb_quad_per_element); Array<Real>::matrix_iterator result_begin = result_vec.begin_reinterpret(field_vec.getNbComponent(), nb_interpolation_points_per_elem, result_vec.getSize() / nb_interpolation_points_per_elem); Array<Real>::const_matrix_iterator inv_quad_coord_it = interp_inv_coord.begin(nb_quad_per_element, nb_quad_per_element); /// 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 Matrix<Real> res(result_begin[elem_fil(el)]); res.mul<true, true>(coefficients, coord); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStressOnFacets(ElementTypeMapArray<Real> & result, const GhostType ghost_type) { interpolateElementalFieldOnFacets(stress, result, ghost_type); } /* -------------------------------------------------------------------------- */ void Material::interpolateElementalFieldOnFacets(const ElementTypeMapArray<Real> & field, ElementTypeMapArray<Real> & result, const GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt sp2 = spatial_dimension * spatial_dimension; const Mesh & mesh = this->model->getMesh(); const Mesh & mesh_facets = mesh.getMeshFacets(); 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; 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); const Array<Real> & field_vec = field(type, ghost_type); Matrix<Real> coefficients(nb_quad_per_element, field_vec.getNbComponent()); const Array<Real> & interp_inv_coord = interpolation_inverse_coordinates(type, ghost_type); const Array<Real> & interp_points_coord = interpolation_points_matrices(type, ghost_type); UInt nb_interpolation_points_per_elem = interp_points_coord.getNbComponent() / nb_quad_per_element; Array<Real>::const_matrix_iterator field_it = field_vec.begin_reinterpret(field_vec.getNbComponent(), nb_quad_per_element, nb_element); Array<Real>::const_matrix_iterator interpolation_points_coordinates_it = interp_points_coord.begin(nb_interpolation_points_per_elem, nb_quad_per_element); Array<Real>::const_matrix_iterator inv_quad_coord_it = interp_inv_coord.begin(nb_quad_per_element, nb_quad_per_element); Matrix<Real> result_tmp(sp2, nb_interpolation_points_per_elem); const Array<Element> & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); UInt nb_quad_per_facet = nb_interpolation_points_per_elem / nb_facet_per_elem; Element element_for_comparison(type, 0, ghost_type); const Array< std::vector<Element> > * element_to_facet = NULL; GhostType current_ghost_type = _casper; Array<Real> * result_vec = NULL; /// 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_tmp.mul<true, true>(coefficients, coord); UInt global_el = elem_fil(el); element_for_comparison.element = global_el; for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element facet_elem = facet_to_element(global_el, f); UInt global_facet = facet_elem.element; if (facet_elem.ghost_type != current_ghost_type) { current_ghost_type = facet_elem.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement(type_facet, current_ghost_type); result_vec = &result(type_facet, current_ghost_type); } bool is_second_element = (*element_to_facet)(global_facet)[0] != element_for_comparison; for (UInt q = 0; q < nb_quad_per_facet; ++q) { Vector<Real> result_local(result_vec->storage() + (global_facet * nb_quad_per_facet + q) * result_vec->getNbComponent() + is_second_element * sp2, sp2); result_local = result_tmp(f * nb_quad_per_facet + q); } } } } 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) << ")"); } 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) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ void Material::addElements(const Array<Element> & elements_to_add) { AKANTU_DEBUG_IN(); UInt mat_id = model->getInternalIndexFromID(getID()); Array<Element>::const_iterator<Element> el_begin = elements_to_add.begin(); Array<Element>::const_iterator<Element> el_end = elements_to_add.end(); for(;el_begin != el_end; ++el_begin) { const Element & element = *el_begin; Array<UInt> & mat_indexes = model->getMaterialByElement (element.type, element.ghost_type); Array<UInt> & mat_loc_num = model->getMaterialLocalNumbering(element.type, element.ghost_type); UInt index = this->addElement(element.type, element.element, element.ghost_type); mat_indexes(element.element) = mat_id; mat_loc_num(element.element) = index; } this->resizeInternals(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::removeElements(const Array<Element> & elements_to_remove) { AKANTU_DEBUG_IN(); Array<Element>::const_iterator<Element> el_begin = elements_to_remove.begin(); Array<Element>::const_iterator<Element> el_end = elements_to_remove.end(); if(el_begin==el_end) return; ElementTypeMapArray<UInt> material_local_new_numbering("remove mat filter elem", getID()); Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; element.ghost_type = ghost_type; ElementTypeMapArray<UInt>::type_iterator it = element_filter.firstType(_all_dimensions, ghost_type, _ek_not_defined); ElementTypeMapArray<UInt>::type_iterator end = element_filter.lastType(_all_dimensions, ghost_type, _ek_not_defined); for(; it != end; ++it) { ElementType type = *it; element.type = type; Array<UInt> & elem_filter = this->element_filter(type, ghost_type); Array<UInt> & mat_loc_num = this->model->getMaterialLocalNumbering(type, ghost_type); if(!material_local_new_numbering.exists(type, ghost_type)) material_local_new_numbering.alloc(elem_filter.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; 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); for (; it != end; ++it) { ElementType type = *it; if(element_filter.exists(type, gt)){ Array<UInt> & elem_filter = element_filter(type, gt); Array<UInt> & mat_indexes = this->model->getMaterialByElement (*it, gt); Array<UInt> & mat_loc_num = this->model->getMaterialLocalNumbering(*it, gt); UInt nb_element = this->model->getMesh().getNbElement(type, gt); // all materials will resize of the same size... mat_indexes.resize(nb_element); mat_loc_num.resize(nb_element); if(!material_local_new_numbering.exists(type, gt)) material_local_new_numbering.alloc(elem_filter.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; 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, 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); for (; tit != end; ++tit) { ElementType type = *tit; try { __attribute__((unused)) const Array<Real> & src_vect = this->getArray(field_id,type,ghost_type); } catch(debug::Exception & e) { continue; } const Array<Real> & src_vect = this->getArray(field_id,type,ghost_type); const Array<UInt> & filter = this->element_filter(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 (!internal_flat.exists(type,ghost_type)) { internal_flat.alloc(nb_element*nb_quad_per_elem,nb_data_per_quad,type,ghost_type); } 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(); Array<Real> & dst_vect = internal_flat(type,ghost_type); dst_vect.resize(nb_element*nb_quad_per_elem); Array<UInt>::const_scalar_iterator it = filter.begin(); Array<UInt>::const_scalar_iterator end = filter.end(); Array<Real>::const_vector_iterator it_src = src_vect.begin_reinterpret(nb_data,nb_element_src); Array<Real>::vector_iterator it_dst = dst_vect.begin_reinterpret(nb_data,nb_element); 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 10d0d12a8..ef9f67ef4 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,600 +1,600 @@ /** * @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); /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points and store the * results per facet */ void interpolateStressOnFacets(ElementTypeMapArray<Real> & result, 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 void interpolateElementalField(const ElementTypeMapArray<Real> & field, ElementTypeMapArray<Real> & result, const GhostType ghost_type); /// interpolate an elemental field and store the results per facet void interpolateElementalFieldOnFacets(const ElementTypeMapArray<Real> & field, ElementTypeMapArray<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); public: /* ------------------------------------------------------------------------ */ /* Conversion functions */ /* ------------------------------------------------------------------------ */ template<UInt dim> static inline void gradUToF (const Matrix<Real> & grad_u, Matrix<Real> & F); static inline void rightCauchy(const Matrix<Real> & F, Matrix<Real> & C); static inline void leftCauchy (const Matrix<Real> & F, Matrix<Real> & B); template<UInt dim> static inline void gradUToEpsilon(const Matrix<Real> & grad_u, Matrix<Real> & epsilon); template<UInt dim> static inline void gradUToGreenStrain(const Matrix<Real> & grad_u, Matrix<Real> & epsilon); static inline Real stressToVonMises(const Matrix<Real> & stress); protected: /// converts global element to local element inline Element convertToLocalElement(const Element & global_element) const; /// converts local element to global element inline Element convertToGlobalElement(const Element & local_element) const; /// converts global quadrature point to local quadrature point inline 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 ID & fe_engine_id = "") 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); + virtual 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_selector.hh b/src/model/solid_mechanics/material_selector.hh index 29f672bd4..c2449bedb 100644 --- a/src/model/solid_mechanics/material_selector.hh +++ b/src/model/solid_mechanics/material_selector.hh @@ -1,100 +1,126 @@ /** * @file material_selector.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> + * @author Lucas Frérot <lucas.frerot@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> & material_index) : material_index(material_index) { } UInt operator()(const Element & element) { try { DebugLevel dbl = debug::getDebugLevel(); debug::setDebugLevel(dblError); const Array<UInt> & mat_indexes = material_index(element.type, element.ghost_type); UInt mat = this->fallback_value; + if(element.element < mat_indexes.getSize()) - mat = mat_indexes(element.element); + mat = mat_indexes(element.element); debug::setDebugLevel(dbl); return mat; } catch (...) { return MaterialSelector::operator()(element); } } private: const ElementTypeMapArray<UInt> & material_index; }; /* -------------------------------------------------------------------------- */ template<typename T> -class MeshDataMaterialSelector : public MaterialSelector { +class ElementDataMaterialSelector : public MaterialSelector { public: - MeshDataMaterialSelector(const std::string & name, const SolidMechanicsModel & model) : mesh_data(name), model(model) { } - UInt operator() (const Element & element) { - return 0; + ElementDataMaterialSelector(const ElementTypeMapArray<T> & element_data, + const SolidMechanicsModel & model, + UInt first_index = 1): + element_data(element_data), + model(model), + first_index(first_index) + {} + + inline T elementData(const Element & element) { + DebugLevel dbl = debug::getDebugLevel(); + debug::setDebugLevel(dblError); + T data = element_data(element.type, element.ghost_type)(element.element); + debug::setDebugLevel(dbl); + return data; + } + + inline UInt operator() (const Element & element) { + return MaterialSelector::operator()(element); } + private: - std::string mesh_data; + const ElementTypeMapArray<T> & element_data; const SolidMechanicsModel & model; + UInt first_index; +}; + +/* -------------------------------------------------------------------------- */ +template<typename T> +class MeshDataMaterialSelector : public ElementDataMaterialSelector<T> { +public: + MeshDataMaterialSelector(const std::string & name, const SolidMechanicsModel & model, UInt first_index = 1); }; __END_AKANTU__ #endif /* __AKANTU_MATERIAL_SELECTOR_HH__ */ diff --git a/src/model/solid_mechanics/material_selector_tmpl.hh b/src/model/solid_mechanics/material_selector_tmpl.hh index ff4394841..35dbdf388 100644 --- a/src/model/solid_mechanics/material_selector_tmpl.hh +++ b/src/model/solid_mechanics/material_selector_tmpl.hh @@ -1,89 +1,70 @@ /** * @file material_selector_tmpl.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> + * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Wed Nov 13 2013 - * @date last modification: Thu Jun 05 2014 + * @date last modification: Fri May 1 2015 * * @brief Implementation of the template MaterialSelector * * @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_MATERIAL_SELECTOR_TMPL_HH__ #define __AKANTU_MATERIAL_SELECTOR_TMPL_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -template<> -class MeshDataMaterialSelector<std::string> : public MaterialSelector { -public: - MeshDataMaterialSelector(const std::string & name, const SolidMechanicsModel & model) : - names(model.getMesh().getData<std::string>(name)), model(model) { } - UInt operator() (const Element & element) { - try { - DebugLevel dbl = debug::getDebugLevel(); - debug::setDebugLevel(dblError); - std::string material_name = names(element.type, element.ghost_type)(element.element); - debug::setDebugLevel(dbl); +template<typename T> +MeshDataMaterialSelector<T>::MeshDataMaterialSelector(const std::string & name, + const SolidMechanicsModel & model, + UInt first_index): + ElementDataMaterialSelector<T>(model.getMesh().getData<T>(name), model, first_index) +{} - return model.getMaterialIndex(material_name); - } catch (...) { - return MaterialSelector::operator()(element); - } +/* -------------------------------------------------------------------------- */ +template<> +inline UInt ElementDataMaterialSelector<std::string>::operator() (const Element & element) { + try { + std::string material_name = this->elementData(element); + return model.getMaterialIndex(material_name); + } catch (...) { + return MaterialSelector::operator()(element); } - -private: - const ElementTypeMapArray<std::string> & names; -protected: - const SolidMechanicsModel & model; -}; +} /* -------------------------------------------------------------------------- */ template<> -class MeshDataMaterialSelector<UInt> : public MaterialSelector { -public: - MeshDataMaterialSelector(const std::string & name, const SolidMechanicsModel & model, UInt first_index = 1) : - indexes(model.getMesh().getData<UInt>(name)), model(model), first_index(first_index) { } - UInt operator() (const Element & element) { - try { - DebugLevel dbl = debug::getDebugLevel(); - debug::setDebugLevel(dblError); - UInt mat = indexes(element.type, element.ghost_type)(element.element) - first_index; - debug::setDebugLevel(dbl); - return mat; - } catch (...) { - return MaterialSelector::operator()(element); - } +inline UInt ElementDataMaterialSelector<UInt>::operator() (const Element & element) { + try { + return this->elementData(element) - first_index; + } catch (...) { + return MaterialSelector::operator()(element); } -protected: - const ElementTypeMapArray<UInt> indexes; - const SolidMechanicsModel & model; - UInt first_index; -}; - +} __END_AKANTU__ #endif /* __AKANTU_MATERIAL_SELECTOR_TMPL_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc index ab360b2d9..c3bac344e 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc +++ b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc @@ -1,693 +1,692 @@ /** * @file material_cohesive_linear.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Thu Aug 07 2014 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @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 <numeric> /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> MaterialCohesiveLinear<spatial_dimension>::MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model,id), sigma_c_eff("sigma_c_eff", *this), delta_c_eff("delta_c_eff", *this), insertion_stress("insertion_stress", *this) { AKANTU_DEBUG_IN(); this->registerParam("beta" , beta , 0. , _pat_parsable | _pat_readable, "Beta parameter" ); this->registerParam("G_c" , G_c , 0. , _pat_parsable | _pat_readable, "Mode I fracture energy" ); this->registerParam("penalty", penalty, 0. , _pat_parsable | _pat_readable, "Penalty coefficient" ); this->registerParam("volume_s", volume_s, 0. , _pat_parsable | _pat_readable, "Reference volume for sigma_c scaling"); this->registerParam("m_s", m_s, 1. , _pat_parsable | _pat_readable, "Weibull exponent for sigma_c scaling"); this->registerParam("kappa" , kappa , 1. , _pat_parsable | _pat_readable, "Kappa parameter"); // if (!model->isExplicit()) use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); /// compute scalars beta2_kappa2 = beta * beta/kappa/kappa; beta2_kappa = beta * beta/kappa; if (Math::are_float_equal(beta, 0)) beta2_inv = 0; else beta2_inv = 1./beta/beta; sigma_c_eff.initialize(1); delta_c_eff.initialize(1); insertion_stress.initialize(spatial_dimension); if (!Math::are_float_equal(delta_c, 0.)) delta_c_eff.setDefaultValue(delta_c); else delta_c_eff.setDefaultValue(2 * G_c / sigma_c); if (model->getIsExtrinsic()) scaleInsertionTraction(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::scaleInsertionTraction() { AKANTU_DEBUG_IN(); // do nothing if volume_s hasn't been specified by the user if (Math::are_float_equal(volume_s, 0.)) return; const Mesh & mesh_facets = model->getMeshFacets(); const FEEngine & fe_engine = model->getFEEngine(); const FEEngine & fe_engine_facet = model->getFEEngine("FacetsFEEngine"); // loop over facet type Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1); Real base_sigma_c = sigma_c; for(;first != last; ++first) { ElementType type_facet = *first; const Array< std::vector<Element> > & facet_to_element = mesh_facets.getElementToSubelement(type_facet); UInt nb_facet = facet_to_element.getSize(); UInt nb_quad_per_facet = fe_engine_facet.getNbQuadraturePoints(type_facet); // iterator to modify sigma_c for all the quadrature points of a facet Array<Real>::vector_iterator sigma_c_iterator = sigma_c(type_facet).begin_reinterpret(nb_quad_per_facet, nb_facet); for (UInt f = 0; f < nb_facet; ++f, ++sigma_c_iterator) { const std::vector<Element> & element_list = facet_to_element(f); // compute bounding volume Real volume = 0; std::vector<Element>::const_iterator elem = element_list.begin(); std::vector<Element>::const_iterator elem_end = element_list.end(); for (; elem != elem_end; ++elem) { if (*elem == ElementNull) continue; // unit vector for integration in order to obtain the volume UInt nb_quadrature_points = fe_engine.getNbQuadraturePoints(elem->type); Vector<Real> unit_vector(nb_quadrature_points, 1); volume += fe_engine.integrate(unit_vector, elem->type, elem->element, elem->ghost_type); } // scale sigma_c *sigma_c_iterator -= base_sigma_c; *sigma_c_iterator *= std::pow(volume_s / volume, 1. / m_s); *sigma_c_iterator += base_sigma_c; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkInsertion() { AKANTU_DEBUG_IN(); const Mesh & mesh_facets = model->getMeshFacets(); CohesiveElementInserter & inserter = model->getElementInserter(); Real tolerance = Math::getTolerance(); 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 type_facet = *it; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); const Array<bool> & facets_check = inserter.getCheckFacets(type_facet); Array<bool> & f_insertion = inserter.getInsertionFacets(type_facet); Array<UInt> & f_filter = facet_filter(type_facet); Array<Real> & sig_c_eff = sigma_c_eff(type_cohesive); Array<Real> & del_c = delta_c_eff(type_cohesive); Array<Real> & ins_stress = insertion_stress(type_cohesive); Array<Real> & trac_old = tractions_old(type_cohesive); const Array<Real> & f_stress = model->getStressOnFacets(type_facet); const Array<Real> & sigma_lim = sigma_c(type_facet); Real max_ratio = 0.; UInt index_f = 0; UInt index_filter = 0; UInt nn = 0; UInt nb_quad_facet = model->getFEEngine("FacetsFEEngine").getNbQuadraturePoints(type_facet); UInt nb_facet = f_filter.getSize(); if (nb_facet == 0) continue; Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin(); Matrix<Real> stress_tmp(spatial_dimension, spatial_dimension); Matrix<Real> normal_traction(spatial_dimension, nb_quad_facet); Vector<Real> stress_check(nb_quad_facet); UInt sp2 = spatial_dimension * spatial_dimension; const Array<Real> & tangents = model->getTangents(type_facet); const Array<Real> & normals = model->getFEEngine("FacetsFEEngine").getNormalsOnQuadPoints(type_facet); Array<Real>::const_vector_iterator normal_begin = normals.begin(spatial_dimension); Array<Real>::const_vector_iterator tangent_begin = tangents.begin(tangents.getNbComponent()); Array<Real>::const_matrix_iterator facet_stress_begin = f_stress.begin(spatial_dimension, spatial_dimension * 2); std::vector<Real> new_sigmas; std::vector< Vector<Real> > new_normal_traction; std::vector<Real> new_delta_c; // loop over each facet belonging to this material for (UInt f = 0; f < nb_facet; ++f, ++sigma_lim_it) { UInt facet = f_filter(f); // skip facets where check shouldn't be realized if (!facets_check(facet)) continue; // compute the effective norm on each quadrature point of the facet for (UInt q = 0; q < nb_quad_facet; ++q) { UInt current_quad = facet * nb_quad_facet + q; const Vector<Real> & normal = normal_begin[current_quad]; const Vector<Real> & tangent = tangent_begin[current_quad]; const Matrix<Real> & facet_stress_it = facet_stress_begin[current_quad]; // compute average stress on the current quadrature point Matrix<Real> stress_1(facet_stress_it.storage(), spatial_dimension, spatial_dimension); Matrix<Real> stress_2(facet_stress_it.storage() + sp2, spatial_dimension, spatial_dimension); stress_tmp.copy(stress_1); stress_tmp += stress_2; stress_tmp /= 2.; Vector<Real> normal_traction_vec(normal_traction(q)); // compute normal and effective stress stress_check(q) = computeEffectiveNorm(stress_tmp, normal, tangent, normal_traction_vec); } // verify if the effective stress overcomes the threshold if (stress_check.mean() > (*sigma_lim_it - tolerance)) { if (model->isExplicit()){ f_insertion(facet) = true; // store the new cohesive material parameters for each quadrature point for (UInt q = 0; q < nb_quad_facet; ++q) { Real new_sigma = stress_check(q); Vector<Real> normal_traction_vec(normal_traction(q)); if (spatial_dimension != 3) normal_traction_vec *= -1.; new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; // set delta_c in function of G_c or a given delta_c value if (Math::are_float_equal(delta_c, 0.)) new_delta = 2 * G_c / new_sigma; else new_delta = (*sigma_lim_it) / new_sigma * delta_c; new_delta_c.push_back(new_delta); } }else{ Real ratio = stress_check.mean()/(*sigma_lim_it); if (ratio > max_ratio){ ++nn; max_ratio = ratio; index_f = f; index_filter = f_filter(f); } } } } /// insertion of only 1 cohesive element in case of implicit approach. The one subjected to the highest stress. if (!model->isExplicit()){ StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Array<Real> abs_max(comm.getNbProc()); abs_max(comm.whoAmI()) = max_ratio; comm.allGather(abs_max.storage(), 1); Array<Real>::scalar_iterator it = std::max_element(abs_max.begin(), abs_max.end()); Int pos = it - abs_max.begin(); if (pos != comm.whoAmI()) { AKANTU_DEBUG_OUT(); return; } if (nn) { f_insertion(index_filter) = true; // Array<Real>::iterator<Matrix<Real> > normal_traction_it = // normal_traction.begin_reinterpret(nb_quad_facet, spatial_dimension, nb_facet); Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin(); for (UInt q = 0; q < nb_quad_facet; ++q) { // Vector<Real> ins_s(normal_traction_it[index_f].storage() + q * spatial_dimension, // spatial_dimension); Real new_sigma = (sigma_lim_it[index_f]); new_sigmas.push_back(new_sigma); new_normal_traction.push_back(0.0); Real new_delta; //set delta_c in function of G_c or a given delta_c value if (!Math::are_float_equal(delta_c, 0.)) new_delta = delta_c; else new_delta = 2 * G_c / (new_sigma); new_delta_c.push_back(new_delta); } } } // update material data for the new elements UInt old_nb_quad_points = sig_c_eff.getSize(); UInt new_nb_quad_points = new_sigmas.size(); sig_c_eff.resize(old_nb_quad_points + new_nb_quad_points); ins_stress.resize(old_nb_quad_points + new_nb_quad_points); trac_old.resize(old_nb_quad_points + new_nb_quad_points); del_c.resize(old_nb_quad_points + new_nb_quad_points); for (UInt q = 0; q < new_nb_quad_points; ++q) { sig_c_eff(old_nb_quad_points + q) = new_sigmas[q]; del_c(old_nb_quad_points + q) = new_delta_c[q]; for (UInt dim = 0; dim < spatial_dimension; ++dim) { ins_stress(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); trac_old(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); } } } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -template<UInt dim> -inline Real MaterialCohesiveLinear<dim>::computeEffectiveNorm(const Matrix<Real> & stress, - const Vector<Real> & normal, - const Vector<Real> & tangent, - Vector<Real> & normal_traction) { - normal_traction.mul<false>(stress, normal); - - Real normal_contrib = normal_traction.dot(normal); - - /// in 3D tangential components must be summed - Real tangent_contrib = 0; - - if (dim == 2) { - Real tangent_contrib_tmp = normal_traction.dot(tangent); - tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; - } - else if (dim == 3) { - for (UInt s = 0; s < dim - 1; ++s) { - const Vector<Real> tangent_v(tangent.storage() + s * dim, dim); - Real tangent_contrib_tmp = normal_traction.dot(tangent_v); - tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; - } - } - - tangent_contrib = std::sqrt(tangent_contrib); - normal_contrib = std::max(0., normal_contrib); - - return std::sqrt(normal_contrib * normal_contrib + tangent_contrib * tangent_contrib * beta2_inv); -} - /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array<Real>::iterator< Vector<Real> > traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator< Vector<Real> > opening_it = opening(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator< Vector<Real> > contact_traction_it = contact_tractions(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator< Vector<Real> > contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Array<Real>::const_iterator< Vector<Real> > normal_it = normal.begin(spatial_dimension); Array<Real>::iterator< Vector<Real> >traction_end = tractions(el_type, ghost_type).end(spatial_dimension); Array<Real>::iterator<Real>sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_max_it = delta_max(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_c_it = delta_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>damage_it = damage(el_type, ghost_type).begin(); Array<Real>::iterator<Vector<Real> > insertion_stress_it = insertion_stress(el_type, ghost_type).begin(spatial_dimension); Real * memory_space = new Real[2*spatial_dimension]; Vector<Real> normal_opening(memory_space, spatial_dimension); Vector<Real> tangential_opening(memory_space + spatial_dimension, spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++normal_it, ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, ++delta_max_prev_it) { if (!model->isExplicit()) *delta_max_it = *delta_max_prev_it; /// compute normal and tangential opening vectors Real normal_opening_norm = opening_it->dot(*normal_it); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \frac{\beta^2}{\kappa^2} \Delta_t^2 + \Delta_n^2 } @f$ */ Real delta = tangential_opening_norm * tangential_opening_norm * beta2_kappa2; bool penetration = normal_opening_norm < -Math::getTolerance(); if (penetration) { /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= penalty; *contact_opening_it = normal_opening; /// don't consider penetration contribution for delta *opening_it = tangential_opening; normal_opening.clear(); } else { delta += normal_opening_norm * normal_opening_norm; contact_traction_it->clear(); contact_opening_it->clear(); } delta = std::sqrt(delta); /// update maximum displacement and damage *delta_max_it = std::max(*delta_max_it, delta); *damage_it = std::min(*delta_max_it / *delta_c_it, 1.); /** * Compute traction @f$ \mathbf{T} = \left( * \frac{\beta^2}{\kappa} \Delta_t \mathbf{t} + \Delta_n * \mathbf{n} \right) \frac{\sigma_c}{\delta} \left( 1- * \frac{\delta}{\delta_c} \right)@f$ */ if (Math::are_float_equal(*damage_it, 1.)) traction_it->clear(); else if (Math::are_float_equal(*damage_it, 0.)) { if (penetration) traction_it->clear(); else *traction_it = *insertion_stress_it; } else { *traction_it = tangential_opening; *traction_it *= beta2_kappa; *traction_it += normal_opening; AKANTU_DEBUG_ASSERT(*delta_max_it != 0., "Division by zero, tolerance might be too low"); *traction_it *= *sigma_c_it / *delta_max_it * (1. - *damage_it); } } delete [] memory_space; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkDeltaMax(GhostType ghost_type) { AKANTU_DEBUG_IN(); + /// This function set a predefined value to the parameter delta_max_prev of the + /// elements that have been inserted in the last loading step for which convergence + /// has not been reached. This is done before reducing the loading and re-doing the step. + /// Otherwise, the updating of delta_max_prev would be done with reference to the + /// non-convergent solution. + 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; ElementType el_type = *it; /// define iterators Array<Real>::iterator<Real>delta_max_it = delta_max(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_max_end = delta_max(el_type, ghost_type).end(); Array<Real>::iterator<Real>delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_c_it = delta_c_eff(el_type, ghost_type).begin(); /// loop on each quadrature point for (; delta_max_it != delta_max_end; ++delta_max_it, ++delta_max_prev_it, ++delta_c_it) { if (*delta_max_prev_it == 0) + /// elements inserted in the last step, that has not converged *delta_max_it = *delta_c_it / 1000; else + /// elements introduced in previous steps, for which a correct + /// value of delta_max_prev already exists *delta_max_it = *delta_max_prev_it; } } - - // delete [] memory_space; } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array<Real>::matrix_iterator tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); Array<Real>::const_vector_iterator normal_it = normal.begin(spatial_dimension); Array<Real>::vector_iterator opening_it = opening(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator<Real>delta_max_it = delta_max.previous(el_type, ghost_type).begin(); Array<Real>::iterator<Real>sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_c_it = delta_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>damage_it = damage(el_type, ghost_type).begin(); Array<Real>::iterator< Vector<Real> > contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); + Array<Real> tang_output(spatial_dimension,spatial_dimension); + for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++ delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it) { /// compute normal and tangential opening vectors *opening_it += *contact_opening_it; Real normal_opening_norm = opening_it->dot(*normal_it); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); - bool penetration = normal_opening_norm < -Math::getTolerance(); - Real derivative = 0; Real t = 0; Real delta = tangential_opening_norm * tangential_opening_norm * beta2_kappa2; delta += normal_opening_norm * normal_opening_norm; delta = std::sqrt(delta); + /// Delta has to be different from 0 to have finite values of tangential stiffness. + /// At the element insertion, delta = 0. Therefore, a fictictious value is defined, + /// for the evaluation of the first value of K. if (delta < Math::getTolerance()) - delta = (*delta_c_it)/1000.; //0.0000001; + delta = (*delta_c_it)/1000.; if (normal_opening_norm >= 0.0){ if (delta >= *delta_max_it){ derivative = -*sigma_c_it/(delta * delta); t = *sigma_c_it * (1 - delta / *delta_c_it); } else if (delta < *delta_max_it){ Real tmax = *sigma_c_it * (1 - *delta_max_it / *delta_c_it); t = tmax / *delta_max_it * delta; } } Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); if (penetration){ - ///don't consider penetration contribution for delta + /// don't consider penetration contribution for delta *opening_it = tangential_opening; + /// stiffness in compression given by the penalty parameter *tangent_it += n_outer_n; *tangent_it *= penalty; } + /// computation of the derivative of the constitutive law (dT/ddelta) Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(beta2_kappa); Matrix<Real> nn(n_outer_n); nn *= (1 - beta2_kappa); nn += I; nn *= t/delta; Vector<Real> t_tilde(normal_opening); t_tilde *= (1 - beta2_kappa2); Vector<Real> mm(*opening_it); mm *= beta2_kappa2; t_tilde += mm; Vector<Real> t_hat(normal_opening); t_hat += beta2_kappa * tangential_opening; Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(t_hat, t_tilde); prov *= derivative/delta; prov += nn; *tangent_it += prov; + /// check if the tangential stiffness matrix is symmetric + for (UInt h = 0; h < spatial_dimension; ++h){ + for (UInt l = h; l < spatial_dimension; ++l){ + if (l > h){ + Real k_ls = (*tangent_it)[spatial_dimension*h+l]; + Real k_us = (*tangent_it)[spatial_dimension*l+h]; + // std::cout << "k_ls = " << k_ls << std::endl; + // std::cout << "k_us = " << k_us << std::endl; + if (std::abs(k_ls) > 1e-13 && std::abs(k_us) > 1e-13){ + Real error = std::abs((k_ls - k_us) / k_us); + if (error > 1e-13){ + std::cout << "non symmetric cohesive matrix" << std::endl; + std::cout << "error " << error << std::endl; + } + } + } + } + } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialCohesiveLinear); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh index fd50f5928..8f0425161 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh +++ b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh @@ -1,168 +1,168 @@ /** * @file material_cohesive_linear.hh * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Tue Jul 29 2014 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @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" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /** * Cohesive material linear damage for extrinsic case * * parameters in the material files : * - sigma_c : critical stress sigma_c (default: 0) * - beta : weighting parameter for sliding and normal opening (default: 0) * - G_cI : fracture energy for mode I (default: 0) * - G_cII : fracture energy for mode II (default: 0) * - penalty : stiffness in compression to prevent penetration */ template<UInt spatial_dimension> class MaterialCohesiveLinear : public MaterialCohesive { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material parameters virtual void initMaterial(); /// check stress for cohesive elements' insertion virtual void checkInsertion(); + /// compute effective stress norm for insertion check + inline Real computeEffectiveNorm(const Matrix<Real> & stress, + const Vector<Real> & normal, + const Vector<Real> & tangent, + Vector<Real> & normal_stress) const; + protected: /// constitutive law virtual void computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type = _not_ghost); /// check delta_max for cohesive elements in case of no convergence /// in the solveStep (only for extrinsic-implicit) void checkDeltaMax(GhostType ghost_type = _not_ghost); - /// compute effective stress norm for insertion check - inline Real computeEffectiveNorm(const Matrix<Real> & stress, - const Vector<Real> & normal, - const Vector<Real> & tangent, - Vector<Real> & normal_stress); - /// compute tangent stiffness matrix void computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type); /** * Scale insertion traction sigma_c according to the volume of the * two elements surrounding a facet * * see the article: F. Zhou and J. F. Molinari "Dynamic crack * propagation with cohesive elements: a methodology to address mesh * dependency" International Journal for Numerical Methods in * Engineering (2004) */ void scaleInsertionTraction(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get sigma_c_eff AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(InsertionTraction, sigma_c_eff, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// beta parameter Real beta; /// beta square inverse to compute effective norm Real beta2_inv; /// mode I fracture energy Real G_c; /// kappa parameter Real kappa; /// constitutive law scalar to compute delta Real beta2_kappa2; /// constitutive law scalar to compute traction Real beta2_kappa; /// penalty coefficient Real penalty; /// reference volume used to scale sigma_c Real volume_s; /// weibull exponent used to scale sigma_c Real m_s; /// critical effective stress RandomInternalField<Real, CohesiveInternalField> sigma_c_eff; /// effective critical displacement (each element can have a /// different value) CohesiveInternalField<Real> delta_c_eff; /// stress at insertion CohesiveInternalField<Real> insertion_stress; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ -//#include "material_cohesive_linear_inline_impl.cc" +#include "material_cohesive_linear_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear_inline_impl.cc b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear_inline_impl.cc new file mode 100644 index 000000000..273427731 --- /dev/null +++ b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear_inline_impl.cc @@ -0,0 +1,58 @@ +/** + * @file material_cohesive_linear_inline_impl.cc + * @author Marco Vocialta <marco.vocialta@epfl.ch> + * @date Tue Apr 21 14:49:56 2015 + * + * @brief Inline functions of the MaterialCohesiveLinear + * + * @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/>. + * + */ + +/* -------------------------------------------------------------------------- */ + +template<UInt dim> +inline Real MaterialCohesiveLinear<dim>::computeEffectiveNorm(const Matrix<Real> & stress, + const Vector<Real> & normal, + const Vector<Real> & tangent, + Vector<Real> & normal_traction) const { + normal_traction.mul<false>(stress, normal); + + Real normal_contrib = normal_traction.dot(normal); + + /// in 3D tangential components must be summed + Real tangent_contrib = 0; + + if (dim == 2) { + Real tangent_contrib_tmp = normal_traction.dot(tangent); + tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; + } + else if (dim == 3) { + for (UInt s = 0; s < dim - 1; ++s) { + const Vector<Real> tangent_v(tangent.storage() + s * dim, dim); + Real tangent_contrib_tmp = normal_traction.dot(tangent_v); + tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; + } + } + + tangent_contrib = std::sqrt(tangent_contrib); + normal_contrib = std::max(0., normal_contrib); + + return std::sqrt(normal_contrib * normal_contrib + tangent_contrib * tangent_contrib * beta2_inv); +} diff --git a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh b/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh index 2692bcc3a..37bb6dae3 100644 --- a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh +++ b/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh @@ -1,81 +1,85 @@ /** * @file embedded_internal_field.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Mar 19 2015 * @date last modification: Thu Mar 19 2015 * * @brief Embedded Material internal properties * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "internal_field.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ #define __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ __BEGIN_AKANTU__ class Material; class FEEngine; +/// This class is used for MaterialReinforcement internal fields template<typename T> class EmbeddedInternalField : public InternalField<T> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: + /// Constructor EmbeddedInternalField(const ID & id, Material & material): InternalField<T>(id, material, material.getModel().getFEEngine("EmbeddedInterfaceFEEngine"), material.getElementFilter()) { this->spatial_dimension = 1; } + /// Copy constructor EmbeddedInternalField(const ID & id, const EmbeddedInternalField & other): InternalField<T>(id, other) { this->spatial_dimension = 1; } void operator=(const EmbeddedInternalField & other) { InternalField<T>::operator=(other); this->spatial_dimension = 1; } }; +/// Method used to initialise the embedded internal fields from material file template<> inline void ParsableParamTyped< EmbeddedInternalField<Real> >::parseParam(const ParserParameter & in_param) { ParsableParam::parseParam(in_param); Real r = in_param; param.setDefaultValue(r); } __END_AKANTU__ #endif // __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc index 87d2e9b4b..b447fec14 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc @@ -1,703 +1,767 @@ /** * @file material_reinforcement.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Mar 12 2015 * @date last modification: Thu Mar 12 2015 * * @brief Reinforcement 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/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_voigthelper.hh" #include "material_reinforcement.hh" __BEGIN_AKANTU__ template<UInt dim> MaterialReinforcement<dim>::MaterialReinforcement(SolidMechanicsModel & model, const ID & id): Material(model, id), model(NULL), gradu("gradu_embedded", *this), stress("stress_embedded", *this), directing_cosines("directing_cosines", *this), pre_stress("pre_stress", *this), area(1.0), shape_derivatives() { this->model = dynamic_cast<EmbeddedInterfaceModel *>(&model); AKANTU_DEBUG_ASSERT(this->model != NULL, "MaterialReinforcement needs an EmbeddedInterfaceModel"); this->model->getInterfaceMesh().initElementTypeMapArray(element_filter, 1, 1, false, _ek_regular); this->registerParam("area", area, _pat_parsable | _pat_modifiable, "Reinforcement cross-sectional area"); this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable, "Uniform pre-stress"); } /* -------------------------------------------------------------------------- */ template<UInt dim> MaterialReinforcement<dim>::~MaterialReinforcement() { AKANTU_DEBUG_IN(); ElementTypeMap<ElementTypeMapArray<Real> *>::type_iterator it = shape_derivatives.firstType(); ElementTypeMap<ElementTypeMapArray<Real> *>::type_iterator end = shape_derivatives.lastType(); for (; it != end ; ++it) { delete shape_derivatives(*it, _not_ghost); delete shape_derivatives(*it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::initMaterial() { Material::initMaterial(); gradu.initialize(dim * dim); stress.initialize(dim * dim); pre_stress.initialize(1); /// We initialise the stuff that is not going to change during the simulation this->allocBackgroundShapeDerivatives(); this->initBackgroundShapeDerivatives(); this->initDirectingCosines(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::allocBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); Mesh & mesh = model->getMesh(); ghost_type_t::iterator int_ghost_it = ghost_type_t::begin(); // Loop over interface ghosts for (; int_ghost_it != ghost_type_t::end() ; ++int_ghost_it) { Mesh::type_iterator interface_type_it = interface_mesh.firstType(); Mesh::type_iterator interface_type_end = interface_mesh.lastType(); for (; interface_type_it != interface_type_end ; ++interface_type_it) { Mesh::type_iterator background_type_it = mesh.firstType(dim, *int_ghost_it); Mesh::type_iterator background_type_end = mesh.lastType(dim, *int_ghost_it); for (; background_type_it != background_type_end ; ++background_type_it) { const ElementType & int_type = *interface_type_it; const ElementType & back_type = *background_type_it; const GhostType & int_ghost = *int_ghost_it; std::string shaped_id = "embedded_shape_derivatives"; if (int_ghost == _ghost) shaped_id += ":ghost"; ElementTypeMapArray<Real> * shaped_etma = new ElementTypeMapArray<Real>(shaped_id, this->name); UInt nb_points = Mesh::getNbNodesPerElement(back_type); UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbQuadraturePoints(int_type); UInt nb_elements = element_filter(int_type, int_ghost).getSize(); shaped_etma->alloc(nb_elements * nb_quad_points, dim * nb_points, back_type); shape_derivatives(shaped_etma, int_type, int_ghost); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::initBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); Mesh & mesh = model->getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, _not_ghost); Mesh::type_iterator type_end = mesh.lastType(dim, _not_ghost); for (; type_it != type_end ; ++type_it) { computeBackgroundShapeDerivatives(*type_it, _not_ghost); //computeBackgroundShapeDerivatives(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::initDirectingCosines() { AKANTU_DEBUG_IN(); Mesh & mesh = model->getInterfaceMesh(); Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost); const UInt voigt_size = getTangentStiffnessVoigtSize(dim); directing_cosines.initialize(voigt_size * voigt_size); for (; type_it != type_end ; ++type_it) { computeDirectingCosines(*type_it, _not_ghost); computeDirectingCosines(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(); Mesh::type_iterator type_end = interface_mesh.lastType(); for (; type_it != type_end ; ++type_it) { assembleStiffnessMatrix(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::updateResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); computeAllStresses(ghost_type); assembleResidual(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(); Mesh::type_iterator type_end = interface_mesh.lastType(); for (; type_it != type_end ; ++type_it) { assembleResidual(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::computeGradU(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbQuadraturePoints(type); Array<Real> & gradu_vec = gradu(type, ghost_type); Mesh::type_iterator back_it = model->getMesh().firstType(dim, ghost_type); Mesh::type_iterator back_end = model->getMesh().lastType(dim, ghost_type); for (; back_it != back_end ; ++back_it) { UInt nodes_per_background_e = Mesh::getNbNodesPerElement(*back_it); Array<Real> * shapesd_filtered = new Array<Real>(nb_element, dim * nodes_per_background_e, "shapesd_filtered"); FEEngine::filterElementalData(model->getInterfaceMesh(), shape_derivatives(type, ghost_type)->operator()(*back_it, ghost_type), *shapesd_filtered, type, ghost_type, elem_filter); Array<UInt> * background_filter = new Array<UInt>(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, *back_it, type, ghost_type, ghost_type); Array<Real> * disp_per_element = new Array<Real>(0, dim * nodes_per_background_e, "disp_elem"); FEEngine::extractNodalToElementField(model->getMesh(), model->getDisplacement(), *disp_per_element, *back_it, ghost_type, *background_filter); Array<Real>::matrix_iterator disp_it = disp_per_element->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator disp_end = disp_per_element->end(dim, nodes_per_background_e); Array<Real>::matrix_iterator shapes_it = shapesd_filtered->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator grad_u_it = gradu_vec.begin(dim, dim); for (; disp_it != disp_end ; ++disp_it) { for (UInt i = 0; i < nb_quad_points; i++, ++shapes_it, ++grad_u_it) { Matrix<Real> & B = *shapes_it; Matrix<Real> & du = *grad_u_it; Matrix<Real> & u = *disp_it; du.mul<false, true>(u, B); } } delete shapesd_filtered; delete background_filter; delete disp_per_element; } AKANTU_DEBUG_OUT(); } template<UInt dim> void MaterialReinforcement<dim>::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = model->getInterfaceMesh().firstType(); Mesh::type_iterator last_type = model->getInterfaceMesh().lastType(); for(; it != last_type; ++it) { computeGradU(*it, ghost_type); computeStress(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleResidual(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = model->getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end ; ++type_it) { assembleResidual(type, *type_it, ghost_type, _not_ghost); //assembleResidual(type, *type_it, ghost_type, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleResidual(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost) { AKANTU_DEBUG_IN(); UInt voigt_size = getTangentStiffnessVoigtSize(dim); Array<Real> & residual = const_cast<Array<Real> &>(model->getResidual()); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); FEEngine & background_engine = model->getFEEngine(); Array<UInt> & elem_filter = element_filter(interface_type, interface_ghost); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbQuadraturePoints(interface_type, interface_ghost); UInt nb_element = elem_filter.getSize(); UInt back_dof = dim * nodes_per_background_e; Array<Real> & shapesd = shape_derivatives(interface_type, interface_ghost)->operator()(background_type, background_ghost); Array<Real> * shapesd_filtered = new Array<Real>(nb_element * nb_quadrature_points, back_dof, "background_shapesd"); FEEngine::filterElementalData(model->getInterfaceMesh(), shapesd, *shapesd_filtered, interface_type, interface_ghost, elem_filter); Array<Real> * integrant = new Array<Real>(nb_quadrature_points * nb_element, back_dof, "integrant"); Array<Real>::vector_iterator integrant_it = integrant->begin(back_dof); Array<Real>::vector_iterator integrant_end = integrant->end(back_dof); Array<Real>::matrix_iterator B_it = shapesd_filtered->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator C_it = directing_cosines(interface_type, interface_ghost).begin(voigt_size, voigt_size); Array<Real>::matrix_iterator sigma_it = stress(interface_type, interface_ghost).begin(dim, dim); Vector<Real> sigma(voigt_size); Matrix<Real> Bvoigt(voigt_size, back_dof); Vector<Real> Ct_sigma(voigt_size); for (; integrant_it != integrant_end ; ++integrant_it, ++B_it, ++C_it, ++sigma_it) { VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, nodes_per_background_e); Matrix<Real> & C = *C_it; Vector<Real> & BtCt_sigma = *integrant_it; stressTensorToVoigtVector(*sigma_it, sigma); Ct_sigma.mul<true>(C, sigma); BtCt_sigma.mul<true>(Bvoigt, Ct_sigma); BtCt_sigma *= area; } delete shapesd_filtered; Array<Real> * residual_interface = new Array<Real>(nb_element, back_dof, "residual_interface"); interface_engine.integrate(*integrant, *residual_interface, back_dof, interface_type, interface_ghost, elem_filter); delete integrant; Array<UInt> * background_filter = new Array<UInt>(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, background_type, interface_type, background_ghost, interface_ghost); background_engine.assembleArray(*residual_interface, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), dim, background_type, background_ghost, *background_filter, -1.0); delete residual_interface; delete background_filter; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::filterInterfaceBackgroundElements(Array<UInt> & filter, const ElementType & type, const ElementType & interface_type, GhostType ghost_type, GhostType interface_ghost_type) { AKANTU_DEBUG_IN(); filter.resize(0); filter.clear(); Array<Element> & elements = model->getInterfaceAssociatedElements(interface_type, interface_ghost_type); Array<UInt> & elem_filter = element_filter(interface_type, interface_ghost_type); Array<UInt>::scalar_iterator filter_it = elem_filter.begin(), filter_end = elem_filter.end(); for (; filter_it != filter_end ; ++filter_it) { Element & elem = elements(*filter_it); if (elem.type == type) filter.push_back(elem.element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::computeDirectingCosines(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = this->model->getInterfaceMesh(); const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const UInt steel_dof = dim * nb_nodes_per_element; const UInt voigt_size = getTangentStiffnessVoigtSize(dim); const UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbQuadraturePoints(type, ghost_type); Array<Real> node_coordinates(this->element_filter(type, ghost_type).getSize(), steel_dof); this->model->getFEEngine().template extractNodalToElementField<Real>(interface_mesh, interface_mesh.getNodes(), node_coordinates, type, ghost_type, this->element_filter(type, ghost_type)); Array<Real>::matrix_iterator directing_cosines_it = directing_cosines(type, ghost_type).begin(voigt_size, voigt_size); Array<Real>::matrix_iterator node_coordinates_it = node_coordinates.begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator node_coordinates_end = node_coordinates.end(dim, nb_nodes_per_element); for (; node_coordinates_it != node_coordinates_end ; ++node_coordinates_it) { for (UInt i = 0 ; i < nb_quad_points ; i++, ++directing_cosines_it) { Matrix<Real> & nodes = *node_coordinates_it; Matrix<Real> & cosines = *directing_cosines_it; computeDirectingCosinesOnQuad(nodes, cosines); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = model->getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end ; ++type_it) { assembleStiffnessMatrix(type, *type_it, ghost_type, _not_ghost); //assembleStiffnessMatrix(type, *type_it, ghost_type, _ghost); } AKANTU_DEBUG_OUT(); } template<UInt dim> void MaterialReinforcement<dim>::assembleStiffnessMatrix(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost) { AKANTU_DEBUG_IN(); UInt voigt_size = getTangentStiffnessVoigtSize(dim); SparseMatrix & K = const_cast<SparseMatrix &>(model->getStiffnessMatrix()); FEEngine & background_engine = model->getFEEngine(); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); Array<UInt> & elem_filter = element_filter(interface_type, interface_ghost); Array<Real> & grad_u = gradu(interface_type, interface_ghost); UInt nb_element = elem_filter.getSize(); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbQuadraturePoints(interface_type, interface_ghost); UInt back_dof = dim * nodes_per_background_e; UInt integrant_size = back_dof; grad_u.resize(nb_quadrature_points * nb_element); //need function model->getInterfaceDisplacement() /*interface_engine.gradientOnQuadraturePoints(model->getInterfaceDisplacement(), grad_u, dim, interface_type, interface_ghost, elem_filter);*/ Array<Real> * tangent_moduli = new Array<Real>(nb_element * nb_quadrature_points, 1, "interface_tangent_moduli"); tangent_moduli->clear(); computeTangentModuli(interface_type, *tangent_moduli, interface_ghost); Array<Real> & shapesd = shape_derivatives(interface_type, interface_ghost)->operator()(background_type, background_ghost); Array<Real> * shapesd_filtered = new Array<Real>(nb_element * nb_quadrature_points, back_dof, "background_shapesd"); FEEngine::filterElementalData(model->getInterfaceMesh(), shapesd, *shapesd_filtered, interface_type, interface_ghost, elem_filter); Array<Real> * integrant = new Array<Real>(nb_element * nb_quadrature_points, integrant_size * integrant_size, "B^t*C^t*D*C*B"); integrant->clear(); /// Temporary matrices for integrant product Matrix<Real> Bvoigt(voigt_size, back_dof); Matrix<Real> DC(voigt_size, voigt_size); Matrix<Real> DCB(voigt_size, back_dof); Matrix<Real> CtDCB(voigt_size, back_dof); Array<Real>::scalar_iterator D_it = tangent_moduli->begin(); Array<Real>::scalar_iterator D_end = tangent_moduli->end(); Array<Real>::matrix_iterator C_it = directing_cosines(interface_type, interface_ghost).begin(voigt_size, voigt_size); Array<Real>::matrix_iterator B_it = shapesd_filtered->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator integrant_it = integrant->begin(integrant_size, integrant_size); for (; D_it != D_end ; ++D_it, ++C_it, ++B_it, ++integrant_it) { Real & D = *D_it; Matrix<Real> & C = *C_it; Matrix<Real> & B = *B_it; Matrix<Real> & BtCtDCB = *integrant_it; VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt, nodes_per_background_e); DC.clear(); DC(0, 0) = D * area; DC *= C; DCB.mul<false, false>(DC, Bvoigt); CtDCB.mul<true, false>(C, DCB); BtCtDCB.mul<true, false>(Bvoigt, CtDCB); } delete tangent_moduli; delete shapesd_filtered; Array<Real> * K_interface = new Array<Real>(nb_element, integrant_size * integrant_size, "K_interface"); interface_engine.integrate(*integrant, *K_interface, integrant_size * integrant_size, interface_type, interface_ghost, elem_filter); delete integrant; Array<UInt> * background_filter = new Array<UInt>(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, background_type, interface_type, background_ghost, interface_ghost); background_engine.assembleMatrix(*K_interface, K, dim, background_type, background_ghost, *background_filter); delete K_interface; delete background_filter; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// In this function, type and ghost type refer to background elements template<UInt dim> void MaterialReinforcement<dim>::computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); FEEngine & engine = model->getFEEngine(); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); Mesh::type_iterator interface_type = interface_mesh.firstType(); Mesh::type_iterator interface_last = interface_mesh.lastType(); for (; interface_type != interface_last ; ++interface_type) { Array<UInt> & filter = element_filter(*interface_type, ghost_type); const UInt nb_elements = filter.getSize(); const UInt nb_nodes = Mesh::getNbNodesPerElement(type); const UInt nb_quad_per_element = interface_engine.getNbQuadraturePoints(*interface_type); Array<Real> quad_pos(nb_quad_per_element * nb_elements, dim, "interface_quad_points"); quad_pos.resize(nb_quad_per_element * nb_elements); interface_engine.interpolateOnQuadraturePoints(interface_mesh.getNodes(), quad_pos, dim, *interface_type, ghost_type, filter); Array<Real> & background_shapesd = shape_derivatives(*interface_type, ghost_type)->operator()(type, ghost_type); background_shapesd.clear(); Array<UInt> * background_elements = new Array<UInt>(nb_elements, 1, "computeBackgroundShapeDerivatives:background_filter"); filterInterfaceBackgroundElements(*background_elements, type, *interface_type, ghost_type, ghost_type); Array<UInt>::scalar_iterator back_it = background_elements->begin(), back_end = background_elements->end(); Array<Real>::matrix_iterator shapesd_it = background_shapesd.begin(dim, nb_nodes); Array<Real>::vector_iterator quad_pos_it = quad_pos.begin(dim); for (; back_it != back_end ; ++back_it) { for (UInt i = 0 ; i < nb_quad_per_element ; i++, ++shapesd_it, ++quad_pos_it) engine.computeShapeDerivatives(*quad_pos_it, *back_it, type, *shapesd_it, ghost_type); } delete background_elements; } AKANTU_DEBUG_OUT(); } template<UInt dim> Real MaterialReinforcement<dim>::getEnergy(std::string id) { AKANTU_DEBUG_IN(); if (id == "potential") { Real epot = 0.; computePotentialEnergyByElements(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension), end = element_filter.lastType(spatial_dimension); for (; it != end ; ++it) { FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); epot += interface_engine.integrate(potential_energy(*it, _not_ghost), *it, _not_ghost, element_filter(*it, _not_ghost)); epot *= area; } return epot; } AKANTU_DEBUG_OUT(); return 0; } +// Author is Nicolas Richart, see material.cc +template<UInt dim> +void MaterialReinforcement<dim>::flattenInternal(const std::string & field_id, + ElementTypeMapArray<Real> & internal_flat, + const GhostType ghost_type, + ElementKind element_kind) { + AKANTU_DEBUG_IN(); + + typedef ElementTypeMapArray<UInt>::type_iterator iterator; + iterator tit = this->element_filter.firstType(1, ghost_type, element_kind); + iterator end = this->element_filter.lastType(1, ghost_type, element_kind); + + for (; tit != end; ++tit) { + ElementType type = *tit; + + try { + __attribute__((unused)) const Array<Real> & src_vect + = this->getArray(field_id,type,ghost_type); + + } catch(debug::Exception & e) { + continue; + } + + const Array<Real> & src_vect = this->getArray(field_id,type,ghost_type); + const Array<UInt> & filter = this->element_filter(type,ghost_type); + + // total number of elements for a given type + UInt nb_element = this->model->getInterfaceMesh().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 (!internal_flat.exists(type,ghost_type)) { + internal_flat.alloc(nb_element*nb_quad_per_elem,nb_data_per_quad,type,ghost_type); + } + + 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(); + + Array<Real> & dst_vect = internal_flat(type,ghost_type); + dst_vect.resize(nb_element*nb_quad_per_elem); + + Array<UInt>::const_scalar_iterator it = filter.begin(); + Array<UInt>::const_scalar_iterator end = filter.end(); + Array<Real>::const_vector_iterator it_src = + src_vect.begin_reinterpret(nb_data,nb_element_src); + + Array<Real>::vector_iterator it_dst = + dst_vect.begin_reinterpret(nb_data,nb_element); + + for (; it != end ; ++it,++it_src) { + it_dst[*it] = *it_src; + } + } + + AKANTU_DEBUG_OUT(); +} + /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialReinforcement); /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh index d5022a548..fd77ec62a 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh @@ -1,171 +1,212 @@ /** * @file material_reinforcement.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Mar 12 2015 * @date last modification: Thu Mar 12 2015 * * @brief Reinforcement 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/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_REINFORCEMENT_HH__ #define __AKANTU_MATERIAL_REINFORCEMENT_HH__ #include "aka_common.hh" #include "material.hh" #include "embedded_interface_model.hh" #include "embedded_internal_field.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ +/** + * @brief Material used to represent embedded reinforcements + * + * This class is used for computing the reinforcement stiffness matrix + * along with the reinforcement residual. Room is made for constitutive law, + * but actual use of contitutive laws is made in MaterialReinforcementTemplate. + */ template<UInt dim> class MaterialReinforcement : virtual public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// Constructor MaterialReinforcement(SolidMechanicsModel & model, const ID & id = ""); /// Destructor virtual ~MaterialReinforcement(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Init the material virtual void initMaterial(); /// Init the background shape derivatives void initBackgroundShapeDerivatives(); /// Init the cosine matrices void initDirectingCosines(); /// Assemble stiffness matrix virtual void assembleStiffnessMatrix(GhostType ghost_type); /// Update the residual virtual void updateResidual(GhostType ghost_type = _not_ghost); /// Assembled the residual virtual void assembleResidual(GhostType ghost_type); /// Compute all the stresses ! virtual void computeAllStresses(GhostType ghost_type); /// Compute the stiffness parameter for elements of a type virtual void computeTangentModuli(const ElementType & type, Array<Real> & tangent, GhostType ghost_type) = 0; virtual Real getEnergy(std::string id); + /// Reimplementation of Material's function to accomodate for interface mesh + virtual void flattenInternal(const std::string & field_id, + ElementTypeMapArray<Real> & internal_flat, + const GhostType ghost_type = _not_ghost, + ElementKind element_kind = _ek_not_defined); + /* ------------------------------------------------------------------------ */ /* Protected methods */ /* ------------------------------------------------------------------------ */ protected: /// Allocate the background shape derivatives void allocBackgroundShapeDerivatives(); /// Compute the directing cosines matrix for one element type void computeDirectingCosines(const ElementType & type, GhostType ghost_type); - /// Compute the directing cosines matrix on quadrature points + /** + * @brief Compute the directing cosines matrix on quadrature points. + * + * The structure of the directing cosines matrix is : + * \f{eqnarray*}{ + * C_{1,\cdot} & = & (l^2, m^2, n^2, lm, mn, ln) \\ + * C_{i,j} & = & 0 + * \f} + * + * with : + * \f[ + * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s} + * \f] + */ inline void computeDirectingCosinesOnQuad(const Matrix<Real> & nodes, Matrix<Real> & cosines); /// Assemble the stiffness matrix for an element type (typically _segment_2) void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); - /// Assemble the stiffness matrix for background & interface types + /** + * @brief Assemble the stiffness matrix for background & interface types + * + * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001) + * \f[ + * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T + * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}} + * \f] + */ void assembleStiffnessMatrix(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost); - /// Compute the background shape derivatives for a type (typically _triangle_3 / _tetrahedron_4) + /// Compute the background shape derivatives for a type void computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type); /// Filter elements crossed by interface of a type void filterInterfaceBackgroundElements(Array<UInt> & filter, const ElementType & type, const ElementType & interface_type, GhostType ghost_type, GhostType interface_ghost_type); /// Assemble the residual of one type of element (typically _segment_2) void assembleResidual(const ElementType & type, GhostType ghost_type); - /// Assemble the residual for a pair of elements + /** + * @brief Assemble the residual for a pair of elements + * + * Computes and assemble the residual. Residual in reinforcement is computed as : + * \f[ + * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s} + * \f] + */ void assembleResidual(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost); - /// TODO figure out why voigt size is 4 in 2D + // TODO figure out why voigt size is 4 in 2D inline void stressTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); inline void strainTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); /// Compute gradu on the interface quadrature points virtual void computeGradU(const ElementType & type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Embedded model EmbeddedInterfaceModel * model; /// grad_u EmbeddedInternalField<Real> gradu; /// stress EmbeddedInternalField<Real> stress; /// C matrix on quad EmbeddedInternalField<Real> directing_cosines; /// Prestress on quad EmbeddedInternalField<Real> pre_stress; /// Cross-sectional area Real area; /// Background mesh shape derivatives ElementTypeMap< ElementTypeMapArray<Real> * > shape_derivatives; }; #include "material_reinforcement_inline_impl.cc" __END_AKANTU__ #endif // __AKANTU_MATERIAL_REINFORCEMENT_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh index 8a6c0dfd7..1514f947c 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh @@ -1,92 +1,107 @@ /** * @file material_reinforcement_template.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Mon Mar 16 2015 * @date last modification: Mon Mar 16 2015 * * @brief Reinforcement material templated with constitutive law * * @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_MATERIAL_REINFORCEMENT_TEMPLATE_HH__ #define __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material_reinforcement.hh" #include "material_elastic.hh" __BEGIN_AKANTU__ +/** + * @brief Implementation of MaterialReinforcement with 1D constitutive law + * @see MaterialReinforcement, MaterialElastic + * + * This class is a reinforcement featuring a constitutive law. + * <strong>Be careful !</strong> Because of multiple inheritance, this class + * forms a diamond. + */ template<UInt dim, class ConstLaw = MaterialElastic<1> > class MaterialReinforcementTemplate : public MaterialReinforcement<dim>, public ConstLaw { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// Constructor MaterialReinforcementTemplate(SolidMechanicsModel & a_model, const ID & id = ""); /// Destructor virtual ~MaterialReinforcementTemplate(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Initialises the material void initMaterial(); /// Compute the stiffness parameter for elements of a type virtual void computeTangentModuli(const ElementType & type, Array<Real> & tangent, GhostType ghost_type); /// Computes stress used by constitutive law virtual void computeStress(ElementType type, GhostType ghost_type); /// Computes gradu to be used by the constitutive law virtual void computeGradU(const ElementType & type, GhostType ghost_type); + /// Compute the potential energy of the reinforcement virtual void computePotentialEnergy(ElementType type, GhostType ghost_type = _not_ghost); + /// Get energy in reinforcement (currently limited to potential) virtual Real getEnergy(std::string id); protected: - /// Compute interface gradu from bulk gradu + /** + * @brief Compute interface gradu from bulk gradu + * \f[ + * \varepsilon_s = C \varepsilon_c + * \f] + */ inline void computeInterfaceGradUOnQuad(const Matrix<Real> & full_gradu, Real & gradu, const Matrix<Real> & C); }; #include "material_reinforcement_template_inline_impl.cc" __END_AKANTU__ #endif // __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc index a36c22dbb..7e1894f01 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc @@ -1,195 +1,196 @@ /** * @file material_reinforcement_template.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Mon Mar 16 2015 * @date last modification: Mon Mar 16 2015 * * @brief Reinforcement material templated with constitutive law * * @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/>. * */ /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> MaterialReinforcementTemplate<dim, ConstLaw>::MaterialReinforcementTemplate(SolidMechanicsModel & model, const ID & id): Material(model, id), MaterialReinforcement<dim>(model, id), ConstLaw(model, id) {} /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> MaterialReinforcementTemplate<dim, ConstLaw>::~MaterialReinforcementTemplate() {} /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::initMaterial() { MaterialReinforcement<dim>::initMaterial(); // Gotta change the dimension from here onwards this->ConstLaw::spatial_dimension = 1; ConstLaw::initMaterial(); this->ConstLaw::gradu.free(); this->ConstLaw::stress.free(); this->ConstLaw::delta_T.free(); this->ConstLaw::sigma_th.free(); this->ConstLaw::potential_energy.free(); Mesh::type_iterator type_it = this->MaterialReinforcement<dim>::model->getInterfaceMesh().firstType(); Mesh::type_iterator type_end = this->MaterialReinforcement<dim>::model->getInterfaceMesh().lastType(); // Reshape the ConstLaw internal fields for (; type_it != type_end ; ++type_it) { UInt nb_elements = this->MaterialReinforcement<dim>::element_filter(*type_it).getSize(); FEEngine & interface_engine = this->MaterialReinforcement<dim>::model->getFEEngine("EmbeddedInterfaceFEEngine"); UInt nb_quad = interface_engine.getNbQuadraturePoints(*type_it); this->ConstLaw::gradu.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); this->ConstLaw::stress.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); + this->ConstLaw::stress.initialize(1); this->ConstLaw::delta_T.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); this->ConstLaw::sigma_th.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); this->ConstLaw::potential_energy.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); //this->ConstLaw::gradu.alloc(0, dim * dim, *type_it, _ghost); } } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeGradU(const ElementType & el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialReinforcement<dim>::computeGradU(el_type, ghost_type); const UInt voigt_size = Material::getTangentStiffnessVoigtSize(dim); Array<Real>::matrix_iterator full_gradu_it = this->MaterialReinforcement<dim>::gradu(el_type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator full_gradu_end = this->MaterialReinforcement<dim>::gradu(el_type, ghost_type).end(dim, dim); Array<Real>::scalar_iterator gradu_it = this->ConstLaw::gradu(el_type, ghost_type).begin(); Array<Real>::matrix_iterator cosines_it = this->directing_cosines(el_type, ghost_type).begin(voigt_size, voigt_size); for (; full_gradu_it != full_gradu_end ; ++full_gradu_it, ++gradu_it, ++cosines_it) { Matrix<Real> & full_gradu = *full_gradu_it; Real & gradu = *gradu_it; Matrix<Real> & C = *cosines_it; computeInterfaceGradUOnQuad(full_gradu, gradu, C); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeInterfaceGradUOnQuad(const Matrix<Real> & full_gradu, Real & gradu, const Matrix<Real> & C) { const UInt voigt_size = Material::getTangentStiffnessVoigtSize(dim); Matrix<Real> epsilon(dim, dim); Vector<Real> e_voigt(voigt_size); Vector<Real> e_interface_voigt(voigt_size); epsilon = 0.5 * (full_gradu + full_gradu.transpose()); MaterialReinforcement<dim>::strainTensorToVoigtVector(epsilon, e_voigt); e_interface_voigt.mul<false>(C, e_voigt); gradu = e_interface_voigt(0); } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeTangentModuli(const ElementType & el_type, Array<Real> & tangent, GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(tangent.getNbComponent() == 1, "Reinforcements only work in 1D"); ConstLaw::computeTangentModuli(el_type, tangent, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeStress(ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); ConstLaw::computeStress(type, ghost_type); Array<Real>::matrix_iterator full_sigma_it = this->MaterialReinforcement<dim>::stress(type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator full_sigma_end = this->MaterialReinforcement<dim>::stress(type, ghost_type).end(dim, dim); Array<Real>::scalar_iterator sigma_it = this->ConstLaw::stress(type, ghost_type).begin(); Array<Real>::scalar_iterator pre_stress_it = this->MaterialReinforcement<dim>::pre_stress(type, ghost_type).begin(); for (; full_sigma_it != full_sigma_end ; ++full_sigma_it, ++sigma_it, ++pre_stress_it) { Matrix<Real> & sigma = *full_sigma_it; sigma(0, 0) = *sigma_it + *pre_stress_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> Real MaterialReinforcementTemplate<dim, ConstLaw>::getEnergy(std::string id) { return MaterialReinforcement<dim>::getEnergy(id); } /* -------------------------------------------------------------------------- */ template <UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computePotentialEnergy(ElementType type, GhostType ghost_type) { ConstLaw::computePotentialEnergy(type, ghost_type); } 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 5b4c0b21a..12bc17a34 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,823 +1,830 @@ /** * @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 "dumper_paraview.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(); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; delete pair_weight[ghost_type]; } 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); + /// 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; 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 last_type = mesh.lastType(spatial_dimension, _ghost); RemovedElementsEvent remove_elem(mesh); - Element element_global; // member element corresponds to global element number - element_global.ghost_type = _ghost; + Element element_local; // member element corresponds to global element number + element_local.ghost_type = _ghost; for(; it != last_type; ++it) { - element_global.type = *it; - UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); + element_local.type = *it; + UInt nb_ghost_elem_global = 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); - + remove_elem.getNewNumbering().alloc(nb_ghost_elem_global, 1, *it, _ghost); + else remove_elem.getNewNumbering(*it, _ghost).resize(nb_ghost_elem_global); + Array<UInt> & elem_filter = element_filter(*it, _ghost); + UInt nb_ghost_elem_local = elem_filter.getSize(); Array<UInt> & new_numbering = remove_elem.getNewNumbering(*it, _ghost); - UInt ng = 0; - for (UInt g = 0; g < nb_ghost_elem; ++g) { - 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()) { + for (UInt g = 0; g < nb_ghost_elem_local; ++g) { + element_local.element = g; + Element element_global = this->convertToGlobalElement(element_local); + if (element_global.element >= nb_ghost_elem_protected && + relevant_ghost_element.find(element_local) == relevant_ghost_element.end()) { + // (std::find(relevant_ghost_element.begin(), + // relevant_ghost_element.end(), + // element_local) == relevant_ghost_element.end())) { + std::cout<< "element removed" << std::endl; remove_elem.getList().push_back(element_global); - new_numbering(g) = UInt(-1); + new_numbering(element_global.element) = UInt(-1); } - } else { - new_numbering(g) = ng; + } + + UInt ng = 0; + for (UInt g = 0; g < nb_ghost_elem_global; ++g) { + if (new_numbering(g) != UInt(-1)) { + 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; std::set<SynchronizationTag> tags; tags.insert(_gst_mnl_for_average); tags.insert(_gst_mnl_weight); tags.insert(_gst_material_id); SynchronizerRegistry & synch_registry = this->model->getSynchronizerRegistry(); std::stringstream sstr; sstr << getID() << ":grid_synchronizer"; grid_synchronizer = GridSynchronizer::createGridSynchronizer(mesh, *spatial_grid, sstr.str(), &synch_registry, tags); 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) { 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.global_num = q.element * nb_quad + 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(); GhostType ghost_type = _not_ghost; 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 q1_coord_it = quads.begin(spatial_dimension); Array<Real>::const_vector_iterator last_quad = quads.end(spatial_dimension); q1.type = *it; q1.global_num = 0; // loop over quad points 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; q1.num_point = 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); // 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 q2 = this->convertToLocalPoint(*first_neigh_quad); Array<Real>::const_vector_iterator q2_coord_it = quadrature_points_coordinates(q2.type, q2.ghost_type).begin(spatial_dimension); const Vector<Real> & q2_coord = q2_coord_it[q2.global_num]; Real distance = q1_coord.distance(q2_coord); if(distance <= weight_func->getRadius() && (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(); 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; if(!(pair_weight[ghost_type2])) { std::string ghost_id = ""; 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()); } pair_weight[ghost_type2]->resize(pair_list[ghost_type2].size()); pair_weight[ghost_type2]->clear(); PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); // 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; QuadraturePoint gq1 = this->convertToGlobalPoint(lq1); QuadraturePoint gq2 = this->convertToGlobalPoint(lq2); // const Real q2_wJ = fem.getIntegratorInterface().getJacobians(gq2.type, gq2.ghost_type)(gq2.global_num); Array<Real>::const_vector_iterator quad_coords_1 = quadrature_points_coordinates(lq1.type, lq1.ghost_type).begin(spatial_dimension); Array<Real>::const_vector_iterator quad_coords_2 = quadrature_points_coordinates(lq2.type, lq2.ghost_type).begin(spatial_dimension); Array<Real> & quad_volumes_1 = quadrature_points_volumes(lq1.type, lq1.ghost_type); const Array<Real> & jacobians_2 = fem.getIntegratorInterface().getJacobians(gq2.type, gq2.ghost_type); const Real & q2_wJ = jacobians_2(gq2.global_num); // Real & q1_volume = quad_volumes(lq1.global_num); const Vector<Real> & q1_coord = quad_coords_1[lq1.global_num]; // quadrature_points_coordinates(lq1.type, lq1.ghost_type).begin(spatial_dimension)[lq1.global_num]; const Vector<Real> & q2_coord = quad_coords_2[lq2.global_num]; // quadrature_points_coordinates(lq1.type, lq1.ghost_type).begin(spatial_dimension)[lq2.global_num]; this->weight_func->selectType(lq1.type, lq1.ghost_type, lq2.type, lq2.ghost_type); // Weight function 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); quad_volumes_1(lq1.global_num) += weight(0); if(lq2.ghost_type != _ghost && lq1.global_num != lq2.global_num) { const Array<Real> & jacobians_1 = fem.getIntegratorInterface().getJacobians(gq1.type, gq1.ghost_type); Array<Real> & quad_volumes_2 = quadrature_points_volumes(lq2.type, lq2.ghost_type); const Real & q1_wJ = jacobians_1(gq1.global_num); //Real & q2_volume = quad_volumes_2(lq2.global_num); Real w2 = this->weight_func->operator()(r, lq2, lq1); weight(1) = q1_wJ * w2; quad_volumes_2(lq2.global_num) += weight(1); //q2_volume += weight(1); } else weight(1) = 0.; } } //normalize the weights for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); // 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; Array<Real> & quad_volumes_1 = quadrature_points_volumes(lq1.type, lq1.ghost_type); Array<Real> & quad_volumes_2 = quadrature_points_volumes(lq2.type, lq2.ghost_type); Real q1_volume = quad_volumes_1(lq1.global_num); weight(0) *= 1. / q1_volume; if(ghost_type2 != _ghost) { Real q2_volume = quad_volumes_2(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 InternalField<T> & to_accumulate, InternalField<T> & accumulated, UInt nb_degree_of_freedom, GhostType ghost_type2) const { AKANTU_DEBUG_IN(); if(ghost_type2 == _not_ghost) { accumulated.reset(); } PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_iterator last_pair = pair_list[ghost_type2].end(); Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); // 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; const Array<T> & to_acc_1 = to_accumulate(lq1.type, lq1.ghost_type); Array<T> & acc_1 = accumulated(lq1.type, lq1.ghost_type); const Array<T> & to_acc_2 = to_accumulate(lq2.type, lq2.ghost_type); Array<T> & acc_2 = accumulated(lq2.type, lq2.ghost_type); // const Vector<T> & q2_to_acc = to_acc_2[lq2.global_num]; // Vector<T> & q1_acc = acc_1[lq1.global_num]; //q1_acc += weight(0) * q2_to_acc; for(UInt d = 0; d < nb_degree_of_freedom; ++d) { acc_1(lq1.global_num, d) += weight(0) * to_acc_2(lq2.global_num, d); } if(ghost_type2 != _ghost) { for(UInt d = 0; d < nb_degree_of_freedom; ++d) { acc_2(lq2.global_num, d) += weight(1) * to_acc_1(lq1.global_num, d); } } // if(ghost_type2 != _ghost) { // const Vector<T> & q1_to_acc = to_acc_1[lq1.global_num]; // Vector<T> & q2_acc = acc_2[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()); for(UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type2 = (GhostType) gt; PairList::const_iterator first_pair = pair_list[ghost_type2].begin(); PairList::const_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, ++weight_it) { Vector<Real> & weight = *weight_it; 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(); } /* -------------------------------------------------------------------------- */ 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(); 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); // 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(); // Array<Real>::vector_iterator weight_it = pair_weight[ghost_type2]->begin(2); for(;first_pair != last_pair; ++first_pair) { 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/weight_function.hh b/src/model/solid_mechanics/materials/weight_function.hh index f62661bcf..cb53123b8 100644 --- a/src/model/solid_mechanics/materials/weight_function.hh +++ b/src/model/solid_mechanics/materials/weight_function.hh @@ -1,373 +1,375 @@ /** * @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 "material_list.hh" + /* -------------------------------------------------------------------------- */ #include <vector> - +#include "material_damage.hh" #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, 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") { - AKANTU_DEBUG_ASSERT(dynamic_cast<MaterialDamage<spatial_dimension> *>(&material) != NULL, "This weight function works only with damage materials!"); + //AKANTU_DEBUG_ASSERT(dynamic_cast<MaterialDamage<spatial_dimension> *>(&material) != NULL, "This weight function works only with damage materials!"); } inline void selectType(__attribute__((unused)) ElementType type1, __attribute__((unused)) GhostType ghost_type1, ElementType type2, GhostType ghost_type2) { selected_damage = &dynamic_cast<MaterialDamage<spatial_dimension> &>(this->material).getDamage(type2, ghost_type2); } 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") { AKANTU_DEBUG_ASSERT(dynamic_cast<MaterialDamage<spatial_dimension> *>(&material) != NULL, "This weight function works only with damage materials!"); 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) { MaterialDamage<spatial_dimension> & mat = dynamic_cast<MaterialDamage<spatial_dimension> &>(this->material); selected_damage = &mat.getDamage(type2, ghost_type2); } 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); } } 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); } } 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, 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, 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/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index ea0758e95..877eec3f3 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1834 +1,1834 @@ /** * @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), 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); 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(); } /*----------------------------------------------------------------------------*/ void SolidMechanicsModel::reInitialize() { } /* -------------------------------------------------------------------------- */ /* 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 } delete solver; 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(); UInt nb_degree_of_freedom = displacement->getNbComponent(); 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 < nb_degree_of_freedom; ++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>::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, ++mat_indexes, ++mat_loc_num) { elem.element = *mat_loc_num; Real el_h = getFEEngine().getElementInradius(*X_el, *it); 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[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; 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::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(!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, 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); } } /* -------------------------------------------------------------------------- */ 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->initSolver(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ 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(); if (method != _explicit_lumped_mass) { this->initSolver(); } } /* -------------------------------------------------------------------------- */ 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, - const std::string & fe_engine_id){ + 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,fe_engine_id); + return materials[m]->getInternalDataPerElem(field_name,element_kind); } return ElementTypeMap<UInt>(); } /* -------------------------------------------------------------------------- */ ElementTypeMapArray<Real> & SolidMechanicsModel::flattenInternal(const std::string & field_name, const ElementKind & kind, const GhostType ghost_type){ 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,ghost_type,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, - const std::string & fe_engine_id){ + const UInt & spatial_dimension, + 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); + field = mesh.createElementalField<UInt, dumper::ElementPartitionField>(mesh.getConnectivities(),group_name,spatial_dimension,kind); else if(field_name == "material_index") - field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(material_index,group_name,this->spatial_dimension,kind); + field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(material_index,group_name,spatial_dimension,kind); else { // this copy of field_name is used to compute derivated data such as // strain and von mises stress that are based on grad_u and stress std::string field_name_copy(field_name); if (field_name == "strain" || field_name == "Green strain" || field_name == "principal strain" || field_name == "principal Green strain") field_name_copy = "grad_u"; else if (field_name == "Von Mises stress") field_name_copy = "stress"; bool is_internal = this->isInternal(field_name_copy,kind); if (is_internal) { - ElementTypeMap<UInt> nb_data_per_elem = this->getInternalDataPerElem(field_name_copy,kind,fe_engine_id); + ElementTypeMap<UInt> nb_data_per_elem = this->getInternalDataPerElem(field_name_copy,kind); ElementTypeMapArray<Real> & internal_flat = this->flattenInternal(field_name_copy,kind); field = mesh.createElementalField<Real, dumper::InternalMaterialField>(internal_flat, group_name, - this->spatial_dimension,kind,nb_data_per_elem); + spatial_dimension,kind,nb_data_per_elem); if (field_name == "strain"){ dumper::ComputeStrain<false> * foo = new dumper::ComputeStrain<false>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "Von Mises stress") { dumper::ComputeVonMisesStress * foo = new dumper::ComputeVonMisesStress(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "Green strain") { dumper::ComputeStrain<true> * foo = new dumper::ComputeStrain<true>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "principal strain") { dumper::ComputePrincipalStrain<false> * foo = new dumper::ComputePrincipalStrain<false>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "principal Green strain") { dumper::ComputePrincipalStrain<true> * foo = new dumper::ComputePrincipalStrain<true>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } //treat the paddings if (padding_flag){ if (field_name == "stress"){ - if (this->spatial_dimension == 2) { + if (spatial_dimension == 2) { dumper::StressPadder<2> * foo = new dumper::StressPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } else if (field_name == "strain" || field_name == "Green strain"){ - if (this->spatial_dimension == 2) { + if (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){ + const ElementKind & kind, + const std::string & fe_engine_id){ 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 << " + 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 3f610dc1f..1fa6a05af 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,747 +1,746 @@ /** * @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; /// re-initialize model to set fields to 0 void reInitialize(); /* ------------------------------------------------------------------------ */ /* 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, - const std::string & fe_engine_id = ""); + virtual 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, const GhostType ghost_type = _not_ghost); //! 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, - const std::string & fe_engine_id = ""); + const UInt & spatial_dimension, + 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(MaterialByElement, material_index, const ElementTypeMapArray<UInt> &); /// vectors containing local material element index for each global element index 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; /// 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 e418083d0..cdf29f034 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc @@ -1,709 +1,705 @@ /** * @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); /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::SolidMechanicsModelCohesive(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, dim, id, memory_id), tangents("tangents", 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); #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->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> & 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(); 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::interpolateStress() { for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat __attribute__((unused)) = dynamic_cast<MaterialCohesive &>(*materials[m]); } catch(std::bad_cast&) { /// interpolate stress on facet quadrature points positions materials[m]->interpolateStressOnFacets(facet_stress); } } #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 } /* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::checkCohesiveStress() { - AKANTU_DEBUG_IN(); - +UInt SolidMechanicsModelCohesive::checkCohesiveStress() { interpolateStress(); 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&) { } } /* if(static and extrinsic) { check max mean stresses and change inserter.getInsertionFacets(type_facet); } */ /// communicate data among processors synch_registry->synchronize(_gst_smmc_facets); /// insert cohesive elements - inserter->insertElements(); - - AKANTU_DEBUG_OUT(); + return inserter->insertElements(); } /* -------------------------------------------------------------------------- */ 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 (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 e853fe01a..daba20874 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh @@ -1,293 +1,290 @@ /** * @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) : SolidMechanicsModelOptions(analysis_method, no_init_materials), extrinsic(extrinsic) {} bool extrinsic; }; 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: /// 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(); + /// cohesive elements if needed (returns the number of new cohesive + /// elements) + UInt checkCohesiveStress(); /// interpolate stress on facets void interpolateStress(); /// 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(); - - // template <SolveConvergenceMethod method, SolveConvergenceCriteria criteria> - // bool solveStepCohesive(Real tolerance, UInt max_iteration = 100); - template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> bool solveStepCohesive(Real tolerance, Real & error, UInt max_iteration = 100, + UInt cont = 1, bool do_not_factorize = false); + /// initialize stress interpolation + void initStressInterpolation(); 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(); /* ------------------------------------------------------------------------ */ /* 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; /// stress on facets on the two sides by quadrature point ElementTypeMapArray<Real> facet_stress; /// material to use if a cohesive element is created on a facet ElementTypeMapArray<UInt> facet_material; bool is_extrinsic; /// cohesive element inserter CohesiveElementInserter * inserter; #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) #include "solid_mechanics_model_cohesive_parallel.hh" #endif }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ class DefaultMaterialCohesiveSelector : public DefaultMaterialSelector { public: DefaultMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model) : 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__ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "solid_mechanics_model_cohesive_inline_impl.cc" #endif #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc index 6d56d64e1..50a9dc1ec 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc @@ -1,261 +1,257 @@ /** * @file solid_mechanics_model_cohesive_inline_impl.cc * * @author Mauro Corrado <mauro.corrado@epfl.ch> * * @date Thu Feb 26 14:23:45 2015 * * @brief Implementation of inline functions for the Cohesive element model * * @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 <algorithm> #include "shape_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" -#include "dumpable_inline_impl.hh" #include "material_cohesive.hh" #ifndef __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> bool SolidMechanicsModelCohesive::solveStepCohesive(Real tolerance, Real & error, UInt max_iteration, + UInt cont, bool do_not_factorize) { EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); this->implicitPred(); bool insertion_new_element = true; bool converged = false; Array<Real> * displacement_tmp = NULL; Array<Real> * velocity_tmp = NULL; Array<Real> * acceleration_tmp = NULL; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); while (insertion_new_element) { //loop for insertion of new cohesive elements if (is_extrinsic) { // If in extrinsic saves the current displacements, velocities and accelerations Array<Real> * tmp_swap; if(!displacement_tmp) { displacement_tmp = new Array<Real>(*(this->displacement)); } else { (*displacement_tmp).resize(this->displacement->getSize()); - // displacement_tmp->resize(this->displacement->getSize()); + //displacement_tmp->resize(this->displacement->getSize()); (*displacement_tmp).copy(*(this->displacement)); //displacement_tmp->copy(*(this->displacement)); } tmp_swap = displacement_tmp; displacement_tmp = this->displacement; this->displacement = tmp_swap; if(!velocity_tmp) { velocity_tmp = new Array<Real>(*(this->velocity)); } else { velocity_tmp->resize(this->velocity->getSize()); velocity_tmp->copy(*(this->velocity)); } tmp_swap = velocity_tmp; velocity_tmp = this->velocity; this->velocity = tmp_swap; if(!acceleration_tmp) { acceleration_tmp = new Array<Real>(*(this->acceleration)); } else { acceleration_tmp->resize(this->acceleration->getSize()); acceleration_tmp->copy(*(this->acceleration)); } tmp_swap = acceleration_tmp; acceleration_tmp = this->acceleration; this->acceleration = tmp_swap; } 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; 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(); this->updateResidual(); converged = this->testConvergence<criteria> (tolerance, error); - // dump(); - // dump("cohesive elements"); - //std::cout << "Error after loop: " << error << std::endl; - 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); if (converged) { //// EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); // !!! add sendEvent to call computeCauchyStress !!!! if (prank==0){ std::cout << "Error after convergence: " << error << std::endl; std::cout << "no. of iterations: " << iter << std::endl; } } else if(iter == max_iteration) { if (prank==0){ AKANTU_DEBUG_WARNING("[" << criteria << "] Convergence not reached after " << std::setw(std::log10(max_iteration)) << iter << " iteration" << (iter == 1 ? "" : "s") << "!" << std::endl); std::cout << "Error after NON convergence: " << error << std::endl; } } if (is_extrinsic) { Array<Real> * tmp_swap; tmp_swap = displacement_tmp; displacement_tmp = this->displacement; this->displacement = tmp_swap; tmp_swap = velocity_tmp; velocity_tmp = this->velocity; this->velocity = tmp_swap; tmp_swap = acceleration_tmp; acceleration_tmp = this->acceleration; this->acceleration = tmp_swap; - if (converged){ + if (converged || cont == 2){ UInt nb_cohesive_elements = this->mesh.getNbElement(this->spatial_dimension, _not_ghost, _ek_cohesive); this->checkCohesiveStress(); UInt new_nb_cohesive_elements = this->mesh.getNbElement(this->spatial_dimension, _not_ghost, _ek_cohesive); UInt nb_cohe[2]; nb_cohe[0] = nb_cohesive_elements; nb_cohe[1] = new_nb_cohesive_elements; StaticCommunicator::getStaticCommunicator().allReduce(nb_cohe, 2, _so_sum); if(nb_cohe[0] == nb_cohe[1]) { insertion_new_element = false; } else { insertion_new_element = true; if (prank==0) std::cout << "1 cohesive element has been inserted" << std::endl; } } } - if (!converged){ + if (!converged && cont != 2){ insertion_new_element = false; for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat = dynamic_cast<MaterialCohesive &>(*materials[m]); mat.checkDeltaMax(_not_ghost); } catch(std::bad_cast&) { } } } } //end while insertion_new_element - if(is_extrinsic && converged) { + if ((is_extrinsic && converged) || (is_extrinsic && cont == 2)) { EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); this->displacement->copy(*displacement_tmp); this->velocity ->copy(*velocity_tmp); this->acceleration->copy(*acceleration_tmp); delete displacement_tmp; delete velocity_tmp; delete acceleration_tmp; } return insertion_new_element; } __END_AKANTU__ #if defined (AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "solid_mechanics_model_cohesive_parallel_inline_impl.cc" #endif #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ */ 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 ac9d5db47..004c1744b 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc @@ -1,613 +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> * 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; 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 = (*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() * 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(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(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]; + Vector<Real> disp(it_disp[index]); buffer << disp; + Vector<Real> velo(it_velo[index]); buffer << velo; break; } case _gst_smm_res: { Array<Real>::const_vector_iterator it_res = residual->begin(spatial_dimension); - buffer << it_res[index]; + Vector<Real> resi(it_res[index]); buffer << resi; 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]; + Vector<Real> mass(it_mass[index]); buffer << mass; 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]; + Vector<Real> disp(it_disp[index]); buffer << disp; + Vector<Real> velo(it_velo[index]); buffer << velo; + Vector<Real> acce(it_acce[index]); buffer << acce; + Vector<Real> resi(it_resi[index]); buffer << resi; + Vector<Real> forc(it_forc[index]); buffer << forc; 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); Vector<Real> disp(it_disp[index]); buffer >> disp; Vector<Real> velo(it_velo[index]); buffer >> velo; break; } case _gst_smm_res: { Array<Real>::vector_iterator it_res = residual->begin(spatial_dimension); Vector<Real> res(it_res[index]); buffer >> res; 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); Vector<Real> mass_v(it_mass[index]); buffer >> mass_v; 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); Vector<Real> disp(it_disp[index]); buffer >> disp; Vector<Real> velo(it_velo[index]); buffer >> velo; Vector<Real> acce(it_acce[index]); buffer >> acce; Vector<Real> resi(it_resi[index]); buffer >> resi; Vector<Real> forc(it_forc[index]); buffer >> forc; 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/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc index 2c41ab2ac..69555bd2f 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.cc +++ b/src/model/structural_mechanics/structural_mechanics_model.cc @@ -1,1147 +1,1148 @@ /** * @file structural_mechanics_model.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Fabian Barras <fabian.barras@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Mon Sep 15 2014 * * @brief Model implementation for StucturalMechanics 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 "structural_mechanics_model.hh" #include "group_manager_inline_impl.cc" #include "dumpable_inline_impl.hh" #include "aka_math.hh" #include "integration_scheme_2nd_order.hh" #include "static_communicator.hh" #include "sparse_matrix.hh" #include "solver.hh" #ifdef AKANTU_USE_MUMPS #include "solver_mumps.hh" #endif #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" # include "dumper_elemental_field.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const StructuralMechanicsModelOptions default_structural_mechanics_model_options(_static); /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::StructuralMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), time_step(NAN), f_m2a(1.0), stress("stress", id, memory_id), element_material("element_material", id, memory_id), set_ID("beam sets", id, memory_id), stiffness_matrix(NULL), mass_matrix(NULL), velocity_damping_matrix(NULL), jacobian_matrix(NULL), solver(NULL), rotation_matrix("rotation_matices", id, memory_id), increment_flag(false), integrator(NULL) { AKANTU_DEBUG_IN(); registerFEEngineObject<MyFEEngineType>("StructuralMechanicsFEEngine", mesh, spatial_dimension); this->displacement_rotation = NULL; this->mass = NULL; this->velocity = NULL; this->acceleration = NULL; this->force_momentum = NULL; this->residual = NULL; this->blocked_dofs = NULL; this->increment = NULL; this->previous_displacement = NULL; if(spatial_dimension == 2) nb_degree_of_freedom = 3; else if (spatial_dimension == 3) nb_degree_of_freedom = 6; else { AKANTU_DEBUG_TO_IMPLEMENT(); } this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_structural); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::~StructuralMechanicsModel() { AKANTU_DEBUG_IN(); delete integrator; delete solver; delete stiffness_matrix; delete jacobian_matrix; delete mass_matrix; delete velocity_damping_matrix; AKANTU_DEBUG_OUT(); } void StructuralMechanicsModel::setTimeStep(Real time_step) { this->time_step = time_step; #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initFull(const ModelOptions & options) { const StructuralMechanicsModelOptions & stmm_options = dynamic_cast<const StructuralMechanicsModelOptions &>(options); method = stmm_options.analysis_method; initModel(); initArrays(); displacement_rotation->clear(); velocity ->clear(); acceleration ->clear(); force_momentum ->clear(); residual ->clear(); blocked_dofs ->clear(); increment ->clear(); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { computeRotationMatrix(*it); } switch(method) { case _implicit_dynamic: initImplicit(); break; case _static: initSolver(); break; default: AKANTU_EXCEPTION("analysis method not recognised by StructuralMechanicsModel"); break; } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initArrays() { AKANTU_DEBUG_IN(); UInt nb_nodes = getFEEngine().getMesh().getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":displacement"; 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"; std::stringstream sstr_incr; sstr_incr << id << ":increment"; displacement_rotation = &(alloc<Real>(sstr_disp.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); velocity = &(alloc<Real>(sstr_velo.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); acceleration = &(alloc<Real>(sstr_acce.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); force_momentum = &(alloc<Real>(sstr_forc.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); residual = &(alloc<Real>(sstr_resi.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); blocked_dofs = &(alloc<bool>(sstr_boun.str(), nb_nodes, nb_degree_of_freedom, false)); increment = &(alloc<Real>(sstr_incr.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { UInt nb_element = getFEEngine().getMesh().getNbElement(*it); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(*it); element_material.alloc(nb_element, 1, *it, _not_ghost); set_ID.alloc(nb_element, 1, *it, _not_ghost); UInt size = getTangentStiffnessVoigtSize(*it); stress.alloc(nb_element * nb_quadrature_points, size , *it, _not_ghost); } dof_synchronizer = new DOFSynchronizer(getFEEngine().getMesh(), nb_degree_of_freedom); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initModel() { getFEEngine().initShapeFunctions(_not_ghost); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) { AKANTU_DEBUG_IN(); const Mesh & mesh = getFEEngine().getMesh(); #if !defined(AKANTU_USE_MUMPS) // 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_node = mesh.getNbGlobalNodes(); std::stringstream sstr; sstr << id << ":jacobian_matrix"; jacobian_matrix = new SparseMatrix(nb_global_node * nb_degree_of_freedom, _symmetric, sstr.str(), memory_id); jacobian_matrix->buildProfile(mesh, *dof_synchronizer, nb_degree_of_freedom); std::stringstream sstr_sti; sstr_sti << id << ":stiffness_matrix"; stiffness_matrix = new SparseMatrix(*jacobian_matrix, sstr_sti.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solv; sstr_solv << id << ":solver"; 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 solver->initialize(options); #endif //AKANTU_HAS_SOLVER AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); if (!increment) setIncrementFlagOn(); initSolver(solver_options); if(integrator) delete integrator; integrator = new TrapezoidalRule2(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt StructuralMechanicsModel::getTangentStiffnessVoigtSize(const ElementType & type) { UInt size; #define GET_TANGENT_STIFFNESS_VOIGT_SIZE(type) \ size = getTangentStiffnessVoigtSize<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(GET_TANGENT_STIFFNESS_VOIGT_SIZE); #undef GET_TANGENT_STIFFNESS_VOIGT_SIZE return size; } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); stiffness_matrix->clear(); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { ElementType type = *it; #define ASSEMBLE_STIFFNESS_MATRIX(type) \ assembleStiffnessMatrix<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(ASSEMBLE_STIFFNESS_MATRIX); #undef ASSEMBLE_STIFFNESS_MATRIX } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeRotationMatrix<_bernoulli_beam_2>(Array<Real> & rotations){ ElementType type = _bernoulli_beam_2; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); Array<UInt>::iterator< Vector<UInt> > connec_it = mesh.getConnectivity(type).begin(2); Array<Real>::vector_iterator nodes_it = mesh.getNodes().begin(spatial_dimension); Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e = 0; e < nb_element; ++e, ++R_it, ++connec_it) { Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x2; x2 = nodes_it[connec(1)]; // X2 Vector<Real> x1; x1 = nodes_it[connec(0)]; // X1 Real le = x1.distance(x2); Real c = (x2(0) - x1(0)) / le; Real s = (x2(1) - x1(1)) / le; /// Definition of the rotation matrix R(0,0) = c; R(0,1) = s; R(0,2) = 0.; R(1,0) = -s; R(1,1) = c; R(1,2) = 0.; R(2,0) = 0.; R(2,1) = 0.; R(2,2) = 1.; } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeRotationMatrix<_bernoulli_beam_3>(Array<Real> & rotations){ ElementType type = _bernoulli_beam_3; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); Array<Real>::vector_iterator n_it = mesh.getNormals(type).begin(spatial_dimension); Array<UInt>::iterator< Vector<UInt> > connec_it = mesh.getConnectivity(type).begin(2); Array<Real>::vector_iterator nodes_it = mesh.getNodes().begin(spatial_dimension); Matrix<Real> Pe (spatial_dimension, spatial_dimension); Matrix<Real> Pg (spatial_dimension, spatial_dimension); Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension); Vector<Real> x_n(spatial_dimension); // x vect n Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e=0 ; e < nb_element; ++e, ++n_it, ++connec_it, ++R_it) { Vector<Real> & n = *n_it; Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x; x = nodes_it[connec(1)]; // X2 Vector<Real> y; y = nodes_it[connec(0)]; // X1 Real l = x.distance(y); x -= y; // X2 - X1 x_n.crossProduct(x, n); Pe.eye(); Pe(0, 0) *= l; Pe(1, 1) *= -l; Pg(0,0) = x(0); Pg(0,1) = x_n(0); Pg(0,2) = n(0); Pg(1,0) = x(1); Pg(1,1) = x_n(1); Pg(1,2) = n(1); Pg(2,0) = x(2); Pg(2,1) = x_n(2); Pg(2,2) = n(2); inv_Pg.inverse(Pg); Pe *= inv_Pg; for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { R(i, j) = Pe(i, j); R(i + spatial_dimension,j + spatial_dimension) = Pe(i, j); } } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeRotationMatrix<_kirchhoff_shell>(Array<Real> & rotations){ ElementType type = _kirchhoff_shell; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); Array<UInt>::iterator< Vector<UInt> > connec_it = mesh.getConnectivity(type).begin(3); Array<Real>::vector_iterator nodes_it = mesh.getNodes().begin(spatial_dimension); Matrix<Real> Pe (spatial_dimension, spatial_dimension); Matrix<Real> Pg (spatial_dimension, spatial_dimension); Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e=0 ; e < nb_element; ++e, ++connec_it, ++R_it) { Pe.eye(); Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x2; x2 = nodes_it[connec(1)]; // X2 Vector<Real> x1; x1 = nodes_it[connec(0)]; // X1 Vector<Real> x3; x3 = nodes_it[connec(2)]; // X3 Vector<Real> Pg_col_1=x2-x1; Vector<Real> Pg_col_2 = x3-x1; Vector<Real> Pg_col_3(spatial_dimension); Pg_col_3.crossProduct(Pg_col_1, Pg_col_2); for (UInt i = 0; i <spatial_dimension; ++i) { Pg(i,0) = Pg_col_1(i); Pg(i,1) = Pg_col_2(i); Pg(i,2) = Pg_col_3(i); } inv_Pg.inverse(Pg); // Pe *= inv_Pg; Pe.eye(); for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { R(i, j) = Pe(i, j); R(i + spatial_dimension,j + spatial_dimension) = Pe(i, j); } } } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeRotationMatrix(const ElementType & type) { Mesh & mesh = getFEEngine().getMesh(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); if(!rotation_matrix.exists(type)) { rotation_matrix.alloc(nb_element, nb_degree_of_freedom*nb_nodes_per_element * nb_degree_of_freedom*nb_nodes_per_element, type); } else { rotation_matrix(type).resize(nb_element); } rotation_matrix(type).clear(); Array<Real>rotations(nb_element, nb_degree_of_freedom * nb_degree_of_freedom); rotations.clear(); #define COMPUTE_ROTATION_MATRIX(type) \ computeRotationMatrix<type>(rotations); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_ROTATION_MATRIX); #undef COMPUTE_ROTATION_MATRIX Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); Array<Real>::matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom*nb_nodes_per_element, nb_degree_of_freedom*nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++R_it, ++T_it) { Matrix<Real> & T = *T_it; Matrix<Real> & R = *R_it; T.clear(); for (UInt k = 0; k < nb_nodes_per_element; ++k){ for (UInt i = 0; i < nb_degree_of_freedom; ++i) for (UInt j = 0; j < nb_degree_of_freedom; ++j) T(k*nb_degree_of_freedom + i, k*nb_degree_of_freedom + j) = R(i, j); } } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeStresses() { AKANTU_DEBUG_IN(); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { ElementType type = *it; #define COMPUTE_STRESS_ON_QUAD(type) \ computeStressOnQuad<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_STRESS_ON_QUAD); #undef COMPUTE_STRESS_ON_QUAD } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::updateResidual() { AKANTU_DEBUG_IN(); residual->copy(*force_momentum); Array<Real> ku(*displacement_rotation, true); ku *= *stiffness_matrix; *residual -= ku; this->updateResidualInternal(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::implicitPred() { AKANTU_DEBUG_IN(); if(previous_displacement) previous_displacement->copy(*displacement_rotation); if(method == _implicit_dynamic) integrator->integrationSchemePred(time_step, *displacement_rotation, *velocity, *acceleration, *blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::implicitCorr() { AKANTU_DEBUG_IN(); Real * incr_val = increment->storage(); bool * boun_val = blocked_dofs->storage(); UInt nb_nodes = displacement_rotation->getSize(); for (UInt j = 0; j < nb_nodes * nb_degree_of_freedom; ++j, ++incr_val, ++boun_val){ *incr_val *= (1. - *boun_val); } if(method == _implicit_dynamic) { integrator->integrationSchemeCorrDispl(time_step, *displacement_rotation, *velocity, *acceleration, *blocked_dofs, *increment); } else { Real * disp_val = displacement_rotation->storage(); incr_val = increment->storage(); for (UInt j = 0; j < nb_nodes *nb_degree_of_freedom; ++j, ++disp_val, ++incr_val){ *disp_val += *incr_val; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::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 StructuralMechanicsModel::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(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::solve() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving an implicit step."); UInt nb_nodes = displacement_rotation->getSize(); /// todo residual = force - Kxr * d_bloq jacobian_matrix->copyContent(*stiffness_matrix); jacobian_matrix->applyBoundary(*blocked_dofs); jacobian_matrix->saveMatrix("Kbound.mtx"); increment->clear(); solver->setRHS(*residual); solver->factorize(); solver->solve(*increment); Real * increment_val = increment->storage(); Real * displacement_val = displacement_rotation->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *displacement_val += *increment_val; } else { *increment_val = 0.0; } displacement_val++; blocked_dofs_val++; increment_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<> bool StructuralMechanicsModel::testConvergence<_scc_increment>(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); UInt nb_nodes = displacement_rotation->getSize(); UInt nb_degree_of_freedom = displacement_rotation->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); Real * displacement_val = displacement_rotation->storage(); for (UInt n = 0; n < nb_nodes; ++n) { for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val)) { 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 went wrong in the solve phase"); AKANTU_DEBUG_OUT(); if(norm[1] > Math::getTolerance()) error = norm[0] / norm[1]; else error = norm[0]; //In case the total displacement is zero! return (error < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool StructuralMechanicsModel::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 < nb_degree_of_freedom; ++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); } /* -------------------------------------------------------------------------- */ bool StructuralMechanicsModel::testConvergenceIncrement(Real tolerance) { Real error; bool tmp = testConvergenceIncrement(tolerance, error); AKANTU_DEBUG_INFO("Norm of increment : " << error); return tmp; } /* -------------------------------------------------------------------------- */ bool StructuralMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error) { AKANTU_DEBUG_IN(); Mesh & mesh= getFEEngine().getMesh(); UInt nb_nodes = displacement_rotation->getSize(); UInt nb_degree_of_freedom = displacement_rotation->getNbComponent(); Real norm = 0; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->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 += *increment_val * *increment_val; } blocked_dofs_val++; increment_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); error = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (error < tolerance); } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_2>(Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_2); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_2); UInt tangent_size = 2; Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); Array<UInt> & el_mat = element_material(_bernoulli_beam_2, _not_ghost); for (UInt e = 0; e < nb_element; ++e) { UInt mat = el_mat(e); Real E = materials[mat].E; Real A = materials[mat].A; Real I = materials[mat].I; for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0,0) = E * A; D(1,1) = E * I; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_3>(Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_3); UInt tangent_size = 4; Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); for (UInt e = 0; e < nb_element; ++e) { UInt mat = element_material(_bernoulli_beam_3, _not_ghost)(e); Real E = materials[mat].E; Real A = materials[mat].A; Real Iz = materials[mat].Iz; Real Iy = materials[mat].Iy; Real GJ = materials[mat].GJ; for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0,0) = E * A; D(1,1) = E * Iz; D(2,2) = E * Iy; D(3,3) = GJ; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeTangentModuli<_kirchhoff_shell>(Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_kirchhoff_shell); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_kirchhoff_shell); UInt tangent_size = 6; Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); for (UInt e = 0; e < nb_element; ++e) { UInt mat = element_material(_kirchhoff_shell, _not_ghost)(e); Real E = materials[mat].E; Real nu = materials[mat].nu; Real t = materials[mat].t; Real HH=E*t/(1-nu*nu); Real DD=E*t*t*t/(12*(1-nu*nu)); for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0,0) = HH; D(0,1) = HH*nu; D(1,0) = HH*nu; D(1,1) = HH; D(2,2) = HH*(1-nu)/2; D(3,3) = DD; D(3,4) = DD*nu; D(4,3) = DD*nu; D(4,4) = DD; D(5,5) = DD*(1-nu)/2; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::transferBMatrixToSymVoigtBMatrix<_bernoulli_beam_2>(Array<Real> & b, bool local) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_2); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_bernoulli_beam_2); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_2); MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); Array<Real>::const_vector_iterator shape_Np = fem.getShapesDerivatives(_bernoulli_beam_2, _not_ghost, 0).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Mpp = fem.getShapesDerivatives(_bernoulli_beam_2, _not_ghost, 1).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Lpp = fem.getShapesDerivatives(_bernoulli_beam_2, _not_ghost, 2).begin(nb_nodes_per_element); UInt tangent_size = getTangentStiffnessVoigtSize<_bernoulli_beam_2>(); UInt bt_d_b_size = nb_nodes_per_element * nb_degree_of_freedom; b.clear(); Array<Real>::matrix_iterator B_it = b.begin(tangent_size, bt_d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q) { Matrix<Real> & B = *B_it; const Vector<Real> & Np = *shape_Np; const Vector<Real> & Lpp = *shape_Lpp; const Vector<Real> & Mpp = *shape_Mpp; B(0,0) = Np(0); B(0,3) = Np(1); B(1,1) = Mpp(0); B(1,2) = Lpp(0); B(1,4) = Mpp(1); B(1,5) = Lpp(1); ++B_it; ++shape_Np; ++shape_Mpp; ++shape_Lpp; } // ++R_it; } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::transferBMatrixToSymVoigtBMatrix<_bernoulli_beam_3>(Array<Real> & b, bool local) { MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_bernoulli_beam_3); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_3); Array<Real>::const_vector_iterator shape_Np = fem.getShapesDerivatives(_bernoulli_beam_3, _not_ghost, 0).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Mpp = fem.getShapesDerivatives(_bernoulli_beam_3, _not_ghost, 1).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Lpp = fem.getShapesDerivatives(_bernoulli_beam_3, _not_ghost, 2).begin(nb_nodes_per_element); UInt tangent_size = getTangentStiffnessVoigtSize<_bernoulli_beam_3>(); UInt bt_d_b_size = nb_nodes_per_element * nb_degree_of_freedom; b.clear(); Array<Real>::matrix_iterator B_it = b.begin(tangent_size, bt_d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q) { Matrix<Real> & B = *B_it; const Vector<Real> & Np = *shape_Np; const Vector<Real> & Lpp = *shape_Lpp; const Vector<Real> & Mpp = *shape_Mpp; B(0,0) = Np(0); B(0,6) = Np(1); B(1,1) = Mpp(0); B(1,5) = Lpp(0); B(1,7) = Mpp(1); B(1,11) = Lpp(1); B(2,2) = Mpp(0); B(2,4) = -Lpp(0); B(2,8) = Mpp(1); B(2,10) = -Lpp(1); B(3,3) = Np(0); B(3,9) = Np(1); ++B_it; ++shape_Np; ++shape_Mpp; ++shape_Lpp; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::transferBMatrixToSymVoigtBMatrix<_kirchhoff_shell>(Array<Real> & b, bool local) { MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); UInt nb_element = getFEEngine().getMesh().getNbElement(_kirchhoff_shell); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_kirchhoff_shell); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_kirchhoff_shell); Array<Real>::const_matrix_iterator shape_Np = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 0).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Nx1p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 1).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Nx2p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 2).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Nx3p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 3).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Ny1p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 4).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Ny2p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 5).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Ny3p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 6).begin(2,nb_nodes_per_element); UInt tangent_size = getTangentStiffnessVoigtSize<_kirchhoff_shell>(); UInt bt_d_b_size = nb_nodes_per_element * nb_degree_of_freedom; b.clear(); Array<Real>::matrix_iterator B_it = b.begin(tangent_size, bt_d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q) { Matrix<Real> & B = *B_it; const Matrix<Real> & Np = *shape_Np; const Matrix<Real> & Nx1p = *shape_Nx1p; const Matrix<Real> & Nx2p = *shape_Nx2p; const Matrix<Real> & Nx3p = *shape_Nx3p; const Matrix<Real> & Ny1p = *shape_Ny1p; const Matrix<Real> & Ny2p = *shape_Ny2p; const Matrix<Real> & Ny3p = *shape_Ny3p; B(0,0) = Np(0,0); B(0,6) = Np(0,1); B(0,12) = Np(0,2); B(1,1) = Np(1,0); B(1,7) = Np(1,1); B(1,13) = Np(1,2); B(2,0) = Np(1,0); B(2,1) = Np(0,0); B(2,6) = Np(1,1); B(2,7) = Np(0,1); B(2,12) = Np(1,2); B(2,13) = Np(0,2); B(3,2) = Nx1p(0,0); B(3,3) = Nx2p(0,0); B(3,4) = Nx3p(0,0); B(3,8) = Nx1p(0,1); B(3,9) = Nx2p(0,1); B(3,10) = Nx3p(0,1); B(3,14) = Nx1p(0,2); B(3,15) = Nx2p(0,2); B(3,16) = Nx3p(0,2); B(4,2) = Ny1p(1,0); B(4,3) = Ny2p(1,0); B(4,4) = Ny3p(1,0); B(4,8) = Ny1p(1,1); B(4,9) = Ny2p(1,1); B(4,10) = Ny3p(1,1); B(4,14) = Ny1p(1,2); B(4,15) = Ny2p(1,2); B(4,16) = Ny3p(1,2); B(5,2) = Nx1p(1,0) + Ny1p(0,0); B(5,3) = Nx2p(1,0) + Ny2p(0,0); B(5,4) = Nx3p(1,0) + Ny3p(0,0); B(5,8) = Nx1p(1,1) + Ny1p(0,1); B(5,9) = Nx2p(1,1) + Ny2p(0,1); B(5,10) = Nx3p(1,1) + Ny3p(0,1); B(5,14) = Nx1p(1,2) + Ny1p(0,2); B(5,15) = Nx2p(1,2) + Ny2p(0,2); B(5,16) = Nx3p(1,2) + Ny3p(0,2); ++B_it; ++shape_Np; ++shape_Nx1p; ++shape_Nx2p; ++shape_Nx3p; ++shape_Ny1p; ++shape_Ny2p; ++shape_Ny3p; } } } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel ::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; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel ::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { UInt n; if(spatial_dimension == 2) { n = 2; } else n = 3; dumper::Field * field = NULL; if (field_name == "displacement"){ field = mesh.createStridedNodalField(displacement_rotation,group_name,n,0,padding_flag); } if (field_name == "rotation"){ field = mesh.createStridedNodalField(displacement_rotation,group_name, nb_degree_of_freedom-n,n,padding_flag); } if (field_name == "force"){ field = mesh.createStridedNodalField(force_momentum,group_name,n,0,padding_flag); } if (field_name == "momentum"){ field = mesh.createStridedNodalField(force_momentum,group_name, nb_degree_of_freedom-n,n,padding_flag); } if (field_name == "residual"){ field = mesh.createNodalField(residual,group_name,padding_flag); } return field; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, - const ElementKind & kind){ + const ElementKind & kind, + const std::string & fe_engine_id){ dumper::Field * field = NULL; if(field_name == "element_index_by_material") field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(field_name,group_name,this->spatial_dimension,kind); return field; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/structural_mechanics/structural_mechanics_model.hh b/src/model/structural_mechanics/structural_mechanics_model.hh index 741652314..9a214db8e 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.hh +++ b/src/model/structural_mechanics/structural_mechanics_model.hh @@ -1,400 +1,401 @@ /** * @file structural_mechanics_model.hh * * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Fabian Barras <fabian.barras@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Tue Sep 02 2014 * * @brief Particular implementation of the structural elements in the StructuralMechanicsModel * * @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_STRUCTURAL_MECHANICS_MODEL_HH__ #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "model.hh" #include "integrator_gauss.hh" #include "shape_linked.hh" #include "aka_types.hh" #include "dumpable.hh" #include "solver.hh" #include "integration_scheme_2nd_order.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class SparseMatrix; } __BEGIN_AKANTU__ struct StructuralMaterial { Real E; Real A; Real I; Real Iz; Real Iy; Real GJ; Real rho; Real t; Real nu; }; struct StructuralMechanicsModelOptions : public ModelOptions { StructuralMechanicsModelOptions(AnalysisMethod analysis_method = _static) : analysis_method(analysis_method) {} AnalysisMethod analysis_method; }; extern const StructuralMechanicsModelOptions default_structural_mechanics_model_options; class StructuralMechanicsModel : public Model { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef FEEngineTemplate<IntegratorGauss, ShapeLinked, _ek_structural> MyFEEngineType; StructuralMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "structural_mechanics_model", const MemoryID & memory_id = 0); virtual ~StructuralMechanicsModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize fully the model void initFull(const ModelOptions & options = default_structural_mechanics_model_options); /// initialize the internal vectors void initArrays(); /// initialize the model void initModel(); /// initialize the solver 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); /// compute the stresses per elements void computeStresses(); /// assemble the stiffness matrix void assembleStiffnessMatrix(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); /// implicit time integration predictor void implicitPred(); /// implicit time integration corrector void implicitCorr(); /// update the residual vector void updateResidual(); /// solve the system void solve(); bool testConvergenceIncrement(Real tolerance); bool testConvergenceIncrement(Real tolerance, Real & error); virtual void printself(std::ostream & stream, int indent = 0) const {}; void computeRotationMatrix(const ElementType & type); protected: UInt getTangentStiffnessVoigtSize(const ElementType & type); /// compute Rotation Matrices template<const ElementType type> void computeRotationMatrix(Array<Real> & rotations) {}; /// 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.); /* ------------------------------------------------------------------------ */ /* Mass (structural_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); /// computes rho void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type); /// finish the computation of residual to solve in increment void updateResidualInternal(); /* ------------------------------------------------------------------------ */ private: template<ElementType type> inline UInt getTangentStiffnessVoigtSize(); template <ElementType type> void assembleStiffnessMatrix(); template <ElementType type> void assembleMass(); template<ElementType type> void computeStressOnQuad(); template <ElementType type> void computeTangentModuli(Array<Real> & tangent_moduli); template <ElementType type> void transferBMatrixToSymVoigtBMatrix(Array<Real> & B, bool local = false); template <ElementType type> void transferNMatrixToSymVoigtNMatrix(Array<Real> & N_matrix); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: virtual dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, - const ElementKind & kind); + const ElementKind & kind, + const std::string & fe_engine_id = ""); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// set the value of the time step void setTimeStep(Real time_step); /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the StructuralMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement_rotation, Array<Real> &); /// get the StructuralMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array<Real> &); /// get the StructuralMechanicsModel::acceleration vector, updated by /// StructuralMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array<Real> &); /// get the StructuralMechanicsModel::force vector (boundary forces) AKANTU_GET_MACRO(Force, *force_momentum, Array<Real> &); /// get the StructuralMechanicsModel::residual vector, computed by StructuralMechanicsModel::updateResidual AKANTU_GET_MACRO(Residual, *residual, const Array<Real> &); /// get the StructuralMechanicsModel::boundary vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(RotationMatrix, rotation_matrix, Real); AKANTU_GET_MACRO(StiffnessMatrix, *stiffness_matrix, const SparseMatrix &); AKANTU_GET_MACRO(MassMatrix, *mass_matrix, const SparseMatrix &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementMaterial, element_material, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Set_ID, set_ID, UInt); void addMaterial(StructuralMaterial & material) { materials.push_back(material); } /** * @brief set the StructuralMechanicsModel::increment_flag to on, the activate the * update of the StructuralMechanicsModel::increment vector */ void setIncrementFlagOn(); /* ------------------------------------------------------------------------ */ /* Boundaries (structural_mechanics_model_boundary.cc) */ /* ------------------------------------------------------------------------ */ public: /// Compute Linear load function set in global axis template <ElementType type> void computeForcesByGlobalTractionArray(const Array<Real> & tractions); /// Compute Linear load function set in local axis template <ElementType type> void computeForcesByLocalTractionArray(const Array<Real> & tractions); /// compute force vector from a function(x,y,momentum) that describe stresses template <ElementType type> void computeForcesFromFunction(BoundaryFunction in_function, BoundaryFunctionType function_type); /** * 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); /// test if the system is converged template<SolveConvergenceCriteria criteria> bool testConvergence(Real tolerance, Real & error); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array<Real> * displacement_rotation; /// displacements array at the previous time step (used in finite deformation) Array<Real> * previous_displacement; /// velocities array Array<Real> * velocity; /// accelerations array Array<Real> * acceleration; /// forces array Array<Real> * force_momentum; /// lumped mass array Array<Real> * mass; /// stress arraz ElementTypeMapArray<Real> stress; /// residuals array Array<Real> * residual; /// boundaries array Array<bool> * blocked_dofs; /// position of a dof in the K matrix Array<Int> * equation_number; ElementTypeMapArray<UInt> element_material; // Define sets of beams ElementTypeMapArray<UInt> set_ID; /// local equation_number to global unordered_map<UInt, UInt>::type local_eq_num_to_global; /// stiffness matrix SparseMatrix * stiffness_matrix; /// mass matrix SparseMatrix * mass_matrix; /// velocity damping matrix SparseMatrix * velocity_damping_matrix; /// jacobian matrix SparseMatrix * jacobian_matrix; /// increment of displacement Array<Real> * increment; /// solver for implicit Solver * solver; /// number of degre of freedom UInt nb_degree_of_freedom; // Rotation matrix ElementTypeMapArray<Real> rotation_matrix; /// analysis method check the list in akantu::AnalysisMethod AnalysisMethod method; /// flag defining if the increment must be computed or not bool increment_flag; /// integration scheme of second order used IntegrationScheme2ndOrder * integrator; /* -------------------------------------------------------------------------- */ std::vector<StructuralMaterial> materials; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model_inline_impl.cc" /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const StructuralMechanicsModel & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ */ diff --git a/src/solver/petsc_matrix.cc b/src/solver/petsc_matrix.cc index 35b40980f..45698bf58 100644 --- a/src/solver/petsc_matrix.cc +++ b/src/solver/petsc_matrix.cc @@ -1,630 +1,636 @@ /** * @file petsc_matrix.cc * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Mon Jul 21 17:40:41 2014 * * @brief Implementation of PETSc matrix class * * @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 "petsc_matrix.hh" #include "static_communicator.hh" #include "static_communicator_mpi.hh" #include "mpi_type_wrapper.hh" #include "dof_synchronizer.hh" #include "petsc_wrapper.hh" /* -------------------------------------------------------------------------- */ #include <cstring> #include <petscsys.h> __BEGIN_AKANTU__ // struct PETScWrapper { // Mat mat; // AO ao; // ISLocalToGlobalMapping mapping; // /// pointer to the MPI communicator for PETSc commands // MPI_Comm communicator; // }; /* -------------------------------------------------------------------------- */ PETScMatrix::PETScMatrix(UInt size, const SparseMatrixType & sparse_matrix_type, const ID & id, const MemoryID & memory_id) : SparseMatrix(size, sparse_matrix_type, id, memory_id), petsc_matrix_wrapper(new PETScMatrixWrapper), d_nnz(0,1,"dnnz"), o_nnz(0,1,"onnz"), first_global_index(0), is_petsc_matrix_initialized(false) { AKANTU_DEBUG_IN(); StaticSolver::getStaticSolver().registerEventHandler(*this); this->offset = 0; this->init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ PETScMatrix::PETScMatrix(const SparseMatrix & matrix, const ID & id, const MemoryID & memory_id) : SparseMatrix(matrix, id, memory_id), petsc_matrix_wrapper(new PETScMatrixWrapper), d_nnz(0,1,"dnnz"), o_nnz(0,1,"onnz"), first_global_index(0), is_petsc_matrix_initialized(false) { // AKANTU_DEBUG_IN(); // StaticSolver::getStaticSolver().registerEventHandler(*this); // this->offset = 0; // this->init(); // AKANTU_DEBUG_OUT(); AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ PETScMatrix::~PETScMatrix() { AKANTU_DEBUG_IN(); /// destroy all the PETSc data structures used for this matrix this->destroyInternalData(); + StaticSolver::getStaticSolver().unregisterEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void PETScMatrix::init() { AKANTU_DEBUG_IN(); /// set the communicator that should be used by PETSc #if defined(AKANTU_USE_MPI) StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); const StaticCommunicatorMPI & mpi_st_comm = dynamic_cast<const StaticCommunicatorMPI &>(comm.getRealStaticCommunicator()); this->petsc_matrix_wrapper->communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator(); #else this->petsc_matrix_wrapper->communicator = PETSC_COMM_SELF; #endif PetscErrorCode ierr; /// create the PETSc matrix object ierr = MatCreate(this->petsc_matrix_wrapper->communicator, &(this->petsc_matrix_wrapper->mat)); CHKERRXX(ierr); /** * Set the matrix type * @todo PETSc does currently not support a straightforward way to * apply Dirichlet boundary conditions for MPISBAIJ * matrices. Therefore always the entire matrix is allocated. It * would be possible to use MATSBAIJ for sequential matrices in case * memory becomes critical. Also, block matrices would give a much * better performance. Modify this in the future! */ ierr = MatSetType(this->petsc_matrix_wrapper->mat, MATAIJ); CHKERRXX(ierr); this->is_petsc_matrix_initialized = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * With this method each processor computes the dimensions of the * local matrix, i.e. the part of the global matrix it is storing. * @param dof_synchronizer dof synchronizer that maps the local * dofs to the global dofs and the equation numbers, i.e., the * position at which the dof is assembled in the matrix */ void PETScMatrix::setSize() { AKANTU_DEBUG_IN(); PetscErrorCode ierr; /// find the number of dofs corresponding to master or local nodes UInt nb_dofs = this->dof_synchronizer->getNbDOFs(); UInt nb_local_master_dofs = 0; /// create array to store the global equation number of all local and master dofs Array<Int> local_master_eq_nbs(nb_dofs); Array<Int>::scalar_iterator it_eq_nb = local_master_eq_nbs.begin(); /// get the pointer to the global equation number array Int * eq_nb_val = this->dof_synchronizer->getGlobalDOFEquationNumbers().storage(); for (UInt i = 0; i <nb_dofs; ++i) { if (this->dof_synchronizer->isLocalOrMasterDOF(i) ) { *it_eq_nb = eq_nb_val[i]; ++it_eq_nb; ++nb_local_master_dofs; } } local_master_eq_nbs.resize(nb_local_master_dofs); /// set the local size this->local_size = nb_local_master_dofs; /// resize PETSc matrix #if defined(AKANTU_USE_MPI) ierr = MatSetSizes(this->petsc_matrix_wrapper->mat, this->local_size, this->local_size, this->size, this->size); CHKERRXX(ierr); #else ierr = MatSetSizes(this->petsc_matrix_wrapper->mat, this->local_size, this->local_size); CHKERRXX(ierr); #endif /// create mapping from akantu global numbering to petsc global numbering this->createGlobalAkantuToPETScMap(local_master_eq_nbs.storage()); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This method generates a mapping from the global Akantu equation * numbering to the global PETSc dof ordering * @param local_master_eq_nbs_ptr Int pointer to the array of equation * numbers of all local or master dofs, i.e. the row indices of the * local matrix */ void PETScMatrix::createGlobalAkantuToPETScMap(Int* local_master_eq_nbs_ptr) { AKANTU_DEBUG_IN(); PetscErrorCode ierr; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt rank = comm.whoAmI(); //initialize vector to store the number of local and master nodes that are assigned to each processor Vector<UInt> master_local_ndofs_per_proc(nb_proc); /// store the nb of master and local dofs on each processor master_local_ndofs_per_proc(rank) = this->local_size; /// exchange the information among all processors comm.allGather(master_local_ndofs_per_proc.storage(), 1); /// each processor creates a map for his akantu global dofs to the corresponding petsc global dofs /// determine the PETSc-index for the first dof on each processor for (UInt i = 0; i < rank; ++i) { this->first_global_index += master_local_ndofs_per_proc(i); } /// create array for petsc ordering Array<Int> petsc_dofs(this->local_size); Array<Int>::scalar_iterator it_petsc_dofs = petsc_dofs.begin(); for (Int i = this->first_global_index; i < this->first_global_index + this->local_size; ++i, ++it_petsc_dofs) { *it_petsc_dofs = i; } ierr = AOCreateBasic(this->petsc_matrix_wrapper->communicator, this->local_size, local_master_eq_nbs_ptr, petsc_dofs.storage(), &(this->petsc_matrix_wrapper->ao)); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ // void PETScMatrix::createLocalAkantuToPETScMap(const DOFSynchronizer & dof_synchronizer) { // AKANTU_DEBUG_IN(); // AKANTU_DEBUG_ASSERT(this->petsc_matrix_wrapper->ao != NULL, // "You should first create a mapping from the global" // << " Akantu numbering to the global PETSc numbering"); // PetscErrorCode ierr; // this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer); // /// get the number of dofs // Int nb_dofs = dof_synchronizer.getNbDOFs(); // /// get the global equation numbers for each node // Array<Int> global_dof_equation_numbers = dof_synchronizer.getGlobalDOFEquationNumbers(); // /// map the global dof equation numbers to the corresponding PETSc ordering // ierr = AOApplicationToPETSc(this->petsc_matrix_wrapper->ao, nb_dofs, // global_dof_equation_numbers.storage()); CHKERRXX(ierr); // /// create the mapping from the local Akantu ordering to the global PETSc ordering // ierr = ISLocalToGlobalMappingCreate(this->petsc_matrix_wrapper->communicator, // 1, nb_dofs, global_dof_equation_numbers.storage(), // PETSC_COPY_VALUES, &(this->petsc_matrix_wrapper-mapping)); CHKERRXX(ierr); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ /** * This function creates the non-zero pattern of the PETSc matrix. In * PETSc the parallel matrix is partitioned across processors such * that the first m0 rows belong to process 0, the next m1 rows belong * to process 1, the next m2 rows belong to process 2 etc.. where * m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores * values corresponding to [m x N] submatrix * (http://www.mcs.anl.gov/petsc/). * @param mesh mesh discretizing the domain we want to analyze * @param dof_synchronizer dof synchronizer that maps the local * dofs to the global dofs and the equation numbers, i.e., the * position at which the dof is assembled in the matrix */ void PETScMatrix::buildProfile(const Mesh & mesh, const DOFSynchronizer & dof_synchronizer, UInt nb_degree_of_freedom) { AKANTU_DEBUG_IN(); //clearProfile(); this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer); this->setSize(); PetscErrorCode ierr; /// resize arrays to store the number of nonzeros in each row this->d_nnz.resize(this->local_size); this->o_nnz.resize(this->local_size); /// set arrays to zero everywhere this->d_nnz.set(0); this->o_nnz.set(0); // if(irn_jcn_to_k) delete irn_jcn_to_k; // irn_jcn_to_k = new std::map<std::pair<UInt, UInt>, UInt>; coordinate_list_map::iterator irn_jcn_k_it; Int * eq_nb_val = dof_synchronizer.getGlobalDOFEquationNumbers().storage(); UInt nb_global_dofs = dof_synchronizer.getNbGlobalDOFs(); + Array<Int> index_pair(2); /// Loop over all the ghost types for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { const GhostType & ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(mesh.getSpatialDimension(), ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType (mesh.getSpatialDimension(), ghost_type, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom; UInt * conn_val = mesh.getConnectivity(*it, ghost_type).storage(); Int * local_eq_nb_val = new Int[nb_degree_of_freedom * nb_nodes_per_element]; for (UInt e = 0; e < nb_element; ++e) { Int * tmp_local_eq_nb_val = local_eq_nb_val; for (UInt i = 0; i < nb_nodes_per_element; ++i) { UInt n = conn_val[i]; for (UInt d = 0; d < nb_degree_of_freedom; ++d) { /** * !!!!!!Careful!!!!!! This is a ugly fix. @todo this is a * very ugly fix, because the offset for the global * equation number, where the dof will be assembled, is * hardcoded. In the future a class dof manager has to be * added to Akantu to handle the mapping between the dofs * and the equation numbers * */ *tmp_local_eq_nb_val++ = eq_nb_val[n * nb_degree_of_freedom + d] - (dof_synchronizer.isPureGhostDOF(n * nb_degree_of_freedom + d) ? nb_global_dofs : 0); } } for (UInt i = 0; i < size_mat; ++i) { Int c_irn = local_eq_nb_val[i]; UInt j_start = 0; for (UInt j = j_start; j < size_mat; ++j) { Int c_jcn = local_eq_nb_val[j]; - Array<Int> index_pair(2,1); index_pair(0) = c_irn; index_pair(1) = c_jcn; AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index_pair.storage()); if (index_pair(0) >= first_global_index && index_pair(0) < first_global_index + this->local_size) { KeyCOO irn_jcn = keyPETSc(c_irn, c_jcn); irn_jcn_k_it = irn_jcn_k.find(irn_jcn); if (irn_jcn_k_it == irn_jcn_k.end()) { irn_jcn_k[irn_jcn] = nb_non_zero; // check if node is slave node if (index_pair(1) >= first_global_index && index_pair(1) < first_global_index + this->local_size) this->d_nnz(index_pair(0) - first_global_index) += 1; else this->o_nnz(index_pair(0) - first_global_index) += 1; nb_non_zero++; } } } } conn_val += nb_nodes_per_element; } delete [] local_eq_nb_val; } } // /// for pbc @todo correct it for parallel // if(StaticCommunicator::getStaticCommunicator().getNbProc() == 1) { // for (UInt i = 0; i < size; ++i) { // KeyCOO irn_jcn = key(i, i); // irn_jcn_k_it = irn_jcn_k.find(irn_jcn); // if(irn_jcn_k_it == irn_jcn_k.end()) { // irn_jcn_k[irn_jcn] = nb_non_zero; // irn.push_back(i + 1); // jcn.push_back(i + 1); // nb_non_zero++; // } // } // } // std::string mat_type; // mat_type.resize(20, 'a'); // std::cout << "MatType: " << mat_type << std::endl; // const char * mat_type_ptr = mat_type.c_str(); MatType type; MatGetType(this->petsc_matrix_wrapper->mat, &type); - std::cout << "the matrix type is: " << type << std::endl; + /// std::cout << "the matrix type is: " << type << std::endl; /** * PETSc will use only one of the following preallocation commands * depending on the matrix type and ignore the rest. Note that for * the block matrix format a block size of 1 is used. This might * result in bad performance. @todo For better results implement * buildProfile() with larger block size. * */ /// build profile: if (strcmp(type, MATSEQAIJ) == 0) { ierr = MatSeqAIJSetPreallocation(this->petsc_matrix_wrapper->mat, 0, d_nnz.storage()); CHKERRXX(ierr); } else if ((strcmp(type, MATMPIAIJ) == 0)) { ierr = MatMPIAIJSetPreallocation(this->petsc_matrix_wrapper->mat, 0, d_nnz.storage(), 0, o_nnz.storage()); CHKERRXX(ierr); } else { AKANTU_DEBUG_ERROR("The type " << type << " of PETSc matrix is not handled by" << " akantu in the preallocation step"); } //ierr = MatSeqSBAIJSetPreallocation(this->petsc_matrix_wrapper->mat, 1, // 0, d_nnz.storage()); CHKERRXX(ierr); if (this->sparse_matrix_type==_symmetric) { /// set flag for symmetry to enable ICC/Cholesky preconditioner ierr = MatSetOption(this->petsc_matrix_wrapper->mat, MAT_SYMMETRIC, PETSC_TRUE); CHKERRXX(ierr); /// set flag for symmetric positive definite ierr = MatSetOption(this->petsc_matrix_wrapper->mat, MAT_SPD, PETSC_TRUE); CHKERRXX(ierr); } /// once the profile has been build ignore any new nonzero locations ierr = MatSetOption(this->petsc_matrix_wrapper->mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_TRUE); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Method to save the nonzero pattern and the values stored at each position * @param filename name of the file in which the information will be stored */ void PETScMatrix::saveMatrix(const std::string & filename) const{ AKANTU_DEBUG_IN(); PetscErrorCode ierr; /// create Petsc viewer PetscViewer viewer; ierr = PetscViewerASCIIOpen(this->petsc_matrix_wrapper->communicator, filename.c_str(), &viewer); CHKERRXX(ierr); /// set the format PetscViewerSetFormat(viewer, PETSC_VIEWER_DEFAULT); CHKERRXX(ierr); /// save the matrix + /// @todo Write should be done in serial -> might cause problems ierr = MatView(this->petsc_matrix_wrapper->mat, viewer); CHKERRXX(ierr); /// destroy the viewer ierr = PetscViewerDestroy(&viewer); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Method to add an Akantu sparse matrix to the PETSc matrix * @param matrix Akantu sparse matrix to be added * @param alpha the factor specifying how many times the matrix should be added */ void PETScMatrix::add(const SparseMatrix & matrix, Real alpha) { PetscErrorCode ierr; // AKANTU_DEBUG_ASSERT(nb_non_zero == matrix.getNbNonZero(), // "The two matrix don't have the same profiles"); + Real val_to_add = 0; + Array<Int> index(2); for (UInt n = 0; n < matrix.getNbNonZero(); ++n) { - Array<Int> index(2,1); - index(0) = matrix.getIRN()(n)-matrix.getOffset(); - index(1) = matrix.getJCN()(n)-matrix.getOffset(); + UInt mat_to_add_offset = matrix.getOffset(); + index(0) = matrix.getIRN()(n)-mat_to_add_offset; + index(1) = matrix.getJCN()(n)-mat_to_add_offset; AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index.storage()); if (this->sparse_matrix_type == _symmetric && index(0) > index(1)) std::swap(index(0), index(1)); + + val_to_add = matrix.getA()(n) * alpha; /// MatSetValue might be very slow for MATBAIJ, might need to use MatSetValuesBlocked - ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(0), index(1), matrix.getA()(n) * alpha, ADD_VALUES); CHKERRXX(ierr); + ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(0), index(1), val_to_add, ADD_VALUES); CHKERRXX(ierr); /// chek if sparse matrix to be added is symmetric. In this case /// the value also needs to be added at the transposed location in /// the matrix because PETSc is using the full profile, also for symmetric matrices if (matrix.getSparseMatrixType() == _symmetric && index(0) != index(1)) - ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(1), index(0), matrix.getA()(n) * alpha, ADD_VALUES); CHKERRXX(ierr); + ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(1), index(0), val_to_add, ADD_VALUES); CHKERRXX(ierr); } this->performAssembly(); } /* -------------------------------------------------------------------------- */ /** * Method to add another PETSc matrix to this PETSc matrix * @param matrix PETSc matrix to be added * @param alpha the factor specifying how many times the matrix should be added */ void PETScMatrix::add(const PETScMatrix & matrix, Real alpha) { PetscErrorCode ierr; ierr = MatAXPY(this->petsc_matrix_wrapper->mat, alpha, matrix.petsc_matrix_wrapper->mat, SAME_NONZERO_PATTERN); CHKERRXX(ierr); this->performAssembly(); } /* -------------------------------------------------------------------------- */ /** * MatSetValues() generally caches the values. The matrix is ready to * use only after MatAssemblyBegin() and MatAssemblyEnd() have been * called. (http://www.mcs.anl.gov/petsc/) */ void PETScMatrix::performAssembly() { PetscErrorCode ierr; ierr = MatAssemblyBegin(this->petsc_matrix_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr); ierr = MatAssemblyEnd(this->petsc_matrix_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr); } /* -------------------------------------------------------------------------- */ /** * Method is called when the static solver is destroyed, just before * PETSc is finalized. So all PETSc objects need to be destroyed at * this point. */ void PETScMatrix::beforeStaticSolverDestroy() { AKANTU_DEBUG_IN(); try{ this->destroyInternalData(); } catch(...) {} AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// destroy all the PETSc data structures used for this matrix void PETScMatrix::destroyInternalData() { AKANTU_DEBUG_IN(); if(this->is_petsc_matrix_initialized) { PetscErrorCode ierr; ierr = MatDestroy(&(this->petsc_matrix_wrapper->mat)); CHKERRXX(ierr); delete petsc_matrix_wrapper; this->is_petsc_matrix_initialized = false; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// access K(i, j). Works only for dofs on this processor!!!! Real PETScMatrix::operator()(UInt i, UInt j) const{ AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(this->dof_synchronizer->isLocalOrMasterDOF(i) && this->dof_synchronizer->isLocalOrMasterDOF(j), "Operator works only for dofs on this processor"); Array<Int> index(2,1); index(0) = this->dof_synchronizer->getDOFGlobalID(i); index(1) = this->dof_synchronizer->getDOFGlobalID(j); AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index.storage()); Real value = 0; PetscErrorCode ierr; /// @todo MatGetValue might be very slow for MATBAIJ, might need to use MatGetValuesBlocked ierr = MatGetValues(this->petsc_matrix_wrapper->mat, 1, &index(0), 1, &index(1), &value); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); return value; } /* -------------------------------------------------------------------------- */ /** * Apply Dirichlet boundary conditions by zeroing the rows and columns which correspond to blocked dofs * @param boundary array of booleans which are true if the dof at this position is blocked * @param block_val the value in the diagonal entry of blocked rows */ void PETScMatrix::applyBoundary(const Array<bool> & boundary, Real block_val) { AKANTU_DEBUG_IN(); PetscErrorCode ierr; /// get the global equation numbers to find the rows that need to be zeroed for the blocked dofs Int * eq_nb_val = dof_synchronizer->getGlobalDOFEquationNumbers().storage(); /// every processor calls the MatSetZero() only for his local or master dofs. This assures that not two processors or more try to zero the same row - Int nb_blocked_local_master_eq_nb = 0; - Array<Int> blocked_local_master_eq_nb(this->local_size / boundary.getNbComponent(), boundary.getNbComponent()); - Int * blocked_lm_eq_nb_ptr = blocked_local_master_eq_nb.storage(); UInt nb_component = boundary.getNbComponent(); UInt size = boundary.getSize(); + Int nb_blocked_local_master_eq_nb = 0; + Array<Int> blocked_local_master_eq_nb(this->local_size); + Int * blocked_lm_eq_nb_ptr = blocked_local_master_eq_nb.storage(); for (UInt i = 0; i < size; ++i) { for (UInt j = 0; j < nb_component; ++j) { UInt local_dof = i * nb_component + j; if (boundary(i, j) == true && this->dof_synchronizer->isLocalOrMasterDOF(local_dof)) { Int global_eq_nb = *eq_nb_val; *blocked_lm_eq_nb_ptr = global_eq_nb; ++nb_blocked_local_master_eq_nb; ++blocked_lm_eq_nb_ptr; } ++eq_nb_val; } } - blocked_local_master_eq_nb.resize(nb_blocked_local_master_eq_nb/boundary.getNbComponent()); + blocked_local_master_eq_nb.resize(nb_blocked_local_master_eq_nb); ierr = AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, nb_blocked_local_master_eq_nb, blocked_local_master_eq_nb.storage() ); CHKERRXX(ierr); ierr = MatZeroRowsColumns(this->petsc_matrix_wrapper->mat, nb_blocked_local_master_eq_nb, blocked_local_master_eq_nb.storage(), block_val, 0, 0); CHKERRXX(ierr); this->performAssembly(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// set all entries to zero while keeping the same nonzero pattern void PETScMatrix::clear() { MatZeroEntries(this->petsc_matrix_wrapper->mat); } __END_AKANTU__ diff --git a/src/solver/solver.cc b/src/solver/solver.cc index 7d9d4746e..2cb5865f9 100644 --- a/src/solver/solver.cc +++ b/src/solver/solver.cc @@ -1,87 +1,88 @@ /** * @file solver.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 * @date last modification: Wed Nov 13 2013 * * @brief Solver interface 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 "solver.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ SolverOptions _solver_no_options(true); /* -------------------------------------------------------------------------- */ Solver::Solver(SparseMatrix & matrix, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), StaticSolverEventHandler(), matrix(&matrix), is_matrix_allocated(false), mesh(NULL), communicator(StaticCommunicator::getStaticCommunicator()), solution(NULL), synch_registry(NULL) { AKANTU_DEBUG_IN(); StaticSolver::getStaticSolver().registerEventHandler(*this); //createSynchronizerRegistry(); this->synch_registry = new SynchronizerRegistry(*this); synch_registry->registerSynchronizer(this->matrix->getDOFSynchronizer(), _gst_solver_solution); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Solver::~Solver() { AKANTU_DEBUG_IN(); this->destroyInternalData(); delete synch_registry; + StaticSolver::getStaticSolver().unregisterEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Solver::beforeStaticSolverDestroy() { AKANTU_DEBUG_IN(); try{ this->destroyInternalData(); } catch(...) {} AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Solver::createSynchronizerRegistry() { //this->synch_registry = new SynchronizerRegistry(this); } __END_AKANTU__ diff --git a/src/solver/solver_mumps.cc b/src/solver/solver_mumps.cc index 727cfcc15..970001120 100644 --- a/src/solver/solver_mumps.cc +++ b/src/solver/solver_mumps.cc @@ -1,383 +1,383 @@ /** * @file solver_mumps.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 * @date last modification: Mon Sep 15 2014 * * @brief implem of SolverMumps 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/>. * * @section DESCRIPTION * * @subsection Ctrl_param Control parameters * * ICNTL(1), * ICNTL(2), * ICNTL(3) : output streams for error, diagnostics, and global messages * * ICNTL(4) : verbose level : 0 no message - 4 all messages * * ICNTL(5) : type of matrix, 0 assembled, 1 elementary * * ICNTL(6) : control the permutation and scaling(default 7) see mumps doc for * more information * * ICNTL(7) : determine the pivot order (default 7) see mumps doc for more * information * * ICNTL(8) : describe the scaling method used * * ICNTL(9) : 1 solve A x = b, 0 solve At x = b * * ICNTL(10) : number of iterative refinement when NRHS = 1 * * ICNTL(11) : > 0 return statistics * * ICNTL(12) : only used for SYM = 2, ordering strategy * * ICNTL(13) : * * ICNTL(14) : percentage of increase of the estimated working space * * ICNTL(15-17) : not used * * ICNTL(18) : only used if ICNTL(5) = 0, 0 matrix centralized, 1 structure on * host and mumps give the mapping, 2 structure on host and distributed matrix * for facto, 3 distributed matrix * * ICNTL(19) : > 0, Shur complement returned * * ICNTL(20) : 0 rhs dense, 1 rhs sparse * * ICNTL(21) : 0 solution in rhs, 1 solution distributed in ISOL_loc and SOL_loc * allocated by user * * ICNTL(22) : 0 in-core, 1 out-of-core * * ICNTL(23) : maximum memory allocatable by mumps pre proc * * ICNTL(24) : controls the detection of "null pivot rows" * * ICNTL(25) : * * ICNTL(26) : * * ICNTL(27) : * * ICNTL(28) : 0 automatic choice, 1 sequential analysis, 2 parallel analysis * * ICNTL(29) : 0 automatic choice, 1 PT-Scotch, 2 ParMetis */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #if defined(AKANTU_USE_MPI) # include "static_communicator_mpi.hh" # include "mpi_type_wrapper.hh" #endif #include "solver_mumps.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ // static std::ostream & operator <<(std::ostream & stream, const DMUMPS_STRUC_C & _this) { // stream << "DMUMPS Data [" << std::endl; // stream << " + job : " << _this.job << std::endl; // stream << " + par : " << _this.par << std::endl; // stream << " + sym : " << _this.sym << std::endl; // stream << " + comm_fortran : " << _this.comm_fortran << std::endl; // stream << " + nz : " << _this.nz << std::endl; // stream << " + irn : " << _this.irn << std::endl; // stream << " + jcn : " << _this.jcn << std::endl; // stream << " + nz_loc : " << _this.nz_loc << std::endl; // stream << " + irn_loc : " << _this.irn_loc << std::endl; // stream << " + jcn_loc : " << _this.jcn_loc << std::endl; // stream << "]"; // return stream; // } __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ SolverMumps::SolverMumps(SparseMatrix & matrix, const ID & id, const MemoryID & memory_id) : Solver(matrix, id, memory_id), is_mumps_data_initialized(false), rhs_is_local(true) { AKANTU_DEBUG_IN(); #ifdef AKANTU_USE_MPI parallel_method = SolverMumpsOptions::_fully_distributed; #else //AKANTU_USE_MPI parallel_method = SolverMumpsOptions::_not_parallel; #endif //AKANTU_USE_MPI AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolverMumps::~SolverMumps() { } /* -------------------------------------------------------------------------- */ void SolverMumps::destroyInternalData() { AKANTU_DEBUG_IN(); if(this->is_mumps_data_initialized) { this->mumps_data.job = _smj_destroy; // destroy dmumps_c(&this->mumps_data); this->is_mumps_data_initialized = false; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverMumps::initMumpsData() { // Default Scaling icntl(8) = 77; // Assembled matrix icntl(5) = 0; /// Default centralized dense second member icntl(20) = 0; icntl(21) = 0; icntl(28) = 0; //automatic choice for analysis analysis switch(this->parallel_method) { case SolverMumpsOptions::_fully_distributed: icntl(18) = 3; //fully distributed this->mumps_data.nz_loc = matrix->getNbNonZero(); this->mumps_data.irn_loc = matrix->getIRN().storage(); this->mumps_data.jcn_loc = matrix->getJCN().storage(); break; case SolverMumpsOptions::_not_parallel: case SolverMumpsOptions::_master_slave_distributed: icntl(18) = 0; //centralized if(prank == 0) { this->mumps_data.nz = matrix->getNbNonZero(); this->mumps_data.irn = matrix->getIRN().storage(); this->mumps_data.jcn = matrix->getJCN().storage(); } else { this->mumps_data.nz = 0; this->mumps_data.irn = NULL; this->mumps_data.jcn = NULL; } break; default: AKANTU_DEBUG_ERROR("This case should not happen!!"); } } /* -------------------------------------------------------------------------- */ void SolverMumps::initialize(SolverOptions & options) { AKANTU_DEBUG_IN(); if(SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions *>(&options)) { this->parallel_method = opt->parallel_method; } this->mumps_data.par = 1; // The host is part of computations switch(this->parallel_method) { case SolverMumpsOptions::_not_parallel: break; case SolverMumpsOptions::_master_slave_distributed: this->mumps_data.par = 0; // The host is not part of the computations case SolverMumpsOptions::_fully_distributed: #ifdef AKANTU_USE_MPI const StaticCommunicatorMPI & mpi_st_comm = dynamic_cast<const StaticCommunicatorMPI &>(communicator.getRealStaticCommunicator()); this->mumps_data.comm_fortran = MPI_Comm_c2f(mpi_st_comm.getMPITypeWrapper().getMPICommunicator()); #endif break; } this->mumps_data.sym = 2 * (matrix->getSparseMatrixType() == _symmetric); this->prank = communicator.whoAmI(); this->mumps_data.job = _smj_initialize; //initialize dmumps_c(&this->mumps_data); this->is_mumps_data_initialized = true; /* ------------------------------------------------------------------------ */ UInt size = matrix->getSize(); if(prank == 0) { std::stringstream sstr_rhs; sstr_rhs << id << ":rhs"; this->rhs = &(alloc<Real>(sstr_rhs.str(), size, 1, 0.)); } else { this->rhs = NULL; } this->mumps_data.nz_alloc = 0; this->mumps_data.n = size; /* ------------------------------------------------------------------------ */ // Output setup if(AKANTU_DEBUG_TEST(dblTrace)) { icntl(1) = 6; icntl(2) = 2; icntl(3) = 2; icntl(4) = 4; } else { /// No outputs icntl(1) = 6; // error output icntl(2) = 0; // dignostics output icntl(3) = 0; // informations icntl(4) = 0; // no outputs } if(AKANTU_DEBUG_TEST(dblDump)) { strcpy(this->mumps_data.write_problem, "mumps_matrix.mtx"); } this->analysis(); // icntl(14) = 80; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverMumps::setRHS(Array<Real> & rhs) { if(prank == 0) { //std::copy(rhs.storage(), rhs.storage() + this->rhs->getSize(), this->rhs->storage()); DebugLevel dbl = debug::getDebugLevel(); debug::setDebugLevel(dblError); matrix->getDOFSynchronizer().gather(rhs, 0, this->rhs); debug::setDebugLevel(dbl); } else { this->matrix->getDOFSynchronizer().gather(rhs, 0); } } /* -------------------------------------------------------------------------- */ void SolverMumps::analysis() { AKANTU_DEBUG_IN(); initMumpsData(); this->mumps_data.job = _smj_analyze; //analyze dmumps_c(&this->mumps_data); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverMumps::factorize() { AKANTU_DEBUG_IN(); if(parallel_method == SolverMumpsOptions::_fully_distributed) this->mumps_data.a_loc = this->matrix->getA().storage(); else { if(prank == 0) this->mumps_data.a = this->matrix->getA().storage(); } if(prank == 0) { this->mumps_data.rhs = this->rhs->storage(); } this->mumps_data.job = _smj_factorize; // factorize dmumps_c(&this->mumps_data); this->printError(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverMumps::solve() { AKANTU_DEBUG_IN(); if(prank == 0) { this->mumps_data.rhs = this->rhs->storage(); } this->mumps_data.job = _smj_solve; // solve dmumps_c(&this->mumps_data); this->printError(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverMumps::solve(Array<Real> & solution) { AKANTU_DEBUG_IN(); this->solve(); if(prank == 0) { matrix->getDOFSynchronizer().scatter(solution, 0, this->rhs); // std::copy(this->rhs->storage(), this->rhs->storage() + this->rhs->getSize(), solution.storage()); } else { this->matrix->getDOFSynchronizer().scatter(solution, 0); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverMumps::printError() { - UInt _info_v[2]; + Int _info_v[2]; _info_v[0] = info(1); // to get errors _info_v[1] = -info(1); // to get warnings communicator.allReduce(_info_v, 2, _so_min); _info_v[1] = -_info_v[1]; if(_info_v[0] < 0) { // < 0 is an error switch(_info_v[0]) { case -10: AKANTU_DEBUG_ERROR("The matrix is singular"); break; case -9: { icntl(14) += 10; if(icntl(14) != 90) { //std::cout << "Dynamic memory increase of 10%" << std::endl; AKANTU_DEBUG_WARNING("MUMPS dynamic memory is insufficient it will be increased of 10%"); this->analysis(); this->factorize(); this->solve(); } else { AKANTU_DEBUG_ERROR("The MUMPS workarray is too small INFO(2)=" << info(2) << "No further increase possible"); break; } } default: AKANTU_DEBUG_ERROR("Error in mumps during solve process, check mumps user guide INFO(1) = " << _info_v[1]); } } else if (_info_v[1] > 0) { AKANTU_DEBUG_WARNING("Warning in mumps during solve process, check mumps user guide INFO(1) = " << _info_v[1]); } } __END_AKANTU__ diff --git a/src/solver/solver_petsc.cc b/src/solver/solver_petsc.cc index dc9f44e7b..635c10ae6 100644 --- a/src/solver/solver_petsc.cc +++ b/src/solver/solver_petsc.cc @@ -1,1106 +1,1109 @@ /** * @file solver_petsc.cc * * @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 Dec 13 10:48:06 2010 * * @brief Solver class implementation for the petsc solver * * @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 <petscksp.h> #include "solver_petsc.hh" #include "petsc_wrapper.hh" #include "petsc_matrix.hh" #include "static_communicator.hh" #include "static_communicator_mpi.hh" #include "mpi_type_wrapper.hh" #include "dof_synchronizer.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ SolverPETSc::SolverPETSc(SparseMatrix & matrix, const ID & id, const MemoryID & memory_id) : Solver(matrix, id, memory_id), is_petsc_data_initialized(false), petsc_solver_wrapper(new PETScSolverWrapper) { } /* -------------------------------------------------------------------------- */ SolverPETSc::~SolverPETSc() { AKANTU_DEBUG_IN(); this->destroyInternalData(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::destroyInternalData() { AKANTU_DEBUG_IN(); if(this->is_petsc_data_initialized) { PetscErrorCode ierr; ierr = KSPDestroy(&(this->petsc_solver_wrapper->ksp)); CHKERRXX(ierr); ierr = VecDestroy(&(this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr); ierr = VecDestroy(&(this->petsc_solver_wrapper->solution)); CHKERRXX(ierr); delete petsc_solver_wrapper; this->is_petsc_data_initialized = false; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::initialize(SolverOptions & options) { AKANTU_DEBUG_IN(); #if defined(AKANTU_USE_MPI) StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); const StaticCommunicatorMPI & mpi_st_comm = dynamic_cast<const StaticCommunicatorMPI &>(comm.getRealStaticCommunicator()); this->petsc_solver_wrapper->communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator(); #else this->petsc_solver_wrapper->communicator = PETSC_COMM_SELF; #endif PetscErrorCode ierr; PETScMatrix * petsc_matrix = static_cast<PETScMatrix*>(this->matrix); /// create a solver context ierr = KSPCreate(this->petsc_solver_wrapper->communicator, &(this->petsc_solver_wrapper->ksp)); CHKERRXX(ierr); + /// create the PETSc vector for the right-hand side ierr = VecCreate(this->petsc_solver_wrapper->communicator, &(this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr); ierr = VecSetSizes((this->petsc_solver_wrapper->rhs), petsc_matrix->getLocalSize(), petsc_matrix->getSize()); CHKERRXX(ierr); ierr = VecSetFromOptions((this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr); + /// create the PETSc vector for the solution ierr = VecDuplicate((this->petsc_solver_wrapper->rhs), &(this->petsc_solver_wrapper->solution)); CHKERRXX(ierr); + /// set the solution to zero ierr = VecZeroEntries(this->petsc_solver_wrapper->solution); this->is_petsc_data_initialized = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::setRHS(Array<Real> & rhs) { PetscErrorCode ierr; PETScMatrix * petsc_matrix = static_cast<PETScMatrix*>(this->matrix); UInt nb_component = rhs.getNbComponent(); UInt size = rhs.getSize(); for (UInt i = 0; i < size; ++i) { for (UInt j = 0; j < nb_component; ++j) { UInt i_local = i * nb_component + j; if (this->matrix->getDOFSynchronizer().isLocalOrMasterDOF(i_local)) { Int i_global = this->matrix->getDOFSynchronizer().getDOFGlobalID(i_local); AOApplicationToPetsc(petsc_matrix->getPETScMatrixWrapper()->ao, 1, &(i_global) ); ierr = VecSetValue((this->petsc_solver_wrapper->rhs), i_global, rhs(i,j), INSERT_VALUES); CHKERRXX(ierr); } } } ierr = VecAssemblyBegin(this->petsc_solver_wrapper->rhs); CHKERRXX(ierr); ierr = VecAssemblyEnd(this->petsc_solver_wrapper->rhs); CHKERRXX(ierr); /// ierr = VecCopy((this->petsc_solver_wrapper->rhs), (this->petsc_solver_wrapper->solution)); CHKERRXX(ierr); } /* -------------------------------------------------------------------------- */ void SolverPETSc::solve() { AKANTU_DEBUG_IN(); PetscErrorCode ierr; ierr = KSPSolve(this->petsc_solver_wrapper->ksp, this->petsc_solver_wrapper->rhs, this->petsc_solver_wrapper->solution); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::solve(Array<Real> & solution) { AKANTU_DEBUG_IN(); this->solution = &solution; this->solve(); PetscErrorCode ierr; PETScMatrix * petsc_matrix = static_cast<PETScMatrix*>(this->matrix); // ierr = VecGetOwnershipRange(this->petsc_solver_wrapper->solution, solution_begin, solution_end); CHKERRXX(ierr); // ierr = VecGetArray(this->petsc_solver_wrapper->solution, PetscScalar **array); CHKERRXX(ierr); UInt nb_component = solution.getNbComponent(); UInt size = solution.getSize(); for (UInt i = 0; i < size; ++i) { for (UInt j = 0; j < nb_component; ++j) { UInt i_local = i * nb_component + j; if (this->matrix->getDOFSynchronizer().isLocalOrMasterDOF(i_local)) { Int i_global = this->matrix->getDOFSynchronizer().getDOFGlobalID(i_local); ierr = AOApplicationToPetsc(petsc_matrix->getPETScMatrixWrapper()->ao, 1, &(i_global) ); CHKERRXX(ierr); ierr = VecGetValues(this->petsc_solver_wrapper->solution, 1, &i_global, &solution(i,j)); CHKERRXX(ierr); } } } synch_registry->synchronize(_gst_solver_solution); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolverPETSc::setOperators() { AKANTU_DEBUG_IN(); PetscErrorCode ierr; /// set the matrix that defines the linear system and the matrix for preconditioning (here they are the same) PETScMatrix * petsc_matrix = static_cast<PETScMatrix*>(this->matrix); #if PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 5 ierr = KSPSetOperators(this->petsc_solver_wrapper->ksp, petsc_matrix->getPETScMatrixWrapper()->mat, petsc_matrix->getPETScMatrixWrapper()->mat); CHKERRXX(ierr); #else ierr = KSPSetOperators(this->petsc_solver_wrapper->ksp, petsc_matrix->getPETScMatrixWrapper()->mat, petsc_matrix->getPETScMatrixWrapper()->mat, SAME_NONZERO_PATTERN); CHKERRXX(ierr); #endif /// If this is not called the solution vector is zeroed in the call to KSPSolve(). ierr = KSPSetInitialGuessNonzero(this->petsc_solver_wrapper->ksp, PETSC_TRUE); KSPSetFromOptions(this->petsc_solver_wrapper->ksp); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ // void finalize_petsc() { // static bool finalized = false; // if (!finalized) { // cout<<"*** INFO *** PETSc is finalizing..."<<endl; // // finalize PETSc // PetscErrorCode ierr = PetscFinalize();CHKERRCONTINUE(ierr); // finalized = true; // } // } // SolverPETSc::sparse_vector_type // SolverPETSc::operator()(const SolverPETSc::sparse_matrix_type& AA, // const SolverPETSc::sparse_vector_type& bb) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside PETSc solver: "<<timer<<endl; // #endif // #ifdef CPPUTILS_VERBOSE // out<<" Inside operator()(const sparse_matrix_type&, const sparse_vector_type&)... "<<timer<<endl; // #endif // assert(AA.rows() == bb.size()); // // KSP ksp; //!< linear solver context // Vec b; /* RHS */ // PC pc; /* preconditioner context */ // PetscErrorCode ierr; // PetscInt nlocal; // PetscInt n = bb.size(); // VecScatter ctx; // /* // Create vectors. Note that we form 1 vector from scratch and // then duplicate as needed. For this simple case let PETSc decide how // many elements of the vector are stored on each processor. The second // argument to VecSetSizes() below causes PETSc to decide. // */ // ierr = VecCreate(PETSC_COMM_WORLD,&b);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(b,PETSC_DECIDE,n);CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(b);CHKERRCONTINUE(ierr); // if (!allocated_) { // ierr = VecDuplicate(b,&x_);CHKERRCONTINUE(ierr); // } else // VecZeroEntries(x_); // #ifdef CPPUTILS_VERBOSE // out<<" Vectors created... "<<timer<<endl; // #endif // /* Set hight-hand-side vector */ // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(b, 1, &row, &it->second, ADD_VALUES); // } // #ifdef CPPUTILS_VERBOSE // out<<" Right hand side set... "<<timer<<endl; // #endif // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(b);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(b);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Right-hand-side vector assembled... "<<timer<<endl; // ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // Vec b_all; // ierr = VecScatterCreateToAll(b, &ctx, &b_all);CHKERRCONTINUE(ierr); // ierr = VecScatterBegin(ctx,b,b_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // ierr = VecScatterEnd(ctx,b,b_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // value_type nrm; // VecNorm(b_all,NORM_2,&nrm); // out<<" Norm of right hand side... "<<nrm<<endl; // #endif // /* Identify the starting and ending mesh points on each // processor for the interior part of the mesh. We let PETSc decide // above. */ // // PetscInt rstart,rend; // // ierr = VecGetOwnershipRange(x_,&rstart,&rend);CHKERRCONTINUE(ierr); // ierr = VecGetLocalSize(x_,&nlocal);CHKERRCONTINUE(ierr); // /* // Create matrix. When using MatCreate(), the matrix format can // be specified at runtime. // Performance tuning note: For problems of substantial size, // preallocation of matrix memory is crucial for attaining good // performance. See the matrix chapter of the users manual for details. // We pass in nlocal as the "local" size of the matrix to force it // to have the same parallel layout as the vector created above. // */ // if (!allocated_) { // ierr = MatCreate(PETSC_COMM_WORLD,&A_);CHKERRCONTINUE(ierr); // ierr = MatSetSizes(A_,nlocal,nlocal,n,n);CHKERRCONTINUE(ierr); // ierr = MatSetFromOptions(A_);CHKERRCONTINUE(ierr); // ierr = MatSetUp(A_);CHKERRCONTINUE(ierr); // } else { // // zero-out matrix // MatZeroEntries(A_); // } // /* // Assemble matrix. // The linear system is distributed across the processors by // chunks of contiguous rows, which correspond to contiguous // sections of the mesh on which the problem is discretized. // For matrix assembly, each processor contributes entries for // the part that it owns locally. // */ // #ifdef CPPUTILS_VERBOSE // out<<" Zeroed-out sparse matrix entries... "<<timer<<endl; // #endif // for (sparse_matrix_type::const_hash_iterator it = AA.map_.begin(); it != AA.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = AA.unhash(it->first); // PetscInt row = subs.first; // PetscInt col = subs.second; // ierr = MatSetValues(A_, 1, &row, 1, &col, &it->second, ADD_VALUES);CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Filled sparse matrix... "<<timer<<endl; // #endif // /* Assemble the matrix */ // ierr = MatAssemblyBegin(A_,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(A_,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // if (!allocated_) { // // set after the first MatAssemblyEnd // // ierr = MatSetOption(A_, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);CHKERRCONTINUE(ierr); // ierr = MatSetOption(A_, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Sparse matrix assembled... "<<timer<<endl; // // view matrix // MatView(A_, PETSC_VIEWER_STDOUT_WORLD); // MatNorm(A_,NORM_FROBENIUS,&nrm); // out<<" Norm of stiffness matrix... "<<nrm<<endl; // #endif // /* // Set operators. Here the matrix that defines the linear system // also serves as the preconditioning matrix. // */ // // ierr = KSPSetOperators(ksp,A_,A_,DIFFERENT_NONZERO_PATTERN);CHKERRCONTINUE(ierr); // ierr = KSPSetOperators(ksp_,A_,A_,SAME_NONZERO_PATTERN);CHKERRCONTINUE(ierr); // // // // /* // // Set runtime options, e.g., // // -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol> // // These options will override those specified above as long as // // KSPSetFromOptions() is called _after_ any other customization // // routines. // // */ // // ierr = KSPSetFromOptions(ksp);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Solving system... "<<timer<<endl; // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Solve the linear system // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // /* // Solve linear system // */ // ierr = KSPSolve(ksp_,b,x_);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // /* // View solver info; we could instead use the option -ksp_view to // print this info to the screen at the conclusion of KSPSolve(). // */ // ierr = KSPView(ksp_,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // int iter; // KSPGetIterationNumber(ksp_, &iter); // out<<" System solved in "<<iter<<" iterations... "<<timer<<endl; // KSPConvergedReason reason; // ierr = KSPGetConvergedReason(ksp_,&reason);CHKERRCONTINUE(ierr); // if (reason < 0) // out<<"*** WARNING *** PETSc solver diverged with flag "; // else // out<<"*** INFO *** PETSc solver converged with flag "; // if (reason == KSP_CONVERGED_RTOL) // out<<"KSP_CONVERGED_RTOL"<<endl; // else if (reason == KSP_CONVERGED_ATOL) // out<<"KSP_CONVERGED_ATOL"<<endl; // else if (reason == KSP_CONVERGED_ITS) // out<<"KSP_CONVERGED_ITS"<<endl; // else if (reason == KSP_CONVERGED_CG_NEG_CURVE) // out<<"KSP_CONVERGED_CG_NEG_CURVE"<<endl; // else if (reason == KSP_CONVERGED_CG_CONSTRAINED) // out<<"KSP_CONVERGED_CG_CONSTRAINED"<<endl; // else if (reason == KSP_CONVERGED_STEP_LENGTH) // out<<"KSP_CONVERGED_STEP_LENGTH"<<endl; // else if (reason == KSP_CONVERGED_HAPPY_BREAKDOWN) // out<<"KSP_CONVERGED_HAPPY_BREAKDOWN"<<endl; // else if (reason == KSP_DIVERGED_NULL) // out<<"KSP_DIVERGED_NULL"<<endl; // else if (reason == KSP_DIVERGED_ITS) // out<<"KSP_DIVERGED_ITS"<<endl; // else if (reason == KSP_DIVERGED_DTOL) // out<<"KSP_DIVERGED_DTOL"<<endl; // else if (reason == KSP_DIVERGED_BREAKDOWN) // out<<"KSP_DIVERGED_BREAKDOWN"<<endl; // else if (reason == KSP_DIVERGED_BREAKDOWN_BICG) // out<<"KSP_DIVERGED_BREAKDOWN_BICG"<<endl; // else if (reason == KSP_DIVERGED_NONSYMMETRIC) // out<<"KSP_DIVERGED_NONSYMMETRIC"<<endl; // else if (reason == KSP_DIVERGED_INDEFINITE_PC) // out<<"KSP_DIVERGED_INDEFINITE_PC"<<endl; // else if (reason == KSP_DIVERGED_NAN) // out<<"KSP_DIVERGED_NAN"<<endl; // else if (reason == KSP_DIVERGED_INDEFINITE_MAT) // out<<"KSP_DIVERGED_INDEFINITE_MAT"<<endl; // else if (reason == KSP_CONVERGED_ITERATING) // out<<"KSP_CONVERGED_ITERATING"<<endl; // PetscReal rnorm; // ierr = KSPGetResidualNorm(ksp_,&rnorm);CHKERRCONTINUE(ierr); // out<<"PETSc last residual norm computed: "<<rnorm<<endl; // ierr = VecView(x_,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // VecNorm(x_,NORM_2,&nrm); // out<<" Norm of solution vector... "<<nrm<<endl; // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check solution and clean up // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // Vec x_all; // ierr = VecScatterCreateToAll(x_, &ctx, &x_all);CHKERRCONTINUE(ierr); // ierr = VecScatterBegin(ctx,x_,x_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // ierr = VecScatterEnd(ctx,x_,x_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Solution vector scattered... "<<timer<<endl; // VecNorm(x_all,NORM_2,&nrm); // out<<" Norm of scattered vector... "<<nrm<<endl; // // ierr = VecView(x_all,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr); // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get values from solution and store them in the object that will be // returned // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // sparse_vector_type xx(bb.size()); // /* Set solution vector */ // double zero = 0.; // double val; // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) { // int row = it->first; // ierr = VecGetValues(x_all, 1, &row, &val); // if (val != zero) // xx[row] = val; // } // #ifdef CPPUTILS_VERBOSE // out<<" Solution vector copied... "<<timer<<endl; // // out<<" Norm of copied solution vector... "<<norm(xx, Insert_t)<<endl; // #endif // /* // Free work space. All PETSc objects should be destroyed when they // are no longer needed. // */ // ierr = VecDestroy(&b);CHKERRCONTINUE(ierr); // // ierr = KSPDestroy(&ksp);CHKERRCONTINUE(ierr); // // set allocated flag // if (!allocated_) { // allocated_ = true; // } // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return xx; // } // SolverPETSc::sparse_vector_type SolverPETSc::operator()(const SolverPETSc::sparse_matrix_type& KKpf, const SolverPETSc::sparse_matrix_type& KKpp, const SolverPETSc::sparse_vector_type& UUp) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::operator()(const sparse_matrix&, const sparse_matrix&, const sparse_vector&). "<<timer<<endl; // #endif // Mat Kpf, Kpp; // Vec Up, Pf, Pp; // PetscErrorCode ierr = MatCreate(PETSC_COMM_WORLD,&Kpf);CHKERRCONTINUE(ierr); // ierr = MatCreate(PETSC_COMM_WORLD,&Kpp);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Allocating memory... "<<timer<<endl; // #endif // ierr = MatSetFromOptions(Kpf);CHKERRCONTINUE(ierr); // ierr = MatSetFromOptions(Kpp);CHKERRCONTINUE(ierr); // ierr = MatSetSizes(Kpf,PETSC_DECIDE,PETSC_DECIDE, KKpf.rows(), KKpf.columns());CHKERRCONTINUE(ierr); // ierr = MatSetSizes(Kpp,PETSC_DECIDE,PETSC_DECIDE, KKpp.rows(), KKpp.columns());CHKERRCONTINUE(ierr); // // get number of non-zeros in both diagonal and non-diagonal portions of the matrix // std::pair<size_t,size_t> Kpf_nz = KKpf.non_zero_off_diagonal(); // std::pair<size_t,size_t> Kpp_nz = KKpp.non_zero_off_diagonal(); // ierr = MatMPIAIJSetPreallocation(Kpf, Kpf_nz.first, PETSC_NULL, Kpf_nz.second, PETSC_NULL); CHKERRCONTINUE(ierr); // ierr = MatMPIAIJSetPreallocation(Kpp, Kpp_nz.first, PETSC_NULL, Kpp_nz.second, PETSC_NULL); CHKERRCONTINUE(ierr); // ierr = MatSeqAIJSetPreallocation(Kpf, Kpf_nz.first, PETSC_NULL); CHKERRCONTINUE(ierr); // ierr = MatSeqAIJSetPreallocation(Kpp, Kpp_nz.first, PETSC_NULL); CHKERRCONTINUE(ierr); // for (sparse_matrix_type::const_hash_iterator it = KKpf.map_.begin(); it != KKpf.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = KKpf.unhash(it->first); // int row = subs.first; // int col = subs.second; // ierr = MatSetValues(Kpf, 1, &row, 1, &col, &it->second, ADD_VALUES);CHKERRCONTINUE(ierr); // } // for (sparse_matrix_type::const_hash_iterator it = KKpp.map_.begin(); it != KKpp.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = KKpp.unhash(it->first); // int row = subs.first; // int col = subs.second; // ierr = MatSetValues(Kpf, 1, &row, 1, &col, &it->second, ADD_VALUES);CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Filled sparse matrices... "<<timer<<endl; // #endif // /* // Assemble matrix, using the 2-step process: // MatAssemblyBegin(), MatAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = MatAssemblyBegin(Kpf,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyBegin(Kpp,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(Kpf,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(Kpp,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Sparse matrices assembled... "<<timer<<endl; // #endif // ierr = VecCreate(PETSC_COMM_WORLD,&Up);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(Up,PETSC_DECIDE, UUp.size());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(Up);CHKERRCONTINUE(ierr); // ierr = VecCreate(PETSC_COMM_WORLD,&Pf);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(Pf,PETSC_DECIDE, KKpf.rows());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(Pf);CHKERRCONTINUE(ierr); // ierr = VecDuplicate(Pf,&Pp);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vectors created... "<<timer<<endl; // #endif // /* Set hight-hand-side vector */ // for (sparse_vector_type::const_hash_iterator it = UUp.map_.begin(); it != UUp.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(Up, 1, &row, &it->second, ADD_VALUES); // } // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(Up);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(Up);CHKERRCONTINUE(ierr); // // add Kpf*Uf // ierr = MatMult(Kpf, x_, Pf); // // add Kpp*Up // ierr = MatMultAdd(Kpp, Up, Pf, Pp); // #ifdef CPPUTILS_VERBOSE // out<<" Matrices multiplied... "<<timer<<endl; // #endif // VecScatter ctx; // Vec Pp_all; // ierr = VecScatterCreateToAll(Pp, &ctx, &Pp_all);CHKERRCONTINUE(ierr); // ierr = VecScatterBegin(ctx,Pp,Pp_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // ierr = VecScatterEnd(ctx,Pp,Pp_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vector scattered... "<<timer<<endl; // #endif // /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Get values from solution and store them in the object that will be // returned // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // sparse_vector_type pp(KKpf.rows()); // // get reaction vector // for (int i=0; i<KKpf.rows(); ++i) { // PetscScalar v; // ierr = VecGetValues(Pp_all, 1, &i, &v); // if (v != PetscScalar()) // pp[i] = v; // } // #ifdef CPPUTILS_VERBOSE // out<<" Vector copied... "<<timer<<endl; // #endif // ierr = MatDestroy(&Kpf);CHKERRCONTINUE(ierr); // ierr = MatDestroy(&Kpp);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Up);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Pf);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Pp);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&Pp_all);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return pp; // } // SolverPETSc::sparse_vector_type SolverPETSc::operator()(const SolverPETSc::sparse_vector_type& aa, const SolverPETSc::sparse_vector_type& bb) { // assert(aa.size() == bb.size()); // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::operator()(const sparse_vector&, const sparse_vector&). "<<timer<<endl; // #endif // Vec r; // PetscErrorCode ierr = VecCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(r,PETSC_DECIDE, aa.size());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vectors created... "<<timer<<endl; // #endif // // set values // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES); // } // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) { // int row = it->first; // ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES); // } // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(r);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(r);CHKERRCONTINUE(ierr); // sparse_vector_type rr(aa.size()); // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) { // int row = it->first; // ierr = VecGetValues(r, 1, &row, &rr[row]); // } // for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) { // int row = it->first; // ierr = VecGetValues(r, 1, &row, &rr[row]); // } // #ifdef CPPUTILS_VERBOSE // out<<" Vector copied... "<<timer<<endl; // #endif // ierr = VecDestroy(&r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return rr; // } // SolverPETSc::value_type SolverPETSc::norm(const SolverPETSc::sparse_matrix_type& aa, Element_insertion_type flag) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::norm(const sparse_matrix&). "<<timer<<endl; // #endif // Mat r; // PetscErrorCode ierr = MatCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr); // ierr = MatSetSizes(r,PETSC_DECIDE,PETSC_DECIDE, aa.rows(), aa.columns());CHKERRCONTINUE(ierr); // ierr = MatSetFromOptions(r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Matrix created... "<<timer<<endl; // #endif // // set values // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) { // // get subscripts // std::pair<size_t,size_t> subs = aa.unhash(it->first); // int row = subs.first; // int col = subs.second; // if (flag == Add_t) // ierr = MatSetValues(r, 1, &row, 1, &col, &it->second, ADD_VALUES); // else if (flag == Insert_t) // ierr = MatSetValues(r, 1, &row, 1, &col, &it->second, INSERT_VALUES); // CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Matrix filled..."<<timer<<endl; // #endif // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = MatAssemblyBegin(r,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // ierr = MatAssemblyEnd(r,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr); // value_type nrm; // MatNorm(r,NORM_FROBENIUS,&nrm); // #ifdef CPPUTILS_VERBOSE // out<<" Norm computed... "<<timer<<endl; // #endif // ierr = MatDestroy(&r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return nrm; // } // SolverPETSc::value_type SolverPETSc::norm(const SolverPETSc::sparse_vector_type& aa, Element_insertion_type flag) { // #ifdef CPPUTILS_VERBOSE // // parallel output stream // Output_stream out; // // timer // cpputils::ctimer timer; // out<<"Inside SolverPETSc::norm(const sparse_vector&). "<<timer<<endl; // #endif // Vec r; // PetscErrorCode ierr = VecCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr); // ierr = VecSetSizes(r,PETSC_DECIDE, aa.size());CHKERRCONTINUE(ierr); // ierr = VecSetFromOptions(r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Vector created... "<<timer<<endl; // #endif // // set values // for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) { // int row = it->first; // if (flag == Add_t) // ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES); // else if (flag == Insert_t) // ierr = VecSetValues(r, 1, &row, &it->second, INSERT_VALUES); // CHKERRCONTINUE(ierr); // } // #ifdef CPPUTILS_VERBOSE // out<<" Vector filled..."<<timer<<endl; // #endif // /* // Assemble vector, using the 2-step process: // VecAssemblyBegin(), VecAssemblyEnd() // Computations can be done while messages are in transition // by placing code between these two statements. // */ // ierr = VecAssemblyBegin(r);CHKERRCONTINUE(ierr); // ierr = VecAssemblyEnd(r);CHKERRCONTINUE(ierr); // value_type nrm; // VecNorm(r,NORM_2,&nrm); // #ifdef CPPUTILS_VERBOSE // out<<" Norm computed... "<<timer<<endl; // #endif // ierr = VecDestroy(&r);CHKERRCONTINUE(ierr); // #ifdef CPPUTILS_VERBOSE // out<<" Temporary data structures destroyed... "<<timer<<endl; // #endif // return nrm; // } // // // ///* -------------------------------------------------------------------------- */ // //SolverMumps::SolverMumps(SparseMatrix & matrix, // // const ID & id, // // const MemoryID & memory_id) : // //Solver(matrix, id, memory_id), is_mumps_data_initialized(false), rhs_is_local(true) { // // AKANTU_DEBUG_IN(); // // // //#ifdef AKANTU_USE_MPI // // parallel_method = SolverMumpsOptions::_fully_distributed; // //#else //AKANTU_USE_MPI // // parallel_method = SolverMumpsOptions::_master_slave_distributed; // //#endif //AKANTU_USE_MPI // // // // CommunicatorEventHandler & comm_event_handler = *this; // // // // communicator.registerEventHandler(comm_event_handler); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* -------------------------------------------------------------------------- */ // //SolverMumps::~SolverMumps() { // // AKANTU_DEBUG_IN(); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* -------------------------------------------------------------------------- */ // //void SolverMumps::destroyMumpsData() { // // AKANTU_DEBUG_IN(); // // // // if(is_mumps_data_initialized) { // // mumps_data.job = _smj_destroy; // destroy // // dmumps_c(&mumps_data); // // is_mumps_data_initialized = false; // // } // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* -------------------------------------------------------------------------- */ // //void SolverMumps::onCommunicatorFinalize(const StaticCommunicator & comm) { // // AKANTU_DEBUG_IN(); // // // // try{ // // const StaticCommunicatorMPI & comm_mpi = // // dynamic_cast<const StaticCommunicatorMPI &>(comm.getRealStaticCommunicator()); // // if(mumps_data.comm_fortran == MPI_Comm_c2f(comm_mpi.getMPICommunicator())) // // destroyMumpsData(); // // } catch(...) {} // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* -------------------------------------------------------------------------- */ // //void SolverMumps::initMumpsData(SolverMumpsOptions::ParallelMethod parallel_method) { // // switch(parallel_method) { // // case SolverMumpsOptions::_fully_distributed: // // icntl(18) = 3; //fully distributed // // icntl(28) = 0; //automatic choice // // // // mumps_data.nz_loc = matrix->getNbNonZero(); // // mumps_data.irn_loc = matrix->getIRN().values; // // mumps_data.jcn_loc = matrix->getJCN().values; // // break; // // case SolverMumpsOptions::_master_slave_distributed: // // if(prank == 0) { // // mumps_data.nz = matrix->getNbNonZero(); // // mumps_data.irn = matrix->getIRN().values; // // mumps_data.jcn = matrix->getJCN().values; // // } else { // // mumps_data.nz = 0; // // mumps_data.irn = NULL; // // mumps_data.jcn = NULL; // // // // icntl(18) = 0; //centralized // // icntl(28) = 0; //sequential analysis // // } // // break; // // } // //} // // // ///* -------------------------------------------------------------------------- */ // //void SolverMumps::initialize(SolverOptions & options) { // // AKANTU_DEBUG_IN(); // // // // mumps_data.par = 1; // // // // if(SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions *>(&options)) { // // if(opt->parallel_method == SolverMumpsOptions::_master_slave_distributed) { // // mumps_data.par = 0; // // } // // } // // // // mumps_data.sym = 2 * (matrix->getSparseMatrixType() == _symmetric); // // prank = communicator.whoAmI(); // //#ifdef AKANTU_USE_MPI // // mumps_data.comm_fortran = MPI_Comm_c2f(dynamic_cast<const StaticCommunicatorMPI &>(communicator.getRealStaticCommunicator()).getMPICommunicator()); // //#endif // // // // if(AKANTU_DEBUG_TEST(dblTrace)) { // // icntl(1) = 2; // // icntl(2) = 2; // // icntl(3) = 2; // // icntl(4) = 4; // // } // // // // mumps_data.job = _smj_initialize; //initialize // // dmumps_c(&mumps_data); // // is_mumps_data_initialized = true; // // // // /* ------------------------------------------------------------------------ */ // // UInt size = matrix->getSize(); // // // // if(prank == 0) { // // std::stringstream sstr_rhs; sstr_rhs << id << ":rhs"; // // rhs = &(alloc<Real>(sstr_rhs.str(), size, 1, REAL_INIT_VALUE)); // // } else { // // rhs = NULL; // // } // // // // /// No outputs // // icntl(1) = 0; // // icntl(2) = 0; // // icntl(3) = 0; // // icntl(4) = 0; // // mumps_data.nz_alloc = 0; // // // // if (AKANTU_DEBUG_TEST(dblDump)) icntl(4) = 4; // // // // mumps_data.n = size; // // // // if(AKANTU_DEBUG_TEST(dblDump)) { // // strcpy(mumps_data.write_problem, "mumps_matrix.mtx"); // // } // // // // /* ------------------------------------------------------------------------ */ // // // Default Scaling // // icntl(8) = 77; // // // // icntl(5) = 0; // Assembled matrix // // // // SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions *>(&options); // // if(opt) // // parallel_method = opt->parallel_method; // // // // initMumpsData(parallel_method); // // // // mumps_data.job = _smj_analyze; //analyze // // dmumps_c(&mumps_data); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* -------------------------------------------------------------------------- */ // //void SolverMumps::setRHS(Array<Real> & rhs) { // // if(prank == 0) { // // matrix->getDOFSynchronizer().gather(rhs, 0, this->rhs); // // } else { // // matrix->getDOFSynchronizer().gather(rhs, 0); // // } // //} // // // ///* -------------------------------------------------------------------------- */ // //void SolverMumps::solve() { // // AKANTU_DEBUG_IN(); // // // // if(parallel_method == SolverMumpsOptions::_fully_distributed) // // mumps_data.a_loc = matrix->getA().values; // // else // // if(prank == 0) { // // mumps_data.a = matrix->getA().values; // // } // // // // if(prank == 0) { // // mumps_data.rhs = rhs->values; // // } // // // // /// Default centralized dense second member // // icntl(20) = 0; // // icntl(21) = 0; // // // // mumps_data.job = _smj_factorize_solve; //solve // // dmumps_c(&mumps_data); // // // // AKANTU_DEBUG_ASSERT(info(1) != -10, "Singular matrix"); // // AKANTU_DEBUG_ASSERT(info(1) == 0, // // "Error in mumps during solve process, check mumps user guide INFO(1) =" // // << info(1)); // // // // AKANTU_DEBUG_OUT(); // //} // // // ///* -------------------------------------------------------------------------- */ // //void SolverMumps::solve(Array<Real> & solution) { // // AKANTU_DEBUG_IN(); // // // // solve(); // // // // if(prank == 0) { // // matrix->getDOFSynchronizer().scatter(solution, 0, this->rhs); // // } else { // // matrix->getDOFSynchronizer().scatter(solution, 0); // // } // // // // AKANTU_DEBUG_OUT(); // //} __END_AKANTU__ diff --git a/src/solver/static_solver.cc b/src/solver/static_solver.cc index 006df3123..b95ae0fa3 100644 --- a/src/solver/static_solver.cc +++ b/src/solver/static_solver.cc @@ -1,109 +1,111 @@ /** * @file static_solver.cc * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Wed Jul 30 15:35:01 2014 * * @brief implementation of the static solver * * @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 "static_solver.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_PETSC #include <petscsys.h> #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ StaticSolver::StaticSolver() : CommunicatorEventHandler(), is_initialized(false) { StaticCommunicator::getStaticCommunicator().registerEventHandler(*this); } /* -------------------------------------------------------------------------- */ StaticSolver::~StaticSolver() { --this->nb_references; - if(this->nb_references == 0) + if(this->nb_references == 0) { + StaticCommunicator::getStaticCommunicator().unregisterEventHandler(*this); delete this->static_solver; + } } /* -------------------------------------------------------------------------- */ StaticSolver & StaticSolver::getStaticSolver() { if(nb_references == 0) static_solver = new StaticSolver(); ++nb_references; return *static_solver; } #ifdef AKANTU_USE_PETSC #if PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 5 static PetscErrorCode PETScErrorHandler(MPI_Comm, int line, const char * dir, const char *file, PetscErrorCode number, PetscErrorType type, const char *message, void *) { AKANTU_DEBUG_ERROR("An error occured in PETSc in file \"" << file << ":" << line << "\" - PetscErrorCode "<< number << " - \""<< message << "\""); } #else static PetscErrorCode PETScErrorHandler(MPI_Comm, int line, const char * func, const char * dir, const char *file, PetscErrorCode number, PetscErrorType type, const char *message, void *) { AKANTU_DEBUG_ERROR("An error occured in PETSc in file \"" << file << ":" << line << "\" - PetscErrorCode "<< number << " - \""<< message << "\""); } #endif #endif /* -------------------------------------------------------------------------- */ void StaticSolver::initialize(int & argc, char ** & argv) { AKANTU_DEBUG_ASSERT(this->is_initialized != true, "The static solver has already been initialized"); #ifdef AKANTU_USE_PETSC PetscErrorCode petsc_error = PetscInitialize(&argc, &argv, NULL, NULL); if(petsc_error != 0) { AKANTU_DEBUG_ERROR("An error occured while initializing Petsc (PetscErrorCode "<< petsc_error << ")"); } PetscPushErrorHandler(PETScErrorHandler, NULL); #endif this->is_initialized = true; } /* -------------------------------------------------------------------------- */ void StaticSolver::finalize() { ParentEventHandler::sendEvent(StaticSolverEvent::BeforeStaticSolverDestroyEvent()); AKANTU_DEBUG_ASSERT(this->is_initialized == true, "The static solver has not been initialized"); #ifdef AKANTU_USE_PETSC PetscFinalize(); #endif this->is_initialized = false; } __END_AKANTU__ diff --git a/src/synchronizer/distributed_synchronizer.cc b/src/synchronizer/distributed_synchronizer.cc index ab9b4e10f..a32dd53dc 100644 --- a/src/synchronizer/distributed_synchronizer.cc +++ b/src/synchronizer/distributed_synchronizer.cc @@ -1,1663 +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; + if((std::abs(barycenter_loc(i)) <= tolerance && std::abs(barycenter(i)) <= tolerance) || + (std::abs((barycenter(i) - barycenter_loc(i))/bary_norm) <= 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)) + << std::abs((barycenter(i) - barycenter_loc(i))/bary_norm) << "] - 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/test/test_geometry/CMakeLists.txt b/test/test_geometry/CMakeLists.txt index 307793fab..082d96d22 100644 --- a/test/test_geometry/CMakeLists.txt +++ b/test/test_geometry/CMakeLists.txt @@ -1,57 +1,57 @@ #=============================================================================== # @file CMakeLists.txt # # @author Lucas Frerot <lucas.frerot@epfl.ch> # # @date creation: Fri Feb 27 2015 # @date last modification: Fri Feb 27 2015 # # @brief configuration for solver 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_geometry_intersection_triangle_3_mesh triangle_3.geo 2 1) add_mesh(test_geometry_intersection_tetrahedron_4_mesh tetrahedron_4.geo 3 1) register_test(test_geometry_predicates SOURCES test_geometry_predicates.cc PACKAGE CGAL ) register_test(test_geometry_intersection SOURCES test_geometry_intersection.cc - DEPENDENCIES test_geometry_intersection_triangle_3_mesh + FILES_TO_COPY test_geometry_triangle.msh PACKAGE CGAL ) register_test(test_geometry_intersection_triangle_3 SOURCES test_geometry_intersection_triangle_3.cc - DEPENDENCIES test_geometry_intersection_triangle_3_mesh + FILES_TO_COPY test_geometry_triangle.msh PACKAGE CGAL ) register_test(test_geometry_intersection_tetrahedron_4 SOURCES test_geometry_intersection_tetrahedron_4.cc - DEPENDENCIES test_geometry_intersection_tetrahedron_4_mesh + FILES_TO_COPY test_geometry_tetrahedron.msh PACKAGE CGAL ) diff --git a/test/test_geometry/test_geometry_intersection.cc b/test/test_geometry/test_geometry_intersection.cc index 6112dbd68..7f17c37c1 100644 --- a/test/test_geometry/test_geometry_intersection.cc +++ b/test/test_geometry/test_geometry_intersection.cc @@ -1,102 +1,96 @@ /** * @file test_geometry_intersection.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Fri Feb 27 2015 * @date last modification: Thu Mar 5 2015 * * @brief Tests the intersection module * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" -#include "mesh_geom_container.hh" #include "mesh_geom_factory.hh" #include "tree_type_helper.hh" #include "geom_helper_functions.hh" #include <CGAL/Cartesian.h> #include <iostream> /* -------------------------------------------------------------------------- */ using namespace akantu; typedef CGAL::Cartesian<Real> K; -typedef TreeTypeHelper<2, _triangle_3>::linear_intersection Line_intersection; -typedef TreeTypeHelper<2, _triangle_3>::tree::Primitive_id Primitive_id; +typedef IntersectionTypeHelper<TreeTypeHelper<Triangle<K>, K>, K::Segment_3>::intersection_type result_type; /* -------------------------------------------------------------------------- */ int main (int argc, char * argv[]) { debug::setDebugLevel(dblWarning); initialize("", argc, argv); Math::setTolerance(1e-10); Mesh mesh(2); - mesh.read("triangle_3.msh"); + mesh.read("test_geometry_triangle.msh"); - MeshGeomContainer container(mesh); - container.constructData(); + MeshGeomFactory<2, _triangle_3, Triangle<K>, K> factory(mesh); + factory.constructData(); - const MeshGeomFactory<2, _triangle_3> * factory = dynamic_cast<const MeshGeomFactory<2, _triangle_3> *>(container.getFactoryForElementType(_triangle_3)); - const TreeTypeHelper<2, _triangle_3>::tree & tree = factory->getTree(); + const TreeTypeHelper<Triangle<K>, K>::tree & tree = factory.getTree(); K::Point_3 a(0., 0.25, 0.), b(1., 0.25, 0.); K::Segment_3 line(a, b); - if (container.numberOfIntersectionsWithInterface(line) != 2) - return EXIT_FAILURE; - K::Point_3 begin(a), intermediate(0.25, 0.25, 0.), end(0.75, 0.25, 0.); K::Segment_3 result_0(begin, intermediate), result_1(intermediate, end); - std::list<Line_intersection> list_of_intersections; + std::list<result_type> list_of_intersections; tree.all_intersections(line, std::back_inserter(list_of_intersections)); - const Line_intersection & intersection_0 = list_of_intersections.front(); - const Line_intersection & intersection_1 = list_of_intersections.back(); + const result_type & intersection_0 = list_of_intersections.front(); + const result_type & intersection_1 = list_of_intersections.back(); if (!intersection_0 || !intersection_1) return EXIT_FAILURE; /// *-> first is the intersection ; *->second is the primitive id if (const K::Segment_3 * segment = boost::get<K::Segment_3>(&(intersection_0->first))) { if (!compareSegments(*segment, result_0)) { return EXIT_FAILURE; } } if (const K::Segment_3 * segment = boost::get<K::Segment_3>(&(intersection_1->first))) { if (!compareSegments(*segment, result_1)) { return EXIT_FAILURE; } } finalize(); return EXIT_SUCCESS; } diff --git a/test/test_geometry/test_geometry_intersection_tetrahedron_4.cc b/test/test_geometry/test_geometry_intersection_tetrahedron_4.cc index 5487390dd..876e21db0 100644 --- a/test/test_geometry/test_geometry_intersection_tetrahedron_4.cc +++ b/test/test_geometry/test_geometry_intersection_tetrahedron_4.cc @@ -1,75 +1,69 @@ /** * @file test_geometry_intersection_tetrahedron_4.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Mar 26 2015 * @date last modification: Thu Mar 26 2015 * * @brief Tests the intersection module with _tetrahedron_4 elements * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" -#include "mesh_geom_container.hh" -#include "mesh_geom_factory.hh" -#include "tree_type_helper.hh" -#include "geom_helper_functions.hh" +#include "mesh_segment_intersector.hh" #include <CGAL/Cartesian.h> #include <iostream> /* -------------------------------------------------------------------------- */ using namespace akantu; typedef CGAL::Cartesian<Real> K; typedef K::Point_3 Point; typedef K::Segment_3 Segment; /* -------------------------------------------------------------------------- */ int main (int argc, char * argv[]) { debug::setDebugLevel(dblWarning); initialize("", argc, argv); - Mesh mesh(3); - mesh.read("tetrahedron_4.msh"); + Mesh mesh(3), interface_mesh(3, "interface_mesh"); + mesh.read("test_geometry_tetrahedron.msh"); - MeshGeomContainer container(mesh); - container.constructData(); + MeshSegmentIntersector<3, _tetrahedron_4> intersector(mesh, interface_mesh); + intersector.constructData(); Point point(1., 1., 1.); Segment segment(CGAL::ORIGIN, point); - std::list<std::pair<Segment, std::string> > interfaces; - interfaces.push_back(std::make_pair(segment, "mat")); - - Mesh & interface_mesh = container.meshOfLinearInterfaces(interfaces); + intersector.computeIntersectionQuery(segment); if (interface_mesh.getNbElement(_segment_2) != 4) return EXIT_FAILURE; return EXIT_SUCCESS; } diff --git a/test/test_geometry/test_geometry_intersection_triangle_3.cc b/test/test_geometry/test_geometry_intersection_triangle_3.cc index 8c437e2e8..c40306c9e 100644 --- a/test/test_geometry/test_geometry_intersection_triangle_3.cc +++ b/test/test_geometry/test_geometry_intersection_triangle_3.cc @@ -1,93 +1,93 @@ /** * @file test_geometry_mesh.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Fri Mar 13 2015 * @date last modification: Fri Mar 13 2015 * * @brief Tests the interface mesh generation * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" -#include "mesh_geom_container.hh" +#include "mesh_segment_intersector.hh" #include "geom_helper_functions.hh" #include <CGAL/Cartesian.h> #include <iostream> /* -------------------------------------------------------------------------- */ using namespace akantu; typedef CGAL::Cartesian<Real> K; /* -------------------------------------------------------------------------- */ int main (int argc, char * argv[]) { - debug::setDebugLevel(dblWarning); + debug::setDebugLevel(dblError); initialize("", argc, argv); Math::setTolerance(1e-10); - Mesh mesh(2); - mesh.read("triangle_3.msh"); + Mesh mesh(2), interface_mesh(2, "interface_mesh"); + mesh.read("test_geometry_triangle.msh"); - MeshGeomContainer container(mesh); - container.constructData(); + MeshSegmentIntersector<2, _triangle_3> intersector(mesh, interface_mesh); + intersector.constructData(); K::Point_3 a(0, 0.25, 0), b(1, 0.25, 0), c(0.25, 0, 0), d(0.25, 1, 0); K::Segment_3 h_interface(a, b), v_interface(c, d); - std::list<std::pair<K::Segment_3, std::string> > interface_list; - interface_list.push_back(std::make_pair(h_interface, "mat")); - interface_list.push_back(std::make_pair(v_interface, "mat")); + std::list<K::Segment_3> interface_list; + interface_list.push_back(h_interface); + interface_list.push_back(v_interface); - Mesh & interface_mesh = container.meshOfLinearInterfaces(interface_list); + intersector.computeIntersectionQueryList(interface_list); if (interface_mesh.getNbElement(_segment_2) != 4) return EXIT_FAILURE; Vector<Real> bary(2); Element test; test.element = 1; test.type = _segment_2; interface_mesh.getBarycenter(test, bary); if (!Math::are_float_equal(bary(0), 0.5) || !Math::are_float_equal(bary(1), 0.25)) return EXIT_FAILURE; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_geometry/test_geometry_tetrahedron.msh b/test/test_geometry/test_geometry_tetrahedron.msh new file mode 100644 index 000000000..26ed3254a --- /dev/null +++ b/test/test_geometry/test_geometry_tetrahedron.msh @@ -0,0 +1,91 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$Nodes +14 +1 0 0 0 +2 1 0 0 +3 1 1 0 +4 0 1 0 +5 0 1 1 +6 0 0 1 +7 1 0 1 +8 1 1 1 +9 0.5 0.5 0 +10 0 0.5 0.5 +11 0.5 0 0.5 +12 1 0.5 0.5 +13 0.5 1 0.5 +14 0.5 0.5 1 +$EndNodes +$Elements +68 +1 15 2 0 1 1 +2 15 2 0 2 2 +3 15 2 0 3 3 +4 15 2 0 4 4 +5 15 2 0 5 5 +6 15 2 0 6 6 +7 15 2 0 10 7 +8 15 2 0 14 8 +9 1 2 0 1 4 3 +10 1 2 0 2 3 2 +11 1 2 0 3 1 2 +12 1 2 0 4 4 1 +13 1 2 0 8 5 6 +14 1 2 0 9 6 7 +15 1 2 0 10 7 8 +16 1 2 0 11 8 5 +17 1 2 0 13 4 5 +18 1 2 0 14 1 6 +19 1 2 0 18 2 7 +20 1 2 0 22 3 8 +21 2 2 0 6 1 2 9 +22 2 2 0 6 3 9 2 +23 2 2 0 6 4 1 9 +24 2 2 0 6 3 4 9 +25 2 2 0 15 10 6 5 +26 2 2 0 15 10 4 1 +27 2 2 0 15 4 10 5 +28 2 2 0 15 6 10 1 +29 2 2 0 19 11 6 1 +30 2 2 0 19 11 2 7 +31 2 2 0 19 2 11 1 +32 2 2 0 19 6 11 7 +33 2 2 0 23 12 3 8 +34 2 2 0 23 12 7 2 +35 2 2 0 23 7 12 8 +36 2 2 0 23 3 12 2 +37 2 2 0 27 13 8 3 +38 2 2 0 27 13 4 5 +39 2 2 0 27 4 13 3 +40 2 2 0 27 8 13 5 +41 2 2 0 28 6 7 14 +42 2 2 0 28 7 8 14 +43 2 2 0 28 6 14 5 +44 2 2 0 28 8 5 14 +45 4 2 0 1 13 12 9 3 +46 4 2 0 1 12 2 9 3 +47 4 2 0 1 12 2 11 9 +48 4 2 0 1 8 12 14 13 +49 4 2 0 1 11 12 9 14 +50 4 2 0 1 4 13 9 3 +51 4 2 0 1 11 14 9 10 +52 4 2 0 1 13 8 5 14 +53 4 2 0 1 13 4 10 5 +54 4 2 0 1 8 12 13 3 +55 4 2 0 1 8 12 7 14 +56 4 2 0 1 11 1 10 9 +57 4 2 0 1 11 2 1 9 +58 4 2 0 1 12 13 9 14 +59 4 2 0 1 14 13 10 5 +60 4 2 0 1 12 2 7 11 +61 4 2 0 1 12 11 7 14 +62 4 2 0 1 11 6 10 1 +63 4 2 0 1 6 14 10 5 +64 4 2 0 1 11 6 7 14 +65 4 2 0 1 14 13 9 10 +66 4 2 0 1 1 4 10 9 +67 4 2 0 1 4 13 10 9 +68 4 2 0 1 6 11 10 14 +$EndElements diff --git a/test/test_geometry/test_geometry_triangle.msh b/test/test_geometry/test_geometry_triangle.msh new file mode 100644 index 000000000..27322b855 --- /dev/null +++ b/test/test_geometry/test_geometry_triangle.msh @@ -0,0 +1,22 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$Nodes +4 +1 0 0 0 +2 1 0 0 +3 0 1 0 +4 0.5000000000016841 0.4999999999983159 0 +$EndNodes +$Elements +9 +1 15 2 0 1 1 +2 15 2 0 2 2 +3 15 2 0 3 3 +4 1 2 0 1 1 2 +5 1 2 0 2 2 4 +6 1 2 0 2 4 3 +7 1 2 0 3 3 1 +8 2 2 0 5 1 4 3 +9 2 2 0 5 2 4 1 +$EndElements diff --git a/test/test_geometry/tetrahedron_4.geo b/test/test_geometry/tetrahedron_4.geo deleted file mode 100644 index dce326158..000000000 --- a/test/test_geometry/tetrahedron_4.geo +++ /dev/null @@ -1,14 +0,0 @@ -f = 1.0; -Point(1) = {0, 0, 0, f}; -Point(2) = {1, 0, 0, f}; -Point(3) = {1, 1, 0, f}; -Point(4) = {0, 1, 0, f}; -Line(1) = {4, 3}; -Line(2) = {3, 2}; -Line(3) = {1, 2}; -Line(4) = {4, 1}; -Line Loop(5) = {4, 3, -2, -1}; -Plane Surface(6) = {5}; -Extrude {0, 0, 1} { - Surface{6}; -} diff --git a/test/test_geometry/triangle_3.geo b/test/test_geometry/triangle_3.geo deleted file mode 100644 index bd7d096ca..000000000 --- a/test/test_geometry/triangle_3.geo +++ /dev/null @@ -1,9 +0,0 @@ -cl__1 = 1; -Point(1) = {0, 0, 0, 1}; -Point(2) = {1, 0, 0, 1}; -Point(3) = {0, 1, 0, 1}; -Line(1) = {1, 2}; -Line(2) = {2, 3}; -Line(3) = {3, 1}; -Line Loop(5) = {2, 3, 1}; -Plane Surface(5) = {5}; diff --git a/test/test_model/test_solid_mechanics_model/CMakeLists.txt b/test/test_model/test_solid_mechanics_model/CMakeLists.txt index 327aaafd3..fc14d4a6e 100644 --- a/test/test_model/test_solid_mechanics_model/CMakeLists.txt +++ b/test/test_model/test_solid_mechanics_model/CMakeLists.txt @@ -1,224 +1,231 @@ #=============================================================================== # @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_akantu_test(test_embedded_interface "test_embedded_interface") #=============================================================================== 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 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 ) #=============================================================================== register_test(test_solid_mechanics_model_orthotropic SOURCES test_solid_mechanics_model_orthotropic.cc DEPENDENCIES test_solid_mechanics_model_square_mesh FILES_TO_COPY orthotropic.dat DIRECTORIES_TO_CREATE paraview PACKAGE core ) + +#=============================================================================== +register_test(test_material_selector + SOURCES test_material_selector.cc + FILES_TO_COPY material_selector.dat material_selector.msh + PACKAGE core + ) diff --git a/test/test_model/test_solid_mechanics_model/material_selector.dat b/test/test_model/test_solid_mechanics_model/material_selector.dat new file mode 100644 index 000000000..b7ecb2831 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/material_selector.dat @@ -0,0 +1,14 @@ +material elastic [ + name = chocolate + E = 2 +] + +material elastic [ + name = chewing-gum + E = 1 +] + +material elastic [ + name = candy + E = 3 +] diff --git a/test/test_model/test_solid_mechanics_model/material_selector.geo b/test/test_model/test_solid_mechanics_model/material_selector.geo new file mode 100644 index 000000000..f09b4d68d --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/material_selector.geo @@ -0,0 +1,10 @@ +Point(1) = {0, 0, 0, 1}; +Point(2) = {1, 0, 0, 1}; +Point(3) = {2, 0, 0, 1}; +Point(4) = {3, 0, 0, 1}; +Line(5) = {1, 2}; +Line(6) = {2, 3}; +Line(7) = {3, 4}; +Physical Line("chocolate") = {5}; +Physical Line("chewing-gum") = {6}; +Physical Line("candy") = {7}; diff --git a/test/test_model/test_solid_mechanics_model/material_selector.msh b/test/test_model/test_solid_mechanics_model/material_selector.msh new file mode 100644 index 000000000..afb5cdac7 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/material_selector.msh @@ -0,0 +1,22 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +3 +1 1 "chocolate" +1 2 "chewing-gum" +1 3 "candy" +$EndPhysicalNames +$Nodes +4 +1 0 0 0 +2 1 0 0 +3 2 0 0 +4 3 0 0 +$EndNodes +$Elements +3 +1 1 2 1 5 1 2 +2 1 2 2 6 2 3 +3 1 2 3 7 3 4 +$EndElements diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/CMakeLists.txt b/test/test_model/test_solid_mechanics_model/test_embedded_interface/CMakeLists.txt index a6a688623..84a2ddabf 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/CMakeLists.txt +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/CMakeLists.txt @@ -1,43 +1,49 @@ #=============================================================================== # @file CMakeLists.txt # # @author Lucas Frérot <lucas.frerot@epfl.ch> # # @date creation: Wed Mar 25 2015 # @date last modification: Wed Mar 25 2015 # # @brief configuration for embedded interface tests # # @section LICENSE # # Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see <http://www.gnu.org/licenses/>. # # @section DESCRIPTION # #=============================================================================== register_test(test_embedded_element_matrix SOURCES test_embedded_element_matrix.cc FILES_TO_COPY triangle.msh embedded_element.dat PACKAGE embedded ) register_test(test_embedded_interface_model SOURCES test_embedded_interface_model.cc FILES_TO_COPY embedded_mesh.msh material.dat matrix PACKAGE embedded ) + +register_test(test_embedded_interface_model_prestress + SOURCES test_embedded_interface_model_prestress.cc + FILES_TO_COPY embedded_mesh_prestress.msh embedded_mesh_prestress_reinforcement.msh prestress.dat + PACKAGE embedded + ) diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_element.dat b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_element.dat index 286250d80..d68d274d9 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_element.dat +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_element.dat @@ -1,22 +1,12 @@ -embedded_interface truc [ - name = reinforcement - material = elastic_r - points = [[0, 0.5], [1, 0.5]] -] - material reinforcement elastic [ - name = elastic_r + name = reinforcement E = 1 area = 1 ] material elastic [ - name = truc + name = null rho = 0 E = 0 nu = 0 ] - -user parameters [ - height = 0.5 -] diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh.msh b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh.msh index a01ac11c7..f7a1dfc04 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh.msh +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh.msh @@ -1,26 +1,30 @@ $MeshFormat 2.2 0 8 $EndMeshFormat +$PhysicalNames +1 +2 1 "concrete" +$EndPhysicalNames $Nodes 9 1 0 0 0 2 0.5 0 0 3 1 0 0 4 0 0.5 0 5 0.5 0.5 0 6 1 0.5 0 7 0 1 0 8 0.5 1 0 9 1 1 0 $EndNodes $Elements 8 -1 2 2 99 99 1 2 5 -2 2 2 99 99 2 3 6 -3 2 2 99 99 1 5 4 -4 2 2 99 99 2 6 5 -5 2 2 99 99 4 5 8 -6 2 2 99 99 5 6 9 -7 2 2 99 99 4 8 7 -8 2 2 99 99 5 9 8 +1 2 2 1 99 1 2 5 +2 2 2 1 99 2 3 6 +3 2 2 1 99 1 5 4 +4 2 2 1 99 2 6 5 +5 2 2 1 99 4 5 8 +6 2 2 1 99 5 6 9 +7 2 2 1 99 4 8 7 +8 2 2 1 99 5 9 8 $EndElements diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh_prestress.msh b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh_prestress.msh new file mode 100644 index 000000000..a799996b4 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh_prestress.msh @@ -0,0 +1,15856 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +4 +0 2 "YBlocked" +0 3 "EndNode" +1 1 "XBlocked" +2 4 "concrete" +$EndPhysicalNames +$Nodes +5420 +1 0 0 0 +2 10 0 0 +3 10 0.25 0 +4 10 1 0 +5 0 1 0 +6 0.04999999999996232 0 0 +7 0.09999999999992584 0 0 +8 0.1499999999998909 0 0 +9 0.199999999999856 0 0 +10 0.249999999999819 0 0 +11 0.2999999999997771 0 0 +12 0.3499999999997248 0 0 +13 0.3999999999996677 0 0 +14 0.4499999999996051 0 0 +15 0.4999999999995511 0 0 +16 0.5499999999995031 0 0 +17 0.5999999999994683 0 0 +18 0.6499999999994334 0 0 +19 0.6999999999993983 0 0 +20 0.7499999999993634 0 0 +21 0.7999999999993286 0 0 +22 0.8499999999992935 0 0 +23 0.8999999999992587 0 0 +24 0.9499999999992237 0 0 +25 0.9999999999991888 0 0 +26 1.049999999999154 0 0 +27 1.099999999999119 0 0 +28 1.149999999999084 0 0 +29 1.199999999999033 0 0 +30 1.24999999999897 0 0 +31 1.299999999998852 0 0 +32 1.349999999998722 0 0 +33 1.399999999998576 0 0 +34 1.44999999999843 0 0 +35 1.499999999998284 0 0 +36 1.549999999998138 0 0 +37 1.599999999997992 0 0 +38 1.649999999997846 0 0 +39 1.6999999999977 0 0 +40 1.749999999997554 0 0 +41 1.799999999997408 0 0 +42 1.849999999997263 0 0 +43 1.899999999997116 0 0 +44 1.949999999996971 0 0 +45 1.999999999996825 0 0 +46 2.049999999996679 0 0 +47 2.099999999996533 0 0 +48 2.149999999996387 0 0 +49 2.199999999996241 0 0 +50 2.249999999996095 0 0 +51 2.299999999995949 0 0 +52 2.349999999995803 0 0 +53 2.399999999995657 0 0 +54 2.449999999995511 0 0 +55 2.499999999995365 0 0 +56 2.54999999999522 0 0 +57 2.599999999995073 0 0 +58 2.649999999994928 0 0 +59 2.699999999994782 0 0 +60 2.749999999994635 0 0 +61 2.79999999999449 0 0 +62 2.849999999994344 0 0 +63 2.899999999994198 0 0 +64 2.949999999994052 0 0 +65 2.999999999993906 0 0 +66 3.04999999999376 0 0 +67 3.099999999993614 0 0 +68 3.149999999993468 0 0 +69 3.199999999993322 0 0 +70 3.249999999993176 0 0 +71 3.299999999993029 0 0 +72 3.349999999992884 0 0 +73 3.399999999992738 0 0 +74 3.449999999992592 0 0 +75 3.499999999992446 0 0 +76 3.5499999999923 0 0 +77 3.599999999992154 0 0 +78 3.649999999992009 0 0 +79 3.699999999991863 0 0 +80 3.749999999991717 0 0 +81 3.799999999991571 0 0 +82 3.849999999991425 0 0 +83 3.899999999991278 0 0 +84 3.949999999991132 0 0 +85 3.999999999991022 0 0 +86 4.049999999990987 0 0 +87 4.099999999991035 0 0 +88 4.149999999991111 0 0 +89 4.199999999991187 0 0 +90 4.249999999991263 0 0 +91 4.299999999991338 0 0 +92 4.349999999991415 0 0 +93 4.399999999991491 0 0 +94 4.449999999991566 0 0 +95 4.499999999991642 0 0 +96 4.549999999991719 0 0 +97 4.599999999991795 0 0 +98 4.649999999991871 0 0 +99 4.699999999991947 0 0 +100 4.749999999992022 0 0 +101 4.799999999992099 0 0 +102 4.849999999992175 0 0 +103 4.89999999999225 0 0 +104 4.949999999992326 0 0 +105 4.999999999992403 0 0 +106 5.049999999992478 0 0 +107 5.099999999992555 0 0 +108 5.14999999999263 0 0 +109 5.199999999992706 0 0 +110 5.249999999992783 0 0 +111 5.299999999992858 0 0 +112 5.349999999992933 0 0 +113 5.39999999999301 0 0 +114 5.449999999993086 0 0 +115 5.499999999993161 0 0 +116 5.549999999993238 0 0 +117 5.599999999993313 0 0 +118 5.649999999993391 0 0 +119 5.699999999993466 0 0 +120 5.749999999993543 0 0 +121 5.799999999993618 0 0 +122 5.849999999993694 0 0 +123 5.899999999993771 0 0 +124 5.949999999993846 0 0 +125 5.999999999993922 0 0 +126 6.049999999993998 0 0 +127 6.099999999994074 0 0 +128 6.14999999999415 0 0 +129 6.199999999994227 0 0 +130 6.249999999994302 0 0 +131 6.299999999994378 0 0 +132 6.349999999994455 0 0 +133 6.39999999999453 0 0 +134 6.449999999994606 0 0 +135 6.499999999994682 0 0 +136 6.549999999994759 0 0 +137 6.599999999994833 0 0 +138 6.64999999999491 0 0 +139 6.699999999994986 0 0 +140 6.749999999995062 0 0 +141 6.799999999995138 0 0 +142 6.849999999995214 0 0 +143 6.899999999995289 0 0 +144 6.949999999995366 0 0 +145 6.999999999995442 0 0 +146 7.049999999995517 0 0 +147 7.099999999995594 0 0 +148 7.14999999999567 0 0 +149 7.199999999995747 0 0 +150 7.249999999995821 0 0 +151 7.299999999995897 0 0 +152 7.349999999995973 0 0 +153 7.39999999999605 0 0 +154 7.449999999996125 0 0 +155 7.499999999996202 0 0 +156 7.549999999996278 0 0 +157 7.599999999996353 0 0 +158 7.64999999999643 0 0 +159 7.699999999996505 0 0 +160 7.749999999996582 0 0 +161 7.799999999996658 0 0 +162 7.849999999996734 0 0 +163 7.899999999996808 0 0 +164 7.949999999996885 0 0 +165 7.999999999996962 0 0 +166 8.049999999997038 0 0 +167 8.099999999997113 0 0 +168 8.14999999999719 0 0 +169 8.199999999997265 0 0 +170 8.249999999997341 0 0 +171 8.299999999997418 0 0 +172 8.349999999997493 0 0 +173 8.399999999997569 0 0 +174 8.449999999997646 0 0 +175 8.499999999997721 0 0 +176 8.549999999997798 0 0 +177 8.599999999997873 0 0 +178 8.649999999997949 0 0 +179 8.699999999998024 0 0 +180 8.749999999998101 0 0 +181 8.799999999998176 0 0 +182 8.849999999998253 0 0 +183 8.899999999998329 0 0 +184 8.949999999998404 0 0 +185 8.999999999998479 0 0 +186 9.049999999998557 0 0 +187 9.099999999998634 0 0 +188 9.149999999998709 0 0 +189 9.199999999998786 0 0 +190 9.24999999999886 0 0 +191 9.299999999998937 0 0 +192 9.349999999999012 0 0 +193 9.399999999999089 0 0 +194 9.449999999999164 0 0 +195 9.499999999999241 0 0 +196 9.549999999999315 0 0 +197 9.599999999999392 0 0 +198 9.649999999999469 0 0 +199 9.699999999999545 0 0 +200 9.749999999999622 0 0 +201 9.799999999999697 0 0 +202 9.849999999999774 0 0 +203 9.899999999999848 0 0 +204 9.949999999999925 0 0 +205 10 0.04999999999988947 0 +206 10 0.09999999999974372 0 +207 10 0.1499999999997367 0 +208 10 0.1999999999998683 0 +209 10 0.299999999999753 0 +210 10 0.3499999999995059 0 +211 10 0.3999999999992588 0 +212 10 0.4499999999990116 0 +213 10 0.4999999999987789 0 +214 10 0.5499999999988947 0 +215 10 0.5999999999990179 0 +216 10 0.6499999999991409 0 +217 10 0.6999999999992638 0 +218 10 0.7499999999993865 0 +219 10 0.7999999999995091 0 +220 10 0.8499999999996319 0 +221 10 0.8999999999997546 0 +222 10 0.9499999999998774 0 +223 9.949999999999999 1 0 +224 9.9 1 0 +225 9.85 1 0 +226 9.799999999999999 1 0 +227 9.75 1 0 +228 9.699999999999999 1 0 +229 9.649999999999999 1 0 +230 9.6 1 0 +231 9.549999999999999 1 0 +232 9.499999999999998 1 0 +233 9.449999999999999 1 0 +234 9.399999999999999 1 0 +235 9.349999999999998 1 0 +236 9.299999999999999 1 0 +237 9.249999999999998 1 0 +238 9.199999999999999 1 0 +239 9.149999999999999 1 0 +240 9.099999999999998 1 0 +241 9.049999999999999 1 0 +242 8.999999999999998 1 0 +243 8.949999999999998 1 0 +244 8.899999999999999 1 0 +245 8.849999999999998 1 0 +246 8.799999999999997 1 0 +247 8.749999999999998 1 0 +248 8.699999999999998 1 0 +249 8.649999999999997 1 0 +250 8.599999999999998 1 0 +251 8.549999999999997 1 0 +252 8.499999999999996 1 0 +253 8.449999999999998 1 0 +254 8.399999999999997 1 0 +255 8.349999999999998 1 0 +256 8.299999999999997 1 0 +257 8.249999999999996 1 0 +258 8.199999999999998 1 0 +259 8.149999999999997 1 0 +260 8.099999999999998 1 0 +261 8.049999999999997 1 0 +262 7.999999999999997 1 0 +263 7.949999999999998 1 0 +264 7.899999999999997 1 0 +265 7.849999999999998 1 0 +266 7.799999999999997 1 0 +267 7.749999999999997 1 0 +268 7.699999999999998 1 0 +269 7.649999999999998 1 0 +270 7.599999999999998 1 0 +271 7.549999999999997 1 0 +272 7.499999999999998 1 0 +273 7.449999999999998 1 0 +274 7.399999999999997 1 0 +275 7.349999999999998 1 0 +276 7.299999999999997 1 0 +277 7.249999999999997 1 0 +278 7.199999999999998 1 0 +279 7.149999999999998 1 0 +280 7.099999999999998 1 0 +281 7.049999999999997 1 0 +282 6.999999999999997 1 0 +283 6.949999999999998 1 0 +284 6.899999999999998 1 0 +285 6.849999999999998 1 0 +286 6.799999999999997 1 0 +287 6.749999999999998 1 0 +288 6.699999999999998 1 0 +289 6.649999999999998 1 0 +290 6.599999999999998 1 0 +291 6.549999999999998 1 0 +292 6.499999999999998 1 0 +293 6.449999999999998 1 0 +294 6.399999999999997 1 0 +295 6.349999999999998 1 0 +296 6.299999999999998 1 0 +297 6.249999999999998 1 0 +298 6.199999999999998 1 0 +299 6.149999999999999 1 0 +300 6.099999999999998 1 0 +301 6.049999999999998 1 0 +302 5.999999999999997 1 0 +303 5.949999999999998 1 0 +304 5.899999999999998 1 0 +305 5.849999999999998 1 0 +306 5.799999999999998 1 0 +307 5.749999999999998 1 0 +308 5.699999999999998 1 0 +309 5.649999999999998 1 0 +310 5.599999999999998 1 0 +311 5.549999999999998 1 0 +312 5.499999999999998 1 0 +313 5.449999999999998 1 0 +314 5.399999999999999 1 0 +315 5.349999999999999 1 0 +316 5.299999999999999 1 0 +317 5.249999999999998 1 0 +318 5.199999999999998 1 0 +319 5.149999999999999 1 0 +320 5.099999999999999 1 0 +321 5.049999999999998 1 0 +322 4.999999999999999 1 0 +323 4.949999999999999 1 0 +324 4.899999999999998 1 0 +325 4.849999999999999 1 0 +326 4.799999999999999 1 0 +327 4.749999999999998 1 0 +328 4.699999999999998 1 0 +329 4.649999999999999 1 0 +330 4.599999999999999 1 0 +331 4.549999999999999 1 0 +332 4.499999999999998 1 0 +333 4.449999999999998 1 0 +334 4.399999999999999 1 0 +335 4.349999999999998 1 0 +336 4.299999999999998 1 0 +337 4.249999999999999 1 0 +338 4.199999999999999 1 0 +339 4.149999999999999 1 0 +340 4.099999999999998 1 0 +341 4.049999999999999 1 0 +342 3.999999999999999 1 0 +343 3.949999999999999 1 0 +344 3.899999999999999 1 0 +345 3.849999999999999 1 0 +346 3.799999999999999 1 0 +347 3.749999999999999 1 0 +348 3.699999999999999 1 0 +349 3.649999999999999 1 0 +350 3.599999999999999 1 0 +351 3.549999999999997 1 0 +352 3.499999999999997 1 0 +353 3.449999999999998 1 0 +354 3.399999999999998 1 0 +355 3.349999999999999 1 0 +356 3.299999999999999 1 0 +357 3.249999999999998 1 0 +358 3.199999999999998 1 0 +359 3.149999999999999 1 0 +360 3.099999999999998 1 0 +361 3.049999999999998 1 0 +362 2.999999999999999 1 0 +363 2.949999999999999 1 0 +364 2.899999999999999 1 0 +365 2.85 1 0 +366 2.799999999999998 1 0 +367 2.749999999999998 1 0 +368 2.699999999999998 1 0 +369 2.649999999999998 1 0 +370 2.599999999999998 1 0 +371 2.549999999999999 1 0 +372 2.499999999999999 1 0 +373 2.449999999999999 1 0 +374 2.399999999999999 1 0 +375 2.349999999999999 1 0 +376 2.299999999999999 1 0 +377 2.249999999999998 1 0 +378 2.199999999999999 1 0 +379 2.149999999999999 1 0 +380 2.1 1 0 +381 2.049999999999999 1 0 +382 1.999999999999998 1 0 +383 1.949999999999999 1 0 +384 1.899999999999999 1 0 +385 1.849999999999998 1 0 +386 1.799999999999999 1 0 +387 1.75 1 0 +388 1.699999999999999 1 0 +389 1.649999999999999 1 0 +390 1.6 1 0 +391 1.549999999999999 1 0 +392 1.5 1 0 +393 1.449999999999999 1 0 +394 1.4 1 0 +395 1.35 1 0 +396 1.299999999999999 1 0 +397 1.249999999999998 1 0 +398 1.199999999999999 1 0 +399 1.149999999999999 1 0 +400 1.099999999999998 1 0 +401 1.049999999999999 1 0 +402 0.9999999999999982 1 0 +403 0.9499999999999993 1 0 +404 0.9000000000000004 1 0 +405 0.8499999999999996 1 0 +406 0.7999999999999989 1 0 +407 0.75 1 0 +408 0.6999999999999993 1 0 +409 0.6499999999999986 1 0 +410 0.6000000000000014 1 0 +411 0.5499999999999989 1 0 +412 0.5 1 0 +413 0.4499999999999993 1 0 +414 0.3999999999999986 1 0 +415 0.3499999999999996 1 0 +416 0.2999999999999989 1 0 +417 0.25 1 0 +418 0.1999999999999993 1 0 +419 0.1500000000000004 1 0 +420 0.09999999999999964 1 0 +421 0.05000000000000071 1 0 +422 0 0.9499999999997918 0 +423 0 0.8999999999995836 0 +424 0 0.8499999999996529 0 +425 0 0.7999999999999998 0 +426 0 0.7500000000003466 0 +427 0 0.7000000000006934 0 +428 0 0.6500000000010401 0 +429 0 0.6000000000013869 0 +430 0 0.5500000000017335 0 +431 0 0.5000000000020587 0 +432 0 0.4500000000018723 0 +433 0 0.4000000000016644 0 +434 0 0.3500000000014564 0 +435 0 0.3000000000012483 0 +436 0 0.2500000000010403 0 +437 0 0.2000000000008322 0 +438 0 0.1500000000006241 0 +439 0 0.100000000000416 0 +440 0 0.05000000000020799 0 +441 1.430518283324115 0.4976618019971546 0 +442 1.974999999996899 0.4999999999999243 0 +443 2.574999999995146 0.4999999999998804 0 +444 3.125330093894958 0.4947288460714284 0 +445 3.674886617398613 0.4990140276472064 0 +446 0.5192516935729574 0.4973828849261724 0 +447 9.475000000000112 0.5000000000000207 0 +448 8.925140624176818 0.5076652462134378 0 +449 8.37499999999995 0.5000000000000628 0 +450 7.82500000000002 0.5000000000000809 0 +451 7.225000000000063 0.5000000000001067 0 +452 6.677302008671008 0.5000666692094893 0 +453 6.125000000000027 0.5000000000001482 0 +454 5.580354820674485 0.5022662309541848 0 +455 5.028130163003213 0.5027845815212975 0 +456 4.275444121874549 0.5106119177145796 0 +457 0.9749999999990133 0.4518749999995468 0 +458 4.649999999999995 0.6093750000000562 0 +459 3.980796307925498 0.3333221928688176 0 +460 2.27499999999602 0.3393749999994408 0 +461 7.522296730190199 0.6567897313550136 0 +462 2.280320680685921 0.6627495663948291 0 +463 7.525011618601767 0.3241298754394778 0 +464 3.980388816233751 0.6615459847132322 0 +465 1.701413441777268 0.3205330984872935 0 +466 2.849700739872998 0.326161503321322 0 +467 3.39999999999272 0.3256249999995008 0 +468 3.404107659046966 0.6719662776496845 0 +469 2.84999999999435 0.6743750000003967 0 +470 1.69553827185582 0.6737313151850558 0 +471 9.199906991856491 0.674083829397035 0 +472 6.951679994184145 0.6762372373876401 0 +473 8.64206551591526 0.6783026862514169 0 +474 8.098320005815939 0.6762372373876404 0 +475 5.856300721221977 0.669681659038336 0 +476 6.40272068833024 0.6743589892498945 0 +477 5.304924497794906 0.6755630800033098 0 +478 9.195309532237422 0.3257868506881895 0 +479 5.300750818336451 0.3278685971749584 0 +480 5.850750818336455 0.3278685971749522 0 +481 6.945523676001898 0.3262846879235006 0 +482 6.397350630857521 0.3227622708962818 0 +483 8.099999999999975 0.3256250000000037 0 +484 8.647350630857398 0.3227622708962696 0 +485 4.765291527106597 0.3139598694665492 0 +486 1.18147565759812 0.6856545378892933 0 +487 0.773093765383302 0.6941478037260413 0 +488 0.3015479573498976 0.7024492606421152 0 +489 9.698513059289731 0.2987160489657017 0 +490 9.699568965517281 0.6995689655172894 0 +491 0.3004310344826103 0.3004310344826083 0 +492 1.219696596628405 0.2917615315165498 0 +493 0.733772231283824 0.2916097568124629 0 +494 4.477543878458116 0.2905197453066146 0 +495 4.885273625285833 0.7328319120596405 0 +496 4.410884831460763 0.7316537921349128 0 +497 3.724603209903936 0.2532771622766008 0 +498 4.213963217801012 0.2535305173297093 0 +499 2.041122701786737 0.2526671060872462 0 +500 2.513963217800962 0.2535305173290744 0 +501 7.758877298209226 0.7473328939127516 0 +502 7.286036782195088 0.746469482670797 0 +503 3.73382844889962 0.747993677410948 0 +504 2.033220105229129 0.746891984215232 0 +505 7.766779894767222 0.2531080157848409 0 +506 2.524632983319323 0.7431080631623237 0 +507 7.283220105226208 0.2531080157841133 0 +508 3.087008815267038 0.2510826926814131 0 +509 3.088350953697555 0.7477182430354211 0 +510 1.460169455693747 0.7472709671486114 0 +511 5.064565328796697 0.2501947261123621 0 +512 5.606355726862414 0.2534583823622315 0 +513 9.44549886542017 0.7476371557028576 0 +514 6.161649046296824 0.2522817569645304 0 +515 8.963300809856433 0.7485325338124637 0 +516 6.710723029652334 0.2522451244596808 0 +517 8.341821480760798 0.748061731302511 0 +518 6.710864399207321 0.7478148962786474 0 +519 6.162991184727303 0.7489173073183618 0 +520 5.608211324582692 0.7483825868432858 0 +521 8.409974621523153 0.2511237310761437 0 +522 8.959974621523266 0.2511237310761604 0 +523 9.440982058438616 0.2512852284112848 0 +524 1.458818016225601 0.2497832209353675 0 +525 0.5379814982609984 0.7561094425715044 0 +526 4.188337319823714 0.7672421443438967 0 +527 0.9987335222071869 0.2252347243805821 0 +528 0.5104466938178189 0.2307643406671599 0 +529 0.9712830368876003 0.7715058266252313 0 +530 5.105139642007704 0.7789239403886293 0 +531 0.2164999010538339 0.4999999999999974 0 +532 9.783500098946211 0.5000000000000109 0 +533 4.482889797266369 0.4880857878277239 0 +534 1.219911647937653 0.4858677802483762 0 +535 0.781255046309727 0.4964808227614237 0 +536 4.824128402664758 0.5088420234221455 0 +537 4.702761258913993 0.8011340588590384 0 +538 3.547617011847963 0.1886355947548539 0 +539 7.099609815120841 0.8051826085297122 0 +540 7.950390184879168 0.8051826085297218 0 +541 1.848040311008615 0.1964587085269267 0 +542 2.701959688983392 0.1964587085269179 0 +543 3.544416070144164 0.8002000283367942 0 +544 7.953792760135513 0.1956142995536484 0 +545 1.846207239861466 0.8043857004468352 0 +546 7.096207239860252 0.195614299551806 0 +547 2.703792760134993 0.8043857004487577 0 +548 3.87342775366692 0.5073780575316897 0 +549 2.173292304601875 0.5078638866840057 0 +550 7.626707695394852 0.4921361133157376 0 +551 4.078010125009483 0.5030883211925514 0 +552 2.38612267402175 0.5050436878897369 0 +553 7.414252120038888 0.4942808511838185 0 +554 2.771096932925257 0.4936306847863497 0 +555 1.617784801134905 0.4999999999999865 0 +556 3.477538148957801 0.4940978491968132 0 +557 8.182215198863579 0.5000000000000233 0 +558 8.732215198863509 0.5000000000000253 0 +559 6.48462398960972 0.5028020736419826 0 +560 5.217784801136348 0.5000000000000641 0 +561 9.278675653778635 0.5017034427309528 0 +562 6.867784801136362 0.5000000000000471 0 +563 5.765966335436372 0.504956827266235 0 +564 8.778999868877964 0.8075966643908132 0 +565 5.431010210602491 0.81138625135396 0 +566 6.535285571069373 0.804389442018221 0 +567 5.982644230439119 0.8026390903090076 0 +568 8.518989789397535 0.8113862513539932 0 +569 3.272131485441452 0.1901410608163633 0 +570 8.789834507461682 0.1941557947103974 0 +571 8.231010210602371 0.1886137486461759 0 +572 6.531010210602409 0.1886137486463453 0 +573 5.982812875076231 0.1980198006563709 0 +574 5.43101021060237 0.1886137486464472 0 +575 3.26898978939127 0.8113862513541422 0 +576 4.625962290159 0.1796334197976945 0 +577 4.8893159441874 0.1913021811452377 0 +578 9.092608517319302 0.519878486772774 0 +579 7.046392400568211 0.5223583109319037 0 +580 5.946392400568187 0.5223583109319349 0 +581 5.396392400568165 0.5223583109319556 0 +582 6.30344116422514 0.5267420088023126 0 +583 8.555898332690807 0.5238264588386284 0 +584 7.999870947003703 0.5300734707276995 0 +585 1.797972291074456 0.4753536916400541 0 +586 3.292808827173693 0.4656408254246505 0 +587 2.954835046838423 0.4803364137354721 0 +588 1.294577003608803 0.8208477907847388 0 +589 3.897186984240525 0.1793344642091185 0 +590 2.195077551816055 0.1785635394621029 0 +591 7.604922448179833 0.821436460537728 0 +592 0.1690496265403879 0.8231385953512296 0 +593 9.829534690638646 0.1791902801706995 0 +594 9.82953469063867 0.8208097198292886 0 +595 0.1734030112728576 0.173242031302223 0 +596 2.188715660953252 0.8173567085858814 0 +597 3.890911372716216 0.8244867905995334 0 +598 7.610349997497245 0.1726408203994202 0 +599 3.229877515508775 0.6378160530944251 0 +600 6.0192087535928 0.3615450947669709 0 +601 5.467531415459707 0.3569836956829541 0 +602 2.934310127771645 0.1733491995091337 0 +603 2.926969957088417 0.8279906846385793 0 +604 5.211195929504441 0.1703397198931947 0 +605 5.765689872222918 0.1733491995089993 0 +606 6.311327673860813 0.1698230051001209 0 +607 6.865689872222939 0.1733491995090737 0 +608 9.284809048754598 0.8246445575461595 0 +609 8.179270574021487 0.8297905125517524 0 +610 6.870729425978591 0.8297905125517582 0 +611 5.765689872222966 0.8266508004907505 0 +612 6.319362528595591 0.8221774026844444 0 +613 8.563525007835201 0.1743152474342938 0 +614 1.61133398536331 0.8302653295808717 0 +615 9.11558364545297 0.1703538256037047 0 +616 4.643168085738238 0.4435438895964657 0 +617 1.619718189509215 0.1752800529034305 0 +618 2.359697201326786 0.8322302093296051 0 +619 7.4444846285629 0.1697286889097305 0 +620 9.123545797262643 0.8265559269446081 0 +621 9.283523525152372 0.1750054430459759 0 +622 7.116798194016961 0.3658099429932526 0 +623 1.866798194013518 0.6341900570050308 0 +624 7.93700660019882 0.3648328448785014 0 +625 8.821764361433949 0.6456896110194781 0 +626 6.569435777915102 0.6412753717584929 0 +627 8.817287547450272 0.356520701403465 0 +628 8.264554758472334 0.3523115262633076 0 +629 6.573411913810156 0.3522295900648488 0 +630 1.022897919956678 0.6158406047139408 0 +631 9.595970349483391 0.8350654559027345 0 +632 9.58987926801224 0.170069325858913 0 +633 2.369971869716289 0.1742391908120009 0 +634 7.430028130279563 0.8257608091879793 0 +635 4.067179789439036 0.1686738815399874 0 +636 4.359482495943295 0.166648473099871 0 +637 2.671392400563293 0.6386545802353529 0 +638 3.57860759942383 0.6386545802329808 0 +639 4.925798754352337 0.3623840530515315 0 +640 2.674091084580459 0.3583755722209621 0 +641 3.571131090911882 0.3629745938753745 0 +642 0.8462222417845408 0.1715859849843672 0 +643 0.6860811775439034 0.8342212222335778 0 +644 1.341557728098243 0.6384796278018947 0 +645 4.540574029743877 0.8346536602517675 0 +646 5.260621941433885 0.8385292989172934 0 +647 1.322792537484855 0.1632053136578535 0 +648 1.902841192191762 0.3518594319947203 0 +649 7.152841192193384 0.648140568004324 0 +650 7.897158807806582 0.6481405680043476 0 +651 0.392454133599435 0.8365157200286039 0 +652 0.370749950526682 0.5525618904084757 0 +653 9.629250049473178 0.4474381095917633 0 +654 1.123542023770052 0.8448831266926744 0 +655 0.6270307030110921 0.6232120581931563 0 +656 6.028232809417121 0.6591431344811698 0 +657 5.478232809417163 0.659143134481153 0 +658 8.479067743831193 0.6523815117459542 0 +659 3.221767190577082 0.3408568655176157 0 +660 0.3703180448468898 0.1576571107486892 0 +661 9.550054025141362 0.6347849726795337 0 +662 0.4477744840394366 0.3650027380097466 0 +663 4.334171981469223 0.3545539419676255 0 +664 5.123218407880917 0.6237282578447575 0 +665 1.146619087923367 0.155031151917063 0 +666 4.045825788112269 0.8439264517075077 0 +667 0.6549228092515382 0.1562340112519045 0 +668 0.8759213419427722 0.3312701541084143 0 +669 0.155441150546656 0.6431126008992799 0 +670 9.844558849453309 0.3568873991007001 0 +671 9.842915214461156 0.6389120656714984 0 +672 0.1576730062711758 0.3590781547327187 0 +673 2.997070103297611 0.6244530782715381 0 +674 6.252929896696918 0.3755469217277503 0 +675 8.499257315055655 0.3760097639045081 0 +676 9.052929896697034 0.3755469217276394 0 +677 1.358179332868707 0.3605547599820908 0 +678 0.5959808887349669 0.3646563443849989 0 +679 4.280590075963453 0.6524018949153594 0 +680 0.8386052474869616 0.8479544010744662 0 +681 4.313425598518642 0.8484648929592054 0 +682 1.520869140205245 0.3832739753938342 0 +683 4.97398790275571 0.8489261712970225 0 +684 1.521392400566691 0.6133495896836937 0 +685 5.121392400568095 0.3866504103164812 0 +686 5.674123815411973 0.3876977073732628 0 +687 6.771392400568134 0.3866504103164936 0 +688 8.243632977908522 0.6355266792403176 0 +689 9.339876662462641 0.6392148094350276 0 +690 6.809228121246596 0.6391664199243745 0 +691 5.706367022091527 0.6355266792403891 0 +692 9.374997127274259 0.3829055742525506 0 +693 1.1122718428724 0.3946254699099378 0 +694 3.413940492792351 0.1436699989309773 0 +695 3.408765679885237 0.8541049923642942 0 +696 8.090556241250392 0.144825227241458 0 +697 2.136737340671246 0.3627295291490304 0 +698 3.772658142298661 0.3987461241839007 0 +699 7.663262659324843 0.6372704708508136 0 +700 2.418827180999553 0.3642229410638813 0 +701 4.113015914275048 0.362821813594386 0 +702 7.38549975948659 0.6360358311947402 0 +703 0.8841552183155736 0.5868177157665101 0 +704 2.490091356416006 0.6061293353119555 0 +705 7.314137156406193 0.3900899083729132 0 +706 2.070205094219137 0.6078599847697252 0 +707 7.729794905777838 0.3921400152303892 0 +708 3.770205094213505 0.6078599847690132 0 +709 4.11575836059407 0.6433746158345833 0 +710 4.498885676445229 0.1413244263935857 0 +711 4.832388872936544 0.8612169347841719 0 +712 9.564173840885777 0.3251054415020542 0 +713 4.511098012849269 0.6326865759324506 0 +714 8.648155267024029 0.858869714277732 0 +715 9.066494928838489 0.6610680296437775 0 +716 6.2624241949476 0.6550414503077703 0 +717 2.983182298445413 0.3383066185245293 0 +718 4.785276139218392 0.6451824803165739 0 +719 4.922957486141573 0.5986157483049962 0 +720 4.767831165019608 0.137863776454347 0 +721 0.486599459106605 0.6292246441214339 0 +722 3.669428695884489 0.1347705334936773 0 +723 1.969076459963331 0.1333274296234274 0 +724 2.584450219413389 0.1332693122053699 0 +725 7.831083354105248 0.8665990959337568 0 +726 7.219428695888782 0.8652294665065227 0 +727 3.666173676806756 0.8654167348789555 0 +728 1.966392913156282 0.8604898240016454 0 +729 7.832245929462478 0.1409251032027161 0 +730 2.582671728268592 0.8654623162292924 0 +731 7.217328271726725 0.1345376837709534 0 +732 3.149001004529248 0.1314273266365487 0 +733 8.901015845851118 0.867519024764336 0 +734 8.403350586792103 0.8668670420075129 0 +735 6.645634681193093 0.8681355596128106 0 +736 5.551015845851177 0.8675190247643486 0 +737 6.098895308791814 0.8704698888150899 0 +738 3.148984154142771 0.8675190247645549 0 +739 8.902472118025342 0.1333205896095784 0 +740 5.552151070022664 0.131970201950201 0 +741 6.652914425453188 0.1319617360607131 0 +742 6.102886468818719 0.1318901145369975 0 +743 8.351015845850997 0.1324809752356674 0 +744 0.3352918265898219 0.4357186617220717 0 +745 9.673209022230857 0.5710493661455918 0 +746 5.013114078686359 0.1316850739013853 0 +747 1.413412190830997 0.8705829640344993 0 +748 2.812802718273097 0.1319026116806354 0 +749 8.057410719203668 0.8743890434435777 0 +750 6.98525634365452 0.8621794836788833 0 +751 4.611084697175735 0.3137509543560204 0 +752 1.73502513314006 0.8680805376286922 0 +753 6.992629884944956 0.132036297517184 0 +754 2.813786963453993 0.868246189707388 0 +755 4.198310807302269 0.1277336127063481 0 +756 9.408373157714751 0.869296682426144 0 +757 1.739991637296969 0.1276868129164424 0 +758 4.391774235540401 0.5860221938201229 0 +759 9.469626768770269 0.1299295013145832 0 +760 2.54094138361973 0.3754123813588162 0 +761 2.391186946458545 0.6998398577420744 0 +762 7.401970103828154 0.2957192273446532 0 +763 0.6516837296116952 0.4811666364825805 0 +764 1.497733584594977 0.1300269477453789 0 +765 3.852919148031527 0.7037136979846949 0 +766 2.155409137029328 0.7102156416372459 0 +767 7.644590862967227 0.2897843583629759 0 +768 9.710399408231559 0.876289544252698 0 +769 9.710399408231488 0.1237104557472336 0 +770 5.010162027326325 0.6957206721720511 0 +771 3.851765488606839 0.2928824328033652 0 +772 4.602584596001142 0.7255590284772507 0 +773 0.5699786094543091 0.8767740848077031 0 +774 1.100801037360065 0.5266552285500364 0 +775 6.427848754627997 0.8766141587869311 0 +776 5.877848754627969 0.876614158786946 0 +777 8.675655253439196 0.1272470158080186 0 +778 6.425655253439332 0.1272470158082739 0 +779 5.877848754628046 0.1233858412135872 0 +780 5.327848754628066 0.1233858412136875 0 +781 8.944073300527728 0.6215190991043934 0 +782 3.105304199027532 0.3790326670291977 0 +783 6.144695800966657 0.6209673329704027 0 +784 3.799177437676519 0.1239942648646494 0 +785 7.709590370201393 0.8786548252820149 0 +786 2.090409629794871 0.121345174717628 0 +787 0.2816511474572365 0.8759975473050119 0 +788 4.429412624652155 0.8812419129259526 0 +789 3.785783456983805 0.8813347001423747 0 +790 2.08578345698605 0.8813347001423125 0 +791 7.714216543010698 0.1186652998578255 0 +792 1.58333048369615 0.2824812018371142 0 +793 9.312681313933961 0.2877169985458785 0 +794 0.9496516850066973 0.1168760035953118 0 +795 6.6864012248694 0.6208201467864438 0 +796 8.354953647406459 0.6198710839899033 0 +797 5.589104911656348 0.6236156890643463 0 +798 5.187337659617425 0.2795826496566871 0 +799 5.738014409278408 0.2799187859977197 0 +800 6.837293081671706 0.2819029479041557 0 +801 1.591268725927366 0.7116793320401992 0 +802 7.273320363275825 0.6046658209007597 0 +803 7.786619639816129 0.6142326745673186 0 +804 2.013380360180741 0.3857673254333099 0 +805 7.334427294638187 0.1160465450862105 0 +806 2.465572705357675 0.8839534549140724 0 +807 6.136168166177357 0.383501706538243 0 +808 3.113831833816396 0.6164982934610005 0 +809 4.155794513115211 0.8833290555267995 0 +810 8.938794127480456 0.3796261575822592 0 +811 8.385648663805204 0.3782697862298459 0 +812 0.4786845190787192 0.1146307559758333 0 +813 5.14635366407033 0.8798188689909391 0 +814 5.662440172155388 0.1136722565419794 0 +815 6.213053004485416 0.113605517031059 0 +816 6.768727824217456 0.1208118697699457 0 +817 6.2131066603917 0.887785304146526 0 +818 6.767257071806294 0.8787175665746734 0 +819 5.66559542211788 0.8851288992563958 0 +820 8.282742928193747 0.8787175665746768 0 +821 3.034404577876179 0.1148711007432793 0 +822 9.021281627200187 0.1083944956899632 0 +823 8.463053004485408 0.1136055170314698 0 +824 3.031272175776854 0.8791881302304293 0 +825 3.974999999996082 0.4550507389588322 0 +826 7.524999999999959 0.5449492610456296 0 +827 2.273005727174112 0.4506535717335504 0 +828 1.108708172492784 0.2794616287693025 0 +829 0.8868716366294677 0.7055376990161805 0 +830 2.866029937758507 0.5602480076242545 0 +831 1.717007667000605 0.5620496693641306 0 +832 3.388615657205206 0.5614804955009991 0 +833 8.627814715584293 0.4410237865815832 0 +834 6.383970062236904 0.4397519923759989 0 +835 8.079510867844954 0.4451268260296568 0 +836 5.316091949340987 0.4368960955434334 0 +837 5.869977423439892 0.4407465429694395 0 +838 6.973677572857993 0.439682180117116 0 +839 9.184646575916503 0.4337045487688155 0 +840 0.4123667289168142 0.7228227520705333 0 +841 1.008181376540124 0.3416914632498105 0 +842 1.015219830318336 0.8782964510292357 0 +843 2.463640520327183 0.1164375212336209 0 +844 7.336359479668396 0.8835624787662436 0 +845 9.013795851948963 0.8864734616033775 0 +846 4.228151573342599 0.3961810719907868 0 +847 5.123652148402528 0.1072982342028689 0 +848 4.519226111890424 0.3969091465925706 0 +849 0.2642107586113116 0.1109580778996508 0 +850 5.185129788145661 0.7092044203682063 0 +851 1.067775162744039 0.7163803870171168 0 +852 0.1197720141876461 0.5389919091778549 0 +853 9.880227985812292 0.4610080908220888 0 +854 1.526811076626504 0.8854238066787141 0 +855 4.634422799671617 0.8900702616226508 0 +856 4.377899117374187 0.4496730474154768 0 +857 0.4093228342755432 0.2609039926399251 0 +858 4.714121425793093 0.5200636310537334 0 +859 4.178454683136143 0.5528898055956797 0 +860 1.80974097332198 0.3010937453662946 0 +861 7.999056835104984 0.6978712565467718 0 +862 7.056635302688625 0.7015772123860812 0 +863 1.923330690281721 0.7261900638688368 0 +864 7.873387420683114 0.2689869194417422 0 +865 7.172621808744757 0.2732517108368719 0 +866 0.730933588629571 0.5875550615371061 0 +867 0.6449587940233172 0.7315077943001043 0 +868 5.355187249533478 0.8905239932340268 0 +869 2.267909220474905 0.8942745756221103 0 +870 7.531053954524845 0.09645012573937585 0 +871 0.7524346483238534 0.1093575499598149 0 +872 9.438574357812943 0.6016013682710053 0 +873 0.2774685787244202 0.5933218073342371 0 +874 9.723596387474057 0.4063854357981637 0 +875 0.6174462888446485 0.2583080367561444 0 +876 4.060570955118482 0.7365994146407349 0 +877 2.277829795567626 0.09992346809147172 0 +878 7.509817788024448 0.8988997724681201 0 +879 3.967009158048057 0.1031375283992548 0 +880 2.265831888529521 0.575223724516477 0 +881 7.534168111467283 0.4247762754832149 0 +882 3.961448709061109 0.5614125266947457 0 +883 0.1020536245254965 0.744025257998073 0 +884 9.903454195848347 0.2579395192420323 0 +885 9.88600957969563 0.7386387774435089 0 +886 0.1114703922261123 0.2565508501759365 0 +887 9.190812433204384 0.8928240209795023 0 +888 9.200961331119426 0.107644692392491 0 +889 3.629271571359367 0.2670494617806151 0 +890 2.627819723664792 0.2663996703502227 0 +891 2.947458677438315 0.7198930991324327 0 +892 6.301677320607148 0.2816483776059863 0 +893 8.552151939878126 0.2822207892560343 0 +894 9.063677338751642 0.2652926412950027 0 +895 1.214421470609538 0.8887654723872104 0 +896 4.580909711132274 0.5204178088106874 0 +897 0.8713095978759507 0.4352507731244732 0 +898 4.920371524283571 0.4655103684913237 0 +899 4.825392147101008 0.4038460431693147 0 +900 2.483116303229818 0.4481378690091752 0 +901 1.321144606868491 0.5284631719222198 0 +902 1.229170078963441 0.6040284039598492 0 +903 3.636400277390967 0.7256554438824269 0 +904 2.623044629396541 0.7341392357647358 0 +905 0.7191564560814898 0.3979107290598961 0 +906 4.053682063810402 0.2744614406261153 0 +907 2.354339472322317 0.2715572350047005 0 +908 7.445632138497966 0.7283958792100466 0 +909 9.201746724024922 0.573352762357514 0 +910 1.694659130298647 0.4241588814956734 0 +911 3.399999999992733 0.4321941169861923 0 +912 2.837945957074693 0.4305454076985892 0 +913 6.955495451191995 0.5709378674997533 0 +914 5.853385893780119 0.5674733449033966 0 +915 5.299999999999986 0.5678058830131445 0 +916 8.094211948522277 0.5752706494027803 0 +917 6.402154541260812 0.5698525089980319 0 +918 8.649129196058675 0.5695787631258608 0 +919 1.260004413570992 0.3943973325044675 0 +920 3.885143525613256 0.399155266932717 0 +921 3.4967539210839 0.3004450233208694 0 +922 2.753409969864845 0.2928159872227278 0 +923 1.234501472292477 0.1047486796587173 0 +924 3.499900609224502 0.7067503287458643 0 +925 2.751326999079028 0.7078570767312499 0 +926 9.504187623355481 0.8912828191495176 0 +927 2.770981435013805 0.605087032614359 0 +928 3.479018564972879 0.6050870326144039 0 +929 9.483258039900951 0.3953165643782303 0 +930 5.886779838998835 0.7751686505370522 0 +931 6.438267164646747 0.7714698691012669 0 +932 8.688538256520264 0.2280915732668652 0 +933 6.438538256520478 0.2280915732670519 0 +934 5.887724211427256 0.2304765359445681 0 +935 5.337724211427291 0.2304765359446422 0 +936 1.754591281335928 0.76690448008968 0 +937 7.004591281335681 0.2330955199097756 0 +938 9.367268927129116 0.1033733625041886 0 +939 8.828607599431702 0.5407215070782788 0 +940 6.575857559637913 0.5373343271888544 0 +941 8.283588497224402 0.4621316459084001 0 +942 8.001076123513437 0.2852856404407899 0 +943 2.348613704348856 0.6041527407306639 0 +944 7.453243929110142 0.3868200900199393 0 +945 9.573157236364459 0.5354409536644044 0 +946 5.500592738300004 0.2653289760885719 0 +947 6.050323179492803 0.2592433764767432 0 +948 3.198397720953515 0.7382102888967912 0 +949 3.299311309125453 0.7071613744440582 0 +950 8.720615194937139 0.3957361224415545 0 +951 6.469658605073944 0.3985244904844331 0 +952 8.170215165293737 0.3980433405742956 0 +953 1.969464870068749 0.599942568133727 0 +954 7.216604718764748 0.3966422375724072 0 +955 7.830535129927974 0.4000574318665838 0 +956 5.578390565929439 0.3499667346893605 0 +957 6.668218944831308 0.3965725910153698 0 +958 8.746779806324223 0.713393657744519 0 +959 8.185038275579648 0.2803760369974497 0 +960 6.771392400568195 0.5379969837195986 0 +961 5.671392400568187 0.5379969837196026 0 +962 3.506565730689533 0.1005222270731675 0 +963 8.23750969141417 0.7383947222695647 0 +964 9.337509691414221 0.7383947222696118 0 +965 6.812490308585843 0.7383947222696114 0 +966 5.710492139310598 0.7414466406345005 0 +967 3.217734690133049 0.5376598773962219 0 +968 6.029262835401692 0.4639637988743506 0 +969 5.479472762867909 0.4614637176359149 0 +970 8.852605110661582 0.7412988644000412 0 +971 6.607299126484939 0.7423592242872206 0 +972 8.851019380527843 0.2578103828707607 0 +973 8.302014180219052 0.2589315521974974 0 +974 6.601144011473353 0.2597044507737227 0 +975 2.672282890385684 0.5320843007551112 0 +976 3.579566238259984 0.5342271385361553 0 +977 4.865635792094654 0.2798318504547465 0 +978 3.50511081379044 0.9038097262249153 0 +979 7.996183191541139 0.09630587115354564 0 +980 1.054182784750804 0.1026615732182947 0 +981 7.180786441657336 0.7445439254597737 0 +982 7.866691760945714 0.7462474583139409 0 +983 1.933308239050742 0.2537525416850273 0 +984 1.633194517890775 0.5993145356960465 0 +985 5.233402837682492 0.4005196003750292 0 +986 5.782288469820391 0.4027633321870296 0 +987 6.883692524271915 0.4000184472228077 0 +988 9.269535277726169 0.3975446399402564 0 +989 0.09797584461925765 0.9025975509220073 0 +990 9.897343863512312 0.1026561364877211 0 +991 9.897343863512294 0.8973438635122891 0 +992 0.09689283781673137 0.09964360737782814 0 +993 1.366736738495928 0.2571384512539909 0 +994 2.140317464393025 0.2610337983047785 0 +995 7.659682535602922 0.738966201695102 0 +996 0.4302816038464583 0.4629398409994273 0 +997 1.358021804897507 0.7393529053370164 0 +998 4.787443931217997 0.7436113020331361 0 +999 5.395434883807368 0.7171905263498608 0 +1000 8.556653346586744 0.716258526793849 0 +1001 3.306653346580351 0.2837414732050502 0 +1002 9.541906388127462 0.739570628386168 0 +1003 3.674791690806167 0.3562657138990394 0 +1004 7.732753002419664 0.5289496721494767 0 +1005 2.067246997577106 0.4710503278510287 0 +1006 7.328797802121198 0.5240862643770704 0 +1007 2.276723693489252 0.7774532117123119 0 +1008 7.519397653653153 0.230181353541429 0 +1009 3.318404701891871 0.09923283818205036 0 +1010 1.707340214173044 0.2240989549601659 0 +1011 8.454673165258328 0.5508270458911612 0 +1012 9.378607599431906 0.532523770276455 0 +1013 3.956793341418138 0.9056840565811393 0 +1014 0.4697630075914747 0.9014821257147698 0 +1015 8.177645617208563 0.09448301247072791 0 +1016 3.319983829432994 0.9107162598402445 0 +1017 7.124619859646564 0.9015152869451711 0 +1018 7.925380140353418 0.9015152869451777 0 +1019 1.874619859643537 0.09848471305459644 0 +1020 2.675380140348479 0.09848471305458835 0 +1021 2.847150129060637 0.7657574119916335 0 +1022 1.403226261126306 0.1013911520476122 0 +1023 4.730084346729286 0.9015874961963957 0 +1024 2.851590188629002 0.2179135378313631 0 +1025 6.953244089826027 0.775648926050571 0 +1026 8.099355578800308 0.7848317307345445 0 +1027 4.286000333867424 0.1001307642515442 0 +1028 1.873091004808564 0.9017083705225617 0 +1029 7.123091004807436 0.09829162947637624 0 +1030 2.676160797666165 0.8983645759602168 0 +1031 7.132008228097444 0.4671798556846657 0 +1032 1.887551763831555 0.5317431624741745 0 +1033 7.911471537956805 0.4674065069698962 0 +1034 9.201614268678441 0.7714914939895461 0 +1035 9.202222424229291 0.2249167367581667 0 +1036 4.282305803629535 0.7528956074149702 0 +1037 2.171858029818762 0.6092986238297178 0 +1038 7.628141970178105 0.3907013761703818 0 +1039 3.875083274653653 0.6083574488572637 0 +1040 9.902391496983263 0.5590564999916023 0 +1041 0.09760850301662062 0.4409435000083599 0 +1042 4.693646229041232 0.6983887994590759 0 +1043 2.579404330844261 0.6476666143905712 0 +1044 3.677116548841837 0.6466851000834714 0 +1045 3.203644246557045 0.4450938867111517 0 +1046 6.037209736513934 0.556110227445817 0 +1047 5.492655571691823 0.5582571834014477 0 +1048 5.93528117975506 0.6218819038123468 0 +1049 5.022045277060927 0.3972033805306975 0 +1050 4.317353901377812 0.261543096886336 0 +1051 4.959310937858155 0.255057301803898 0 +1052 9.017327591633792 0.4773078303201124 0 +1053 6.223168017961723 0.4782563330103204 0 +1054 3.026831982032411 0.5217436669890072 0 +1055 5.121392400568183 0.5239550988210496 0 +1056 6.05615176777834 0.7454296037698073 0 +1057 5.510920629406412 0.752727490471191 0 +1058 8.439079370593639 0.7527274904712301 0 +1059 3.196186115823688 0.2499688807004046 0 +1060 1.208087592254619 0.7788506165951099 0 +1061 0.2063560772887988 0.7306557621240342 0 +1062 9.793643922711134 0.2693442378760341 0 +1063 9.788533766954147 0.7279746248784608 0 +1064 0.2063560772888402 0.269344237875925 0 +1065 8.739984088753136 0.9014971850118543 0 +1066 8.560015911246895 0.9014971850118632 0 +1067 0.9206820521428879 0.9032306132427997 0 +1068 4.587876842906619 0.091288144742717 0 +1069 4.726404074002581 0.2303887158091769 0 +1070 0.5741065750616468 0.09544809124907527 0 +1071 3.769885038275676 0.4895117232188005 0 +1072 0.7541799476081342 0.9051737001346341 0 +1073 1.424419722467132 0.5981542726327265 0 +1074 5.030617716755092 0.6024264157703995 0 +1075 1.521392400566706 0.4836602106336062 0 +1076 3.323078119500063 0.3773905348275628 0 +1077 5.383105675475295 0.6191236345544817 0 +1078 8.568199652574201 0.6198776679814634 0 +1079 5.058728739707893 0.9004718727799832 0 +1080 1.62090292913255 0.370128423147336 0 +1081 4.42832761320987 0.3722138120453406 0 +1082 4.508429011310015 0.7452969292668725 0 +1083 5.46099385259441 0.09636969847488797 0 +1084 6.01099385259452 0.09636969847489751 0 +1085 6.560993852594601 0.09636969847494678 0 +1086 8.810993852594903 0.09636969847505472 0 +1087 6.560993852595095 0.903630301524856 0 +1088 5.4609938525951 0.903630301524864 0 +1089 6.010993852595067 0.903630301524872 0 +1090 4.733581020344665 0.4047896506709576 0 +1091 5.943739201633544 0.3014828291394314 0 +1092 5.393739201633502 0.3014828291395358 0 +1093 3.968023847328683 0.7625330326191539 0 +1094 2.764907729003708 0.3863793109788893 0 +1095 3.482200819228765 0.3905741165546065 0 +1096 2.271521539062964 0.2473880986156212 0 +1097 7.528478460933123 0.7526119013838927 0 +1098 3.970927916055819 0.244729744499719 0 +1099 6.491372129154812 0.6929586133409223 0 +1100 6.256390809598039 0.745225579355841 0 +1101 2.993832990170146 0.2489451686680492 0 +1102 0.2796349259585124 0.2043770749176417 0 +1103 4.852497506603047 0.09586254246595177 0 +1104 8.743653511959973 0.3013701472413153 0 +1105 6.49434703190308 0.3000861783695338 0 +1106 5.218974364843493 0.6243689796942151 0 +1107 9.055474030050917 0.7491254222547679 0 +1108 8.725641983397463 0.6281058029696359 0 +1109 1.115583834935889 0.6092951362891293 0 +1110 8.458976627807548 0.4636857153438183 0 +1111 6.484783800789138 0.5886588275503534 0 +1112 8.852669594921982 0.449528856558251 0 +1113 4.547255587892531 0.2222550234004959 0 +1114 0.7709986884283341 0.7874886360105416 0 +1115 8.296832156366204 0.5526943035342723 0 +1116 4.417685557675471 0.08824360877992075 0 +1117 8.660347708111638 0.7593025583038151 0 +1118 9.013374053460572 0.5729781950330834 0 +1119 0.2349673295802572 0.4075392956135419 0 +1120 9.765032670419901 0.5924607043864091 0 +1121 6.555840184654148 0.4464461339195119 0 +1122 1.238052738892907 0.1970990399397134 0 +1123 1.272935652716031 0.7059916098083372 0 +1124 6.223961362260051 0.567470290815571 0 +1125 3.036407087520135 0.427353518928436 0 +1126 0.9547135987987223 0.5401967043658182 0 +1127 0.9044087006510035 0.2390034254544241 0 +1128 0.8187763483333139 0.2593305691158495 0 +1129 1.340592719627352 0.9159640890544613 0 +1130 0.3154777704549517 0.7904044302519373 0 +1131 3.377585034794977 0.7629128439632091 0 +1132 4.161745128814085 0.4613561903421154 0 +1133 4.673762074155774 0.08741273401397616 0 +1134 8.112909845024172 0.237326680118717 0 +1135 5.960316359457609 0.7171579318299154 0 +1136 9.668829406036432 0.21111414038295 0 +1137 9.672727421727222 0.7883125215067196 0 +1138 1.883212540397345 0.4436446095118923 0 +1139 7.151514198809333 0.5558497447605721 0 +1140 7.916787459600839 0.556355390487795 0 +1141 7.041500760540989 0.3137520085899285 0 +1142 1.791500760537952 0.6862479914080204 0 +1143 7.030303343846039 0.6131800063127482 0 +1144 8.019815806665413 0.6182084136602539 0 +1145 1.781262171923929 0.3867608589588063 0 +1146 0.7337857518875398 0.2002936502633889 0 +1147 3.868704060594455 0.08609204606518882 0 +1148 2.168080574806102 0.08853449821750928 0 +1149 7.61663900015178 0.9100174769790664 0 +1150 3.429643586475336 0.2368844043765951 0 +1151 9.324105670927409 0.9111037567165691 0 +1152 4.244301860527706 0.9110252552948782 0 +1153 5.345010816308191 0.7946774887552641 0 +1154 3.321497198669015 0.6244244493968933 0 +1155 3.228843166688361 0.0886204945537178 0 +1156 2.895378433659187 0.09098473771686569 0 +1157 8.145378433664314 0.9090152622829755 0 +1158 6.904621566335792 0.9090152622830283 0 +1159 9.525926230208679 0.2481108712517434 0 +1160 9.79685325680413 0.9078971152909124 0 +1161 9.796853256804051 0.0921028847090497 0 +1162 1.654168216827872 0.9122949307664358 0 +1163 2.896415297077262 0.9092204834003921 0 +1164 6.903087986952523 0.08891695324633089 0 +1165 3.228234827299948 0.9118433601087881 0 +1166 8.272028497853086 0.08866585507286052 0 +1167 0.521414902511702 0.3182077188191916 0 +1168 1.445481451296553 0.3365359332817964 0 +1169 1.580981944369599 0.09212787804681012 0 +1170 9.630900077617151 0.9153689852010396 0 +1171 9.626589713896161 0.08298815925951841 0 +1172 2.172036356566428 0.9081374518964777 0 +1173 7.636073780047811 0.09070894979607587 0 +1174 0.3661052940909629 0.6443822655359728 0 +1175 4.902299695960685 0.9121398434229087 0 +1176 3.86431432263896 0.9099783806013142 0 +1177 2.698334499377164 0.4468039599701591 0 +1178 3.603991805419499 0.4485900386533035 0 +1179 0.7951626498709321 0.3483628897683213 0 +1180 5.953236675721854 0.419265155658802 0 +1181 5.39790437566977 0.4162314269285761 0 +1182 3.586148386530797 0.08850704291294247 0 +1183 3.813625162640775 0.207969292790774 0 +1184 4.44025512145562 0.2090616474847614 0 +1185 8.021464602537481 0.3756775936841785 0 +1186 4.11002076048384 0.08713438975908848 0 +1187 3.590421161896058 0.9110905692479534 0 +1188 7.90927138114312 0.08523930384179816 0 +1189 4.196198810358308 0.6792560200404052 0 +1190 6.344503922335183 0.9110177962401703 0 +1191 5.796934453928326 0.9098512458351857 0 +1192 8.596804518859324 0.08456230997899671 0 +1193 6.346804518859816 0.08456230997878957 0 +1194 5.796934453928944 0.09014875416435683 0 +1195 5.244503922335757 0.08898220376003814 0 +1196 0.1995494976918412 0.9116921259506984 0 +1197 0.5199598749290806 0.4110719424371932 0 +1198 0.9747005565528359 0.6907399209438131 0 +1199 1.328137153341573 0.4442694697463191 0 +1200 9.373857156709903 0.1921046838636485 0 +1201 1.536062880972406 0.8048888301372732 0 +1202 4.04259124647511 0.5913812066783469 0 +1203 2.107268890380905 0.7954377348776932 0 +1204 3.813231588180361 0.7900082669864533 0 +1205 7.692731109615494 0.2045622651223432 0 +1206 6.344209490164359 0.7429634000201885 0 +1207 5.127265275470333 0.1967013897581864 0 +1208 2.373255368064931 0.9095056305912715 0 +1209 7.420966855348262 0.08989144240409622 0 +1210 8.470324624450805 0.9180568740613374 0 +1211 8.826946379173636 0.9150594067561594 0 +1212 4.813442580548323 0.21737277990216 0 +1213 3.017694297752662 0.7988284330155438 0 +1214 5.682305702241944 0.2011715669847009 0 +1215 6.232305702241979 0.201171566984764 0 +1216 6.786786795740863 0.1995840911220728 0 +1217 8.482305702241936 0.2011715669849314 0 +1218 7.052524727350477 0.4249777214381773 0 +1219 1.802524727348392 0.5750222785603455 0 +1220 0.8728011026503273 0.08108878447645647 0 +1221 0.652032441222357 0.9134782902428916 0 +1222 4.93703876511996 0.07899859594605377 0 +1223 5.798763695069393 0.7460204829262508 0 +1224 9.098992329304455 0.0828221171357766 0 +1225 2.443517240638722 0.7988151844931227 0 +1226 7.351746068575703 0.2058332512147071 0 +1227 1.539457555912121 0.2048012953360123 0 +1228 4.26511876076 0.1842016984326775 0 +1229 2.431735431357592 0.2263866726856309 0 +1230 4.128951810008872 0.2344173682323016 0 +1231 7.368264568638446 0.7736133273142206 0 +1232 9.093962364664572 0.9145748604037506 0 +1233 9.642627012913225 0.3587040796441973 0 +1234 1.662757667089563 0.7496569169096259 0 +1235 6.917877700285286 0.2451510578712051 0 +1236 2.383734180160873 0.08438891890323043 0 +1237 7.416265819834795 0.9156110810968098 0 +1238 4.040979438564739 0.3907817640631691 0 +1239 2.213172037705867 0.3993338727279612 0 +1240 2.34213073511094 0.3893646698089988 0 +1241 7.460932227490368 0.6027871305228768 0 +1242 7.589067772509554 0.6027871305228344 0 +1243 4.507395457888714 0.9134776601093049 0 +1244 0.3556083835352742 0.9211062090965834 0 +1245 9.280945986108074 0.08697675055060552 0 +1246 0.1899429681739539 0.07874813215525042 0 +1247 4.393598800730065 0.2894366269717669 0 +1248 0.5600012071771625 0.6734043431914687 0 +1249 0.5538379505496925 0.5869797709601254 0 +1250 0.4737636467403332 0.8127407151285359 0 +1251 5.234214516403394 0.9161254209754228 0 +1252 0.4574626705662553 0.5492925252566723 0 +1253 3.462036385999782 0.7854564078168939 0 +1254 5.020042488549805 0.7802527233527519 0 +1255 4.689784587415069 0.3364690120822927 0 +1256 9.614843596368491 0.6963388648090686 0 +1257 1.668207950614241 0.08272307029347692 0 +1258 8.03781409753508 0.2056063737604844 0 +1259 1.401618054074141 0.1868674379661285 0 +1260 9.541347655086811 0.4534633624575446 0 +1261 9.497072917428536 0.8110851332705306 0 +1262 9.544938543125634 0.09143379394778721 0 +1263 5.184662838665716 0.7970058464519166 0 +1264 5.261244580226923 0.7537259725367899 0 +1265 2.619389636688991 0.4308455089239185 0 +1266 4.901231831071173 0.8145882293166193 0 +1267 1.42567389396372 0.4177502849728216 0 +1268 0.2929574804017542 0.5025480993507047 0 +1269 9.706930452612008 0.4973046329297882 0 +1270 4.619485817487942 0.807336918685979 0 +1271 1.322822929578392 0.08000685954990773 0 +1272 2.914236053428131 0.2728784161160928 0 +1273 9.025162368969017 0.1999516744745277 0 +1274 4.080901696548188 0.9191902570600706 0 +1275 4.312404446644865 0.5782659506862171 0 +1276 4.386755237874041 0.8105839274858934 0 +1277 4.357012501080477 0.6619782778700729 0 +1278 5.00830261350989 0.3164091061958987 0 +1279 3.35498361196039 0.2023937129150092 0 +1280 9.135579212146384 0.724314035529565 0 +1281 0.08083211276605271 0.816740456772829 0 +1282 9.919565106500013 0.1820233182411789 0 +1283 9.919565106500103 0.817976681758794 0 +1284 0.08043489349988231 0.1820233182412086 0 +1285 1.094358506570013 0.917815058024946 0 +1286 4.866060774669254 0.6526101560091683 0 +1287 1.414626361270174 0.6817422323788995 0 +1288 0.4030844526509201 0.08220335917218419 0 +1289 2.912658288470344 0.3789095584928421 0 +1290 9.26206867577949 0.6234519391296051 0 +1291 9.135534385829825 0.6243939876065797 0 +1292 8.161466940086106 0.6281816424099413 0 +1293 6.888621799165451 0.6280790322330534 0 +1294 5.78734171152399 0.6210904415066121 0 +1295 6.337386931367361 0.6221619540704459 0 +1296 0.3618802550228964 0.3547905958419226 0 +1297 4.356317237479963 0.9182939374484015 0 +1298 0.897250147212592 0.793540354385087 0 +1299 0.6050587514819641 0.8028970273260273 0 +1300 2.945430653300356 0.5596681606093188 0 +1301 6.304569346694824 0.440331839389723 0 +1302 8.54861170265599 0.4448592356187249 0 +1303 9.100261819599037 0.4380095835457201 0 +1304 4.259815609321276 0.3210008126860023 0 +1305 9.484778769539314 0.6785952842223533 0 +1306 0.8519507296321727 0.5076707909693006 0 +1307 1.0543200477296 0.7984053985827967 0 +1308 0.6729083476946491 0.07890716476480164 0 +1309 5.091382955273861 0.6988166511293636 0 +1310 2.015633198421373 0.6693796602586612 0 +1311 7.784366801575421 0.3306203397414539 0 +1312 7.265702376928225 0.3322033763674328 0 +1313 0.07973314678986762 0.6143000360271021 0 +1314 9.92026685321018 0.3856999639728226 0 +1315 0.6972177415197366 0.6641730585290893 0 +1316 2.197886621501271 0.3210940132147425 0 +1317 7.602113378494717 0.6789059867849488 0 +1318 1.050684557733905 0.4513499993262554 0 +1319 3.028172825727972 0.6969772545038846 0 +1320 6.221827174266609 0.3030227454956757 0 +1321 8.474261588662133 0.3000301610183283 0 +1322 9.119319367598903 0.3295350625281987 0 +1323 6.65856281002546 0.3151406891112122 0 +1324 5.255467698329588 0.2455056570582304 0 +1325 5.80558858108377 0.2455687186681657 0 +1326 9.606240910107848 0.2577173584317954 0 +1327 8.278794928367855 0.8072201500563552 0 +1328 6.771412412139651 0.807360486589189 0 +1329 5.667493789121079 0.804874925211994 0 +1330 1.298466271022606 0.3069773927304827 0 +1331 9.923490005312576 0.6592015456028308 0 +1332 0.07526747113800566 0.3389958722498989 0 +1333 3.724179719193985 0.07633757876264137 0 +1334 7.774358373069213 0.925508464986481 0 +1335 2.025641626927192 0.07449153501339946 0 +1336 8.99082067946622 0.3250135174175403 0 +1337 5.697247926232499 0.4623236970180365 0 +1338 6.742454760687727 0.462124054002361 0 +1339 5.602120383563557 0.4181199066091606 0 +1340 9.43590533467844 0.3309365642786926 0 +1341 1.9844195454032 0.3156618365468492 0 +1342 7.815195183225327 0.685141682238726 0 +1343 7.234375743223527 0.6811701738218775 0 +1344 0.5807822081540095 0.1777728729199378 0 +1345 1.132590432509096 0.07363842095280194 0 +1346 0.4445449191332682 0.1866259763429388 0 +1347 4.236171818433139 0.8292341687333851 0 +1348 2.918001238473659 0.6331114120188717 0 +1349 8.584298498124072 0.3702356743575648 0 +1350 6.334298498124116 0.3702356743575422 0 +1351 1.077522637584689 0.2103953196349466 0 +1352 2.603846328068153 0.575132629744648 0 +1353 3.647913401257194 0.5747148957466161 0 +1354 0.8047667427540702 0.6165290222649297 0 +1355 6.890823987804183 0.7269594964743967 0 +1356 8.159176012195891 0.726959496474381 0 +1357 0.9395501709565416 0.3811114166576227 0 +1358 9.260858797436542 0.7230826325211245 0 +1359 2.503199331144571 0.5325709641500843 0 +1360 2.75173043253923 0.07882244332508967 0 +1361 8.001730432544267 0.9211775566747692 0 +1362 7.048269567455737 0.9211775566747996 0 +1363 4.465083865396021 0.8099983164565033 0 +1364 9.750429313904313 0.2014696003861693 0 +1365 9.751031763449204 0.7969105759556059 0 +1366 4.112099080559044 0.7925138662767937 0 +1367 1.170341952814511 0.5531366059684836 0 +1368 8.597091341583845 0.8019781395255942 0 +1369 1.183683741639446 0.3616777898647829 0 +1370 8.391923202276081 0.6898238368940466 0 +1371 5.558952869790807 0.6876757203796577 0 +1372 4.300964708387993 0.4258037206613771 0 +1373 2.019780828928624 0.9239604200666024 0 +1374 7.780219171068223 0.07603957993354153 0 +1375 3.719780828926052 0.923960420066012 0 +1376 9.412191560719688 0.455896216440384 0 +1377 1.79714102689964 0.921552476418924 0 +1378 2.752858973095679 0.9215524764197571 0 +1379 7.047141026899328 0.07844752358034807 0 +1380 0.189026194910785 0.577945762999047 0 +1381 9.81097380508918 0.4220542370009517 0 +1382 3.141121092694582 0.3115893090712608 0 +1383 6.109036680919353 0.6861554123070878 0 +1384 1.509074406723581 0.6925629167526985 0 +1385 5.109070775440135 0.3072595339502479 0 +1386 5.66074520055771 0.3074732695576148 0 +1387 6.759264587706591 0.3074968179027018 0 +1388 8.309846358799673 0.6778727626417056 0 +1389 5.640121507022412 0.676852351199593 0 +1390 6.740722858455707 0.6766665746101733 0 +1391 2.06276158798831 0.3267906981423575 0 +1392 7.737238412007638 0.6732093018575832 0 +1393 7.313320588859828 0.6681917949769318 0 +1394 2.099754301331176 0.1928989271830768 0 +1395 7.700245698664872 0.8071010728166885 0 +1396 2.512521417896072 0.1755104553922059 0 +1397 7.287321051808521 0.824207610945333 0 +1398 1.801081705132342 0.07533781047703619 0 +1399 1.158469406224541 0.4589553741342307 0 +1400 3.70602104789771 0.4288476566184082 0 +1401 3.735230858386777 0.1759235311963927 0 +1402 2.487790008393906 0.3303418828400448 0 +1403 3.781068211945874 0.316702358413263 0 +1404 3.735765117367345 0.8267393988472932 0 +1405 2.035885555243287 0.8266877018468889 0 +1406 7.764114444753499 0.173312298153215 0 +1407 1.164743217035401 0.2301744051507063 0 +1408 0.8304133004913958 0.9246598008152165 0 +1409 7.270427277172581 0.07346906918412821 0 +1410 2.529572722823062 0.9265309308160306 0 +1411 0.6640436809850125 0.3379153037288923 0 +1412 3.083940223330968 0.1741287759001346 0 +1413 6.169334674786912 0.8246206551212741 0 +1414 8.966002950796996 0.8258429848411849 0 +1415 1.130716476909433 0.7641404957462418 0 +1416 4.441996767532093 0.6588855657713367 0 +1417 3.77393593403755 0.6890785827361289 0 +1418 2.474271139424336 0.6877491957547786 0 +1419 9.405253333639049 0.6816156068838664 0 +1420 4.464452284142832 0.5751683978057321 0 +1421 5.087280820057898 0.4553027545687932 0 +1422 8.912236154161695 0.3110886122695723 0 +1423 8.362236154161687 0.3110886122695561 0 +1424 4.585551916303829 0.6508406183171388 0 +1425 0.6616951496497896 0.5550100300044746 0 +1426 7.283779724663682 0.1773499901415275 0 +1427 2.516361355812633 0.8222661861669119 0 +1428 6.82801723201983 0.9269340348989756 0 +1429 8.221982767980236 0.9269340348989581 0 +1430 2.969890986416825 0.07382936969496608 0 +1431 4.177887992542596 0.3239459131384522 0 +1432 2.530071145125244 0.07295807022404149 0 +1433 7.269928854870146 0.9270419297758932 0 +1434 6.662206124609451 0.6893845008254645 0 +1435 7.993726654959147 0.446728078476022 0 +1436 1.92242539182837 0.803873351572842 0 +1437 7.877574608168716 0.1961266484271381 0 +1438 7.172425391826406 0.1961266484250011 0 +1439 3.424999999992664 0.0719646785609707 0 +1440 6.82944209904753 0.07333933661525764 0 +1441 2.970557900946968 0.9266606633849835 0 +1442 6.487970721499136 0.9248996668712705 0 +1443 5.9379707214991 0.9248996668712907 0 +1444 8.737970721498922 0.07510033312889158 0 +1445 6.487970721498702 0.07510033312926187 0 +1446 5.937970721498647 0.07510033312932569 0 +1447 5.387970721498549 0.07510033312940134 0 +1448 3.136861937949401 0.688969586090833 0 +1449 6.113138062045063 0.3110304139086894 0 +1450 3.428824574694609 0.9285688676868609 0 +1451 8.075176926880864 0.06866417590247585 0 +1452 9.383102918735196 0.7990387716491164 0 +1453 8.021022532547384 0.7744925473459419 0 +1454 7.02897746745271 0.7744925473459517 0 +1455 4.722392643890726 0.6042845280692847 0 +1456 4.837604956408103 0.5825092756004389 0 +1457 8.907948015451909 0.6918301239486535 0 +1458 0.2295251359491669 0.6586030939621722 0 +1459 9.770474864050755 0.341396906037947 0 +1460 3.099077482376802 0.07563740232019261 0 +1461 6.701810288998463 0.9232826609036301 0 +1462 6.151301951082512 0.9239888907865006 0 +1463 5.600922517617139 0.9243625976796136 0 +1464 8.349077482382917 0.9243625976796533 0 +1465 8.950664281544725 0.0746983036148061 0 +1466 8.402496501897119 0.07602541625623085 0 +1467 6.702062993584829 0.0761570773572504 0 +1468 6.151198438131553 0.07618174016021753 0 +1469 5.600922517616709 0.07563740232026485 0 +1470 3.096638942644224 0.923999246547189 0 +1471 1.514466325820847 0.3028312624641283 0 +1472 1.482176087030211 0.5512830521297206 0 +1473 1.562887338534537 0.5475038276499485 0 +1474 3.058671192196945 0.319736014084369 0 +1475 6.191539251039836 0.6817218226891468 0 +1476 8.990678196019028 0.6826103873781822 0 +1477 2.77876541042418 0.1987233845161453 0 +1478 4.938900966014081 0.671619744118123 0 +1479 7.285430877741875 0.4617267296228186 0 +1480 2.034975037856891 0.5390861356214196 0 +1481 7.765024962139773 0.4609138643790237 0 +1482 4.980460653204507 0.9283966173066793 0 +1483 8.949347309589472 0.924945022685901 0 +1484 5.1621117149777 0.4496835429364069 0 +1485 3.301979558004816 0.5465391131820504 0 +1486 0.9468817143180065 0.6220258789911643 0 +1487 6.714338420581806 0.1768141093236163 0 +1488 6.163022620581796 0.1771824660046274 0 +1489 5.613674265472588 0.1769273729261728 0 +1490 8.414509568384814 0.1763734865654376 0 +1491 3.086237582014895 0.8228830424466099 0 +1492 3.617982188699485 0.1883644114087442 0 +1493 2.627465839239854 0.1927692274028019 0 +1494 2.778342353261075 0.8061377014981244 0 +1495 9.334555438409719 0.4520867068332665 0 +1496 8.212706328650651 0.5682864177685979 0 +1497 1.395905305420772 0.8018267861555154 0 +1498 6.818177921525484 0.4422778259651328 0 +1499 4.564271564915767 0.4526980749571548 0 +1500 3.475139955738982 0.1820307984490761 0 +1501 3.616798572285077 0.8146245175107992 0 +1502 2.630425331767495 0.8121512711355974 0 +1503 4.654238333979408 0.2561934202923218 0 +1504 1.780831501929844 0.2256046219275671 0 +1505 1.851322320111301 0.72839666109672 0 +1506 7.100827017877905 0.2711211017732674 0 +1507 2.138815630153798 0.4378710502277335 0 +1508 7.661184369842567 0.5621289497720868 0 +1509 7.388815630155487 0.5621289497739443 0 +1510 9.312536625973211 0.571118869706602 0 +1511 0.5840527663512176 0.448748291441004 0 +1512 0.3262656014492959 0.07102029523677617 0 +1513 5.529078162883624 0.4066523871323401 0 +1514 6.363390192577314 0.2375832037693026 0 +1515 8.609508652504726 0.2355120373099345 0 +1516 0.4916675985750147 0.7029574344602907 0 +1517 5.056864084581172 0.07324968255808155 0 +1518 4.893314382564455 0.534487087278707 0 +1519 4.13167572059697 0.7170484432431578 0 +1520 7.847311678141747 0.5768755006971633 0 +1521 1.952688321856048 0.4231244993032812 0 +1522 5.723566720348377 0.06964611113095161 0 +1523 6.273566720348318 0.06964611113110855 0 +1524 8.523566720348112 0.06964611113190186 0 +1525 6.273566720348188 0.9303538888675815 0 +1526 5.723566720348174 0.9303538888675699 0 +1527 4.519674266120275 0.07082173520627703 0 +1528 2.223827866561579 0.7228422161615762 0 +1529 7.576172133434926 0.277157783838331 0 +1530 8.672385157680329 0.9300967959136193 0 +1531 8.15918718072494 0.1735859827489369 0 +1532 2.424507258924541 0.5644319819192775 0 +1533 7.376224606593413 0.4361929396423228 0 +1534 2.401828937170615 0.4335411335165532 0 +1535 3.337147737698325 0.8216041348785474 0 +1536 0.9527927720951328 0.3012216130816511 0 +1537 5.73710109827704 0.5714581333347212 0 +1538 6.841328368901966 0.567890177973859 0 +1539 2.111488338344994 0.5476596125648349 0 +1540 7.688511661651707 0.4523403874350017 0 +1541 1.462587895995064 0.9281172236292535 0 +1542 5.509126757607094 0.1883526152416956 0 +1543 6.063105485515941 0.1877537995834923 0 +1544 3.200368199477247 0.8182956633279547 0 +1545 9.142127886107469 0.2606436344919079 0 +1546 4.215064366229283 0.6155198813056918 0 +1547 4.774133602289522 0.8192087691517078 0 +1548 8.876281612180783 0.5954951220622915 0 +1549 3.830043484074865 0.4476616224696247 0 +1550 3.528749399791319 0.4443315556275433 0 +1551 4.807616896222051 0.9298430144588037 0 +1552 0.2368008991256586 0.3351003838670938 0 +1553 9.764962623283358 0.6634163081588896 0 +1554 9.624285345481082 0.6239246797753448 0 +1555 1.575794146878483 0.4366474525790115 0 +1556 3.728129089988372 0.5490518623042527 0 +1557 3.81509699257778 0.5511722183582998 0 +1558 1.033919572049158 0.5443926695002075 0 +1559 0.172017020898098 0.4430406859770119 0 +1560 9.827982979101897 0.5569593140228577 0 +1561 4.049187139460224 0.6654973741840812 0 +1562 3.989592072016053 0.1760658074535439 0 +1563 7.505085427351585 0.8217327579224331 0 +1564 2.294914572644428 0.1782672420772835 0 +1565 8.849890360139051 0.8196518633172438 0 +1566 6.602860350936433 0.8141243779112338 0 +1567 6.608505146328838 0.1871210661122953 0 +1568 8.905454621399491 0.2042461288597069 0 +1569 8.299142521124287 0.1797900335455587 0 +1570 7.4512809754436 0.2426875435841568 0 +1571 2.346270349092835 0.7512150310837474 0 +1572 9.507288795636493 0.5642215556618884 0 +1573 4.411948611110277 0.5190078120821626 0 +1574 4.578265711175895 0.9316967942397518 0 +1575 7.772613260941813 0.8190630345783555 0 +1576 2.027386739054387 0.1809369654215353 0 +1577 2.081995081378227 0.6946019360372061 0 +1578 7.718004918618402 0.3053980639632907 0 +1579 0.8317461309430093 0.7510536513050715 0 +1580 4.774999999992039 0.06695349644024538 0 +1581 2.561437179203433 0.306953220263467 0 +1582 7.335158883848034 0.3208019631648298 0 +1583 1.751077082793908 0.6250325957572181 0 +1584 7.002765361826767 0.3737503767756301 0 +1585 0.2437246147837425 0.7904864515752045 0 +1586 5.008793185357743 0.2013823442339394 0 +1587 9.041445440623407 0.8206909876515381 0 +1588 4.964486698995318 0.5375937549565101 0 +1589 0.7134898193848496 0.742628880434865 0 +1590 7.88182902079212 0.8158165276576963 0 +1591 7.168170979207872 0.815816527657687 0 +1592 1.918170979204307 0.1841834723415055 0 +1593 9.426168648752844 0.06325484987151828 0 +1594 0.5935456199967475 0.5214640952253774 0 +1595 1.587795465140592 0.9258695965777487 0 +1596 8.712380524153678 0.8285443660270543 0 +1597 0.3478969046928685 0.2251184987556752 0 +1598 1.686640650929794 0.8247131207805701 0 +1599 6.936640650931539 0.1752868792199962 0 +1600 1.941029826553931 0.07026288842693486 0 +1601 2.610745759047529 0.0656821293187192 0 +1602 7.189670770566129 0.9298249776136651 0 +1603 7.859364837691299 0.9297880997159691 0 +1604 4.597050215418555 0.3822689828629745 0 +1605 1.938093307761353 0.9300816632733447 0 +1606 7.188093307759924 0.06991833672646637 0 +1607 2.611906692235295 0.9300816632736191 0 +1608 4.039731507639155 0.07016597415443819 0 +1609 6.62546558229659 0.9336848402551985 0 +1610 6.076046606582236 0.9379827418759891 0 +1611 5.525255969884418 0.9335658838880757 0 +1612 8.875255969884192 0.06643411611223712 0 +1613 6.625255969883684 0.06643411611283596 0 +1614 6.075255969883579 0.06643411611300089 0 +1615 5.525255969883429 0.06643411611311725 0 +1616 4.958805325019367 0.7445669197602699 0 +1617 5.760920605803523 0.6867645714113515 0 +1618 6.24195139175602 0.8206107861482453 0 +1619 3.004790962356597 0.1790854819681962 0 +1620 9.445295214530658 0.929452612288176 0 +1621 4.350277651080498 0.07069588689053077 0 +1622 4.223883971524288 0.06648390444069549 0 +1623 5.177552691666598 0.06684717685292406 0 +1624 1.285465447468889 0.2379680062635699 0 +1625 4.765638434507404 0.4735083478064284 0 +1626 6.641871033447496 0.5693013324399993 0 +1627 0.6481180469563156 0.4084561500222071 0 +1628 1.639020514149873 0.2394104211771201 0 +1629 7.100080534805061 0.5991838994308422 0 +1630 8.775907952698427 0.4453006842310374 0 +1631 1.010884815696388 0.1574472684370993 0 +1632 0.06876026046820008 0.679932303380943 0 +1633 9.931239739531739 0.3200676966190188 0 +1634 0.7957656788661265 0.4217075271971804 0 +1635 4.09633566120137 0.4370701213367055 0 +1636 3.921684130881016 0.7127765290421628 0 +1637 1.461878910505258 0.05842140609223882 0 +1638 8.345226503033746 0.8208766228831835 0 +1639 5.604168061585851 0.8203720814463489 0 +1640 6.70127387608911 0.8230551662698887 0 +1641 8.962701749606412 0.1618929385809654 0 +1642 6.376949362550385 0.822642852268435 0 +1643 5.825134836694193 0.8223667245764843 0 +1644 5.28498978236698 0.1760704447751724 0 +1645 5.83498978236699 0.1760704447750484 0 +1646 3.20144719782307 0.1767456345450055 0 +1647 5.510106068352188 0.8260028597174308 0 +1648 8.439896745942244 0.8235073614064732 0 +1649 6.047462905754812 0.8269341647314385 0 +1650 5.359213909075859 0.3614843847670847 0 +1651 5.909213909075935 0.3614843847670164 0 +1652 5.0743573154571 0.1697106409598489 0 +1653 5.060895914209248 0.8406332706174928 0 +1654 9.380456592747393 0.2896230680027898 0 +1655 4.014328811685717 0.517564102697547 0 +1656 7.489435045266999 0.482125112179762 0 +1657 2.310564954728861 0.5178748878193641 0 +1658 0.9701363544740987 0.8484666830338564 0 +1659 9.57634839639638 0.3914146912024515 0 +1660 8.340650050715798 0.4322838195101212 0 +1661 6.090696466810673 0.4331554727519737 0 +1662 3.160062560473127 0.5643506734639803 0 +1663 4.695771972463635 0.1581693891977123 0 +1664 7.370566994306738 0.7043722045792122 0 +1665 9.496701915736121 0.2987415371045092 0 +1666 4.541716854913227 0.3244384275355101 0 +1667 9.251114000323827 0.9349520209857973 0 +1668 0.5315848545257428 0.9337818307772806 0 +1669 5.173069879834423 0.5549821448836618 0 +1670 7.115306774660514 0.7371410238405585 0 +1671 7.934693225339479 0.737141023840572 0 +1672 1.86530677465733 0.2628589761584215 0 +1673 2.420528516712162 0.636274436857673 0 +1674 0.9190578068799826 0.4912263148266232 0 +1675 2.429859236795247 0.2953255939772417 0 +1676 9.516686161868721 0.1717014075038947 0 +1677 1.161072404321896 0.9325757831246756 0 +1678 4.650977597639463 0.5381903976470758 0 +1679 5.300707790672911 0.9317087507608365 0 +1680 9.614790127286454 0.7639321827841761 0 +1681 4.838817467680281 0.7910144880287848 0 +1682 0.7117371640256057 0.5137557276779471 0 +1683 2.87789829494555 0.5049035571239656 0 +1684 1.730021211348363 0.4934662947973203 0 +1685 3.375832706443365 0.5052110078045314 0 +1686 8.663991273587452 0.5010241701867038 0 +1687 8.0699787886493 0.5065337052023927 0 +1688 6.37206033713948 0.4958603548026077 0 +1689 5.330021211350716 0.5065337052024262 0 +1690 5.842558493611745 0.4980201506880138 0 +1691 6.936008726412349 0.5010241701867135 0 +1692 9.169897018097759 0.5024343835453716 0 +1693 4.343017636484294 0.5162189956623577 0 +1694 3.656670939629714 0.06772784768365191 0 +1695 4.111456507096583 0.5648218792415231 0 +1696 3.901286875688425 0.2463941086795984 0 +1697 9.702605097739987 0.6319610256376073 0 +1698 0.8034515037925029 0.07701459277003894 0 +1699 0.2951082883848204 0.3686258292607669 0 +1700 3.978857288507705 0.8337025901725198 0 +1701 3.561685119294089 0.2627903576670592 0 +1702 2.681869216689762 0.2657623551380726 0 +1703 1.468178677314773 0.8254270462326491 0 +1704 7.179224336975142 0.3411215374445956 0 +1705 1.929224336972193 0.6588784625531419 0 +1706 7.86905574618312 0.3375172492685535 0 +1707 8.763718072886176 0.5598757397777262 0 +1708 7.993569632345157 0.8563363918561986 0 +1709 7.056430367654866 0.8563363918561807 0 +1710 9.56235896406187 0.9335919991646772 0 +1711 9.24611117547602 0.2762639250129718 0 +1712 6.628387130648419 0.4511201002691674 0 +1713 0.9965558465436403 0.06744685472681988 0 +1714 8.075000000000072 0.9373413225567924 0 +1715 6.975000000000006 0.9373413225567987 0 +1716 2.824999999994418 0.06265867744297549 0 +1717 0.6832297192105035 0.2434756303691292 0 +1718 8.840798452803149 0.1756116662839234 0 +1719 3.1656260058887 0.06548050466612874 0 +1720 1.80501133473595 0.1447977660825865 0 +1721 1.800875036317054 0.850639386716547 0 +1722 7.045857706520128 0.1460547042631614 0 +1723 0.3621891483780627 0.4901803882724045 0 +1724 9.636975419449362 0.5144918663793371 0 +1725 1.269788623787813 0.9358544583254145 0 +1726 3.563007916599636 0.7070098461640192 0 +1727 2.687343271453247 0.7071755215341794 0 +1728 8.326356562309408 0.06559356592796751 0 +1729 3.173795671370935 0.9344332271135983 0 +1730 1.725000000000001 0.9378523918159786 0 +1731 6.974999999995389 0.062147608183911 0 +1732 2.825000000000005 0.9378523918162054 0 +1733 4.471622565809287 0.4329287829280689 0 +1734 7.941071217882342 0.3042841565973204 0 +1735 7.846459505817038 0.06678932586125953 0 +1736 3.65423199928192 0.9390178046182698 0 +1737 4.532747655005308 0.5694370189867213 0 +1738 1.078454518595158 0.3438736219960243 0 +1739 1.38895560590001 0.9294288137731965 0 +1740 4.019658508527534 0.9284899633538541 0 +1741 8.632300467910634 0.1702855197329138 0 +1742 6.385527572884168 0.1666876036647811 0 +1743 6.536221185167228 0.7413441839370017 0 +1744 4.129443971922266 0.2913833356164945 0 +1745 7.324742720735595 0.597402308834051 0 +1746 2.079316070829602 0.401771439574485 0 +1747 7.720683929166992 0.5982285604259274 0 +1748 2.19064271236381 0.2442800073734608 0 +1749 7.609357287632188 0.7557199926263612 0 +1750 4.359463758281662 0.7649061190165438 0 +1751 4.57202043656076 0.167425169227786 0 +1752 9.719351922784311 0.9299780769030929 0 +1753 9.719351922784067 0.07002192309682526 0 +1754 2.541055474297612 0.4487776523485719 0 +1755 1.034574838777175 0.2843042543070124 0 +1756 2.481272937183828 0.3966217485464635 0 +1757 0.7974931497502779 0.5473140326385845 0 +1758 9.0838541996361 0.5875055163460555 0 +1759 2.966062529362965 0.4125440126623393 0 +1760 6.275383276105208 0.5877214144469531 0 +1761 7.199790813430899 0.6013105564377619 0 +1762 3.911766953697564 0.3323925120428756 0 +1763 3.831878883119578 0.3593061078571074 0 +1764 5.435439786378762 0.2592823327420475 0 +1765 5.985091548956819 0.2587880093325692 0 +1766 0.9134217140116269 0.1636063687532872 0 +1767 0.9716962679883038 0.9357516459423082 0 +1768 8.787207843301617 0.2579168954232338 0 +1769 6.536511119273883 0.2574123690016891 0 +1770 1.832851638961891 0.3902381530561844 0 +1771 7.967268136435134 0.6103139883454233 0 +1772 7.590647555872838 0.3498669011011744 0 +1773 2.209352444123764 0.6501330988989636 0 +1774 4.773100561741158 0.5488099684888214 0 +1775 3.176764881932454 0.3784239738050321 0 +1776 6.07895824991363 0.6166576314677475 0 +1777 2.859134230675749 0.1585563761557318 0 +1778 6.930674131372204 0.8375558871014461 0 +1779 8.122924063295832 0.8365668216153643 0 +1780 9.443338857371096 0.1778045298654263 0 +1781 4.951765144384567 0.1576772947556157 0 +1782 2.348144879576697 0.6738123235234413 0 +1783 7.459227279708637 0.3294647421541981 0 +1784 4.684658875119521 0.9364896629951015 0 +1785 2.869497670088444 0.8373246192299229 0 +1786 1.723179150909181 0.07102613422689878 0 +1787 5.115935418041544 0.9363822696942017 0 +1788 0.5257773341162677 0.065416438890755 0 +1789 4.134718209234039 0.1597829162266059 0 +1790 1.685564915510161 0.1674371100803347 0 +1791 0.3903999286350058 0.4136662269724677 0 +1792 5.399367117023382 0.9358144800418604 0 +1793 4.188676492166108 0.1923075205263543 0 +1794 4.86614009314154 0.3487805035828371 0 +1795 9.372920818456898 0.9358931156035512 0 +1796 2.606580006716266 0.3541208045875424 0 +1797 3.443302499823557 0.7276088993076003 0 +1798 6.196504371517874 0.408225139739484 0 +1799 3.0534956284762 0.5917748602594503 0 +1800 0.3509752377195017 0.7407403545572482 0 +1801 2.737727506670502 0.1414961397876075 0 +1802 6.749970977991681 0.6025826861669178 0 +1803 5.98932030247544 0.5802615311191552 0 +1804 8.959293283552652 0.4447207148427135 0 +1805 5.649797516503107 0.6031622359978327 0 +1806 2.566305870640764 0.2149144608568379 0 +1807 9.165091720166341 0.3859084295354416 0 +1808 3.683644438144932 0.2154852530203074 0 +1809 7.228998847076508 0.7931481788120814 0 +1810 1.363755360691119 0.8404150506686617 0 +1811 5.440004717196294 0.5800660883140344 0 +1812 3.267228312454635 0.4215159060016637 0 +1813 0.06608356644610197 0.4871742122636522 0 +1814 9.933916433553808 0.5128257877363427 0 +1815 3.680086320298984 0.7904272641467714 0 +1816 5.912301916590312 0.8273830529610201 0 +1817 6.462554785612529 0.8267429823900031 0 +1818 8.712124102237771 0.1735146229823093 0 +1819 6.462124102237871 0.1735146229825588 0 +1820 5.912476375361964 0.1734260015325418 0 +1821 5.362476375361982 0.1734260015326193 0 +1822 8.061172688918825 0.270232756481823 0 +1823 3.818584382745252 0.07012473158900888 0 +1824 2.117790951138507 0.07114923095675937 0 +1825 7.680753770282748 0.9287128619190005 0 +1826 4.662461679151721 0.7486559055444169 0 +1827 8.385605980158166 0.5609726821512666 0 +1828 2.74129469813274 0.8580051932264164 0 +1829 9.331610984788263 0.351543855101037 0 +1830 0.4225246941552745 0.6056863982382399 0 +1831 8.958560361690772 0.5516370961495365 0 +1832 7.380098320403619 0.3669306594536612 0 +1833 2.573500761052992 0.7864799801787399 0 +1834 1.468750953250376 0.1729266082570629 0 +1835 2.257141005673099 0.8340285134280954 0 +1836 7.49210375003929 0.1660506343248088 0 +1837 3.141026255226185 0.2042085408312774 0 +1838 6.108973744767685 0.795791459168222 0 +1839 3.095288816265829 0.4427504568411351 0 +1840 6.157644960834797 0.5563348463417709 0 +1841 8.503672714406074 0.6020249640411808 0 +1842 3.928459705729451 0.6243638348984761 0 +1843 8.412342659583057 0.9367299924591862 0 +1844 1.575583454680246 0.6482559325377404 0 +1845 5.175583454681497 0.3517440674621367 0 +1846 5.718904648234066 0.3548310588770804 0 +1847 6.825583454681517 0.3517440674621626 0 +1848 3.372639525884696 0.2729597918046352 0 +1849 6.318227135248292 0.6796216308753101 0 +1850 6.716173059970396 0.3538386339935996 0 +1851 6.889602119820103 0.328276192496536 0 +1852 5.233719005633407 0.3289076927238402 0 +1853 5.78371900563342 0.3289076927238625 0 +1854 1.639734864142197 0.6718771033328839 0 +1855 9.335313918415826 0.8548165042339844 0 +1856 7.685588878784555 0.0700114052404695 0 +1857 2.115844398996484 0.937917535020852 0 +1858 3.934609455768764 0.5047677684509768 0 +1859 2.231306609284841 0.5066714248546215 0 +1860 7.568693390711671 0.4933285751448283 0 +1861 0.4244920956722937 0.9336957127480464 0 +1862 5.638634667276711 0.4821194022632028 0 +1863 3.523552410910818 0.5591990131296052 0 +1864 2.726708121195102 0.5591091179825384 0 +1865 5.073906387769855 0.3552355794360837 0 +1866 8.214793833369956 0.4329359034338964 0 +1867 0.540451471761065 0.8200291902763002 0 +1868 4.988729601678808 0.06980769405795478 0 +1869 8.877914155262637 0.9368418899454122 0 +1870 5.59508723464544 0.5546294592560809 0 +1871 3.865011885765474 0.7751014178048008 0 +1872 2.161333602321089 0.7691862526636533 0 +1873 7.638577412766232 0.2298611310493177 0 +1874 0.4812924551374869 0.2758492643802846 0 +1875 8.91003499822518 0.7934971837808061 0 +1876 4.22062876022567 0.4601924295476279 0 +1877 3.948232745174358 0.3972128694807525 0 +1878 5.525509368871728 0.6164083396954593 0 +1879 2.539253173876468 0.5850609728597311 0 +1880 1.532024898720292 0.0541539173735336 0 +1881 5.447356423847165 0.7498945009259403 0 +1882 8.502643576152847 0.7498945009260264 0 +1883 3.254829548441335 0.2499281183295221 0 +1884 4.566333047760172 0.777614084476329 0 +1885 2.115940692176388 0.6440147756151449 0 +1886 7.684059307820474 0.3559852243851954 0 +1887 7.365814934238837 0.06156385177431992 0 +1888 2.43418506575706 0.9384361482259073 0 +1889 1.741417818648738 0.2876038585294276 0 +1890 4.983611356449255 0.4542709859470183 0 +1891 4.364244673979744 0.2244135553563184 0 +1892 2.233333696733072 0.06013060919536315 0 +1893 3.933476072735058 0.06227132571275366 0 +1894 7.57505953508666 0.940484792463517 0 +1895 6.708230777665437 0.555870637670731 0 +1896 1.385942290234374 0.5560896495182103 0 +1897 8.442990085301497 0.3561392688706104 0 +1898 6.996464024799569 0.7126799886233254 0 +1899 8.053996696534368 0.7127367865704928 0 +1900 7.81790799334534 0.2118184243479101 0 +1901 1.982396486853509 0.7874091943430073 0 +1902 9.650678922861241 0.8476920475471111 0 +1903 9.654234017302276 0.1570407924720567 0 +1904 1.481121850169554 0.4347764617904587 0 +1905 5.304041912113105 0.07113139851526983 0 +1906 5.853807819133137 0.07162778053462507 0 +1907 6.40307537737152 0.07277605774646248 0 +1908 8.653075377371076 0.07277605774664828 0 +1909 6.403576339933283 0.9284833195036313 0 +1910 5.853807819132596 0.9283722194650736 0 +1911 4.191375877916483 0.938535118710233 0 +1912 8.428194415914476 0.62087685264397 0 +1913 5.324197594670475 0.7245902783555915 0 +1914 2.225966958871815 0.9325205156026889 0 +1915 7.568444921297388 0.05915077495237761 0 +1916 3.807775860511662 0.9332290851447579 0 +1917 6.435768453518883 0.6176782081324779 0 +1918 0.9298956846155938 0.0598984291070852 0 +1919 4.241574306889828 0.5535466278906629 0 +1920 8.357315979309027 0.2084080769928342 0 +1921 6.660053698988558 0.2125303039309493 0 +1922 4.034155349798034 0.3357278565810021 0 +1923 7.465127919053797 0.6713471404380719 0 +1924 2.334975047025725 0.3347892209581531 0 +1925 9.153836598168155 0.9304379623239922 0 +1926 9.15240084391278 0.06517084375362202 0 +1927 9.176213941748015 0.8416824007238122 0 +1928 9.222041266102634 0.1590271505375111 0 +1929 7.232130791652902 0.2162407622599772 0 +1930 9.313292243546444 0.2284698026778763 0 +1931 3.693392765589553 0.2888032305468964 0 +1932 1.071059926149195 0.6626612766880615 0 +1933 9.849095170235898 0.06548456558736203 0 +1934 9.849095170235953 0.934515434412674 0 +1935 2.813713371330909 0.2723862563967748 0 +1936 8.19056520436243 0.6727637631538584 0 +1937 6.85950362363172 0.673200565214901 0 +1938 2.423792817350498 0.1648312422952774 0 +1939 7.376088249583719 0.8347607554565694 0 +1940 4.862940262881372 0.4610414319185072 0 +1941 0.8558337723821922 0.6526779717837109 0 +1942 2.802595105485447 0.5522362790972476 0 +1943 3.438962777510219 0.5481258443221197 0 +1944 2.840654859779871 0.6196016654703622 0 +1945 3.40858170910423 0.6163288681858119 0 +1946 1.024664310918341 0.4056801790784055 0 +1947 1.467082407423866 0.6457489791603205 0 +1948 2.810545869229985 0.7261938716949493 0 +1949 8.624213301639653 0.7298611831948421 0 +1950 2.630555655539494 0.4839377336191901 0 +1951 2.434765087333115 0.06948448605775337 0 +1952 7.365234912662471 0.9305155139422044 0 +1953 0.2486097881189421 0.9406228879018064 0 +1954 2.885072153589761 0.7263754112538147 0 +1955 7.780543760419849 0.5473960477425137 0 +1956 2.019456239577246 0.4526039522580139 0 +1957 7.264567866148822 0.5486178520095191 0 +1958 6.448569976381733 0.4468990660748524 0 +1959 8.14597973429545 0.4488612719157771 0 +1960 8.8778410341219 0.3926815435018725 0 +1961 1.209009370795114 0.4354634750458747 0 +1962 5.915278150538335 0.6790167124918769 0 +1963 1.652912147683466 0.5541439730455213 0 +1964 9.246158978881668 0.4512066532550159 0 +1965 5.251839952780751 0.4545231820605335 0 +1966 2.32697088239573 0.9413941963206526 0 +1967 7.477034747420654 0.06559820131694283 0 +1968 8.606539216736103 0.9357263574931163 0 +1969 1.185288754638819 0.6292385472361798 0 +1970 3.633516644147182 0.4006271401467945 0 +1971 9.294898731079634 0.6745664808688256 0 +1972 8.666043318515516 0.3787012407809944 0 +1973 6.415877077208389 0.3789756303056026 0 +1974 8.11419720450245 0.3876078081906805 0 +1975 4.703159916660931 0.4625967890373412 0 +1976 6.104572286589404 0.2125828018172118 0 +1977 5.5576370629287 0.2110538463373572 0 +1978 3.142772235988428 0.7916329773529301 0 +1979 1.263463243537586 0.536839134739438 0 +1980 5.085877447968079 0.5743124851011452 0 +1981 1.189962774824008 0.06136227976859469 0 +1982 8.804459305861755 0.707128677637588 0 +1983 8.260204435134463 0.2903514507818848 0 +1984 0.5935226698861518 0.9382406430332204 0 +1985 5.1861897516546 0.9418986484852603 0 +1986 4.821322427501069 0.1461926436248581 0 +1987 4.42499999999997 0.943170377553355 0 +1988 1.685246948977875 0.6141135754832018 0 +1989 5.835246948979345 0.3858864245170158 0 +1990 5.28524694897937 0.3858864245170073 0 +1991 6.9352469489794 0.3858864245170103 0 +1992 6.16412573614712 0.3330262629732116 0 +1993 3.085874263847379 0.6669737370262738 0 +1994 0.7054346559584892 0.9381231787525317 0 +1995 4.600200412096694 0.594933833215787 0 +1996 1.553202942940497 0.1465802569435792 0 +1997 4.536789835577868 0.6890718143584844 0 +1998 8.701648717682531 0.4565775669042888 0 +1999 3.24566845038791 0.7035438895841462 0 +2000 1.264035960053122 0.7663396749678094 0 +2001 3.684157966676827 0.7075707380135035 0 +2002 2.564828192296801 0.7121046097934429 0 +2003 1.584352241988849 0.7733460454812828 0 +2004 2.1428223544608 0.1624682666129037 0 +2005 7.657177645535193 0.8375317333869167 0 +2006 5.801557924825824 0.4467764276129056 0 +2007 6.902648594938078 0.4582586497381131 0 +2008 4.305566634287258 0.9402706104940902 0 +2009 0.5121257545493278 0.1571551916060206 0 +2010 9.388567646605923 0.5933449708245373 0 +2011 8.236742569859999 0.5116814220013663 0 +2012 2.319144270470916 0.04902244848619167 0 +2013 7.479483238813368 0.9508468004648685 0 +2014 4.156031794467266 0.06097373949218658 0 +2015 5.51426781995112 0.3164261112984999 0 +2016 4.038467441272769 0.4590615098263713 0 +2017 7.461509308933604 0.5412134114902342 0 +2018 2.338490691062599 0.4587865885089181 0 +2019 7.358372542470158 0.2702402199908048 0 +2020 1.638640856150605 0.3207973120046082 0 +2021 1.566568479562423 0.350235459851574 0 +2022 5.185616230743535 0.2220615695698122 0 +2023 0.42496240987196 0.7817337668817865 0 +2024 0.7856524955947597 0.1672745547287962 0 +2025 3.364746492258996 0.9403477836146739 0 +2026 8.135253507737179 0.05965221638425524 0 +2027 2.433641334127216 0.518664859448816 0 +2028 0.2355559265810621 0.1634486389457663 0 +2029 2.297306366507681 0.6129473433532224 0 +2030 7.502488960082679 0.3906354590715659 0 +2031 2.787230397806079 0.4469547322440698 0 +2032 3.459546060242143 0.443419123191529 0 +2033 3.848156277749675 0.1466030482316883 0 +2034 3.82121145744915 0.6361923388528044 0 +2035 8.412168753201739 0.4405062748940196 0 +2036 1.647071506826557 0.4491312332027885 0 +2037 9.938381860880655 0.6047200398089907 0 +2038 0.06148008094711575 0.3950796732858122 0 +2039 3.370699261296192 0.06166122149390858 0 +2040 4.631201053978376 0.6803093987409605 0 +2041 8.17048482141646 0.3325392000949396 0 +2042 0.7474541993482835 0.8415454198726234 0 +2043 9.266459598827286 0.3311102109202654 0 +2044 1.237956658837047 0.8461540041617566 0 +2045 0.3339935434538535 0.8488075347857209 0 +2046 9.045027646075742 0.06587952254510142 0 +2047 2.733493407877924 0.6495349638847436 0 +2048 3.516642993033541 0.6494119918856609 0 +2049 0.579292528606081 0.3059475089061532 0 +2050 4.692214286648289 0.8624154086455549 0 +2051 5.737851463731199 0.2220141170671592 0 +2052 6.838001611838308 0.2235694759465399 0 +2053 1.160244269912131 0.3053714765368851 0 +2054 4.841101431238489 0.702536922280762 0 +2055 1.300643524632979 0.5849736179465382 0 +2056 5.917189076962542 0.4656938651403441 0 +2057 1.939005776247975 0.5490961892953347 0 +2058 7.186628778527204 0.4512075639444407 0 +2059 7.860994223748973 0.4509038107047813 0 +2060 4.163482412682888 0.4089414482775415 0 +2061 1.266090001678474 0.6470475011162142 0 +2062 1.289602343586385 0.4902439288098706 0 +2063 8.300186980540337 0.6133769144262399 0 +2064 4.033845011228175 0.7978162171087192 0 +2065 8.992423941264635 0.3993137029337582 0 +2066 9.932490051040856 0.06054439748870012 0 +2067 9.932490051040894 0.9394556025113125 0 +2068 0.06308211961276154 0.9440199296255695 0 +2069 0.06223035248747356 0.05580344853242834 0 +2070 2.143132900402788 0.8617604660686099 0 +2071 7.655416635103267 0.1367478915735336 0 +2072 3.459668889180999 0.6639796590469722 0 +2073 2.790331110806292 0.6639796590474806 0 +2074 5.411607096523208 0.8686882432530577 0 +2075 0.2309620070988828 0.8630181876522449 0 +2076 9.041727643141655 0.9401019876777694 0 +2077 0.3173880747668893 0.1590990306216976 0 +2078 3.554130835557813 0.1363239547015734 0 +2079 3.039502560354304 0.3823490515356249 0 +2080 6.210533584231533 0.6165583285320345 0 +2081 5.053746281565451 0.6481677994662023 0 +2082 7.914923059620439 0.1509679291090025 0 +2083 4.89786283050135 0.4171475345966214 0 +2084 0.4322331325398293 0.6741212262921478 0 +2085 3.314987697628645 0.772375801568845 0 +2086 4.925209297587413 0.2962230235429905 0 +2087 0.3122431749196797 0.6420483203131871 0 +2088 9.437156971257068 0.5469461216168585 0 +2089 6.63396946720704 0.6175295311330256 0 +2090 5.723945281155552 0.1298988881200175 0 +2091 6.280671313422562 0.1341752718853756 0 +2092 8.530671313422367 0.1341752718858115 0 +2093 5.725574791202712 0.8689275516042149 0 +2094 3.838792712006491 0.864316034645809 0 +2095 0.1452678325186997 0.9399371240236324 0 +2096 9.010425669330509 0.6176975927680827 0 +2097 3.5536893160797 0.863543696571287 0 +2098 4.314642298468002 0.702082024370896 0 +2099 9.759955791286462 0.1448756432018196 0 +2100 9.759955791286488 0.8551243567981398 0 +2101 0.8988132735249104 0.8471285187836586 0 +2102 5.244682422169682 0.5495143222431547 0 +2103 0.2591131143522244 0.4615076127344033 0 +2104 9.740875160586443 0.5385553900926086 0 +2105 3.627632556580211 0.3271652103041056 0 +2106 1.417496006659806 0.2862968569791662 0 +2107 4.416893181407356 0.151780641243747 0 +2108 2.440221161692591 0.7361135281006899 0 +2109 5.24623174281742 0.6704233226646021 0 +2110 6.778694304818472 0.9513245621209799 0 +2111 8.271305695181589 0.9513245621210008 0 +2112 3.021956506229051 0.05553292995389783 0 +2113 9.438237190107293 0.8225715932521382 0 +2114 2.3345764565113 0.2124848781966242 0 +2115 7.465420839753599 0.7875106564903692 0 +2116 4.038817015578882 0.2203063641174252 0 +2117 1.367392082700966 0.4889717602971339 0 +2118 8.15442047015946 0.5521879635465599 0 +2119 3.499273418676342 0.8440173955113544 0 +2120 4.628233331428465 0.05317685895199255 0 +2121 5.961541108112034 0.8698346314104716 0 +2122 8.761541108111979 0.1301653685896776 0 +2123 6.511541108112091 0.8698346314104626 0 +2124 5.970480335728962 0.1259124953038765 0 +2125 6.520282308479595 0.1258481271615349 0 +2126 5.420480335728909 0.1259124953039172 0 +2127 7.390470420673624 0.1336813219991666 0 +2128 2.409529579322355 0.8663186780010391 0 +2129 0.3568576822708232 0.2964967626674195 0 +2130 9.489846937509988 0.05374801921704161 0 +2131 3.021328964596349 0.9512422683387223 0 +2132 6.778657299273702 0.04875938588268582 0 +2133 3.275037260776837 0.05306363982850525 0 +2134 8.185444625609124 0.2272400948380527 0 +2135 3.996329226826563 0.6137468967492786 0 +2136 6.986697806037783 0.4868967835217871 0 +2137 8.61022715399741 0.4879818784325211 0 +2138 3.924914791919938 0.9515716259272394 0 +2139 0.1605430739231987 0.5052568630171074 0 +2140 9.839456926076785 0.4947431369828332 0 +2141 3.27617301466544 0.9478851211571561 0 +2142 8.224103889130545 0.05260398137863809 0 +2143 8.333151875165564 0.3872380923320078 0 +2144 6.656729779675234 0.7756638587967197 0 +2145 8.031953211258084 0.1516536137962925 0 +2146 6.820001752633225 0.1292812983706368 0 +2147 2.974722312130375 0.8726686817910529 0 +2148 0.1519631860197425 0.6964485476275397 0 +2149 9.848192701485804 0.3038712268807562 0 +2150 9.85275784981587 0.6942202293256126 0 +2151 0.1455778941159008 0.3029189635051853 0 +2152 6.005546948915624 0.5118870475134232 0 +2153 5.45640821753388 0.5119398025680154 0 +2154 3.244451093469189 0.484054493193566 0 +2155 0.2439360706439927 0.06266323712914589 0 +2156 6.082439454284811 0.3842793288862674 0 +2157 3.173266072369802 0.6185171869530415 0 +2158 0.4513707295018103 0.05695462229657147 0 +2159 9.233013981655507 0.05400746359961318 0 +2160 6.824534865825079 0.8708607055691527 0 +2161 8.225968201305889 0.8706982144596509 0 +2162 5.18226037217872 0.1350574579070771 0 +2163 0.6287099401582847 0.8558434907987493 0 +2164 0.8502376225791539 0.3748006971005947 0 +2165 2.820568879327971 0.3767313205617021 0 +2166 3.425907302226175 0.3745486627496481 0 +2167 4.476071697815978 0.3443608120746599 0 +2168 0.6227591992463229 0.05330765841236582 0 +2169 2.202581424751326 0.5547035979968169 0 +2170 7.597418575245451 0.4452964020029088 0 +2171 3.901484264294194 0.5521504391295191 0 +2172 4.716481892470169 0.2881990901515743 0 +2173 1.046398428837069 0.9427952611783843 0 +2174 5.8799175519279 0.6160340852328237 0 +2175 5.909283287418872 0.568597345318873 0 +2176 2.626361054012239 0.6727456147707068 0 +2177 3.62515949707118 0.6718441570359657 0 +2178 6.27753687431221 0.8715724422663679 0 +2179 1.274537769673715 0.05354957252174463 0 +2180 7.837626759300076 0.6315553940249332 0 +2181 1.962109047447421 0.3685412264761808 0 +2182 5.171754802062797 0.6543625180181569 0 +2183 4.373653633747365 0.3955409111127247 0 +2184 0.1601614662625759 0.7675646364240435 0 +2185 9.834264158718538 0.2304663122218376 0 +2186 9.842924347772852 0.7698097873090449 0 +2187 0.1639539020428971 0.2306754725452193 0 +2188 8.491906315115751 0.5089367427428373 0 +2189 4.73308385279275 0.7410412355430541 0 +2190 6.154962863899692 0.4531917564265052 0 +2191 3.097341987679252 0.5521938280196094 0 +2192 5.377816557622015 0.4695884466559593 0 +2193 5.210569081662324 0.8438975169200381 0 +2194 5.137320216098034 0.8245065435673563 0 +2195 4.986905195595438 0.6415061624897676 0 +2196 3.54420102473461 0.05903176355356984 0 +2197 4.180882346636821 0.8332618166078137 0 +2198 1.279934717666822 0.8721380332999239 0 +2199 7.881034673436259 0.514492737542164 0 +2200 7.107480269200887 0.5189549452416234 0 +2201 1.918651377113689 0.485295944864211 0 +2202 4.103339204604153 0.8565694169634653 0 +2203 8.789490755850521 0.8696420610425869 0 +2204 8.509811060867451 0.869769640371777 0 +2205 2.228770223207788 0.1261250512315095 0 +2206 3.922933981110398 0.1251566280372339 0 +2207 7.579623008611828 0.8744903504274087 0 +2208 0.7294695845545996 0.05516294912074261 0 +2209 7.234374980717312 0.2857626494335109 0 +2210 1.983871730200814 0.7145231631373594 0 +2211 7.816041678242307 0.2845808964509554 0 +2212 3.545032541044358 0.9413722554408523 0 +2213 7.955523063262046 0.05895677558047663 0 +2214 2.203647633741863 0.4549833164260547 0 +2215 7.596565681513575 0.5452186838830926 0 +2216 7.574881865173045 0.1304233012011507 0 +2217 4.229569619672253 0.7346891593692652 0 +2218 4.807079429661352 0.2671914792795749 0 +2219 3.895523795012298 0.4564731433667812 0 +2220 9.060861237929888 0.1522942829685132 0 +2221 4.756596125836884 0.6934092724743034 0 +2222 4.592672673599536 0.2481781205902829 0 +2223 5.321871070045207 0.6176483613721212 0 +2224 8.627464616148107 0.6230243347944778 0 +2225 0.5869909270352563 0.7259759872096696 0 +2226 5.674326998316075 0.05510676642549554 0 +2227 6.224378067677191 0.0551012047997042 0 +2228 8.474378067678357 0.0551012048002372 0 +2229 6.224418199124412 0.9449689863195849 0 +2230 5.674589935815277 0.9447933298900743 0 +2231 3.803782048620201 0.732953629907245 0 +2232 9.248323134681275 0.5481786171170367 0 +2233 1.200319309904546 0.1522606257286818 0 +2234 2.963773882613875 0.7760910763095183 0 +2235 6.290749934859065 0.2202455956815653 0 +2236 8.536226117380673 0.2239089236906812 0 +2237 1.011916119616023 0.7328615648651877 0 +2238 8.737985740580791 0.7718414516800312 0 +2239 6.519854040939943 0.54949412022647 0 +2240 0.9348214620141041 0.7294017278069671 0 +2241 5.316595122619808 0.8466860137541756 0 +2242 4.003243273024433 0.7213520960257916 0 +2243 5.420067456036516 0.6643340381408516 0 +2244 8.536769571931607 0.66511470002216 0 +2245 3.279932543957367 0.335665961857741 0 +2246 3.183241015222155 0.4906307027309981 0 +2247 6.062549989505876 0.5074724561572213 0 +2248 5.5166169823012 0.5043763272246978 0 +2249 8.522439025778493 0.9461369860065677 0 +2250 8.77756097422151 0.9461369860065568 0 +2251 4.471865460788837 0.05516635817665286 0 +2252 3.258726800336636 0.866241527972747 0 +2253 8.241240970388793 0.1334144513575303 0 +2254 5.135129187148555 0.7328250106026059 0 +2255 3.341744911652361 0.4335834219442006 0 +2256 5.358255088340409 0.5664165780547136 0 +2257 8.593297011411858 0.571084919020762 0 +2258 3.271454921949725 0.135125466715551 0 +2259 1.066396242488731 0.8502029371115457 0 +2260 0.05726171555473158 0.5605797435792595 0 +2261 9.942738284445305 0.4394202564207957 0 +2262 8.706033353956473 0.5520005433947237 0 +2263 2.334535166749272 0.8691367255484038 0 +2264 9.145312724495559 0.124592584279406 0 +2265 4.783679244600966 0.3707736593885267 0 +2266 1.533946876012719 0.7454518713406336 0 +2267 1.679138292624931 0.3799868478538064 0 +2268 0.484860815818728 0.4515131598092176 0 +2269 4.90548664961044 0.2423034438238409 0 +2270 7.51649733861792 0.6003103692067064 0 +2271 2.269072992555805 0.397212869476483 0 +2272 3.894307603429958 0.6552839988769996 0 +2273 1.120481602181347 0.6895921357408403 0 +2274 3.503679211325406 0.2345466587425376 0 +2275 9.328404915781816 0.05518774142815941 0 +2276 6.97286304447675 0.6210904415065759 0 +2277 8.077601713923144 0.6244171267092684 0 +2278 6.894361739960735 0.5515214887236967 0 +2279 5.794361739960721 0.5515214887236894 0 +2280 9.216650715787514 0.3959092042835526 0 +2281 2.302603566995582 0.732252264223783 0 +2282 7.496380355560886 0.2818144324880326 0 +2283 4.161923170890765 0.608398568171733 0 +2284 7.829631435461929 0.7907426316509407 0 +2285 1.970368564534123 0.2092573683481297 0 +2286 1.58050721626525 0.8726369866318585 0 +2287 3.44928554955116 0.3229595316102463 0 +2288 0.0557343116027233 0.7656276716089513 0 +2289 9.946030479696535 0.22636787147026 0 +2290 9.943338795249655 0.7724312759947694 0 +2291 0.05573431160255494 0.2343723283912383 0 +2292 5.137278014694301 0.2589436425892584 0 +2293 1.17961533988174 0.8533087037741109 0 +2294 2.797152175227705 0.3260395257838735 0 +2295 6.427600901300315 0.5200387333750401 0 +2296 9.695393983113334 0.363744640628502 0 +2297 3.807359969491215 0.2666847834706963 0 +2298 3.526378132662282 0.3443890595877758 0 +2299 2.72613826054187 0.3435516207617655 0 +2300 4.636914304591023 0.1286857059087355 0 +2301 5.361974241073987 0.6684139179538595 0 +2302 8.58877272617471 0.6690714765555568 0 +2303 3.3423791566596 0.3290821857479805 0 +2304 9.841948988725951 0.8774826964693712 0 +2305 9.841948988725955 0.1225173035306344 0 +2306 8.322318710761166 0.4993270704267971 0 +2307 6.01262422312525 0.7236280090220697 0 +2308 8.21022238995859 0.3562047051564695 0 +2309 8.689194121600545 0.2833776365888716 0 +2310 6.439194121600827 0.2833776365890881 0 +2311 0.1411448884074848 0.05989546511478173 0 +2312 5.889088813996358 0.2833426817507864 0 +2313 5.339088813996362 0.2833426817508515 0 +2314 7.096629959112569 0.6629363348522705 0 +2315 4.139717600131671 0.5194462430438136 0 +2316 6.498832667639947 0.4507261193495108 0 +2317 2.221031751926681 0.8789554225186386 0 +2318 6.438722956691654 0.7167787575607256 0 +2319 7.060141202419977 0.3680636578851087 0 +2320 1.810141202416609 0.6319363421131644 0 +2321 0.7266128818586526 0.4498755383768804 0 +2322 2.969803443506841 0.1330473997345902 0 +2323 5.128434802380942 0.05239715866750024 0 +2324 6.452071826012877 0.3409842353818535 0 +2325 8.705363505291109 0.3400493638755807 0 +2326 5.688758881508124 0.2581965509094357 0 +2327 6.788758881508227 0.2581965509094908 0 +2328 1.373185445846347 0.05249497210602134 0 +2329 8.703860114243426 0.6786943729071583 0 +2330 3.247526994696239 0.5867245262908216 0 +2331 6.555869146140166 0.5870688986348357 0 +2332 4.856842484599998 0.9440332030747233 0 +2333 6.528650822076253 0.395524038751967 0 +2334 5.560296795556283 0.2796863141882536 0 +2335 9.151509896712826 0.5634764967487249 0 +2336 6.348289799235898 0.5676987012831918 0 +2337 2.907153704429391 0.435919411166921 0 +2338 2.327558217932591 0.1224637612400891 0 +2339 7.470794793209408 0.8773793375011782 0 +2340 0.7079424840180334 0.1476378604008806 0 +2341 9.669212643496323 0.4132623177793734 0 +2342 4.574719608434738 0.8773758454447345 0 +2343 1.805100974816942 0.7646349296426305 0 +2344 7.055100974815832 0.2353650703559347 0 +2345 0.3117040986711642 0.9440350884558272 0 +2346 3.35461862966836 0.153738065237793 0 +2347 4.131389076920015 0.9459667649269257 0 +2348 8.741845752093333 0.2188793324523967 0 +2349 6.490787860883774 0.2182074910652258 0 +2350 9.641449963711667 0.2990887777906019 0 +2351 3.246568394814307 0.7588959934614732 0 +2352 8.759936980709128 0.3513829610076852 0 +2353 0.4123199150470901 0.317914871796828 0 +2354 9.143061498028096 0.8811497259744785 0 +2355 6.491228716816393 0.7809082337416186 0 +2356 9.254595904013616 0.8668186130148047 0 +2357 1.524943138492711 0.9580943944234307 0 +2358 8.764823452733866 0.6641377357993519 0 +2359 6.517941978983708 0.6509071163469903 0 +2360 4.002495489155296 0.2894714675971004 0 +2361 2.304626312636812 0.2878637927526339 0 +2362 7.495373687359274 0.7121362072467886 0 +2363 9.265273121445912 0.2208603839629934 0 +2364 8.902479545859231 0.4407883639781862 0 +2365 8.869238680048841 0.5061981389852468 0 +2366 1.271891713661229 0.1480746395200299 0 +2367 5.971680806584017 0.6656485138190286 0 +2368 5.940759350327435 0.2194679602914261 0 +2369 5.390597747321688 0.2184777682247474 0 +2370 0.2579074660929249 0.7442416207638247 0 +2371 9.737852459314222 0.2583963011037819 0 +2372 9.741542989551142 0.7465242279689212 0 +2373 2.82340903053472 0.4882476008397138 0 +2374 3.422702934885093 0.4841317829365348 0 +2375 0.05384435039210328 0.8682158539353787 0 +2376 9.948557434957715 0.1339159485270518 0 +2377 9.948557434957818 0.8660840514728091 0 +2378 0.05075486512925088 0.1333964203900839 0 +2379 2.931908171504539 0.328515393393891 0 +2380 1.67342246113425 0.4884783124887076 0 +2381 6.615187729226935 0.4014711053058082 0 +2382 9.135156784960907 0.7751157744180248 0 +2383 3.470377542818667 0.0516096060833055 0 +2384 1.892076512619642 0.8471238801593821 0 +2385 7.142068923077837 0.1528691440523132 0 +2386 4.887778966930301 0.05538534173565613 0 +2387 7.924058154810179 0.243869559905585 0 +2388 7.364326921466968 0.4831822647099551 0 +2389 0.8779928557905575 0.9476662512310297 0 +2390 5.407592871243676 0.3490905070385722 0 +2391 5.957853274094752 0.3494833934506548 0 +2392 3.716090294555528 0.5996987001237372 0 +2393 1.217484431924112 0.7289297064933513 0 +2394 8.788833250219694 0.5004252820817101 0 +2395 0.6205015575780386 0.6788444375042959 0 +2396 3.740349139836265 0.3510484070405442 0 +2397 1.751686667877862 0.1937089693095684 0 +2398 4.488804367904672 0.235573261312991 0 +2399 3.341471112679394 0.6781880848002744 0 +2400 5.278049804558104 0.5119243620062278 0 +2401 8.43850774059891 0.5069448037775259 0 +2402 7.009244973886705 0.5617109061777874 0 +2403 8.048332961828859 0.5509480082751214 0 +2404 1.752849987208178 0.435522014497182 0 +2405 4.478286123714315 0.865199023919776 0 +2406 8.126697037724119 0.5038890197647885 0 +2407 0.1455390618513147 0.5897000170740123 0 +2408 9.854946388393953 0.4103050473215378 0 +2409 7.472645838070708 0.1227071937283686 0 +2410 0.6764701681396718 0.7732035886675438 0 +2411 8.022199823708457 0.05185679930411124 0 +2412 3.47430117993929 0.9515677137781099 0 +2413 2.902709690281229 0.7799411900428419 0 +2414 3.942862767448681 0.2908958114035358 0 +2415 4.683339107875842 0.3841022550949182 0 +2416 5.884273008196046 0.5184573869135786 0 +2417 9.417447617288039 0.1324162368506439 0 +2418 7.160589651718709 0.4023010001238497 0 +2419 1.910589651715387 0.5976989998756942 0 +2420 7.889410348281144 0.4023010001243665 0 +2421 4.279748475564877 0.373654212824519 0 +2422 3.04259119541313 0.2208039684125522 0 +2423 6.207209618459772 0.783979609214274 0 +2424 1.014468061943088 0.4891208342907433 0 +2425 1.079378970017765 0.05235171814148168 0 +2426 9.23130502172773 0.5029434860303513 0 +2427 5.939262453956536 0.773731995618641 0 +2428 6.026197904916457 0.3027679581567828 0 +2429 0.423756655043308 0.1339059708144002 0 +2430 1.755120116268727 0.336580103553773 0 +2431 4.626500623062643 0.4898126940321233 0 +2432 1.086829224311736 0.1509359761373379 0 +2433 0.3257347032484146 0.5861145542009931 0 +2434 4.372866099587001 0.8652729544354859 0 +2435 4.95464834520222 0.8009055398915406 0 +2436 0.2616519416435748 0.2598960844124848 0 +2437 6.996193487935081 0.8085117615038655 0 +2438 8.051601287829453 0.8066112765923283 0 +2439 1.330573804442633 0.6955379935690703 0 +2440 4.895707776241139 0.1260508767959664 0 +2441 4.038878677397723 0.1244366028557762 0 +2442 4.723926221930848 0.04817266437347287 0 +2443 9.558713012494058 0.8793492864269471 0 +2444 6.99437757336063 0.2884737529571729 0 +2445 1.744358148458956 0.7114925128253811 0 +2446 9.077132546286776 0.2128497709891161 0 +2447 0.2545161023538894 0.541097787379949 0 +2448 9.745483897646267 0.4589022126200925 0 +2449 6.354577443737531 0.2820098460960521 0 +2450 8.604000159989191 0.2825147185783147 0 +2451 0.4743480350939552 0.7663508153959037 0 +2452 5.550718597754584 0.566457914261367 0 +2453 9.29324701516467 0.7660610133547272 0 +2454 9.658120049678493 0.7377493336042698 0 +2455 9.672938722502781 0.9522188368585724 0 +2456 9.672864703670074 0.04743738024770502 0 +2457 2.221212091662383 0.7803266810538498 0 +2458 7.57487205660916 0.2228666202285036 0 +2459 8.401507678002046 0.7940567077602578 0 +2460 5.548492321998043 0.7940567077601989 0 +2461 0.7408340373285525 0.3470775728361167 0 +2462 4.53836709282483 0.4953665081114378 0 +2463 2.509054220956537 0.6542221946499409 0 +2464 5.468768526582801 0.3030717885636222 0 +2465 9.616891714911086 0.5761263728805013 0 +2466 6.863105103735501 0.7681048285901064 0 +2467 8.186931331356996 0.7680612698960636 0 +2468 0.1530273516199136 0.8797801722048182 0 +2469 8.804546137612027 0.7603017154305683 0 +2470 8.25477464670538 0.2390201134729476 0 +2471 8.562759138793973 0.8458534878108996 0 +2472 6.692846070511343 0.4425511574081349 0 +2473 8.046561643983845 0.3225753906372361 0 +2474 4.462385910636775 0.7104746004770399 0 +2475 8.258880788761871 0.4136585082210694 0 +2476 5.720958303525235 0.411968787135123 0 +2477 2.313196144867511 0.8199426167634436 0 +2478 6.805964727342785 0.5053044950598576 0 +2479 7.008061281905785 0.6641747723365286 0 +2480 8.040213386463954 0.66373880239951 0 +2481 8.979999831791991 0.5083303267159694 0 +2482 1.85866244903707 0.3180760833658699 0 +2483 7.941337550961077 0.6819239166333311 0 +2484 2.637877563963746 0.143423378020723 0 +2485 0.6831908438076296 0.6103022368776768 0 +2486 0.7477223441611417 0.639891338617447 0 +2487 2.902297152814045 0.2218254429266227 0 +2488 0.6236781953783044 0.2028354360003482 0 +2489 0.5692938731549942 0.2305991642373997 0 +2490 9.048954074110162 0.5124690122459472 0 +2491 0.765981974708721 0.2463173591681278 0 +2492 0.9623088705337606 0.1944004241866267 0 +2493 1.311868546986448 0.3911833753655596 0 +2494 2.225021701023387 0.5983441025835966 0 +2495 7.574978298973581 0.4016558974163587 0 +2496 1.082565609307463 0.5711087462373207 0 +2497 9.223031758371402 0.8197038373769077 0 +2498 9.170877296417972 0.1791287672172678 0 +2499 2.744050955727169 0.7699260841343147 0 +2500 9.008364081499789 0.2753641732047126 0 +2501 9.045468394123505 0.3194748216856126 0 +2502 9.461468395296292 0.4462651091221094 0 +2503 5.716058382868165 0.795288491827 0 +2504 3.072503152435636 0.5017800313961494 0 +2505 6.177533524658408 0.4976342848334146 0 +2506 1.623303902029387 0.05026655840201168 0 +2507 3.152026140246953 0.4502180525844737 0 +2508 6.096994312744792 0.5493300541072705 0 +2509 2.350981637068247 0.5522895092469697 0 +2510 7.449018362926984 0.4477104907529214 0 +2511 6.24853256730097 0.5164295470796423 0 +2512 2.999822755040995 0.4876443384067606 0 +2513 8.417368113698977 0.30978565013812 0 +2514 1.773436293951678 0.5246627176354604 0 +2515 0.834502808612957 0.6997537466012571 0 +2516 0.2079748238366587 0.2134552353793873 0 +2517 4.69484407990551 0.6418031472500765 0 +2518 2.740709719949947 0.2321182950249431 0 +2519 9.109855884155115 0.3818200186652184 0 +2520 2.65727050762807 0.308540637013285 0 +2521 3.531933077406151 0.4971861567019664 0 +2522 3.584936127914291 0.7529043315835732 0 +2523 2.672478591282248 0.7588481403298186 0 +2524 1.251873230838698 0.336684984015782 0 +2525 9.006019442326492 0.783619924498506 0 +2526 2.663801599835761 0.8422364219261905 0 +2527 5.392846862755735 0.7714762635615793 0 +2528 8.810829343259801 0.5855498720040248 0 +2529 1.683724553097748 0.2704711568722923 0 +2530 7.980438909127291 0.3388347087072428 0 +2531 1.855326502451704 0.4852028235962432 0 +2532 7.168270974418474 0.5060175756026757 0 +2533 7.947054621052326 0.511289178160243 0 +2534 9.119177072617342 0.6690656930225701 0 +2535 2.960184944032797 0.6632438898899333 0 +2536 6.288315075045543 0.3333263062005407 0 +2537 8.538315075045542 0.3333263062006491 0 +2538 8.82746044870235 0.3028327536606841 0 +2539 6.572322798713097 0.2972010538688815 0 +2540 2.029608828784914 0.1287122801364944 0 +2541 7.770404489050748 0.8712815969931129 0 +2542 7.687871473886836 0.2593655536711795 0 +2543 2.112128526109964 0.7406344463290307 0 +2544 6.578382152160691 0.699391228577657 0 +2545 8.456756492800205 0.4107706244075467 0 +2546 9.336106875436935 0.1502122462308919 0 +2547 0.4224042120880117 0.8813314225836719 0 +2548 5.976029169680806 0.4672269514821063 0 +2549 9.493600523047069 0.6288997550944844 0 +2550 4.250421967903829 0.1367718721985057 0 +2551 5.025000292442598 0.9509751808262052 0 +2552 3.372308751749823 0.3906272748884918 0 +2553 3.191315441584635 0.6819171086986168 0 +2554 6.714069172567688 0.8756945238733331 0 +2555 8.342770245245855 0.8727511873928558 0 +2556 5.606532396329908 0.8729665066565967 0 +2557 1.447101961983583 0.1343314963065589 0 +2558 8.136316666987025 0.2919459283092358 0 +2559 4.428558812335778 0.4734813476199379 0 +2560 2.083758143031718 0.2802621137336727 0 +2561 7.71583909774852 0.7200109193437674 0 +2562 6.626859549303842 0.5040356279042199 0 +2563 4.303821461929704 0.150173291273197 0 +2564 5.047859175982491 0.7332822065639345 0 +2565 6.007028233669897 0.4114959232942192 0 +2566 5.46238645253121 0.4102000423514187 0 +2567 2.243162128475306 0.2962948065905318 0 +2568 7.557330214173331 0.7041644305558933 0 +2569 2.718837947236602 0.5012167838108063 0 +2570 3.621259188038532 0.4949590425625887 0 +2571 0.5158260514823638 0.8688976507094509 0 +2572 5.851715178115905 0.7290627794479875 0 +2573 1.757698050291764 0.8214547745703235 0 +2574 7.007698050291945 0.1785452254287391 0 +2575 7.392393676425772 0.2284299532409167 0 +2576 9.543487902896352 0.786483672632189 0 +2577 4.630419840236402 0.9462631906951192 0 +2578 2.689804309348504 0.5872379817732958 0 +2579 3.560195690639727 0.5872379817712384 0 +2580 3.506051056357553 0.7628947473402747 0 +2581 3.911024508806117 0.871572838148238 0 +2582 7.94612646969606 0.420546387934831 0 +2583 0.1259524325892267 0.1519729845805327 0 +2584 0.9237522854449264 0.4332868396579562 0 +2585 3.615027442567902 0.1409130906826226 0 +2586 3.734621697917203 0.65326416629839 0 +2587 1.343789087590907 0.7866810758237749 0 +2588 7.077637863727624 0.4732633348466632 0 +2589 3.655563409944287 0.4491875613632799 0 +2590 1.216835016094009 0.9482792011384751 0 +2591 5.629217125486565 0.352303773826356 0 +2592 0.8188963961234218 0.1246370071344973 0 +2593 3.278830230772671 0.6609920535906586 0 +2594 5.271118761471241 0.6323290896421313 0 +2595 0.7054243471132664 0.8840040330100355 0 +2596 4.971330562518136 0.4002587967784249 0 +2597 3.613804887239447 0.8596905830573266 0 +2598 7.139550736867371 0.3144700155591787 0 +2599 1.889655671644928 0.6854388140777442 0 +2600 3.983498572228215 0.04992709222565424 0 +2601 0.8674593895144748 0.2748998740751163 0 +2602 2.023938229757966 0.584383457630684 0 +2603 7.2726713906999 0.4155799763903226 0 +2604 7.776061770238834 0.4156165423697047 0 +2605 0.8562807340524328 0.2245356656533097 0 +2606 2.711667311021532 0.3954083079573789 0 +2607 7.560151546157511 0.1723658248796536 0 +2608 0.9055511615225201 0.5445766784862689 0 +2609 8.308167696508674 0.3133225723483181 0 +2610 8.858160629580031 0.6866755444223697 0 +2611 9.513157680266801 0.350255538609467 0 +2612 8.29520950881421 0.7288101294657008 0 +2613 5.700317282909475 0.6863721757704299 0 +2614 1.220323065028922 0.654726350259801 0 +2615 6.796804539844208 0.687944196436336 0 +2616 9.589300729495516 0.4838526416231419 0 +2617 9.528037210378303 0.5031904905271446 0 +2618 4.314445607659288 0.2037484290068766 0 +2619 9.065010805931081 0.8692979992486605 0 +2620 2.40614068200791 0.7741786832149551 0 +2621 0.783678073183253 0.2999212483490752 0 +2622 9.20867257123788 0.621090441506484 0 +2623 9.582138901300377 0.05266931303784347 0 +2624 5.101391821947804 0.8642811565299131 0 +2625 1.587880434871064 0.2357134163292784 0 +2626 8.553631711155031 0.7700820387600842 0 +2627 8.89624106869738 0.5455029635273296 0 +2628 7.987267971341998 0.2340367343348455 0 +2629 9.453955185882299 0.8790601742167354 0 +2630 3.299644234492778 0.23148803335743 0 +2631 1.633437531387353 0.1101870830354816 0 +2632 9.429966012447 0.4026584241929579 0 +2633 1.015891332675569 0.8297231025583481 0 +2634 2.154936381781765 0.2107609341097945 0 +2635 7.645063618214033 0.7892390658900712 0 +2636 0.7843699705439584 0.9511121989129753 0 +2637 4.81905387131247 0.04772209790811354 0 +2638 4.272603815891906 0.05006418718404896 0 +2639 0.6285985195368179 0.1128671179611764 0 +2640 2.704487199737436 0.0534414140210366 0 +2641 7.954487199742393 0.9465585859788157 0 +2642 7.09551280025762 0.9465585859788495 0 +2643 9.331600791136278 0.5022659866900139 0 +2644 0.4123491237793549 0.5132255226587679 0 +2645 7.107055864900176 0.4194521381426634 0 +2646 1.857800274086134 0.5810429541960511 0 +2647 9.945113507301173 0.7125370018513832 0 +2648 0.05303385506098789 0.2869312754533109 0 +2649 1.844306189387823 0.9468042670548613 0 +2650 7.094306189386915 0.05319573294476881 0 +2651 2.705693810608255 0.9468042670553023 0 +2652 1.356649032872272 0.2029595508447603 0 +2653 4.760635152164717 0.190551843515124 0 +2654 5.541183484647846 0.4586665438168689 0 +2655 6.755496726456244 0.7297501658927666 0 +2656 8.252347547114832 0.6882510376786041 0 +2657 5.655293194205192 0.7298016739337567 0 +2658 7.183482904316254 0.6955276688290255 0 +2659 7.860386258322984 0.6925404489641368 0 +2660 1.939541578938528 0.3075595665113193 0 +2661 8.720145007258196 0.9512459083329047 0 +2662 0.6061715456281931 0.5719321920646832 0 +2663 3.202026019616416 0.8627136669531474 0 +2664 3.916360135563087 0.777600042581377 0 +2665 0.9259082447925987 0.6691874057274095 0 +2666 9.658957916030637 0.6626432458241048 0 +2667 5.465353607205048 0.1515769470981172 0 +2668 6.015864143729771 0.1549065590003212 0 +2669 8.683516267984741 0.6047031452333802 0 +2670 9.493212668450834 0.9422497621297323 0 +2671 4.384958806284593 0.3410716668091391 0 +2672 9.352023894485839 0.6882092080607634 0 +2673 9.394207191484519 0.7297240749279561 0 +2674 4.318926774713834 0.626097861678535 0 +2675 1.846803540925747 0.05311874613504688 0 +2676 5.351695170371637 0.9393411405283866 0 +2677 9.561413550909505 0.6894471965344566 0 +2678 1.36955283541139 0.1463022139316164 0 +2679 0.5040757226710804 0.5800600020967183 0 +2680 1.375848313650597 0.6003480978467495 0 +2681 4.433850472079466 0.3185854322969767 0 +2682 0.4427021493282376 0.4139151953783943 0 +2683 7.164499222596181 0.8636656848785784 0 +2684 7.886155357853326 0.8645957539369394 0 +2685 1.915363768003231 0.1365220507156988 0 +2686 9.496492609539516 0.7568355946754266 0 +2687 6.52257420507325 0.3440303497707572 0 +2688 2.481511659560233 0.04458790514204983 0 +2689 7.31848834043524 0.9554120948579187 0 +2690 1.025685316132838 0.683357319972134 0 +2691 5.427966644328483 0.477182952509732 0 +2692 4.574685363079171 0.04386152173238386 0 +2693 1.538936214944911 0.2590855602040904 0 +2694 9.481144442827047 0.2136284964726173 0 +2695 5.606250292271886 0.304082455260216 0 +2696 4.210593469648388 0.518329091655291 0 +2697 8.815639143551163 0.4125886817626487 0 +2698 4.267792938315364 0.2338783883299448 0 +2699 4.315339734541606 0.7928396870265945 0 +2700 1.835990512965468 0.4368038598358177 0 +2701 7.964174586099413 0.5636220722167038 0 +2702 0.8260592053573091 0.4651474758910933 0 +2703 7.206385306524709 0.5486393733663238 0 +2704 9.583149953475287 0.117598197311762 0 +2705 0.5431046440968044 0.3635165425823192 0 +2706 9.889353368921476 0.6150387658407561 0 +2707 0.1107566033032333 0.383029086172708 0 +2708 2.924448616926818 0.04685161158146035 0 +2709 8.177162319121161 0.9530780924412271 0 +2710 6.872837680878893 0.9530780924412615 0 +2711 0.4777553829405877 0.9527723634415449 0 +2712 6.529576213212827 0.9502656433634459 0 +2713 5.979576213212788 0.9502656433634614 0 +2714 8.779576213212218 0.04973435663673768 0 +2715 6.529103222572687 0.04971161671218241 0 +2716 5.97910573720418 0.04971243408549375 0 +2717 5.429105737203915 0.04971243408559331 0 +2718 7.318090032033294 0.04406464430769822 0 +2719 2.481909967962526 0.9559353556924461 0 +2720 8.848799223811552 0.8640474867868342 0 +2721 1.469631908735266 0.877162640979812 0 +2722 2.925127556409988 0.9534769718087072 0 +2723 6.872006562729355 0.04852600929868773 0 +2724 0.3665705151685306 0.7924046607840808 0 +2725 9.555937304759894 0.5820392497436342 0 +2726 5.366395558353036 0.839890802930174 0 +2727 8.344617995510275 0.5755877331438092 0 +2728 6.304667833947324 0.7714900787271712 0 +2729 4.346082111606609 0.3051475889271196 0 +2730 4.005140718848374 0.8736749806179309 0 +2731 6.565433864985599 0.1507639554879552 0 +2732 6.599447273504716 0.8627519737308122 0 +2733 4.825940708535753 0.3226634858795051 0 +2734 6.535243711426889 0.4951969544496644 0 +2735 6.016126942244246 0.7695319264749735 0 +2736 8.298208513309961 0.1364007316740209 0 +2737 1.468854895257562 0.3836415519219661 0 +2738 1.413685353208293 0.7324574075301691 0 +2739 5.277092306448139 0.8841899513522621 0 +2740 5.717877623016339 0.5073262588045475 0 +2741 3.451688622417679 0.107864313544966 0 +2742 4.780625808396507 0.864934263979358 0 +2743 4.52287775595908 0.277695926538004 0 +2744 9.205922910340286 0.9442484937715777 0 +2745 8.699053410219301 0.7312998009023998 0 +2746 2.122332568085346 0.3134418566411178 0 +2747 7.6758039308405 0.6876729914687374 0 +2748 1.367919098426455 0.3060353493745022 0 +2749 5.481337657753122 0.9545223405708534 0 +2750 9.04615442698462 0.4284505405995384 0 +2751 6.24858722949721 0.4297929309693953 0 +2752 3.001412770497442 0.5702070690299514 0 +2753 3.751645896264291 0.4422972489327178 0 +2754 8.130262192731067 0.1097987497999223 0 +2755 3.36919014596086 0.8882605555717478 0 +2756 4.438872352471829 0.2624201795378672 0 +2757 2.248659167580203 0.198155076765548 0 +2758 7.551996904721001 0.8025663614580583 0 +2759 3.951602041954622 0.1941105771519591 0 +2760 3.011474873045406 0.2999592547961699 0 +2761 6.238963666339494 0.7017231100124126 0 +2762 1.730059208769056 0.3866876825746058 0 +2763 7.972303436746712 0.1463497307669211 0 +2764 0.8669369968425511 0.8920281853916118 0 +2765 4.756258912668763 0.9481576367719815 0 +2766 7.73108245505462 0.04485569759253861 0 +2767 2.068668619868546 0.9558498349167396 0 +2768 0.3940318007050439 0.2095888920913388 0 +2769 3.041504175926912 0.7476993041988018 0 +2770 6.208423533178359 0.2519420193281634 0 +2771 8.462119315234441 0.2492855741223228 0 +2772 1.984692091016647 0.26270119109599 0 +2773 7.815307908979517 0.7372988089046252 0 +2774 7.233125765161682 0.740227845411337 0 +2775 3.452561355683935 0.8821477182070484 0 +2776 9.038003222894758 0.6994177443683465 0 +2777 4.886182709463093 0.8605856476227102 0 +2778 9.193887294016241 0.2739923392114037 0 +2779 4.206668714338502 0.8721588169891275 0 +2780 1.370240325338915 0.412452705458944 0 +2781 9.186916863228465 0.7228839516757698 0 +2782 2.618711393080364 0.6203302753033686 0 +2783 3.632137642123691 0.6201743287851299 0 +2784 1.162260703018735 0.4091088862433414 0 +2785 6.068854503273704 0.3322472843751188 0 +2786 1.17045362039874 0.1105815914339322 0 +2787 4.371697422854427 0.1180568908129546 0 +2788 4.521605786835355 0.4464025127470262 0 +2789 6.659323586067331 0.2613948933651143 0 +2790 6.44819581472101 0.5654061852524223 0 +2791 6.726230147564996 0.4097933533568627 0 +2792 1.126514298832539 0.3447613775937173 0 +2793 4.475583150659896 0.9543189065589099 0 +2794 3.223263480719214 0.4005759736477016 0 +2795 5.473674853626084 0.6075558522035081 0 +2796 6.032895569363975 0.6092070024811443 0 +2797 2.521615844624252 0.1253007702080699 0 +2798 7.27876148106839 0.8744434657471393 0 +2799 0.8152631743193292 0.7993357217405926 0 +2800 7.678932818775753 0.5080631646451441 0 +2801 2.120784954866338 0.4920173348420665 0 +2802 5.013005843236134 0.2660532033809915 0 +2803 2.522547106806542 0.8734735245456605 0 +2804 7.277476198127378 0.1264769941639402 0 +2805 8.908268871614668 0.2577808992107506 0 +2806 5.651565081491448 0.4343916460698956 0 +2807 3.533029628893041 0.3949398643871149 0 +2808 3.771395933531676 0.04446752557091017 0 +2809 2.070831251040951 0.04437973609827367 0 +2810 7.729030150995972 0.9556071298898611 0 +2811 6.911705461471389 0.7951578619404663 0 +2812 8.144638968623521 0.7941757404615097 0 +2813 5.480948720932667 0.7106953982446401 0 +2814 8.469051279067401 0.710695398244682 0 +2815 3.21905127906125 0.289304601754385 0 +2816 2.867943031009944 0.2714335590156021 0 +2817 2.416296229515535 0.1128879956477841 0 +2818 7.38368791273858 0.8870576040524579 0 +2819 6.9423100555368 0.7253102523399451 0 +2820 8.106144298674648 0.7295273897040827 0 +2821 5.036085463271321 0.4497069588258635 0 +2822 5.076037500258759 0.4101529110390713 0 +2823 4.779515576964766 0.425363144254876 0 +2824 3.088900871339824 0.8736756280609951 0 +2825 5.60969138710452 0.1256120102202163 0 +2826 6.159658397592055 0.125502668006013 0 +2827 6.71088989397381 0.1260249937018433 0 +2828 8.410127066825595 0.1258080985855889 0 +2829 6.816517585546841 0.8041222405499849 0 +2830 8.233864982923691 0.8036648742624328 0 +2831 0.8071701589331481 0.2104967286132996 0 +2832 1.888274774526838 0.7655009512086751 0 +2833 7.136336904207958 0.2327225703190812 0 +2834 0.6588528292894965 0.2886560641318126 0 +2835 7.945924251080508 0.8544963317132425 0 +2836 7.104075748919501 0.8544963317131966 0 +2837 1.868026367978028 0.1418423747789363 0 +2838 0.2730717526042272 0.8262476161745598 0 +2839 3.76163630693415 0.9540914955935705 0 +2840 3.722873800980589 0.4815904830758074 0 +2841 5.072687954375638 0.5237530547448387 0 +2842 4.458908257264002 0.7609122264274539 0 +2843 0.8304847665701947 0.3100259744735622 0 +2844 3.57737108967636 0.3171747359920693 0 +2845 4.636851957852675 0.3523617948819615 0 +2846 5.056785285525507 0.3020404032195677 0 +2847 6.707069160887001 0.3027196415041497 0 +2848 9.621800220791323 0.2092577406293178 0 +2849 8.887959654019514 0.6452068605225119 0 +2850 3.718814560416589 0.1268722291281506 0 +2851 5.170168608606298 0.5016821164343878 0 +2852 0.3505023270505415 0.6897098444337568 0 +2853 1.680123649524364 0.9544878676492613 0 +2854 6.929952571033022 0.04603953606104624 0 +2855 2.869727181645765 0.9539738370583667 0 +2856 4.733545686154797 0.3561376000484331 0 +2857 2.015530264341303 0.8739084005899487 0 +2858 3.716036622665976 0.8739038027737094 0 +2859 7.783803425448334 0.1267075672030012 0 +2860 7.317788608320571 0.7865386148460596 0 +2861 2.481736310639991 0.2124197150308979 0 +2862 3.365016710901346 0.6063569026149663 0 +2863 9.873432617951883 0.8393924239528062 0 +2864 9.873432617951853 0.1606075760473303 0 +2865 3.41505256230995 0.801674556088078 0 +2866 2.869307030885755 0.04629594222624483 0 +2867 8.11956547871878 0.9536973629186876 0 +2868 6.930434521281252 0.9536973629186986 0 +2869 7.059426783608135 0.5715032862418289 0 +2870 2.692956906176679 0.1493786284783918 0 +2871 1.575507327765762 0.5972593076737005 0 +2872 9.259666175042462 0.129088887171371 0 +2873 0.5333313498561547 0.6281625335444444 0 +2874 8.910669312135502 0.7437860134352937 0 +2875 1.255962816658395 0.4515222902195742 0 +2876 5.462899310049924 0.8482925286643392 0 +2877 6.049965312411729 0.867675035630771 0 +2878 2.907782177154524 0.6780989578696954 0 +2879 5.906767709370651 0.7296658353146149 0 +2880 8.959773502286062 0.8757377646267926 0 +2881 6.450317883260501 0.6674885366009558 0 +2882 8.083387603338711 0.1946025970345958 0 +2883 5.560044212072114 0.7404260271169366 0 +2884 8.389955787927962 0.740426027116866 0 +2885 1.460774464377534 0.7025854351460529 0 +2886 5.754327606734677 0.4574987098229079 0 +2887 5.019715179440255 0.8679464274638485 0 +2888 2.630918741084337 0.8806516340764721 0 +2889 3.139991603997168 0.2549623398021155 0 +2890 6.109173287680753 0.7430061134341733 0 +2891 4.935402991001548 0.9528525886255236 0 +2892 3.370936288250136 0.7157526274316681 0 +2893 1.245799693555927 0.2484606276054622 0 +2894 4.972981784257279 0.5878820647043455 0 +2895 5.00875930055599 0.5497436610823683 0 +2896 1.919756215839495 0.8824064760119666 0 +2897 7.169756215838066 0.1175935239873909 0 +2898 0.5245216385071676 0.1113728787665811 0 +2899 8.035834390581137 0.4668260096297019 0 +2900 8.996234363003316 0.05707988288999873 0 +2901 1.914765177830249 0.4051860625253667 0 +2902 7.88520546736236 0.594824673085534 0 +2903 6.39585645722205 0.7347939975003094 0 +2904 7.239439593791952 0.4508922435507496 0 +2905 7.81394574843669 0.454700810025627 0 +2906 1.986054251560138 0.5452991899747831 0 +2907 6.631001804915744 0.351896383790817 0 +2908 9.337962922411728 0.799047040228686 0 +2909 3.093718376299266 0.1249534094335267 0 +2910 6.160735237690919 0.8760152420038122 0 +2911 5.288806331517996 0.7964339786151712 0 +2912 2.953812746769966 0.2263105282139511 0 +2913 1.310673010439973 0.744651222144628 0 +2914 8.696842427960112 0.8705228324562445 0 +2915 8.871798013009265 0.3410521393217651 0 +2916 0.7911966209194584 0.8680458874363572 0 +2917 8.501716363532561 0.4280081288520836 0 +2918 1.105470708369108 0.4444681553553191 0 +2919 7.984859100293095 0.6525142802697128 0 +2920 1.811937506996171 0.3441523698105814 0 +2921 0.4951636870099725 0.3616330039741892 0 +2922 9.708471293420621 0.1763483334952653 0 +2923 9.70938950716819 0.8245522562155374 0 +2924 3.450899495414075 0.2805500233270164 0 +2925 9.95502305249574 0.5582911148315276 0 +2926 0.0449616077072363 0.4416866310680574 0 +2927 0.5395332685147504 0.2709298259607114 0 +2928 8.993292232659419 0.9519116037739094 0 +2929 8.608411334485048 0.8882599962520962 0 +2930 8.826996478076413 0.2198235275693876 0 +2931 3.856138932324107 0.2425928160316668 0 +2932 9.391376286155335 0.2389031162254406 0 +2933 1.829910624470792 0.5330121165608219 0 +2934 6.619537575651879 0.6700287519915166 0 +2935 0.5677283330335682 0.04199164490549442 0 +2936 5.804437178779597 0.8618730836424173 0 +2937 6.354749145480912 0.8615650193407886 0 +2938 5.254169976198151 0.1436372123156546 0 +2939 5.804760592196274 0.1439635296456066 0 +2940 6.907233543554903 0.1411529975761187 0 +2941 1.653737729202194 0.8600773105080913 0 +2942 3.198234587051082 0.1335404120022042 0 +2943 8.453054102574951 0.8694831908084625 0 +2944 0.7492306873138552 0.5395564437483032 0 +2945 9.768275039707223 0.9543254442719535 0 +2946 9.768275039706973 0.04567455572802048 0 +2947 3.344517946678567 0.5368776519385534 0 +2948 9.384828627725417 0.04863040191487602 0 +2949 9.678145992079978 0.2574023734765334 0 +2950 1.135610282386558 0.8895132522717234 0 +2951 2.663372341016481 0.4113509330585086 0 +2952 4.51253321205215 0.7932438201963782 0 +2953 5.133943634085605 0.5748697514675589 0 +2954 7.33497985408632 0.7363242035375934 0 +2955 5.766601135289839 0.04723241545279052 0 +2956 6.316800642960066 0.04592305233131964 0 +2957 8.566800642960592 0.04592305233190509 0 +2958 6.316417153573101 0.9530529358411088 0 +2959 5.766601135290979 0.9527675845460279 0 +2960 2.465031719340259 0.2636407366691746 0 +2961 4.170666319513288 0.2686662839590627 0 +2962 4.263803263585786 0.6026456262001237 0 +2963 4.088917335138747 0.3202027555923733 0 +2964 9.372240932174632 0.3371376362354812 0 +2965 1.065283475270994 0.3858081256200244 0 +2966 6.7262511190254 0.5144849629327689 0 +2967 8.542269182621069 0.5791606198739728 0 +2968 4.240184605931079 0.7795497848177928 0 +2969 0.1289169871533001 0.8064012896388937 0 +2970 5.219724781516464 0.04477322037875472 0 +2971 2.39103674903826 0.3196391738921395 0 +2972 7.410219395635876 0.6806518423695378 0 +2973 0.9522680281231737 0.2479748751148026 0 +2974 7.819349061904247 0.9553843208682816 0 +2975 1.980756479419777 0.04463042915791355 0 +2976 4.432783633110049 0.6086179256069362 0 +2977 5.175874084419621 0.4021131243147534 0 +2978 1.410720423978222 0.3716150644961049 0 +2979 4.875516292859364 0.6093415917781315 0 +2980 3.976086487435338 0.9578574391145662 0 +2981 4.091013716760075 0.6882840905300953 0 +2982 4.854924107940741 0.2324362737631005 0 +2983 4.675355259582737 0.2086813077005671 0 +2984 0.1879061910153189 0.4032877666576613 0 +2985 9.812166428828249 0.5964641124045054 0 +2986 4.544450206926512 0.1175392053638537 0 +2987 3.399069536124683 0.1951197027416894 0 +2988 4.503823177377971 0.1886972607370256 0 +2989 3.141763600053692 0.7425615785327392 0 +2990 6.107774720062589 0.2586369255085055 0 +2991 1.474510142286955 0.4851208053435714 0 +2992 1.409996509719076 0.2323508674572729 0 +2993 0.678747036200899 0.1963150698770178 0 +2994 2.656019463384593 0.04963428305105336 0 +2995 7.906322650638741 0.9504330149406699 0 +2996 7.143645435157218 0.9502981840806716 0 +2997 1.568243794460003 0.5013018792583289 0 +2998 4.331948521991241 0.467420639735564 0 +2999 1.159444017069499 0.801676714541799 0 +3000 3.381355138620717 0.1061110954163149 0 +3001 8.358070197214989 0.2565401683230387 0 +3002 5.236635905143284 0.7951754193595674 0 +3003 0.7842701062891588 0.7372177751754579 0 +3004 4.394767302477942 0.04915318759773712 0 +3005 4.077432271975008 0.04535547886070287 0 +3006 8.070112111425013 0.3670077494657247 0 +3007 3.820137488631894 0.496463445048434 0 +3008 4.265326783115367 0.6993740672888936 0 +3009 0.3609064427497416 0.1086479905521398 0 +3010 8.857230633094014 0.1212499863207202 0 +3011 2.11855549632333 0.5913449522324913 0 +3012 7.681444503673434 0.4086550477676137 0 +3013 1.978330576251138 0.9559317685382263 0 +3014 1.317417519852946 0.9569735214005171 0 +3015 2.743474794487169 0.4602252744292766 0 +3016 1.892001507492771 0.9516771018928016 0 +3017 2.657776917418151 0.9510142711438183 0 +3018 7.142001507490932 0.04832289810710258 0 +3019 0.3697941801202331 0.0465909675122565 0 +3020 4.757947134773503 0.2640976217382979 0 +3021 5.507287585849829 0.8831101689343998 0 +3022 8.645337025959938 0.8088603080030371 0 +3023 0.1139369177733554 0.6682623707316832 0 +3024 9.885851562285017 0.3310534909932735 0 +3025 1.434587274651886 0.5476426409474595 0 +3026 4.462602528355564 0.1140882655314161 0 +3027 5.2894464387518 0.2732685252005844 0 +3028 5.839457951395038 0.2732745310681656 0 +3029 4.728759942113482 0.1004492256440283 0 +3030 9.092386892595567 0.7860121711687932 0 +3031 1.894222697430256 0.04954390592125987 0 +3032 1.421479978982037 0.04908917936054917 0 +3033 1.175944031753404 0.5040828326508021 0 +3034 0.4657050962588395 0.5015457479992342 0 +3035 2.963659165416086 0.2857875414551415 0 +3036 5.082578686262067 0.2115043186554708 0 +3037 2.822548707055318 0.1768976404811349 0 +3038 2.51688802063827 0.4856040661006358 0 +3039 0.1980936957469237 0.1320316794642779 0 +3040 0.9045364375491719 0.114742522568144 0 +3041 0.2885416880199907 0.04327541479945607 0 +3042 1.529951545574989 0.4339731200592798 0 +3043 0.7232981465535614 0.7919105066343328 0 +3044 7.227845652916462 0.04347911183728186 0 +3045 2.57215434707906 0.956520888162775 0 +3046 0.5660034310588502 0.4070659927062161 0 +3047 1.624000849446732 0.9534390592949241 0 +3048 6.382605411264287 0.6169900714836115 0 +3049 9.573836769692445 0.2234993979352927 0 +3050 6.608984148191276 0.1132045874495748 0 +3051 9.561906863323291 0.2755383132713249 0 +3052 0.931949224073546 0.9583497753762104 0 +3053 3.734759561411536 0.3017287506523464 0 +3054 6.29831574558846 0.7266344840424072 0 +3055 4.268008372010168 0.8680985516578 0 +3056 3.782334178499241 0.1719046706686665 0 +3057 1.473058211951805 0.5961973009084722 0 +3058 5.508926151655218 0.1131730724905203 0 +3059 6.059044812162033 0.1134825510132787 0 +3060 4.800408788185761 0.1022256096119304 0 +3061 2.385475287163744 0.2166350022352544 0 +3062 7.414473466177 0.7832631776874225 0 +3063 4.082102901395174 0.2284327454475391 0 +3064 0.4625733615997239 0.3213751915733907 0 +3065 3.764906180892686 0.2200852609314834 0 +3066 9.086343667972555 0.7091208557731101 0 +3067 6.348002882689491 0.7893877171138041 0 +3068 5.907849221878027 0.4111408858857794 0 +3069 5.355531139243565 0.4162170965790395 0 +3070 2.615902562496685 0.5327084351837543 0 +3071 7.332452414527672 0.4390646267955214 0 +3072 4.963891239938018 0.3244096343590621 0 +3073 6.870149728742743 0.8749260011061146 0 +3074 8.179850271257319 0.8749260011059899 0 +3075 6.341574044166401 0.4155433724011938 0 +3076 8.589195513796792 0.4166480328708525 0 +3077 2.904864975414128 0.5896953544537877 0 +3078 9.534031506899339 0.4037039897613279 0 +3079 4.731041688392442 0.8400976980117711 0 +3080 1.576508099348077 0.04002250128034036 0 +3081 5.805564700011415 0.7005051084160309 0 +3082 2.926194757543548 0.5168054709000026 0 +3083 6.324720225024569 0.4840658995954146 0 +3084 9.146989405280531 0.4678569335379345 0 +3085 2.518545604259328 0.6997474758971378 0 +3086 7.132857297247451 0.6921276793699439 0 +3087 0.9878039668910436 0.5840196752021517 0 +3088 1.609758801425818 0.55788842095098 0 +3089 2.824866269352488 0.8189653718640086 0 +3090 9.331189767224796 0.962091079331571 0 +3091 8.623775150962556 0.1224788026097583 0 +3092 6.37413371818209 0.122079034157755 0 +3093 6.004364178825126 0.8469189321035144 0 +3094 9.324095168070256 0.3995127100096025 0 +3095 6.448295597558715 0.9505769849166666 0 +3096 5.898324746791179 0.9505629945414437 0 +3097 8.698200017070008 0.04963880591627217 0 +3098 6.448200017069786 0.04963880591625713 0 +3099 5.898324746790627 0.04943700545855646 0 +3100 5.348354225165791 0.04937449809315922 0 +3101 3.616446203460085 0.04818448942994888 0 +3102 2.929901533327636 0.8746081413088257 0 +3103 7.202013696972079 0.6515712590391936 0 +3104 0.6789021673845415 0.4378642458928756 0 +3105 6.057088694857248 0.6980769099452451 0 +3106 9.247465030328296 0.6667072048072337 0 +3107 8.143026873829676 0.6651275903993487 0 +3108 6.906994135136486 0.6651721493172483 0 +3109 2.571710412184208 0.04276890327801521 0 +3110 7.228144609435113 0.9567247009962434 0 +3111 6.033596797495539 0.9538722062908027 0 +3112 6.583257326368988 0.9540728302925187 0 +3113 8.833354270737138 0.04618946178797609 0 +3114 6.583188069641342 0.04592721641943825 0 +3115 6.033162086127574 0.04587100186917024 0 +3116 5.483162086127216 0.04587100186927727 0 +3117 4.224181261103189 0.9561623967619571 0 +3118 5.171519203059736 0.6033990629795909 0 +3119 1.163964898074734 0.738681944200881 0 +3120 4.535797041479648 0.9541222719899568 0 +3121 3.877777274443238 0.04382348049343074 0 +3122 2.177647333330107 0.04393400007652395 0 +3123 7.624757362430588 0.9602772401627038 0 +3124 1.282477796000356 0.1059983890682306 0 +3125 4.422371429688036 0.4195787845254461 0 +3126 0.1248182213794652 0.2019408563200512 0 +3127 4.935308797670622 0.872866827129178 0 +3128 0.3158150559627009 0.2511759720118277 0 +3129 9.89284463860546 0.04420467962940603 0 +3130 9.892844638605521 0.9557953203706422 0 +3131 3.222761706676076 0.03997299496919512 0 +3132 4.917706338903179 0.7660261312020797 0 +3133 0.6195185570092619 0.3240428650959699 0 +3134 8.804016188263157 0.1461199408078978 0 +3135 2.229402672128872 0.3526491776480036 0 +3136 2.182351332415453 0.3614236394911574 0 +3137 7.57317202321792 0.6484861424488968 0 +3138 7.618183612643912 0.6389381742139153 0 +3139 1.128542440065306 0.1983448679994827 0 +3140 8.508060849702051 0.2625530441636316 0 +3141 6.255086148621811 0.2607157157230054 0 +3142 2.995312465221508 0.7390086700833519 0 +3143 6.599527103363388 0.583641386018239 0 +3144 8.254170779220685 0.5886322428733075 0 +3145 7.086545303433327 0.3226459402486521 0 +3146 1.836600337012156 0.6773004778460213 0 +3147 1.570430825208695 0.3962441242550538 0 +3148 4.814672526577731 0.4590723140409497 0 +3149 8.280014718097103 0.0400199320165702 0 +3150 3.219800390370705 0.9604252232701855 0 +3151 9.068126380886349 0.4752121139323926 0 +3152 0.7674569096685477 0.3876087919005222 0 +3153 9.881419656983931 0.2138651461256125 0 +3154 9.88275750713658 0.7911245881529949 0 +3155 1.367646034830471 0.6745629965936324 0 +3156 4.948489278947197 0.203521511290621 0 +3157 3.306469589433947 0.1564250459696084 0 +3158 4.591959530475979 0.2083566370391398 0 +3159 0.1925965356102349 0.6230100034280172 0 +3160 9.807623523237728 0.3769979677211358 0 +3161 4.65783530065585 0.2998192318629943 0 +3162 2.063832675310645 0.7821037820208122 0 +3163 3.763113934585059 0.7804853101226611 0 +3164 2.077951595051735 0.8318573201157698 0 +3165 3.778515245608455 0.8307513374698428 0 +3166 7.736167324685932 0.2178962179792409 0 +3167 7.722048404944955 0.1681426798843727 0 +3168 3.992792033439963 0.3762040009119516 0 +3169 7.13883093240446 0.776213362675947 0 +3170 7.91145935357611 0.7786277535590457 0 +3171 1.888540646420567 0.2213722464400984 0 +3172 0.1104209807647991 0.4912713000986179 0 +3173 9.88957901923512 0.5087286999013537 0 +3174 6.272730872298209 0.4770865799314771 0 +3175 2.978107629473472 0.5242493843481055 0 +3176 4.36283656925252 0.7137625685094724 0 +3177 3.878904387227028 0.9574213542820866 0 +3178 9.245190415740289 0.77624876736624 0 +3179 6.91127903399178 0.2875472096089363 0 +3180 1.666020111009874 0.7083741699029172 0 +3181 1.124439054820285 0.9616304443049378 0 +3182 6.397572298391203 0.2611400546884622 0 +3183 8.647076873522014 0.2609660220242811 0 +3184 7.886958353028986 0.04057621255694061 0 +3185 3.610868903681564 0.9538583034210235 0 +3186 9.718015944037178 0.5864934667387856 0 +3187 0.1139705296853428 0.85010772483359 0 +3188 3.047416485017551 0.8358111526330261 0 +3189 5.652049131606597 0.1628843686754853 0 +3190 6.201685235544151 0.1628848992428187 0 +3191 6.75347808430026 0.1639537955803915 0 +3192 8.452376781116904 0.1625014269146549 0 +3193 0.9382953395591789 0.8133636789902728 0 +3194 0.2852915206420736 0.4122807530812079 0 +3195 5.837759742839991 0.7788281940847382 0 +3196 8.980580507203042 0.205279119910982 0 +3197 2.467633604352288 0.558437333878691 0 +3198 1.507848366638783 0.8416328810171917 0 +3199 9.513606669792868 0.1299637469580549 0 +3200 7.972566091923103 0.7649658915485866 0 +3201 7.07682629868244 0.7573940083055875 0 +3202 0.3808957502840611 0.9588538931008932 0 +3203 8.041331240253918 0.4169508266014844 0 +3204 2.922137969911047 0.1308796917362059 0 +3205 1.400889432548257 0.459386702004953 0 +3206 5.208101007088571 0.4390323627105308 0 +3207 1.470370442494028 0.2970219336608623 0 +3208 2.572280165194312 0.2658526472060675 0 +3209 4.676917157816916 0.4914697558433385 0 +3210 2.473780810234708 0.8372326436558403 0 +3211 7.326219189761463 0.1627673563445307 0 +3212 3.041236661405377 0.642205510683142 0 +3213 6.208763338589069 0.3577944893161036 0 +3214 4.675242575334625 0.03855319039147162 0 +3215 9.615701138078876 0.9557079072463919 0 +3216 2.27756478700391 0.9551818574122279 0 +3217 7.525162606222176 0.03924564408340656 0 +3218 4.551005426131152 0.6099766184045295 0 +3219 5.75495079048288 0.7667251940427017 0 +3220 7.412879436133762 0.6015124659842429 0 +3221 9.793924782402211 0.2223330685108122 0 +3222 9.794426844721842 0.7744597903991404 0 +3223 0.9665902768204648 0.4952724056807713 0 +3224 0.5808890551620303 0.6321443879655689 0 +3225 5.074586874476687 0.9526889666565526 0 +3226 3.204787446576641 0.5867153039364417 0 +3227 6.827015387588544 0.3987027662141615 0 +3228 4.681320944186678 0.5792776566331217 0 +3229 0.4501695431607991 0.2348071397729175 0 +3230 2.173937877565212 0.9606674157170163 0 +3231 7.623263939679803 0.04340719951366678 0 +3232 4.225586043051667 0.3486712579923777 0 +3233 3.588456568233641 0.2257577902831108 0 +3234 2.663303112936716 0.2230760576956582 0 +3235 2.559663452620117 0.5502282571379703 0 +3236 6.793389906900006 0.5889523610972879 0 +3237 9.443472442049273 0.6546109143093823 0 +3238 5.134452103411864 0.6811504741738976 0 +3239 3.510524072369462 0.1554271369372512 0 +3240 5.568498419285641 0.04309616801143413 0 +3241 6.118524697430285 0.04314800971054926 0 +3242 6.669042485156655 0.04342820291402406 0 +3243 8.916853699908852 0.0430264900294432 0 +3244 5.568498419288702 0.9569038319881888 0 +3245 6.669083062751967 0.9565007762493171 0 +3246 6.116386302367056 0.956071628027602 0 +3247 4.789105936708102 0.5918428163025116 0 +3248 2.270144971268119 0.03942348690329814 0 +3249 7.531582389122379 0.9551095081162945 0 +3250 9.805953705043052 0.6819980053975633 0 +3251 0.1916251878276503 0.3180674610119497 0 +3252 8.03304006589507 0.9574149331395193 0 +3253 7.016959934104947 0.9574149331395442 0 +3254 2.783040065889685 0.04258506686034649 0 +3255 5.692709880797157 0.5890675894056475 0 +3256 0.8903674348457435 0.3894212426500503 0 +3257 7.012009800034847 0.4483618695898542 0 +3258 9.520390937087347 0.8513633709716348 0 +3259 0.848680339645246 0.5532242988461817 0 +3260 3.047804338583992 0.271011460156459 0 +3261 6.203807066486916 0.7325664000566003 0 +3262 1.373134727664988 0.8880227778314238 0 +3263 4.003099071467049 0.5622984168067893 0 +3264 5.211897639123354 0.7528067476804698 0 +3265 4.315740068740404 0.8951306131653135 0 +3266 2.134440842996712 0.1189870377063157 0 +3267 7.663699634375779 0.8808367476349025 0 +3268 1.084047338645992 0.7623863236244193 0 +3269 2.156287302741385 0.5608493227254947 0 +3270 7.64371269725535 0.4391506772744752 0 +3271 4.350440944726975 0.5599815932979914 0 +3272 2.060086249142282 0.6534075652569161 0 +3273 7.739913750854814 0.3465924347432592 0 +3274 7.298984705046913 0.2956193714627207 0 +3275 5.143622609049754 0.146954753189583 0 +3276 7.306694949637722 0.2114914134106054 0 +3277 2.489106372537233 0.7808803589987163 0 +3278 4.07480453243905 0.6297199494905902 0 +3279 6.574664870613622 0.7832713231808587 0 +3280 8.049011392081006 0.1044900721872888 0 +3281 4.98980540931977 0.3595504488868791 0 +3282 8.567736127033536 0.9569418687098782 0 +3283 0.9881894388209628 0.6452533004614407 0 +3284 8.744188318006051 0.8501778122183299 0 +3285 7.146081009943685 0.6020828169007332 0 +3286 9.428476083410496 0.5012229054273516 0 +3287 0.04758854218523682 0.7187719747392125 0 +3288 9.95310408749793 0.2806528176722137 0 +3289 8.531961155670292 0.4845330420701795 0 +3290 4.151318982491675 0.6725109545663306 0 +3291 6.55433976581672 0.8516240653147759 0 +3292 7.997392155085211 0.1858988369678289 0 +3293 5.266794032017202 0.9597740871280123 0 +3294 9.629679625091772 0.8058893018847852 0 +3295 9.002859825029187 0.7309079958588808 0 +3296 0.1522679859099491 0.1143624591870348 0 +3297 4.501247641405363 0.5396781145867295 0 +3298 3.32221772693521 0.9596037367307766 0 +3299 8.17770815373305 0.04076845565120354 0 +3300 6.956414684492072 0.2625091072734221 0 +3301 1.70637204168938 0.7364588508586769 0 +3302 4.376380806251402 0.957298436476046 0 +3303 3.454151568662957 0.8295033009944964 0 +3304 2.850177602183534 0.1016963901243955 0 +3305 8.098984820090179 0.893684435929075 0 +3306 6.949193190539091 0.8974318047368917 0 +3307 1.698979297312278 0.8993747189434603 0 +3308 6.948979297311763 0.1006252810582445 0 +3309 2.851179058599581 0.8984801386743277 0 +3310 0.9927205390583617 0.2728400231282762 0 +3311 0.2144638073501683 0.9606584627433512 0 +3312 3.328567826373116 0.04008034940591609 0 +3313 4.494926624217524 0.6711198226963377 0 +3314 7.868377697282237 0.1184706504320743 0 +3315 4.424772350518122 0.8347035795301038 0 +3316 2.783729405162299 0.9574056815549109 0 +3317 7.016270594832969 0.04259431844515713 0 +3318 1.766270594836204 0.9574056815547257 0 +3319 2.954644217733565 0.6061927845321964 0 +3320 8.544062354845307 0.3948590050316939 0 +3321 6.295055575132408 0.3948813011603003 0 +3322 5.477794390281232 0.2216479286598325 0 +3323 6.024533930525163 0.2150831824161791 0 +3324 4.646729091650051 0.8448061114560032 0 +3325 1.128292258242786 0.5650407797909005 0 +3326 6.649454777180893 0.8202630654053521 0 +3327 0.538386645163456 0.4523561815594208 0 +3328 1.569403359021265 0.8276900653808897 0 +3329 1.768664059787013 0.0424520554622753 0 +3330 4.179615143388882 0.7201769938508603 0 +3331 4.057138927854878 0.5433420449796661 0 +3332 9.114927715213351 0.03881286968071111 0 +3333 9.132786545984594 0.2163091541834923 0 +3334 5.639945739894468 0.2176153811985135 0 +3335 6.741341472142748 0.2175286207795943 0 +3336 0.4383649268693181 0.8372485598093695 0 +3337 1.827921751616198 0.2350155159571499 0 +3338 9.274999999999006 0.03886014803916983 0 +3339 8.347740763239131 0.7033256429721116 0 +3340 5.60225923676099 0.7033256429721768 0 +3341 4.958556225169338 0.4942583725662922 0 +3342 4.078588445826827 0.1220377039319747 0 +3343 0.8749999999992761 0.03882635244387774 0 +3344 9.667748076061706 0.8996126364646977 0 +3345 9.668790823458465 0.100271095359398 0 +3346 8.83138016762863 0.9615845939344114 0 +3347 8.475713403864356 0.9642275376343045 0 +3348 6.57622804400202 0.2235427167419387 0 +3349 0.5319389709320395 0.7106411967297303 0 +3350 0.9704987851398725 0.8923651791133429 0 +3351 0.2168258834061785 0.453896114807282 0 +3352 9.783174116593891 0.5461038851926308 0 +3353 3.727220545115772 0.7052486060460555 0 +3354 7.282510729546743 0.5061501352578339 0 +3355 7.774154218895701 0.5059702556508827 0 +3356 2.025523236695886 0.4941217437634477 0 +3357 4.395876701003261 0.6336417064339198 0 +3358 2.375000000000007 0.9613152401196251 0 +3359 7.423934908283673 0.03848509486475651 0 +3360 2.387298933482959 0.3963226412668979 0 +3361 9.296496398427189 0.8720226833362813 0 +3362 0.1621704785044678 0.5494804238005877 0 +3363 9.837894248194859 0.4505202514521082 0 +3364 9.369461292229264 0.889462611859662 0 +3365 4.234734363564997 0.6562324697464204 0 +3366 0.6358838303229345 0.9562056657822796 0 +3367 7.491693617356418 0.4329169927334823 0 +3368 2.308490044868236 0.5664780776192414 0 +3369 4.464807670507713 0.1680296825958382 0 +3370 6.616903067219905 0.3048951423443456 0 +3371 1.060611592938698 0.4981355721282253 0 +3372 9.749775076128275 0.9025413459145244 0 +3373 9.749775076128147 0.09745865408536485 0 +3374 1.399393503707782 0.6367019991703845 0 +3375 2.184123085681804 0.1331073087108916 0 +3376 7.6177262034327 0.8621562038318699 0 +3377 6.050343573426536 0.4202687660949451 0 +3378 5.234772291553576 0.286073199300013 0 +3379 5.784935697812139 0.286156834146979 0 +3380 8.303271886418893 0.4224101362924702 0 +3381 1.002425075107823 0.1151082137909231 0 +3382 6.864378642847741 0.1083935114148974 0 +3383 8.569779552303654 0.127641995563102 0 +3384 6.325127778475263 0.1264672661771098 0 +3385 1.496733306027697 0.3472009961877631 0 +3386 6.363685628232394 0.698923907372855 0 +3387 3.098081180641171 0.2962752429375069 0 +3388 6.151918819353277 0.7037247570624892 0 +3389 1.072046585917953 0.2563624058481413 0 +3390 9.701134362313942 0.4491721787513058 0 +3391 2.868233807961417 0.3676663250664655 0 +3392 3.826444888356018 0.5955594569288932 0 +3393 1.75586183604804 0.5767236644089957 0 +3394 3.579432035206774 0.4088458406989559 0 +3395 4.739730136782839 0.650949231757489 0 +3396 1.220001193457407 0.5426190072589586 0 +3397 0.9623920197161566 0.3414253237048925 0 +3398 1.972771040077812 0.6533739049885229 0 +3399 7.827056911500235 0.3461975018126457 0 +3400 7.221351955335383 0.3464689124946422 0 +3401 9.120451552023066 0.9610722901596662 0 +3402 0.3785341583877611 0.5976696791444961 0 +3403 5.825447491174557 0.6095582426227004 0 +3404 4.972993837610621 0.1176899974223526 0 +3405 3.127677294764267 0.03993171727410336 0 +3406 1.491029940471972 0.7836753684545679 0 +3407 0.9001738827760327 0.6313927496963274 0 +3408 5.126657153733037 0.4771676946794843 0 +3409 3.128324483484167 0.9577813120062609 0 +3410 8.37117222723152 0.04194104650893009 0 +3411 4.149833267297889 0.1172892919026116 0 +3412 5.725118723606936 0.171546176653825 0 +3413 6.271009535430051 0.1752127346118926 0 +3414 8.520699337629475 0.1763001439913546 0 +3415 4.142453235539931 0.7583694103511314 0 +3416 3.683373535837418 0.5514938046511875 0 +3417 3.331015244944585 0.5789105535314173 0 +3418 0.2548864472607498 0.6965531707944761 0 +3419 9.745108460480518 0.3034556431563817 0 +3420 9.141877290404947 0.4209319012277489 0 +3421 2.02844602847952 0.297397396117754 0 +3422 2.017541942149093 0.3437606049669026 0 +3423 7.779673010217301 0.6565953222585694 0 +3424 7.770999253144591 0.7030981114253085 0 +3425 7.272571824432171 0.6549553189138836 0 +3426 7.283979535966986 0.7030559738443114 0 +3427 1.535190032200482 0.1023967720092232 0 +3428 8.955358882899858 0.2964340156892867 0 +3429 7.977534273707809 0.3827526130997258 0 +3430 4.552308130773273 0.7251609273632904 0 +3431 7.475958432657923 0.2056587307585682 0 +3432 1.035639315798613 0.04396454660034427 0 +3433 0.5123366442998969 0.6678793231153466 0 +3434 0.04412326129555322 0.6404509399635269 0 +3435 9.955876738704413 0.3595490600365318 0 +3436 3.940922239233652 0.8183800756439283 0 +3437 7.637856205375954 0.3363615001924384 0 +3438 2.162143794620699 0.663638499807884 0 +3439 3.074118437744506 0.04167870378556763 0 +3440 6.730041372570689 0.9592094827068349 0 +3441 8.319958627429401 0.959209482706929 0 +3442 1.296715406410455 0.1954776766488581 0 +3443 4.929533600091007 0.03618166769092712 0 +3444 9.29398999191363 0.4355042472802001 0 +3445 1.679410111504367 0.03824925817767075 0 +3446 8.377668652126333 0.9578503985613428 0 +3447 9.613995462670074 0.8768409257268307 0 +3448 6.729572215664448 0.04048610388144314 0 +3449 3.070427784329719 0.9595138961184583 0 +3450 9.443300882934103 0.7025976292811893 0 +3451 9.618537512920964 0.402401966682848 0 +3452 9.529179201238856 0.04539359883282486 0 +3453 9.607882351085001 0.329381746061868 0 +3454 8.940415532008924 0.1220148606090308 0 +3455 4.08397290930553 0.3960110386951878 0 +3456 8.206475832627847 0.6096290491312134 0 +3457 5.056272578106521 0.1216369302825857 0 +3458 1.690999634645648 0.1221856987039831 0 +3459 7.051914255064321 0.6529538718412803 0 +3460 0.1787198824814716 0.03995121735198132 0 +3461 3.771917860093485 0.5376096813240187 0 +3462 9.321995550098348 0.1067036977180401 0 +3463 1.824305390098833 0.8903602072780544 0 +3464 7.07943527140171 0.1101116705217587 0 +3465 0.1015630943780993 0.9612354985834772 0 +3466 1.425972293513429 0.9577325043830469 0 +3467 4.463307816637345 0.9112320000296862 0 +3468 4.397592629995686 0.1941862539866618 0 +3469 3.853293450475631 0.1914452257920925 0 +3470 2.878609616520301 0.6332406295581503 0 +3471 4.220716600129979 0.2989220397502282 0 +3472 5.795266151809324 0.7889517906302023 0 +3473 2.979244833337078 0.8224578129290412 0 +3474 6.820665998069077 0.1764718042945107 0 +3475 4.850961705217832 0.8993465394385949 0 +3476 4.829832737082835 0.6258633258346014 0 +3477 7.950618535221428 0.1059110294006494 0 +3478 2.377604714836857 0.04260324106796283 0 +3479 7.422264571757737 0.9573843064512145 0 +3480 2.787079824680081 0.7618867948970898 0 +3481 7.416571612861258 0.3410463194584016 0 +3482 1.618724407193335 0.7441695662138544 0 +3483 6.174999999999987 0.9624805875561802 0 +3484 5.623155203054032 0.9587052227190428 0 +3485 8.423603639062254 0.04119782473882377 0 +3486 6.173165239775011 0.04134930108343661 0 +3487 5.62312598777224 0.04128367687073715 0 +3488 3.178603685952998 0.3311785219700906 0 +3489 4.908257065491747 0.6413685977225614 0 +3490 1.656184443778532 0.1997178603693175 0 +3491 9.388009308610098 0.6367884496010403 0 +3492 5.521455623607647 0.6679227330941765 0 +3493 1.801137422853435 0.8091822569560254 0 +3494 7.051066902239934 0.1905472926779492 0 +3495 7.725793439284503 0.4820504280913424 0 +3496 2.074768837413187 0.5184395621168938 0 +3497 5.981029070111055 0.6216734778021029 0 +3498 1.802847429907594 0.1881259812014194 0 +3499 2.702117125859849 0.3055639244210825 0 +3500 4.528783875797959 0.8749588164174593 0 +3501 4.894872391728312 0.6870906848691922 0 +3502 2.645883657929023 0.5785362843742843 0 +3503 3.604994519952168 0.5791384733467002 0 +3504 1.0357835526762 0.191175591569745 0 +3505 8.920275115559669 0.9597192258443854 0 +3506 6.69702867625803 0.6625233875824411 0 +3507 2.781329792545675 0.2410568518184268 0 +3508 2.06772074927573 0.1638103090569396 0 +3509 7.732280730480475 0.8361890106238618 0 +3510 2.148854736597807 0.8217474930767736 0 +3511 7.655246559333362 0.1818906268663238 0 +3512 0.3066261862100644 0.7475539839824105 0 +3513 5.276769596574867 0.7136709490979026 0 +3514 5.010437303314565 0.8177771870224915 0 +3515 5.690364979143597 0.8462557506702046 0 +3516 6.373213416861003 0.360931260670856 0 +3517 8.62323558236856 0.3608946754008977 0 +3518 0.7779068810502835 0.0405060111242689 0 +3519 9.586167144870013 0.4351316973787216 0 +3520 8.947926701719194 0.3390147495094802 0 +3521 1.982180561622199 0.09185186389470093 0 +3522 7.817819438374088 0.9081481361050093 0 +3523 2.606132413752059 0.3093628980361448 0 +3524 1.97451669056392 0.9059844642675652 0 +3525 8.430011655508823 0.6683220402678065 0 +3526 6.922841680167361 0.6026461360443247 0 +3527 8.127109806032461 0.603858751623978 0 +3528 3.856380301735553 0.5584896559976986 0 +3529 1.647540962963876 0.7959165370966633 0 +3530 6.899231030232016 0.2039455429869851 0 +3531 5.819103470279724 0.04098607962675407 0 +3532 6.369029818150894 0.04034746517183752 0 +3533 6.368787248890588 0.95918758723199 0 +3534 5.819103470280614 0.9590139203721546 0 +3535 8.619029818151269 0.04034746517244833 0 +3536 5.835718748518842 0.8884644431976191 0 +3537 6.385405409306713 0.8885937213498472 0 +3538 5.834774389911236 0.1084112293038528 0 +3539 5.28539026302649 0.1120485386071644 0 +3540 6.583772921556433 0.4821351147769126 0 +3541 6.843802552323494 0.6111905456505715 0 +3542 5.743802552323497 0.6111905456505958 0 +3543 9.593775965229426 0.6569734645782539 0 +3544 2.402304015217296 0.8235042994683793 0 +3545 7.396922239122298 0.1776967693334734 0 +3546 9.305639843442581 0.6130108929467094 0 +3547 3.848755830386309 0.8213680548723631 0 +3548 8.621678203356652 0.5333253485495479 0 +3549 1.143761797699136 0.6454215997285955 0 +3550 0.5494727936722964 0.539134892090855 0 +3551 3.269763172151886 0.3811863840480815 0 +3552 5.431202802837641 0.621151595208102 0 +3553 5.441823467286883 0.7020701439259196 0 +3554 8.513345715755694 0.7057073925207726 0 +3555 3.258746426398818 0.2980304719145784 0 +3556 9.153813829241338 0.3053719250721365 0 +3557 3.961571918918397 0.1473783840928009 0 +3558 2.262496066719249 0.1492409854475381 0 +3559 7.538428081078565 0.8526216159081556 0 +3560 7.996162973381638 0.8091854339458633 0 +3561 7.053837026618355 0.8091854339458697 0 +3562 4.842150894869214 0.186870959749209 0 +3563 9.501508737657916 0.4656459409678283 0 +3564 0.4988057526053454 0.5341310860365052 0 +3565 4.054260764234102 0.9559154642634354 0 +3566 6.422562650705379 0.1815508150928589 0 +3567 8.672132370042144 0.182030537235095 0 +3568 8.954191404199809 0.7047599993374982 0 +3569 1.831506856057919 0.1114569687351757 0 +3570 6.876396573318067 0.2567172824293311 0 +3571 2.348703902441173 0.7131952577166162 0 +3572 7.446343926936659 0.2868920618722461 0 +3573 0.1876999585241622 0.6737336452386486 0 +3574 9.812300041475787 0.3262663547613955 0 +3575 5.475921212908589 0.7936015358498207 0 +3576 3.225719323323754 0.2079161913156129 0 +3577 8.473712824544048 0.7917105302209891 0 +3578 2.475018186571107 0.1623544696101057 0 +3579 7.324695714467627 0.8376666919531691 0 +3580 1.098354238337165 0.8044709180795903 0 +3581 3.064338021638807 0.7882205948096148 0 +3582 6.185471937497753 0.2116019478408424 0 +3583 8.439048247566724 0.2113143977242739 0 +3584 2.89214808294068 0.3098808493310505 0 +3585 6.414360803613398 0.4709330960428761 0 +3586 3.584096461243242 0.1705711869265799 0 +3587 9.160968123577861 0.6862636753661165 0 +3588 0.03663894384019267 0.8249999999998265 0 +3589 9.963361056159812 0.1749999999998025 0 +3590 9.963361056159954 0.8249999999995711 0 +3591 0.03663894384001325 0.1750000000007281 0 +3592 1.229178323928807 0.04210879945454871 0 +3593 9.063310595800051 0.1081545299788604 0 +3594 9.097935849546925 0.1290332981207374 0 +3595 4.404961233217184 0.6859728041469181 0 +3596 5.002819814959818 0.7394223212907701 0 +3597 8.919276210965183 0.5848051246827299 0 +3598 3.694013964045717 0.04389427983756326 0 +3599 0.6487071323517583 0.8104678293877636 0 +3600 7.398819555980347 0.7415606289474149 0 +3601 3.582072537328383 0.8303424928190388 0 +3602 9.626842499145884 0.03719783354117178 0 +3603 5.170919263602351 0.177503610321325 0 +3604 1.51285669015783 0.1694845140093362 0 +3605 1.494921443135639 0.218366633323986 0 +3606 5.524900378978366 0.3623055246317609 0 +3607 4.841349066167172 0.7523278706260366 0 +3608 6.667213715756062 0.7350190537638078 0 +3609 0.2979093323003766 0.5501203529534495 0 +3610 9.349376378463504 0.2619213263737059 0 +3611 1.299076274124968 0.3516575562314152 0 +3612 0.4157893427273532 0.03826539123256956 0 +3613 6.972492248648589 0.5306415209068629 0 +3614 2.436771682452956 0.4045891960411333 0 +3615 2.400869250087336 0.2579823437029446 0 +3616 4.223704556195056 0.2097326399893933 0 +3617 0.41615301699759 0.5669771051059648 0 +3618 8.304383545528911 0.8378421941824791 0 +3619 6.748178486279175 0.8445674710074766 0 +3620 4.318496707514699 0.04007169905613956 0 +3621 2.166222461162679 0.4095276463879542 0 +3622 7.634062116980428 0.5907280504942365 0 +3623 6.776119239515916 0.4305191560023704 0 +3624 4.069222726502846 0.7761237393992687 0 +3625 4.267860806692193 0.2814530773419823 0 +3626 0.1186921339377784 0.3336040864127913 0 +3627 9.894834088078101 0.6938654813302765 0 +3628 3.069652006204697 0.7132677456177863 0 +3629 6.18083112594559 0.286330238158147 0 +3630 3.690624227978367 0.9569683314923569 0 +3631 7.809375772016247 0.04303166850785441 0 +3632 7.081549169103286 0.8923365997413292 0 +3633 7.968450830896654 0.8923365997414602 0 +3634 3.821988677157141 0.4050931357531394 0 +3635 1.191767446730467 0.1954348350957189 0 +3636 4.260526469602436 0.4253036141078875 0 +3637 7.22640453063509 0.09150853236953573 0 +3638 2.573595469360262 0.9084914676305743 0 +3639 8.611236593437692 0.8419422825760658 0 +3640 6.706408726510881 0.7050606382785277 0 +3641 0.9341469487871127 0.5790701273938174 0 +3642 5.567923577667944 0.3908068107398674 0 +3643 2.574328039744454 0.4044966176977633 0 +3644 2.586225864342345 0.4546451201935007 0 +3645 1.324406152679066 0.03684923217970663 0 +3646 0.8795390075696667 0.474817535233887 0 +3647 1.515740042116947 0.5242914042096392 0 +3648 2.09240157422169 0.3629356949574692 0 +3649 7.707391370099938 0.6371881770548306 0 +3650 7.340447267265903 0.6342738421428233 0 +3651 0.6088579028945115 0.8971242375193906 0 +3652 0.3919409839233838 0.6815409513815774 0 +3653 6.206808507321471 0.842141039623341 0 +3654 3.043191492672625 0.1578589603761106 0 +3655 4.573144954546454 0.2878706877905007 0 +3656 9.374991012968717 0.4303549271652579 0 +3657 5.062755732243601 0.7901338388151725 0 +3658 8.97841270076794 0.5942654481666312 0 +3659 4.121057413629034 0.03796827748605504 0 +3660 5.078028701091181 0.6170275481536095 0 +3661 1.067611632952447 0.6170445597757629 0 +3662 4.328487184507311 0.1108229300382773 0 +3663 9.586420371734354 0.7298130292656939 0 +3664 0.7053777475792251 0.5520005188227474 0 +3665 6.857234540879992 0.4428988848374477 0 +3666 0.3115328349356956 0.1108210837562967 0 +3667 9.102562056280034 0.2933922619986792 0 +3668 3.89929617895259 0.2900620777530755 0 +3669 3.071166746470557 0.406312845240859 0 +3670 6.178833253523371 0.5936871547587818 0 +3671 2.562405185653549 0.8267567941631523 0 +3672 6.337987502694626 0.32450655684762 0 +3673 8.587978558364622 0.3246221900546036 0 +3674 3.695502319715246 0.1727412682080715 0 +3675 0.5803081769336026 0.7669042004702225 0 +3676 2.51479232322916 0.2950160756310436 0 +3677 4.850606091134678 0.5435582456220321 0 +3678 2.55790080758045 0.1720768083557113 0 +3679 4.108971594890386 0.1892879983550315 0 +3680 5.124270514100348 0.4302067200645925 0 +3681 1.12325017354356 0.1171450937558392 0 +3682 0.7279561576131576 0.6981795496307801 0 +3683 7.55833732907123 0.5718663611048502 0 +3684 2.238661602252415 0.4308999684874865 0 +3685 5.147667848024969 0.7754879794506098 0 +3686 0.8794087965326044 0.750241799768237 0 +3687 5.590975618878829 0.6612086416741166 0 +3688 8.359024381121372 0.6612086416740589 0 +3689 8.266946416285306 0.1662574222742798 0 +3690 1.3596712778737 0.1033072273263224 0 +3691 7.235081502903861 0.1739380937585809 0 +3692 5.025952204219215 0.04200149908838118 0 +3693 6.477145022160479 0.8810008825732096 0 +3694 5.927123878814832 0.8810604308810788 0 +3695 8.726860884408282 0.1194564050662668 0 +3696 6.477220389042804 0.119022499291319 0 +3697 5.927521372940128 0.1185896638255303 0 +3698 5.37752434554937 0.1185833605618668 0 +3699 0.6282303992793716 0.4442833351807487 0 +3700 0.3235832177301827 0.8948388091491319 0 +3701 0.370198174978224 0.8792101770505479 0 +3702 0.7091815851275831 0.1044264812042218 0 +3703 4.276953776155397 0.8151560187004894 0 +3704 8.194320821966773 0.14396636541454 0 +3705 3.693316221715981 0.8284869470826209 0 +3706 1.583259864490655 0.1856462739843117 0 +3707 1.19747969977362 0.2491868425937527 0 +3708 4.411921122549449 0.7751239704659538 0 +3709 3.579068880046375 0.4863294247338575 0 +3710 0.5928377227124784 0.1353949601789778 0 +3711 5.224028859124361 0.9624243066547101 0 +3712 1.745173888384639 0.6658409859139071 0 +3713 6.995342550365261 0.33404315616568 0 +3714 2.03963599522385 0.7039834592642512 0 +3715 7.760364004772769 0.2960165407359202 0 +3716 0.8638439641858677 0.1254026548334967 0 +3717 2.304070382530677 0.3715766469797419 0 +3718 2.310476697061023 0.4239786238138202 0 +3719 4.303071460240384 0.3243087942559978 0 +3720 5.840220992038744 0.2191347473432134 0 +3721 5.795626866846864 0.2031492339108422 0 +3722 5.290220992038847 0.2191347473433117 0 +3723 5.244831886359715 0.2027850083748985 0 +3724 7.805401770103739 0.1746614104938056 0 +3725 1.994411321419889 0.8254934697417998 0 +3726 8.501757733053109 0.5589149371114224 0 +3727 7.30326194502114 0.3473706487051904 0 +3728 3.678687487637319 0.4034863760477906 0 +3729 0.7742424692389889 0.5857527973119814 0 +3730 8.771270482725628 0.6133965760643842 0 +3731 5.192517690103112 0.8906627541659384 0 +3732 3.528480131490975 0.6079811312315654 0 +3733 2.721572792902148 0.6079855414796012 0 +3734 4.555865536709666 0.3673982316202987 0 +3735 9.005782861279766 0.1565364396865017 0 +3736 1.323341140143452 0.8718497284066631 0 +3737 1.94850915780685 0.7659780627488141 0 +3738 7.849451680500799 0.2325090337241696 0 +3739 1.081253917091225 0.9639327560021144 0 +3740 0.6783451509162904 0.7070440474940126 0 +3741 3.312722865638643 0.8578800994499328 0 +3742 6.111245711539835 0.6416150778303624 0 +3743 3.275474163330545 0.5132579108120765 0 +3744 1.782185038219238 0.7285971933932832 0 +3745 7.031824001585593 0.2713473106687266 0 +3746 2.574901645290758 0.09062114986574858 0 +3747 7.22907172089385 0.9075736698261984 0 +3748 4.875050373671027 0.5025530673586482 0 +3749 9.005149427814358 0.8441371565046704 0 +3750 4.008635886255991 0.4266956092719115 0 +3751 3.840870213540268 0.1078352765431869 0 +3752 6.36064810357463 0.6582136773606223 0 +3753 0.9727697039993938 0.4087310013892393 0 +3754 4.583651791315267 0.8314580327810881 0 +3755 4.859001889372093 0.8274224177942736 0 +3756 9.696818828234433 0.7516922863309066 0 +3757 3.934076880252527 0.671645226943466 0 +3758 2.955503646144445 0.3738203179480664 0 +3759 6.294496353849778 0.6261796820510903 0 +3760 9.095355108500616 0.6250619926701135 0 +3761 9.516686097686424 0.706172381458917 0 +3762 4.112497440395115 0.4789990161584683 0 +3763 0.804286641278511 0.6596507136760583 0 +3764 9.454137632380849 0.2918649819008949 0 +3765 5.643771685751926 0.8376609416642941 0 +3766 2.379396452403537 0.647708851321107 0 +3767 4.660767801953301 0.7939087408412782 0 +3768 4.621459763307649 0.7642935069045551 0 +3769 3.232592058401612 0.8321143846471298 0 +3770 0.2657782264550078 0.6337588615287637 0 +3771 0.6340033565469082 0.5213962942800606 0 +3772 4.34239160862142 0.4265862505789779 0 +3773 4.424197630177088 0.5602426565062787 0 +3774 8.391970148983434 0.3407888043268634 0 +3775 2.717830700463211 0.1052553802251519 0 +3776 4.053296670772318 0.8862500076762139 0 +3777 0.3325956043899349 0.5243792032322596 0 +3778 9.666638624207229 0.4759743861139004 0 +3779 9.277533522099963 0.2580909393894435 0 +3780 0.5079422233063939 0.7882843495886854 0 +3781 0.3233142260821257 0.4772545474409318 0 +3782 8.770454813811869 0.3955321784074921 0 +3783 9.677616289684973 0.528340555405486 0 +3784 6.664336620571056 0.9033369718781433 0 +3785 5.560702856745076 0.9093441113881867 0 +3786 6.109242527553958 0.9112576375109013 0 +3787 8.908333422744585 0.09252355690350279 0 +3788 6.66070285674491 0.09065588861186141 0 +3789 5.560702856744776 0.09065588861186319 0 +3790 6.110702856744805 0.0906558886119096 0 +3791 3.724628699425145 0.3962084162187965 0 +3792 1.523093112312897 0.5704571611583928 0 +3793 3.13654259794983 0.4084346525458454 0 +3794 6.11345740204461 0.5915653474536389 0 +3795 8.873217917658474 0.2954639181411663 0 +3796 0.2263774632134052 0.1063321013700942 0 +3797 6.419719144017798 0.820817016382994 0 +3798 5.868817532196533 0.8208180372242779 0 +3799 5.320310312871156 0.179499112971085 0 +3800 5.870310312871128 0.1794991129709823 0 +3801 5.663880311261916 0.6411789931957046 0 +3802 6.767437518806952 0.6391592245157589 0 +3803 8.045385273092688 0.9108520576530863 0 +3804 7.003597512850376 0.9099118142134398 0 +3805 2.792822609802423 0.09094570927774251 0 +3806 8.817709509822965 0.832526224210114 0 +3807 2.182013755932927 0.2857164455648186 0 +3808 7.622650290091715 0.720588778452811 0 +3809 4.308511535054426 0.5355551481577187 0 +3810 1.32110649882794 0.2706367365244917 0 +3811 4.454101721370521 0.5296037348371915 0 +3812 9.03494755262089 0.238358378694004 0 +3813 9.376935495205878 0.4826231230882823 0 +3814 1.124947958234905 0.0331012250699594 0 +3815 9.478835993608808 0.1682842255256665 0 +3816 0.6750182841990592 0.03655038673581889 0 +3817 0.03385499731820188 0.328033355933905 0 +3818 9.965732314523438 0.6716554034205823 0 +3819 7.197098299820695 0.2393890820572726 0 +3820 4.798403558747639 0.6816986160893683 0 +3821 0.4076400304923672 0.3727851882508745 0 +3822 2.056018771240371 0.2104004020896736 0 +3823 7.743981393173466 0.7895995223192377 0 +3824 0.3233673063327678 0.3364149208843228 0 +3825 5.01457445708933 0.9078317480043965 0 +3826 2.722630989704407 0.8932351701801576 0 +3827 9.665563091925323 0.612993790084527 0 +3828 8.374833602320908 0.1704472335108625 0 +3829 6.667554645349409 0.1712061570228945 0 +3830 0.3901033728154807 0.7576491545041029 0 +3831 5.270835995975109 0.03917957852732858 0 +3832 3.235754797635025 0.1598759131335569 0 +3833 0.2024029303643471 0.7730707501225711 0 +3834 4.398119282866008 0.9101335903325332 0 +3835 0.2470524471700189 0.9000884354533363 0 +3836 9.416354357153006 0.9606857013367102 0 +3837 2.072470909091587 0.5649846738681599 0 +3838 7.727591566094186 0.4350697694884437 0 +3839 3.125302683213148 0.8291326755935302 0 +3840 5.566670201783741 0.1712214432277836 0 +3841 6.11700239654561 0.1716382954640103 0 +3842 0.3326138223805001 0.3869472684059097 0 +3843 9.710376453538361 0.2217649057244743 0 +3844 8.316600102975229 0.7849514393137775 0 +3845 5.633012711715056 0.7848883548763352 0 +3846 6.734478885102338 0.7861059839125886 0 +3847 6.84940876025643 0.717275183542737 0 +3848 8.200591239743581 0.7172751835427713 0 +3849 5.801524976358108 0.656280752213999 0 +3850 1.336502901340967 0.5752432489632571 0 +3851 0.6836771157964164 0.3763714013270992 0 +3852 0.6373427686783364 0.369134864042798 0 +3853 5.090830915187909 0.6582428098690348 0 +3854 7.483868589084932 0.6340888881253021 0 +3855 9.301020276245403 0.7166172125406581 0 +3856 9.45975978047993 0.7849998080774198 0 +3857 1.53349253029254 0.6540826673332749 0 +3858 5.679616699610601 0.3437642076710098 0 +3859 5.129227555263585 0.3434906769462585 0 +3860 6.778272718649378 0.3434047676592218 0 +3861 2.793541318277643 0.9092911455434159 0 +3862 7.00645868171744 0.09070885445696857 0 +3863 1.751584224475084 0.9098609666849278 0 +3864 2.372057461761186 0.12867792827031 0 +3865 7.427772844933925 0.8712630904147822 0 +3866 1.014770059952817 0.7815028735609206 0 +3867 9.96287411335005 0.480265829565781 0 +3868 0.03712588664998986 0.5197341704344344 0 +3869 4.125069711654375 0.4026435296273889 0 +3870 5.075427196633943 0.03961929094052331 0 +3871 8.624003954161564 0.7707891631325215 0 +3872 9.470996811860431 0.354730524750321 0 +3873 2.838876387520925 0.5277066469011451 0 +3874 3.411123612466099 0.5277066469011585 0 +3875 1.442601996429918 0.4568502708866244 0 +3876 7.109552849941236 0.5616004136181078 0 +3877 8.92750918907544 0.8310454443218382 0 +3878 5.748662215740143 0.9030574520045364 0 +3879 5.748481159068231 0.09681215240820017 0 +3880 0.9077100005955279 0.292429860505839 0 +3881 7.236528529345946 0.5803108206900177 0 +3882 2.52682028308033 0.3384934761058339 0 +3883 3.412080000366567 0.2802311025294346 0 +3884 3.105260625215283 0.336760429214291 0 +3885 2.023904003339772 0.966735868561004 0 +3886 2.025297247649775 0.03316007261403207 0 +3887 7.774698344795921 0.9668401428545094 0 +3888 9.349101398510314 0.5906442076391351 0 +3889 0.8583577337432362 0.8106361445032625 0 +3890 4.968674143757142 0.7035217320416167 0 +3891 4.927627987194352 0.716924514713237 0 +3892 6.743636682474614 0.2682111364455269 0 +3893 5.6429565103676 0.2685630409432 0 +3894 4.602430049946801 0.4330136245243381 0 +3895 4.154682510488209 0.3648488015122877 0 +3896 1.710065250620758 0.7861016772620811 0 +3897 6.960065250619276 0.2138983227400192 0 +3898 1.690920967057398 0.530103390467273 0 +3899 7.485600065116232 0.5663151711756585 0 +3900 8.829437643165313 0.4886574712555334 0 +3901 7.273848394947163 0.03279183277857403 0 +3902 2.526151605048617 0.9672081672215183 0 +3903 1.438146430562484 0.7852319921554711 0 +3904 8.944071118958341 0.6643143022008046 0 +3905 2.71088668119171 0.745741766615222 0 +3906 0.4739811926665978 0.1564924562745671 0 +3907 8.271795222176648 0.7698954307478336 0 +3908 1.213440562038147 0.3823287857862553 0 +3909 3.68728742952321 0.0966369418493235 0 +3910 4.638942129458462 0.4010017352457432 0 +3911 4.346300204783546 0.8221873484774879 0 +3912 3.142537941597881 0.6472709241609749 0 +3913 6.107462058395658 0.352729075838447 0 +3914 8.462399092202006 0.6001633867076612 0 +3915 3.963535838972621 0.7106371255849996 0 +3916 4.782068193468382 0.5092930036103088 0 +3917 0.8181515536268904 0.5127559852553712 0 +3918 1.844857745719558 0.8450650996239074 0 +3919 7.094854520527258 0.1546325918557214 0 +3920 2.430643929074247 0.4676054363794694 0 +3921 4.821364592601763 0.9670422316421029 0 +3922 8.263330124448203 0.8403117266689298 0 +3923 6.787049140032453 0.8408726851103621 0 +3924 5.030839920090904 0.1670048740546385 0 +3925 4.336098869041368 0.9626420681685948 0 +3926 5.631110599729609 0.3936073976015704 0 +3927 7.270165065847606 0.7852894510873604 0 +3928 6.767986549908531 0.4966223296945413 0 +3929 3.824236573767053 0.8973857654304672 0 +3930 1.261397126429205 0.2873815535966303 0 +3931 1.193509827753731 0.5858118110222462 0 +3932 9.481154684640931 0.2598054918232426 0 +3933 5.525254082683904 0.712103215320952 0 +3934 8.425058364140591 0.7124428718126896 0 +3935 0.9205373736582053 0.3437518444655021 0 +3936 1.62430798351256 0.2791799457351385 0 +3937 4.745005917220835 0.7857384455294915 0 +3938 0.9660523647022511 0.03871093934313028 0 +3939 0.5837783926338388 0.8378914550976662 0 +3940 6.536739982282043 0.6851677681624389 0 +3941 7.246988183398825 0.829510500083747 0 +3942 3.669805929433705 0.2572302259378454 0 +3943 0.6268193065356046 0.7695439529158644 0 +3944 6.14966432304169 0.6616684831950091 0 +3945 2.526105762246464 0.03257270867145734 0 +3946 7.273874907298716 0.96735977189844 0 +3947 4.716605160232063 0.9615727455988247 0 +3948 4.116046355555079 0.896452664921478 0 +3949 7.31999408184916 0.4836996046046448 0 +3950 7.54036309839842 0.3664676822493137 0 +3951 2.25513563283376 0.6305413577250978 0 +3952 3.175745441132358 0.287402614315108 0 +3953 0.8273701502434542 0.9652772230733009 0 +3954 6.249515706509591 0.616698164415597 0 +3955 2.999363325486497 0.3879620153075666 0 +3956 0.5656581362731602 0.4906231986092301 0 +3957 1.617478522576991 0.8981770420231254 0 +3958 2.520340702734383 0.4075852486227629 0 +3959 2.4449550914603 0.3316022975988551 0 +3960 9.050609497910683 0.6119592058440888 0 +3961 0.6592639630922048 0.6557969025787558 0 +3962 9.238302201316158 0.5893588379167873 0 +3963 4.190745599411801 0.6444432135482938 0 +3964 5.597291980328042 0.4580880061857223 0 +3965 2.265845589401013 0.7073738224874409 0 +3966 7.540178413437587 0.2899075451309892 0 +3967 2.574126626589042 0.6022824567892787 0 +3968 1.056258985873251 0.8975501840721457 0 +3969 4.939073988858758 0.4225648136350033 0 +3970 9.192300312783596 0.04098370456047545 0 +3971 6.392319528704845 0.7828817308280239 0 +3972 2.776895811504863 0.1563897878914616 0 +3973 4.193680406860838 0.4249898022710863 0 +3974 8.030318149019703 0.2475473196380763 0 +3975 1.147033100148481 0.2626420997420322 0 +3976 7.990374397216401 0.4860330772700354 0 +3977 0.09912159905027255 0.03778668577783832 0 +3978 9.173007141380976 0.6426336030555756 0 +3979 9.167458051160473 0.6015561851081244 0 +3980 3.681632287625003 0.9073329173610164 0 +3981 7.816776197266655 0.0960255259781531 0 +3982 4.87697780108344 0.7764708211710196 0 +3983 4.560986199072705 0.4124245883516873 0 +3984 9.084132764340696 0.3413693201868972 0 +3985 0.6092752790735846 0.4842753073458827 0 +3986 8.643106744469581 0.2113494689900036 0 +3987 6.3934448983502 0.2111408072208073 0 +3988 4.92668697881057 0.5563451193578086 0 +3989 1.32107715277464 0.1216054544290057 0 +3990 2.103308681909752 0.239295250692225 0 +3991 7.696691318086183 0.7607047493076151 0 +3992 9.012829486956251 0.3574703467615652 0 +3993 2.607859684777157 0.2241855796011938 0 +3994 6.476735530776684 0.634077432344735 0 +3995 4.578293830448063 0.6917957342290223 0 +3996 6.779039813402242 0.7706052432593944 0 +3997 5.677968879550565 0.7693486776289702 0 +3998 9.755928827727598 0.7006149340189552 0 +3999 0.3458059480329897 0.1893664023773117 0 +4000 2.460810310742461 0.6443690530865451 0 +4001 2.430440680149801 0.679235593704164 0 +4002 4.135718117881081 0.8305045939384924 0 +4003 0.7422707645349121 0.95917780505428 0 +4004 3.871656473818187 0.3381409619608148 0 +4005 5.096613516920947 0.2706517293976624 0 +4006 1.760513871150137 0.09160965231215633 0 +4007 8.785784760861285 0.3142878821880382 0 +4008 3.764337113043636 0.09469694433208625 0 +4009 7.736561087604072 0.910200037670863 0 +4010 2.06343891239217 0.08979996232899025 0 +4011 7.902514114086615 0.7027500354451824 0 +4012 1.897476264212554 0.2972632999504717 0 +4013 3.124645962382819 0.1660859780106312 0 +4014 6.12778812586521 0.8320771080041751 0 +4015 2.77994589683371 0.8475943505290853 0 +4016 7.959751802652718 0.2649913117538898 0 +4017 9.283681415638965 0.961910525735362 0 +4018 3.639955334467205 0.1056439099392282 0 +4019 3.27636696292368 0.6196293234794352 0 +4020 6.304008457228481 0.9022440776207237 0 +4021 5.09032811641362 0.740232647471449 0 +4022 2.39557944508786 0.5960952079489401 0 +4023 0.03793778435097343 0.5949737765283329 0 +4024 9.962062215649034 0.4050262234718821 0 +4025 0.4847431325636215 0.1964497204589731 0 +4026 6.675752024470346 0.34793437724047 0 +4027 3.002351812340121 0.6652801380173778 0 +4028 8.496966727422215 0.3346106777186494 0 +4029 6.246966727422204 0.334610677718587 0 +4030 3.63817182478342 0.894805740355299 0 +4031 3.638133562813901 0.7773004507601291 0 +4032 0.6711022550141187 0.9631592060162657 0 +4033 1.111825625080191 0.732547839840479 0 +4034 0.102699881434869 0.7800892579713177 0 +4035 6.82500000000002 0.9671412754207362 0 +4036 8.225000000000083 0.9671412754207619 0 +4037 2.97383948127275 0.03444809635703197 0 +4038 9.074560850993143 0.03317527891802483 0 +4039 5.236579933411996 0.8749464097438313 0 +4040 5.430647263539894 0.9556021686906927 0 +4041 3.577732465798682 0.03715262585989657 0 +4042 8.222054823012897 0.3913290135955988 0 +4043 5.295862606104987 0.4685035751040048 0 +4044 4.626395033511582 0.2269736648177676 0 +4045 0.6732825331825752 0.1194818776159368 0 +4046 7.896010926152227 0.3077598508168483 0 +4047 8.922734789702536 0.1678316942818519 0 +4048 4.101112305198988 0.7447254043063103 0 +4049 5.90713863765353 0.3203564410138601 0 +4050 5.357138637653513 0.3203564410139278 0 +4051 1.492597416080789 0.7324093169006686 0 +4052 3.469917578896693 0.2176674194642313 0 +4053 8.737156289270095 0.45914672672933 0 +4054 9.813827021058863 0.03976699178059218 0 +4055 9.813827021059023 0.9602330082194152 0 +4056 1.475000000000001 0.9673343594828987 0 +4057 4.472773031719138 0.6264968914864922 0 +4058 5.632474985313706 0.5248268922772374 0 +4059 2.009322354427706 0.2223169163016508 0 +4060 7.790677645568102 0.7776830836983254 0 +4061 3.671812854197223 0.6015060957426263 0 +4062 9.744479173026704 0.6293243677252092 0 +4063 4.86264196193896 0.1504100063489731 0 +4064 7.420739087625772 0.5362973518568783 0 +4065 7.37358360132361 0.5278798392578719 0 +4066 9.736416233925187 0.3678190623637028 0 +4067 1.179791630928757 0.8998195426710601 0 +4068 8.3052611434961 0.9170287779101441 0 +4069 6.745597433081159 0.9172358223217388 0 +4070 3.062596308760956 0.08223471704596567 0 +4071 6.824999999995115 0.03254318050485842 0 +4072 2.975000000000005 0.9674568194952068 0 +4073 8.111125066752816 0.4705136212472147 0 +4074 1.333713723889354 0.4891532380281463 0 +4075 0.2595675929989306 0.304575152931062 0 +4076 3.537906935501687 0.3004832882219236 0 +4077 1.015445351006179 0.4450628515836967 0 +4078 8.874144446866406 0.8984970661420861 0 +4079 7.604907439450855 0.3055740246546139 0 +4080 2.195092560545652 0.6944259753455284 0 +4081 3.102365102444699 0.2117666831337272 0 +4082 6.149306044532262 0.7884573824780646 0 +4083 5.67578355922956 0.4972436124474317 0 +4084 4.923539323820844 0.5127003768717582 0 +4085 9.550404686077902 0.1474722123874774 0 +4086 3.135010337975901 0.09119879169791072 0 +4087 1.932035913907428 0.8419101253290844 0 +4088 7.185792912693 0.1554970182798203 0 +4089 2.127254727047196 0.8974066942605895 0 +4090 7.674094097934751 0.1034739223388024 0 +4091 0.8318165588140132 0.04364666083544941 0 +4092 9.073233489804471 0.9662710409831881 0 +4093 1.114251551807429 0.2393271223691938 0 +4094 8.36420589204714 0.09181630958465292 0 +4095 3.135674008517642 0.9080714085487287 0 +4096 3.887562807261264 0.7341052195668002 0 +4097 9.413471974902087 0.3651856958482735 0 +4098 9.534385132353805 0.9627643324199219 0 +4099 1.330174304171794 0.3224067714693743 0 +4100 0.6097775330968855 0.4055075979321031 0 +4101 3.82187874872118 0.3196314696538133 0 +4102 3.637543145324591 0.5365589786843139 0 +4103 2.616429046617311 0.7760608109735715 0 +4104 2.293227424869364 0.8618681945729326 0 +4105 9.235477572268598 0.3543210092629969 0 +4106 3.333136196202647 0.7329288314796809 0 +4107 4.471648235647097 0.3883478161996583 0 +4108 0.2548137113310276 0.3717989846044374 0 +4109 3.792980847252903 0.3574582441958243 0 +4110 6.7450406441742 0.08354396756989214 0 +4111 3.054815126512782 0.9164734017530043 0 +4112 7.302971832840461 0.5625924303542651 0 +4113 7.755887816066258 0.5796823613407986 0 +4114 2.04411218393061 0.4203176386597249 0 +4115 3.475607866567622 0.7421858942214974 0 +4116 3.764755719286825 0.2728743364361889 0 +4117 9.804105796681998 0.1416625345551135 0 +4118 9.804105796682022 0.8583374654448509 0 +4119 6.659041864834924 0.6513495434510744 0 +4120 9.770532583515644 0.4038728114222858 0 +4121 0.2309624958707925 0.5961938645242519 0 +4122 5.868396974397617 0.3620655159542243 0 +4123 5.318396974397578 0.3620655159541437 0 +4124 3.974653751493914 0.5186830894874395 0 +4125 7.526034658152511 0.5063982948455694 0 +4126 2.273743755974463 0.4931131310178763 0 +4127 1.21137402229705 0.331707673606933 0 +4128 8.059567945679598 0.7588634955607383 0 +4129 6.990852689802081 0.7569708248858223 0 +4130 4.49979001118664 0.593485970602017 0 +4131 8.385505531098968 0.9060152083367401 0 +4132 1.14017647633498 0.5272508742589356 0 +4133 0.09918486598934734 0.5770518452177988 0 +4134 0.1192913712158157 0.6242282968915259 0 +4135 9.885296133602434 0.3758195616465922 0 +4136 9.901324856768191 0.4229534723975177 0 +4137 5.155522320282594 0.3104971542644477 0 +4138 6.805900561208914 0.3110124961015691 0 +4139 5.705403131654451 0.3111324162307717 0 +4140 1.556849802249449 0.6937417977733128 0 +4141 4.21806338147575 0.1686708357883057 0 +4142 9.223503913498126 0.7406173399800979 0 +4143 0.7849502631291234 0.8255621090529623 0 +4144 4.027194590308808 0.6360696742986491 0 +4145 2.067661893203069 0.7342694747518865 0 +4146 7.732338106793522 0.2657305252484237 0 +4147 4.024999999991006 0.03217571836666079 0 +4148 0.141795419012303 0.4174270332886886 0 +4149 9.858269938846796 0.5823496578672757 0 +4150 0.476013069157079 0.8602703735583089 0 +4151 4.813866234338239 0.8243693830310036 0 +4152 3.859514042807341 0.4658570117364841 0 +4153 9.587348987260297 0.6136612649364469 0 +4154 5.052224393273968 0.6859508889071128 0 +4155 0.3892299529433321 0.4543446043421427 0 +4156 7.436154328698816 0.637267707671815 0 +4157 8.867234717338933 0.2181889424144784 0 +4158 3.938673082117077 0.4367499149481342 0 +4159 3.540393731415517 0.7439273564791908 0 +4160 0.7230221342416456 0.2517711039616689 0 +4161 3.762963950742875 0.7285571403446013 0 +4162 0.4412819511493588 0.09607155606382975 0 +4163 2.48751305494826 0.7274905744313371 0 +4164 3.818842866527204 0.6816320632641442 0 +4165 2.526419736876519 0.2089860330537354 0 +4166 5.870729255786976 0.480045250427751 0 +4167 4.379130253845632 0.4952786658575385 0 +4168 1.426149583682777 0.8318588834218802 0 +4169 8.644841799735088 0.9598123751843509 0 +4170 8.349464446300541 0.3474055844279028 0 +4171 3.724011368485862 0.2148477197190969 0 +4172 0.8449387428364126 0.6113218474754095 0 +4173 8.873695456642936 0.7793932093998114 0 +4174 9.786926233654777 0.1786023673948282 0 +4175 9.7869262336548 0.821397632605176 0 +4176 0.7068784276144698 0.3247628946944121 0 +4177 0.5408930794517006 0.1955733092132688 0 +4178 4.977397593353549 0.966578080682295 0 +4179 1.426155859472806 0.9106120431241863 0 +4180 7.376719128325566 0.3266556521765546 0 +4181 2.44236798882821 0.6021846266927878 0 +4182 7.923629019981168 0.03693872302724831 0 +4183 3.576370980014048 0.9630612769724104 0 +4184 1.121633242364453 0.4897732776603316 0 +4185 3.75789470868304 0.9105639724200015 0 +4186 9.522501995121834 0.6650000069852061 0 +4187 5.981155359514108 0.3166855448573048 0 +4188 8.909591089561117 0.3528365265718817 0 +4189 5.375328465620869 0.2655563818871253 0 +4190 5.92532846562083 0.2655563818870466 0 +4191 4.828754218175031 0.3651725790015046 0 +4192 6.573147277788403 0.4097078349451367 0 +4193 0.4626617246077068 0.5958676144336459 0 +4194 8.915680696853954 0.9093902566971044 0 +4195 8.589542046060096 0.4544685758503373 0 +4196 7.778671381975743 0.3716293781425992 0 +4197 2.021328618021229 0.6283706218576656 0 +4198 2.05774239221597 0.9103281221564508 0 +4199 7.742257607780885 0.08967187784372189 0 +4200 9.106399697982958 0.4821268361396859 0 +4201 3.418703936851386 0.03377063747337782 0 +4202 3.948532947014415 0.8602699820263018 0 +4203 4.799654249109634 0.7837503544652353 0 +4204 4.624543477030353 0.6406262492734616 0 +4205 4.009030201278423 0.2497001603436634 0 +4206 4.733737747758727 0.5613611635798804 0 +4207 1.496848668910662 0.2656237059117525 0 +4208 1.364948574053843 0.9625988171973334 0 +4209 8.483804212729206 0.8337689763153605 0 +4210 5.527586280868172 0.2320042055452629 0 +4211 6.070492863723411 0.2263065228966065 0 +4212 3.179371451951367 0.7823961634393873 0 +4213 7.989224316276349 0.9634140052598311 0 +4214 7.060775683723668 0.9634140052598563 0 +4215 2.739224316271145 0.03658599474002451 0 +4216 2.628255801180464 0.3880341189631138 0 +4217 7.425807557341711 0.136407569741284 0 +4218 9.103645177634506 0.2476488446627486 0 +4219 0.2058679177077519 0.5422733048477373 0 +4220 0.2572287767182596 0.502104263486552 0 +4221 9.794132082292304 0.4577266951522698 0 +4222 9.742769269104942 0.4979062369846107 0 +4223 3.39996706794259 0.9597762239407355 0 +4224 8.100032932053816 0.04022377605878243 0 +4225 4.121985550294348 0.6036394292827897 0 +4226 6.327648519565967 0.2442843674528532 0 +4227 8.574792692562621 0.212518767347683 0 +4228 9.879551769224882 0.6588461105414828 0 +4229 6.474840851241912 0.7344491887376791 0 +4230 1.406136095524472 0.3282577692498772 0 +4231 1.492492328515952 0.03947964131748239 0 +4232 7.033956897086374 0.4820233345274726 0 +4233 2.675921629389342 0.4848176921598201 0 +4234 5.624562387537977 0.6346564984350179 0 +4235 6.071051239208503 0.6563851899381585 0 +4236 9.723083293458734 0.666999589210832 0 +4237 2.880061715854276 0.4075482585539688 0 +4238 0.7709437137094017 0.4547048986666629 0 +4239 3.176939044479549 0.8963402218076949 0 +4240 9.105135002624097 0.8679872754629999 0 +4241 3.439559141057555 0.1842941601384806 0 +4242 7.680445150038704 0.5973507877315185 0 +4243 7.703705297769288 0.5610618546719649 0 +4244 2.119000455078312 0.4027109553823711 0 +4245 2.096201744312427 0.4389539500618482 0 +4246 7.368089607701959 0.5985852249789212 0 +4247 1.303335237991227 0.7803938036546855 0 +4248 6.275883231466366 0.6984547226656975 0 +4249 0.09904008949202993 0.3018692342913099 0 +4250 9.420217354298558 0.78377684200912 0 +4251 0.5607299257157322 0.9613463354234749 0 +4252 8.351687830992185 0.5335144306779881 0 +4253 2.183193231621231 0.8638522044117972 0 +4254 0.324999999999751 0.03136772190188118 0 +4255 0.1792366609958639 0.9642688466670835 0 +4256 6.971504739232548 0.3994608697306014 0 +4257 3.383228171145774 0.2355959995528591 0 +4258 3.374115368267249 0.8049495135945427 0 +4259 6.347169688080493 0.1982823869380216 0 +4260 8.948948051504637 0.787878558390011 0 +4261 8.216897088991288 0.2520372018173213 0 +4262 0.9935613979617169 0.5295215956173028 0 +4263 8.123088199043313 0.1804202092279442 0 +4264 0.04080054103309298 0.9164777517460928 0 +4265 9.960373509926981 0.09437016143752659 0 +4266 9.960373509927107 0.905629838562487 0 +4267 0.04024229001190354 0.08393078278537731 0 +4268 8.281415029160623 0.6487206151985591 0 +4269 1.948749984255971 0.6955070614488016 0 +4270 7.854623696281606 0.3075033018890936 0 +4271 7.192533170569452 0.3096409562848251 0 +4272 9.19743794663548 0.4774301111467554 0 +4273 1.698986650316362 0.8575700589432647 0 +4274 6.95046672580503 0.1426095601547935 0 +4275 4.524999999991679 0.03119862571865157 0 +4276 5.315409147275983 0.8945305327782913 0 +4277 2.378008255802926 0.4648184023757018 0 +4278 5.095780612774452 0.8193324357447629 0 +4279 1.573477238633641 0.9627204105674905 0 +4280 1.741933649429733 0.2437001895540772 0 +4281 4.207044294276994 0.8018414654755288 0 +4282 7.263319710514273 0.3714367755956672 0 +4283 0.4082497328404397 0.1711629005249196 0 +4284 3.426310594632484 0.7606231053127047 0 +4285 4.946819147706266 0.9094534104304434 0 +4286 2.738586337799757 0.1802807961666834 0 +4287 9.478755806279038 0.7188389210635118 0 +4288 5.205152276890685 0.09568776322826629 0 +4289 5.262689840779396 0.5925331044691281 0 +4290 2.474934351239252 0.5013117905925972 0 +4291 9.381798584465347 0.8389094752629079 0 +4292 5.743102554702866 0.6510747932962445 0 +4293 2.739992922346921 0.9636771211512144 0 +4294 7.060007077648357 0.03632287884883908 0 +4295 1.810007077650904 0.9636771211512115 0 +4296 6.478171652809523 0.2600726597983131 0 +4297 8.728313132181935 0.2604007046889502 0 +4298 4.278692164210314 0.4658627244188239 0 +4299 4.895458065769886 0.9604006718671129 0 +4300 0.6674964430209281 0.8732813514233054 0 +4301 4.325308084320724 0.3944744269403434 0 +4302 5.023227710062743 0.09206311613881771 0 +4303 7.810439389401798 0.8272768018663486 0 +4304 1.989579847473595 0.1727143539874182 0 +4305 8.646498199382403 0.8998507864892014 0 +4306 3.224751508129439 0.7918349810655403 0 +4307 3.720945101740456 0.7847349373055752 0 +4308 3.546168341484293 0.09678498019432703 0 +4309 9.37932812237737 0.1511806595317595 0 +4310 1.719408783160828 0.599377368732426 0 +4311 8.662322790907844 0.7149259528395834 0 +4312 4.86856776975434 0.3862103797272904 0 +4313 9.238726110282407 0.09533742814680195 0 +4314 0.4570255785606565 0.7237148817465356 0 +4315 1.553611186704541 0.3075725348080885 0 +4316 0.8259578557808408 0.8855817580673561 0 +4317 9.410064772939611 0.9111726864550329 0 +4318 8.995491170854484 0.4427360134200862 0 +4319 0.4826482812043845 0.3976015591030442 0 +4320 7.491419587087939 0.7516070883487733 0 +4321 2.308580412907921 0.2483929116509195 0 +4322 9.487149822079253 0.5390047451257631 0 +4323 3.640060434422739 0.2232950101571509 0 +4324 8.364341896424332 0.7802092351539057 0 +4325 5.58565810357584 0.7802092351539645 0 +4326 1.094086185266955 0.09623759009721543 0 +4327 1.495196866332983 0.08259619697928042 0 +4328 3.549522284694204 0.9046062294815057 0 +4329 9.224901980912941 0.7047038199432027 0 +4330 1.041095735182141 0.1428707915463651 0 +4331 5.557198162377597 0.6422659154457877 0 +4332 4.190737661588275 0.08819547956150398 0 +4333 5.635862926650317 0.08322645423524078 0 +4334 6.185989071276484 0.08328356339549971 0 +4335 6.186403591360289 0.9176470288566819 0 +4336 5.635901381579604 0.9164093682418819 0 +4337 8.436283088914839 0.08328324743990395 0 +4338 4.675434305197486 0.8976013936109579 0 +4339 9.79226869896285 0.6380159140210798 0 +4340 0.2096644698069 0.3645360338248393 0 +4341 6.537590488178393 0.3095233675862113 0 +4342 2.741739055824723 0.8204065582626715 0 +4343 8.322964619358059 0.1031248917946364 0 +4344 5.433109062743562 0.3150286992934795 0 +4345 4.082314858675434 0.818966572102249 0 +4346 3.690342561451731 0.7482934914442023 0 +4347 7.773074656064463 0.03304637774145168 0 +4348 5.063300414565626 0.4858024399525396 0 +4349 4.6412182046297 0.7171260086095829 0 +4350 9.90903808959691 0.1434749405978315 0 +4351 9.909038089597002 0.8565250594021534 0 +4352 8.014204865666015 0.7371662436124858 0 +4353 7.030759825136119 0.7380145573098015 0 +4354 4.7181445485972 0.1860778481459111 0 +4355 6.621172656107508 0.2261550466096225 0 +4356 8.320150900892246 0.2147584873761778 0 +4357 4.087142381068748 0.9630926930691732 0 +4358 7.615236834168281 0.1246073491115472 0 +4359 3.069458820662336 0.3598501276852781 0 +4360 7.310287663184358 0.08593597183667229 0 +4361 2.489715444136505 0.9140574306581283 0 +4362 4.946745244053229 0.629980734738483 0 +4363 7.863447959625138 0.1592627815790437 0 +4364 2.372409796743391 0.3606443955636837 0 +4365 6.725815307783773 0.6326430317168968 0 +4366 2.370081408377515 0.8665593840999278 0 +4367 1.175 0.9694842362779486 0 +4368 1.191528742577202 0.4702245914628816 0 +4369 8.768128948761126 0.7464184224830251 0 +4370 5.498324813713054 0.425140040882954 0 +4371 4.636198724015117 0.5738307317161528 0 +4372 2.665343265369192 0.1818835963044386 0 +4373 3.783345090083521 0.6508318458817043 0 +4374 7.358363240606936 0.3997853203268033 0 +4375 9.347092689784798 0.3068455531880676 0 +4376 2.530485614176043 0.7837947747942785 0 +4377 3.339680346729659 0.2438727199444359 0 +4378 9.183156512939826 0.1420129452632182 0 +4379 4.193184811846796 0.04042580629884213 0 +4380 5.723634372193923 0.9669383625099408 0 +4381 6.27358694307276 0.9669998302065601 0 +4382 8.52363272413025 0.03287299369896744 0 +4383 6.273632724127998 0.03287299369853779 0 +4384 5.723599313856673 0.03304831699812701 0 +4385 2.360923434192175 0.4279773611074633 0 +4386 4.26844918825812 0.9569635728991509 0 +4387 4.693595111396395 0.2546509991644416 0 +4388 8.393350555515594 0.6420534920759911 0 +4389 7.873817135950083 0.5545031063138475 0 +4390 1.926137090147412 0.4454701494220681 0 +4391 7.915748147665361 0.2054602088435709 0 +4392 2.893474877277791 0.8697902999764303 0 +4393 5.230975004634633 0.7145442964904017 0 +4394 2.65656718698249 0.4509374919466982 0 +4395 4.969488458896993 0.03407561745557967 0 +4396 8.419278574940197 0.4053480225392083 0 +4397 5.88134108381112 0.7015166629859771 0 +4398 4.812140854499652 0.551373843931084 0 +4399 7.405381136412483 0.4039700679935415 0 +4400 0.09320199164883382 0.2202354510313257 0 +4401 2.319991633065134 0.7761019068024212 0 +4402 1.812435988610441 0.03537495113106858 0 +4403 3.886859979793223 0.1278313359090044 0 +4404 2.430726269637462 0.8993453016961271 0 +4405 7.369273730358293 0.1006546983041915 0 +4406 4.17301594356827 0.4989393437828759 0 +4407 5.304793358023383 0.7581225518338773 0 +4408 7.205219771387045 0.8286767125489881 0 +4409 9.213237940691817 0.8614359726768465 0 +4410 8.066756325431754 0.2314565263465316 0 +4411 9.621392032536024 0.1262417678807015 0 +4412 9.372473584969079 0.767586377672426 0 +4413 6.840029357643609 0.5276882836609891 0 +4414 3.369511120520384 0.6418610765399758 0 +4415 8.394604813923049 0.2127246430532111 0 +4416 4.428247018097196 0.03709978024253623 0 +4417 1.651199114879631 0.6334989691284263 0 +4418 5.25393143725403 0.3565612884561059 0 +4419 6.901199114881417 0.3665010308719169 0 +4420 5.803807618602684 0.3568105919907872 0 +4421 3.49859096900298 0.4260696274956258 0 +4422 3.758840968619316 0.1394776460544621 0 +4423 2.186348548207656 0.7342425567732627 0 +4424 7.613651451788912 0.2657574432269128 0 +4425 8.136995496744774 0.7590189965543852 0 +4426 6.917511985626524 0.7556347387549243 0 +4427 8.24897433739142 0.545340089847048 0 +4428 2.985594388853861 0.6976697389101204 0 +4429 8.516609123336607 0.3007520039203953 0 +4430 6.264052700573967 0.3020271776726223 0 +4431 0.3666424952831575 0.2514965478358874 0 +4432 6.906377790890651 0.8698718310084007 0 +4433 8.14385903648242 0.8692403064358378 0 +4434 3.725717242303368 0.9671406367419036 0 +4435 9.555541609327772 0.3656368547420082 0 +4436 5.773364397901338 0.5845413627484848 0 +4437 6.876582284702973 0.5896907716662234 0 +4438 1.785542190911448 0.2676651171174699 0 +4439 2.612387268133026 0.8412335467645283 0 +4440 2.991922773574025 0.4448277756381793 0 +4441 6.273570772649511 0.5541157437776647 0 +4442 2.574941308529202 0.7526657808881168 0 +4443 4.360261236084621 0.2685922584387401 0 +4444 7.916658648053739 0.8243465203897329 0 +4445 7.133467334136943 0.823900592397529 0 +4446 7.428762229760181 0.2107553205098624 0 +4447 6.96861654877454 0.3630581861373807 0 +4448 9.05757439762554 0.555366559648782 0 +4449 3.15680752018369 0.5226760411957564 0 +4450 6.075808498682976 0.4656057299947098 0 +4451 3.407940891380705 0.8931548899802901 0 +4452 8.092059108613789 0.1068451100197916 0 +4453 9.456387666089118 0.08634093818404849 0 +4454 5.935239665931966 0.9638506847270144 0 +4455 6.48523966593208 0.963850684726981 0 +4456 8.735239665931891 0.03614931527341586 0 +4457 6.48523966593192 0.03614931527429419 0 +4458 5.935239665931915 0.03614931527449867 0 +4459 5.385239665931932 0.03614931527470508 0 +4460 9.329802225603268 0.1915048901192387 0 +4461 1.156508785646462 0.59690694003232 0 +4462 6.078862795926028 0.2923632171860449 0 +4463 8.781865507957541 0.9077633248945841 0 +4464 8.517563295432867 0.9082841660003318 0 +4465 2.997948056794363 0.1009517931624391 0 +4466 1.290674676365454 0.4314682973517099 0 +4467 6.627645536255914 0.708155533869222 0 +4468 8.154130304029282 0.2505003777004029 0 +4469 2.568585382721985 0.3452981525059062 0 +4470 7.35999573586773 0.6685223753839729 0 +4471 9.59369404464181 0.9096422368845289 0 +4472 7.808233260733751 0.5802457266821865 0 +4473 7.825838945377719 0.5396003094770188 0 +4474 1.991766739263717 0.4197542733184847 0 +4475 1.974096076738404 0.4603857798143752 0 +4476 0.7949698720751388 0.9092415739859184 0 +4477 8.153042643275921 0.210394482445011 0 +4478 7.095624997649356 0.7079963982939794 0 +4479 8.590552638395586 0.751134898619731 0 +4480 9.335072582452959 0.5440865174884842 0 +4481 6.699011791768909 0.213720963438839 0 +4482 1.718149825366003 0.636675340453795 0 +4483 9.454657169844324 0.03867412701428415 0 +4484 3.284855071197948 0.7476439717763859 0 +4485 0.03070975758306403 0.4760446379442356 0 +4486 9.969290242416577 0.5239553620558401 0 +4487 8.275172886087349 0.2060010944693672 0 +4488 1.098106911443701 0.8790640941995399 0 +4489 2.12348896124342 0.6883737709709171 0 +4490 7.676511038753221 0.3116262290294152 0 +4491 4.011417533755373 0.6828330259134507 0 +4492 7.344210568114509 0.359361382785393 0 +4493 1.61046673880336 0.4170393738543775 0 +4494 6.790527124074813 0.9099422930801226 0 +4495 8.25965442841966 0.9098930216773186 0 +4496 1.599830878299655 0.3235750393009389 0 +4497 4.584237341576301 0.4810858582903354 0 +4498 3.498148530395547 0.4616124043676585 0 +4499 5.565936059627955 0.8280197952130552 0 +4500 8.384404657386884 0.8277022108914124 0 +4501 2.636491188794103 0.09894672319319436 0 +4502 3.912965518785708 0.3678570732989478 0 +4503 4.975423215310199 0.2905280562056295 0 +4504 1.647601428262437 0.4047247170630987 0 +4505 2.39497881478746 0.5457162351344814 0 +4506 7.405025918100096 0.4545320129636035 0 +4507 8.219714409281314 0.3115837204238375 0 +4508 7.781168521805046 0.213518050359066 0 +4509 2.021898062995124 0.7840596637115895 0 +4510 4.317862024804139 0.6633648668515766 0 +4511 8.698181068125612 0.7896973531166812 0 +4512 4.598668121662858 0.1355025216379432 0 +4513 6.305734499278326 0.09142369198006206 0 +4514 8.555734499278232 0.0914236919802056 0 +4515 3.105397763972603 0.7126105751756832 0 +4516 6.144605096325699 0.2874956231998841 0 +4517 7.190915497574788 0.7843340547919929 0 +4518 2.165290282854608 0.4662877208084164 0 +4519 7.63470971714204 0.5337122791912315 0 +4520 9.574999999999967 0.9702986212887561 0 +4521 2.162764579087882 0.3285482588627096 0 +4522 7.63768015291105 0.6724893259148186 0 +4523 3.72914449633079 0.03335317882990878 0 +4524 2.844139490148665 0.7151852525302652 0 +4525 8.980219615482499 0.640184699056998 0 +4526 1.928531216968152 0.9676830216674186 0 +4527 7.178531216966367 0.03231697833328043 0 +4528 2.621468783028953 0.9676830216666146 0 +4529 2.935592935531003 0.09302459260388306 0 +4530 5.727191860775208 0.8314421695306813 0 +4531 4.577597679052263 0.9677261392437785 0 +4532 6.79009073793353 0.09008632975823241 0 +4533 3.006475633932237 0.9120353540091182 0 +4534 7.30293004473866 0.631437514730111 0 +4535 7.748934121356792 0.6278541252391481 0 +4536 2.050733422716831 0.3721991857874202 0 +4537 9.102459439926212 0.7463237155478389 0 +4538 7.016809913632122 0.4098886867845516 0 +4539 2.490143612584509 0.08729662264050551 0 +4540 7.309856387410997 0.9127033773594206 0 +4541 5.972381333303139 0.9070518766054807 0 +4542 6.52238133330321 0.9070518766055197 0 +4543 8.77238133330296 0.09294812339464514 0 +4544 6.517414931597628 0.09270935418287056 0 +4545 5.967441335230811 0.09271793660185167 0 +4546 5.417441335230708 0.09271793660192945 0 +4547 9.27646441210122 0.5817178881431508 0 +4548 5.402066158345419 0.5772194520135892 0 +4549 3.30620731069189 0.4181270002090086 0 +4550 4.988318115391157 0.1649069884055683 0 +4551 5.040231069862649 0.2143391333784675 0 +4552 8.979764429852809 0.1089092513235091 0 +4553 0.6462023987151299 0.5910733219750329 0 +4554 6.266290523981967 0.7884320341223919 0 +4555 0.472734738157216 0.6677192171623939 0 +4556 0.2802974215704486 0.9666732333621323 0 +4557 8.82552041738537 0.7929316298779527 0 +4558 8.208109838066898 0.5332953071947609 0 +4559 3.55367537736501 0.6682334198171974 0 +4560 2.696324622623375 0.6682334198169275 0 +4561 8.275404792442517 0.5103586725420544 0 +4562 2.539628586525028 0.5164974914738411 0 +4563 0.2782985055978466 0.7797101044326621 0 +4564 3.026790323663482 0.3446570575238374 0 +4565 6.222779028071999 0.6537339020518504 0 +4566 5.092593678561638 0.0860862285176382 0 +4567 1.008088973371661 0.9621991348316041 0 +4568 3.141122144215832 0.3580729121528389 0 +4569 5.346663832796224 0.08657879810440305 0 +4570 5.896632620398935 0.08664498237360059 0 +4571 6.44624249467223 0.08731290928112001 0 +4572 8.696242494672134 0.08731290928095918 0 +4573 6.446601756505689 0.9133698309651296 0 +4574 5.896632620398912 0.9133550176266667 0 +4575 3.163213990608513 0.1684027215159166 0 +4576 6.086786009385063 0.831597278483973 0 +4577 4.134371391270817 0.3315764958126591 0 +4578 2.327650203648355 0.6427543311850927 0 +4579 7.494741611456416 0.3479353504027271 0 +4580 1.792089155887312 0.4236092036353283 0 +4581 8.009052598725329 0.57775287931379 0 +4582 0.2783156005206999 0.149692896167419 0 +4583 0.489838119500794 0.03784028393517283 0 +4584 2.744276916951801 0.419034061076362 0 +4585 9.023099718949522 0.6554283153113771 0 +4586 8.882880535609765 0.1693186381938698 0 +4587 1.04183970874296 0.5821885150157213 0 +4588 4.502187521427171 0.8304483295054067 0 +4589 0.2802620919270863 0.3333596127301509 0 +4590 1.072950382393189 0.299608783486618 0 +4591 2.618195235948723 0.03211919837016509 0 +4592 7.870134038519098 0.9670565395776548 0 +4593 7.179865961480934 0.9670565395775979 0 +4594 6.48211176649658 0.5386061559097828 0 +4595 4.209783259407885 0.575439606767608 0 +4596 7.437211795037771 0.5712020072056756 0 +4597 3.793471808351845 0.4506062389589425 0 +4598 4.354095633598973 0.5985037430707268 0 +4599 8.961163206790411 0.03588292098286516 0 +4600 6.679468278415101 0.5805420178593352 0 +4601 2.596399307833548 0.1699303956550818 0 +4602 5.219891586155738 0.2480839466957429 0 +4603 4.159008320759606 0.7972015456021717 0 +4604 5.318238386783921 0.9660397355309172 0 +4605 9.168804289957446 0.9681467116262084 0 +4606 5.952525197751252 0.5787196413980998 0 +4607 5.595298107254239 0.2127873773747329 0 +4608 5.144789912533086 0.9618608489576327 0 +4609 8.187925246058393 0.9090306055224793 0 +4610 6.862141829559154 0.9090522710038591 0 +4611 4.070611610200589 0.3603380969145951 0 +4612 6.625346643802235 0.8961114423533881 0 +4613 5.548653335827842 0.5280385940728431 0 +4614 1.41809490673388 0.1544098297675123 0 +4615 3.653510516108923 0.1760745672230765 0 +4616 2.886076717571417 0.1315212775962274 0 +4617 4.544910658399217 0.5355058648413884 0 +4618 0.5776300558401165 0.266798031269687 0 +4619 2.937798341322319 0.9091380126309919 0 +4620 8.424431365224377 0.8995975016352756 0 +4621 5.97938490717351 0.7571688559483079 0 +4622 3.929211028297352 0.5823963460143472 0 +4623 9.714300860249462 0.7829610025188615 0 +4624 0.6751296811975048 0.5179063146873409 0 +4625 7.270433910645093 0.2135364993137914 0 +4626 3.651465266252381 0.8304988957043907 0 +4627 3.852767912572685 0.6636587069870564 0 +4628 0.9892891329392081 0.3726917633483923 0 +4629 8.73052067701366 0.5879903296658909 0 +4630 3.499309439039329 0.7993219221267227 0 +4631 8.322666212932011 0.6434531932903896 0 +4632 0.9262226420366602 0.2076374489286911 0 +4633 6.618300711926569 0.784448171576917 0 +4634 8.989622847245574 0.914761012062938 0 +4635 1.046672454315077 0.7564700817025697 0 +4636 4.247801869914196 0.09648920020195283 0 +4637 0.9737583180880501 0.7304544836554153 0 +4638 2.931784983218653 0.7549107085778856 0 +4639 4.885784705751955 0.3131877350420483 0 +4640 3.27958619850123 0.9013234789493278 0 +4641 8.221104619353104 0.09970319228051583 0 +4642 1.930579481166537 0.03304734755580462 0 +4643 0.6163913165767655 0.1656281105896338 0 +4644 2.363934591197315 0.7884556035973871 0 +4645 2.66034487551296 0.7980434178845798 0 +4646 1.628296368672435 0.7090747710555703 0 +4647 3.434504944787467 0.9661483563059657 0 +4648 8.057722294664416 0.03752005324445143 0 +4649 0.4408671018949242 0.2841362053848119 0 +4650 8.09412066687406 0.2888047011581109 0 +4651 1.884341416310865 0.8078635268539091 0 +4652 1.464368965605743 0.5205520418876128 0 +4653 8.841504810041318 0.6115097686254791 0 +4654 3.479355865031609 0.5421300439151947 0 +4655 2.765362501036423 0.5378658241389983 0 +4656 9.277234091503821 0.9071292579236593 0 +4657 9.408797919175759 0.09090628625307756 0 +4658 1.499932551811656 0.9198582452446327 0 +4659 0.8908785316196739 0.2027842185062196 0 +4660 1.038105569050168 0.3230588727159788 0 +4661 3.178753407258582 0.2104526578319794 0 +4662 6.065815796792437 0.7885495458880953 0 +4663 4.736475548178325 0.4453100704882725 0 +4664 4.725954891581568 0.4856051508813508 0 +4665 4.773401885050581 0.2265958402203138 0 +4666 7.1342731104475 0.1920736910613121 0 +4667 3.266063414296298 0.09738330531964438 0 +4668 3.997287594855325 0.2123243229880583 0 +4669 1.38780432551981 0.7633094227384583 0 +4670 9.672907076636669 0.3278155196591501 0 +4671 2.503804506501164 0.5707824532927305 0 +4672 6.250984496589187 0.8995332134917101 0 +4673 4.533076413516896 0.1646932681149279 0 +4674 0.7483475542643585 0.1473334478635089 0 +4675 0.5546287891155716 0.1447191828171498 0 +4676 5.813852191671516 0.3121722290428983 0 +4677 5.263845378304795 0.3121270364763454 0 +4678 1.24144000501482 0.8037394952480331 0 +4679 8.598631391951809 0.1562403813352169 0 +4680 6.348484732785049 0.1555172714059048 0 +4681 3.88642894524551 0.2164647117345778 0 +4682 8.557754194130338 0.8075861732075227 0 +4683 6.93132350998246 0.4238572685932491 0 +4684 5.831323509982429 0.4238572685932014 0 +4685 7.957562260145859 0.463509710728049 0 +4686 0.2167337423020433 0.8226768412851629 0 +4687 0.8372037558513383 0.4122611465918414 0 +4688 5.354856659582561 0.7493512913964567 0 +4689 4.774999999992039 0.0288093295397496 0 +4690 5.174999999992686 0.02879748606630752 0 +4691 8.004628903067623 0.4102019461280034 0 +4692 8.861195676785286 0.5604915328489281 0 +4693 0.9663405321271765 0.08029084987417728 0 +4694 8.627331933913347 0.3997074835843868 0 +4695 6.378199254836234 0.3994425566730391 0 +4696 3.363878251142379 0.8469690878274528 0 +4697 4.402693689902061 0.2382141464996532 0 +4698 4.544098331382854 0.6516958792520338 0 +4699 7.150668473712047 0.7278486151973413 0 +4700 5.746920234367825 0.7221613483517746 0 +4701 3.704994716174747 0.3261900001041503 0 +4702 4.756563081871858 0.6154449385394588 0 +4703 7.499495110550095 0.8592766198266494 0 +4704 2.298761521785058 0.1407939055940625 0 +4705 6.673365689480922 0.5380170697462064 0 +4706 8.188074518667284 0.4542294187173647 0 +4707 8.668552886376801 0.4239421273835667 0 +4708 5.700556575153421 0.09991825877085074 0 +4709 6.250556575153456 0.09991825877105809 0 +4710 8.500556575153269 0.09991825877161872 0 +4711 5.703335976647563 0.8976402328862877 0 +4712 4.980113166382174 0.8895520345376181 0 +4713 3.174999999993406 0.02863881605626397 0 +4714 8.940761470120151 0.21832621345652 0 +4715 4.176162917519719 0.2255514852582524 0 +4716 8.885472126978556 0.8280918749709323 0 +4717 2.332017992327566 0.1597609838033161 0 +4718 7.467586146163222 0.8402223692558457 0 +4719 9.461165151342938 0.9655847841894823 0 +4720 8.321877221490061 0.4584643926243682 0 +4721 9.965451434069927 0.6362486755325886 0 +4722 0.03430946327943528 0.3634427765078396 0 +4723 3.306922342561893 0.8094894960542566 0 +4724 0.6464975678512328 0.2338590568715825 0 +4725 8.033172058643867 0.8456483254523319 0 +4726 7.02227581344294 0.8449179063569735 0 +4727 5.642893149330019 0.5656421209344266 0 +4728 1.599587750104838 0.4622643047858874 0 +4729 3.175000000000002 0.9714438297041086 0 +4730 8.324999999997369 0.02855617029506825 0 +4731 0.5583830192387368 0.9124958616512584 0 +4732 6.313948114394251 0.8645498786726695 0 +4733 5.524999999993207 0.02851364273337658 0 +4734 6.074999999993992 0.02851364273333118 0 +4735 6.624999999994843 0.02851364273319832 0 +4736 8.874999999998312 0.02851364273284639 0 +4737 6.624999999999968 0.9714863572673312 0 +4738 5.524999999999967 0.9714863572673063 0 +4739 6.074999999999967 0.9714863572673035 0 +4740 5.520047437049815 0.1519037310090224 0 +4741 6.070804172849629 0.1523540029543259 0 +4742 4.987114510478222 0.7757390444094683 0 +4743 1.601515533351546 0.1425800754715243 0 +4744 8.422696147181851 0.5774830559175358 0 +4745 1.615516084717585 0.209703691087375 0 +4746 0.9732253524783864 0.1544044259727771 0 +4747 3.263902214057216 0.5532796923403251 0 +4748 8.187465975947958 0.1892383534192961 0 +4749 8.679001363302245 0.9677149451244748 0 +4750 0.1884825109549131 0.8601758493177869 0 +4751 0.5241213662709872 0.97086366682549 0 +4752 8.575510570519786 0.2483323563583834 0 +4753 1.441160549653699 0.2031397354186789 0 +4754 2.86547087444458 0.5965449688757724 0 +4755 2.292143934039289 0.2159260568455678 0 +4756 7.506869057361133 0.7860971123853208 0 +4757 1.814477979901929 0.7161457473881838 0 +4758 7.064356463576396 0.2837754106139458 0 +4759 8.367833384429048 0.4616788237326702 0 +4760 1.327781295791846 0.233299464639499 0 +4761 3.508636073219232 0.1998549190583453 0 +4762 1.681928765229657 0.5764886214860216 0 +4763 5.283017055722167 0.4240318461222944 0 +4764 4.172202219666527 0.1601284374392414 0 +4765 9.295011218956576 0.5399303061607181 0 +4766 5.770725959994325 0.2483482148314035 0 +4767 3.754423609464987 0.8636119957635707 0 +4768 7.745634467499481 0.1363603955158646 0 +4769 2.054276691136359 0.863721733523334 0 +4770 9.051675882329119 0.9026953211453798 0 +4771 8.408060471979418 0.4820647624797645 0 +4772 3.710144621264028 0.5182668739694474 0 +4773 3.053445876659788 0.5498850733553666 0 +4774 6.196866327158991 0.4507549134007098 0 +4775 3.439261657630476 0.4120581008125857 0 +4776 2.797283166390321 0.4057062246627675 0 +4777 9.595725822949396 0.2964003446385589 0 +4778 6.173505959025446 0.3783661809363799 0 +4779 3.076494040968539 0.621633819062141 0 +4780 3.99251259415325 0.7978352522422422 0 +4781 8.237206859844715 0.4701780656855637 0 +4782 6.418297299197308 0.4228218474603036 0 +4783 8.117465323667302 0.4248261107232808 0 +4784 5.761946808481472 0.1347603874961363 0 +4785 5.764197064718194 0.8642917376777449 0 +4786 1.768301211806515 0.1536842036714396 0 +4787 1.160546916821807 0.03423429141397211 0 +4788 4.192432177309091 0.3774124474225381 0 +4789 4.620707009986418 0.2746995646554165 0 +4790 4.043381969795847 0.7031165702988964 0 +4791 9.030448495512571 0.03020099185268332 0 +4792 9.571191383422923 0.7634527025776799 0 +4793 3.757621248608181 0.5724071481292562 0 +4794 8.388438572163302 0.2819668043695996 0 +4795 6.133314698126712 0.4166542142621859 0 +4796 3.122732085953416 0.5799494562557724 0 +4797 0.08929840225767749 0.1406329937021185 0 +4798 3.511948465950695 0.03566382538673057 0 +4799 9.23514518293493 0.3122380870012746 0 +4800 5.173255287203451 0.7512347561483046 0 +4801 9.27454892736025 0.2980669710272659 0 +4802 5.046992261657121 0.552519897178389 0 +4803 1.449824983164266 0.09419444612219802 0 +4804 0.1427519598241574 0.461869599026722 0 +4805 9.857255302160134 0.5381055888794382 0 +4806 2.810074396539616 0.2184861737804255 0 +4807 7.237002393684364 0.631735293318657 0 +4808 3.442246503622007 0.5854074691194225 0 +4809 2.828210376486624 0.5815943785957696 0 +4810 2.707477994984803 0.8491448400042867 0 +4811 5.213030033942542 0.5775880832481324 0 +4812 2.540477089015814 0.6266983470411933 0 +4813 8.437586878753349 0.9645465596495313 0 +4814 8.567541092194457 0.4810095427889698 0 +4815 4.082586246206369 0.5880610284685198 0 +4816 4.776073833442021 0.9062023099402392 0 +4817 3.819888054505511 0.1687541073359482 0 +4818 2.76449717680331 0.1164611687972977 0 +4819 1.846001926750206 0.7661647214870703 0 +4820 7.09559639799049 0.2334588259114011 0 +4821 8.998276902892941 0.2379149466332646 0 +4822 4.150278792781333 0.1937696417120761 0 +4823 4.007914129938789 0.4781174481377758 0 +4824 3.177197021808329 0.09825002029601262 0 +4825 0.1832714887241638 0.4744381813060085 0 +4826 9.816729479540431 0.525558510414749 0 +4827 1.888011580560491 0.7253420268530647 0 +4828 7.137743013398161 0.2767371645637259 0 +4829 0.03156996602696446 0.677962896712469 0 +4830 9.968522384597387 0.321960408942502 0 +4831 4.500391384982297 0.1011854725850241 0 +4832 4.025173117214346 0.1766499701852192 0 +4833 2.238632162536453 0.6792693756703455 0 +4834 7.562129507834347 0.3186383853771753 0 +4835 5.691512132791921 0.1477188399772516 0 +4836 6.241830552831685 0.1485940325084014 0 +4837 8.491872924806307 0.1486722477367677 0 +4838 9.296647126433681 0.1351310749785115 0 +4839 0.6991220794376676 0.2797124768167641 0 +4840 8.657262163381992 0.4625971800369019 0 +4841 7.529904667059107 0.1438078936421813 0 +4842 1.23244940797702 0.6880868744535821 0 +4843 5.190355660177382 0.472681404425762 0 +4844 4.931712391601038 0.8369223644233722 0 +4845 6.208251770703844 0.5242718797868506 0 +4846 3.037279905570581 0.4718892480681094 0 +4847 9.483457694083947 0.8495431723924797 0 +4848 3.690418232891526 0.4628970435002626 0 +4849 4.096796209258533 0.2673929845948125 0 +4850 6.943105453900232 0.4624973055275915 0 +4851 6.833366367773404 0.4779145020755115 0 +4852 6.243836516272882 0.8589404486812037 0 +4853 6.744061648073058 0.564636334186768 0 +4854 5.383577454614832 0.9663895716032932 0 +4855 6.715273311318573 0.5913640099578999 0 +4856 5.836639167423276 0.4629077965531676 0 +4857 4.060006153361555 0.4281986720327202 0 +4858 4.074820198901754 0.4676580378180585 0 +4859 9.300081484645855 0.4694905202407139 0 +4860 8.083722219989605 0.4063400205901584 0 +4861 9.477936536322392 0.5787905845783031 0 +4862 4.914840775912417 0.1575951072211953 0 +4863 3.433591928699865 0.690745155357375 0 +4864 9.193852626215143 0.5287608529438219 0 +4865 1.549125974537621 0.9207087009850922 0 +4866 6.874339674114226 0.2948974837047391 0 +4867 0.749171291954397 0.7451507573381797 0 +4868 9.012426959132492 0.5268348739940107 0 +4869 0.7721994227174589 0.2075590775453731 0 +4870 4.809306332692379 0.8906358830427811 0 +4871 8.703538630523342 0.9095428397223001 0 +4872 1.612372779516919 0.6388391968097398 0 +4873 5.212071839552222 0.3600554278236409 0 +4874 6.862580926393627 0.3606550645942768 0 +4875 5.760645975790541 0.361770504443881 0 +4876 1.648496072028387 0.1518176533795838 0 +4877 5.7535821578814 0.541930692425757 0 +4878 4.147640005108239 0.5739287106003952 0 +4879 4.682469168431144 0.1283969073107132 0 +4880 3.373674119662725 0.4658786590697616 0 +4881 5.328571945684097 0.5438143735751459 0 +4882 9.963066034177999 0.03686566792464895 0 +4883 9.963066034178064 0.9631343320753167 0 +4884 0.03165871623781736 0.9635919960311343 0 +4885 0.03147071381827914 0.03643892566079619 0 +4886 1.378105499221352 0.7063476189036415 0 +4887 1.361771460464886 0.4554612846313676 0 +4888 5.566304770698796 0.4273374247851437 0 +4889 3.009642064972504 0.1387857474333086 0 +4890 8.698328681454033 0.5155298610758491 0 +4891 4.556058093426993 0.07883299525862314 0 +4892 9.418375039013796 0.2814379133147085 0 +4893 9.422611214242352 0.2119894745375899 0 +4894 2.766354238826739 0.8840400421551097 0 +4895 9.536330266652914 0.5409221522860761 0 +4896 0.7699852529796362 0.07654822721820355 0 +4897 6.620660721147272 0.1512063632485465 0 +4898 4.624794307210288 0.0935286749150879 0 +4899 0.4068129148210217 0.6393039404444083 0 +4900 4.385281564644163 0.5423921349582257 0 +4901 4.043412935324118 0.4956328141450798 0 +4902 7.455453950330299 0.5043163841076719 0 +4903 2.344448509387484 0.4957325373701347 0 +4904 0.9270157750131313 0.7711869649262193 0 +4905 6.809509997822771 0.5457133767696628 0 +4906 9.418012148217315 0.03250374890160455 0 +4907 2.242775512711052 0.4675189646341656 0 +4908 7.55655733900447 0.5322253805047429 0 +4909 1.147057858181908 0.376522018847146 0 +4910 6.447819681712516 0.4859646165415705 0 +4911 3.601091271217485 0.7057006468975291 0 +4912 2.651406244127552 0.707766611395918 0 +4913 7.161512518888931 0.9056613368104602 0 +4914 7.856228199146072 0.8944818825860025 0 +4915 1.913358277699443 0.09294017441629188 0 +4916 5.335826937960373 0.463079013920588 0 +4917 6.706869367101418 0.4809620965542865 0 +4918 6.901677286219826 0.5151323312939374 0 +4919 5.83312334642574 0.5286816839733673 0 +4920 5.389535131661986 0.9054288320532333 0 +4921 1.274999999999999 0.9725872689906347 0 +4922 7.349141390204917 0.562695423178993 0 +4923 0.936438409476672 0.8630428280358121 0 +4924 3.539552995139006 0.2305949819564505 0 +4925 9.780981590333562 0.3082836772471135 0 +4926 5.611806520900429 0.5953382079640596 0 +4927 3.166685233212538 0.8285750827781879 0 +4928 5.199757022760909 0.3208120243077531 0 +4929 5.748936611325616 0.3214628133288234 0 +4930 6.849345161268641 0.3221040310891733 0 +4931 1.600323625412281 0.6781133451123342 0 +4932 0.219016564576051 0.6917181183066433 0 +4933 4.174999999999981 0.9726035120911628 0 +4934 0.3441792229821614 0.6183059968888874 0 +4935 3.176765531595396 0.4177085660166982 0 +4936 6.073468684134159 0.5830403409497225 0 +4937 8.977004598169025 0.3613410150046529 0 +4938 2.382280546043566 0.7418072188125513 0 +4939 4.674999999999993 0.972621243386825 0 +4940 9.238910747264431 0.9646228526605166 0 +4941 4.991985205334 0.2344268921548478 0 +4942 6.05798519101533 0.9079068719357836 0 +4943 0.09796345089159246 0.7044552863580082 0 +4944 9.9020365491082 0.2955447136420358 0 +4945 2.254601883389497 0.7464254004264853 0 +4946 7.545026572716722 0.256531390355646 0 +4947 7.986188965134219 0.03941173619485145 0 +4948 3.51099553599507 0.9646125698311201 0 +4949 8.376347489452771 0.4181668583274306 0 +4950 1.994787183345509 0.7568571604682308 0 +4951 7.805839457584861 0.2430450776074641 0 +4952 0.5081032712265571 0.905129134543542 0 +4953 8.875000000000044 0.9726637276538228 0 +4954 2.305629565836286 0.4758813180725373 0 +4955 7.491793814475457 0.52418596451371 0 +4956 0.6940825407783742 0.4813296988549045 0 +4957 3.650062265489323 0.2976965234107388 0 +4958 5.803421919746019 0.4906416545710798 0 +4959 1.859628666335595 0.359498767738413 0 +4960 7.939960184687928 0.6401304044586303 0 +4961 5.899577402652674 0.6456581695326372 0 +4962 5.427856581270168 0.3886965433578823 0 +4963 5.977856581270121 0.3886965433578072 0 +4964 8.174009207144513 0.5906279602173677 0 +4965 3.859162476921221 0.4325050052005567 0 +4966 0.502041670823781 0.7401581131269374 0 +4967 4.795640866277073 0.1785370043078378 0 +4968 2.968663656993805 0.1871144002586992 0 +4969 3.102178563702781 0.783831477417778 0 +4970 6.142550812938693 0.2147144179274401 0 +4971 8.678527786952403 0.8319097689430669 0 +4972 5.712993995955895 0.547974716836488 0 +4973 0.8121777333503446 0.3833735483694203 0 +4974 2.452122291631517 0.1924582429777153 0 +4975 7.347731022855434 0.8073036718875523 0 +4976 5.208132048177646 0.6743315336315159 0 +4977 5.55683022075405 0.3204854905135715 0 +4978 7.488211590534799 0.2436382844079987 0 +4979 1.545086810322259 0.8499923125101638 0 +4980 0.286000593118823 0.917526275936929 0 +4981 6.277965268004735 0.8366017605052366 0 +4982 9.079018657440805 0.8288746967357339 0 +4983 5.158948118101633 0.09955432297560728 0 +4984 9.551537264640622 0.8276606599812748 0 +4985 4.587402767242474 0.3408001380307062 0 +4986 5.217944353964155 0.1299799010727244 0 +4987 1.719150873879207 0.8314241470465663 0 +4988 6.970362184185453 0.1686153801862832 0 +4989 3.934599383116784 0.2305332701290963 0 +4990 5.867965503997623 0.4029171739164807 0 +4991 5.318922910917911 0.3994236019582731 0 +4992 8.333316710237112 0.170709644941206 0 +4993 9.533579615371591 0.2991540262863973 0 +4994 4.826574454629211 0.6628332976687331 0 +4995 9.526204248568794 0.9263704507756966 0 +4996 4.360602144268632 0.03530684979796661 0 +4997 5.39101119685997 0.8142499657948488 0 +4998 9.024999999999906 0.9729324413321699 0 +4999 0.08523218267977557 0.6471934804940178 0 +5000 9.915351281970405 0.3527216822076973 0 +5001 9.35348770601137 0.2232955084769474 0 +5002 1.076386505897599 0.4218725347321231 0 +5003 7.554070382534649 0.6142600396460436 0 +5004 8.389620759963742 0.5992338841014246 0 +5005 8.882170879525827 0.7155617939535442 0 +5006 9.167430890162375 0.2369688674077141 0 +5007 8.676819733190165 0.6449866763572134 0 +5008 8.737680052566478 0.8090807367735879 0 +5009 1.734483950176237 0.5348311575326253 0 +5010 7.066612530195532 0.6192096271602512 0 +5011 3.700972914627622 0.6771791435617565 0 +5012 8.126830270543779 0.3506129539258745 0 +5013 1.034728277304596 0.2420688288142762 0 +5014 2.549763826582018 0.6725114014846114 0 +5015 3.838606918031231 0.9650265853450432 0 +5016 8.097332723412027 0.5311219971379266 0 +5017 3.167945552362387 0.7124919938467092 0 +5018 9.502990674118884 0.431214610843055 0 +5019 2.505459924932421 0.3692578794087729 0 +5020 2.799437806559718 0.6283625124173484 0 +5021 3.442670507932609 0.6284900783545588 0 +5022 3.564616966016494 0.4555524974402896 0 +5023 4.323364821867543 0.7431337476249384 0 +5024 1.900621475546108 0.5637523589340656 0 +5025 7.89987019871354 0.436370809661781 0 +5026 7.149177318440995 0.4362012850219106 0 +5027 1.671028463673349 0.3469757048096125 0 +5028 4.545140215186247 0.9119400097527383 0 +5029 6.0211979185862 0.8059644839930821 0 +5030 3.007372963555934 0.8461010004185463 0 +5031 6.790830406141023 0.1566467144123768 0 +5032 7.186179595207913 0.3719508456852164 0 +5033 1.936750160011605 0.6275728374055283 0 +5034 7.86417341077856 0.369094545090251 0 +5035 5.389891022519242 0.3845128950794559 0 +5036 5.940945793924297 0.3842929490059538 0 +5037 4.882331556600792 0.5698483800232684 0 +5038 7.033986444680864 0.8829283130470753 0 +5039 8.013833590678018 0.8864983549673927 0 +5040 3.615336303215166 0.3617751561203696 0 +5041 4.280494898531989 0.9115227328429886 0 +5042 6.61530581469852 0.5416921966165826 0 +5043 7.865501729577701 0.7829377556058915 0 +5044 1.934498270418502 0.2170622443931871 0 +5045 1.252514322277658 0.9012364632770219 0 +5046 4.698426952325486 0.7626683726635739 0 +5047 0.9815175888878809 0.8113110136477538 0 +5048 4.602839852720088 0.9044479441389083 0 +5049 1.944857730479128 0.1054509516205668 0 +5050 7.889116773711101 0.9071139387381306 0 +5051 2.641006481298221 0.3414301088531597 0 +5052 6.346531144933184 0.4535157351613009 0 +5053 2.90311053962836 0.5474007994085397 0 +5054 1.781073181574998 0.6102219662107154 0 +5055 1.776933792626213 0.6464628836531665 0 +5056 7.029214931599228 0.3483233015996778 0 +5057 9.720319411126896 0.3330207919635402 0 +5058 4.312132611833946 0.07506724350406097 0 +5059 5.686477644488405 0.4250527053549155 0 +5060 2.877087065686221 0.4569131653771451 0 +5061 6.37630087473194 0.538468317394334 0 +5062 9.139912149905983 0.5275274594121878 0 +5063 3.998586592466976 0.137870117758666 0 +5064 1.553561915242183 0.466100273750902 0 +5065 9.538964097342321 0.2030388917619859 0 +5066 4.025076688514195 0.7542855056793694 0 +5067 5.205891964442737 0.5364478835814992 0 +5068 4.014446243422643 0.8250282482071097 0 +5069 8.030486921510128 0.5058852687586728 0 +5070 3.292144633001368 0.5861141173516119 0 +5071 0.8892855811602111 0.6689941673807166 0 +5072 3.330857186998679 0.4963579053041852 0 +5073 5.147475046050633 0.9196184844013197 0 +5074 9.521381811837815 0.5980110179467267 0 +5075 8.760349884910097 0.5234225777890682 0 +5076 1.036238223295099 0.3609090672470726 0 +5077 0.3773881086574299 0.7153991981815198 0 +5078 2.913265362634089 0.4727908525099839 0 +5079 6.343264535308604 0.5241597027312388 0 +5080 0.526112504886467 0.02827495811333659 0 +5081 5.98355500496337 0.5466904983818096 0 +5082 3.661641036302288 0.6806150403366638 0 +5083 2.588358963687779 0.6806150403397075 0 +5084 1.069707736248457 0.5368743679755473 0 +5085 7.686583219828749 0.1622931402849153 0 +5086 2.113770224360409 0.83799305672653 0 +5087 7.674999999996523 0.02668271539108838 0 +5088 2.125000000000003 0.9733172846089809 0 +5089 8.896669193762028 0.4768867773829486 0 +5090 0.07996267091104757 0.5292748390984667 0 +5091 9.920093964950837 0.470725751747682 0 +5092 2.123835938065821 0.03015188450609164 0 +5093 7.676272171161243 0.9703894753743083 0 +5094 3.824999999991495 0.02667046666505109 0 +5095 6.487111698788079 0.3594296790706583 0 +5096 7.244579954587372 0.2443030797458927 0 +5097 4.659350432502298 0.1610982800030445 0 +5098 3.240526650766048 0.4477270868584299 0 +5099 5.428256672786927 0.5402398616901993 0 +5100 2.437618961533495 0.8487082032305537 0 +5101 7.361768767747201 0.1519417417152132 0 +5102 7.334284069891649 0.6973599145636332 0 +5103 1.724500442958651 0.0291101423380686 0 +5104 9.402948610913491 0.5597638255591288 0 +5105 4.505466145359732 0.3185652689194102 0 +5106 1.204998582907555 0.8180702614099112 0 +5107 4.020837462782217 0.9693804172651119 0 +5108 2.141819706310935 0.5273137491777186 0 +5109 7.658180293685843 0.472686250822141 0 +5110 6.692770557906901 0.7815420712974763 0 +5111 3.843357944359224 0.7442026335633241 0 +5112 9.924999999999971 0.02660719903026835 0 +5113 9.924999999999994 0.9733928009697578 0 +5114 2.872890248067743 0.8009853175105183 0 +5115 1.530862752673216 0.3377285484434935 0 +5116 3.873137785846022 0.8581744154668495 0 +5117 0.8150122975113091 0.5826039986389213 0 +5118 8.531482900079574 0.6278872724835322 0 +5119 6.956671660096971 0.8119662885253468 0 +5120 8.079158375247474 0.8404613978171155 0 +5121 5.104025177114029 0.1397928235214676 0 +5122 3.590556806599848 0.7949530825516142 0 +5123 5.469667509892702 0.1869525682048943 0 +5124 9.121188154673114 0.5923306964352847 0 +5125 1.598769896111984 0.5251430450594937 0 +5126 8.932458440590041 0.4200422562740591 0 +5127 9.056026346878626 0.7872794337087351 0 +5128 2.932328131780512 0.4095794532084356 0 +5129 6.309509322452765 0.583986793867205 0 +5130 8.443463458892193 0.2805745954243081 0 +5131 3.314602779153277 0.1954205227228797 0 +5132 4.071673251428791 0.0876733953724068 0 +5133 1.010725976676553 0.9193608245806111 0 +5134 4.514310361293014 0.3566150851886279 0 +5135 3.81403163680098 0.8364259470297799 0 +5136 7.034645010349734 0.1119370155724253 0 +5137 1.772465922930708 0.876609457181777 0 +5138 8.956014102428147 0.4809632320594735 0 +5139 3.933434758701528 0.7423331382268629 0 +5140 4.728070990342903 0.322394018539841 0 +5141 1.722918494594943 0.1627282642237735 0 +5142 1.707731539458873 0.4633005488101288 0 +5143 6.117334120160269 0.4571385435816887 0 +5144 0.8357209929028147 0.08880431751407722 0 +5145 7.37499999999599 0.02639108165422489 0 +5146 2.424999999999998 0.9736089183458889 0 +5147 9.375000000000009 0.9736099213683929 0 +5148 6.931579123122986 0.5348969923302985 0 +5149 4.160793456381274 0.9226636902518691 0 +5150 4.725410153808334 0.1457017133898856 0 +5151 6.677574417239232 0.8553746553797598 0 +5152 3.341860160635542 0.29274585104851 0 +5153 3.841003735490997 0.5273102989973349 0 +5154 0.2271656738223588 0.2993882874371135 0 +5155 3.48011651941587 0.3477808002736435 0 +5156 4.895321019177791 0.0942489887035023 0 +5157 5.094834871527678 0.4947974071464423 0 +5158 1.87992716891943 0.1770104515202601 0 +5159 8.134252897770576 0.7005386470279317 0 +5160 6.915747102229642 0.7005386470278724 0 +5161 8.075000000000074 0.9736579992298716 0 +5162 6.975000000000004 0.9736579992298459 0 +5163 2.824999999994418 0.02634200077004679 0 +5164 9.194208668711259 0.3614762426711436 0 +5165 3.594653231140602 0.2780134004914764 0 +5166 4.610782058488294 0.8576612307378358 0 +5167 1.267384742642544 0.5829168396980664 0 +5168 7.415070914206849 0.2582581302304446 0 +5169 6.661327565221199 0.4663728713350605 0 +5170 3.417617702002348 0.1074948042214244 0 +5171 4.228960129758504 0.03123395161394118 0 +5172 8.60500619622144 0.1940410551676887 0 +5173 8.668238464515779 0.5351747379752234 0 +5174 5.095639239547809 0.9063269037324785 0 +5175 4.678623333423412 0.4303401165750717 0 +5176 1.616440515858496 0.8644765431369098 0 +5177 4.989528734081171 0.5095011479651397 0 +5178 5.845666655144933 0.1449104578842106 0 +5179 5.295670022760569 0.14535192348074 0 +5180 5.844236417657478 0.8552850894942305 0 +5181 6.394598386346391 0.8552979322543786 0 +5182 5.360361039842386 0.5263816533939587 0 +5183 0.2486492723530488 0.2260590495093596 0 +5184 8.309468031268215 0.3544182693201113 0 +5185 7.114997478723927 0.6284080673244236 0 +5186 1.304362363488866 0.662417659000035 0 +5187 1.948516155986011 0.1643693999305753 0 +5188 7.851483844010558 0.8356306000690523 0 +5189 1.957831781034434 0.8115949513301165 0 +5190 3.924999999991198 0.02621122822313044 0 +5191 2.224999999996172 0.02621122822162307 0 +5192 7.575000000000037 0.9737887717783583 0 +5193 4.474882746183972 0.2009782398219984 0 +5194 7.009931690019087 0.5194039617675947 0 +5195 4.007988265472838 0.0962160554108191 0 +5196 9.597021805557297 0.3636122365938417 0 +5197 3.790052360405581 0.5753815879246561 0 +5198 5.570998975806374 0.2406182094621506 0 +5199 1.760416997293524 0.4738530420413424 0 +5200 5.172012886814989 0.848060094127401 0 +5201 3.00685597620827 0.2151986535790349 0 +5202 7.842209030086707 0.1885404571010504 0 +5203 2.894845374114033 0.175753898469175 0 +5204 3.907227997752409 0.9165462410903322 0 +5205 2.228797037370398 0.2507400016850749 0 +5206 7.5715589996673 0.7506009207591532 0 +5207 3.372491461534629 0.3490520533704406 0 +5208 0.2142154337014438 0.03321494994268382 0 +5209 2.466241769297036 0.3019964321319613 0 +5210 5.030022986249199 0.3472900495740348 0 +5211 4.279342938196913 0.5569768784039121 0 +5212 9.473612748691108 0.9089082937184925 0 +5213 2.207159189769983 0.2145521300769999 0 +5214 7.592975758138908 0.785722851345255 0 +5215 2.76882181544205 0.3468746087836488 0 +5216 1.725000000000001 0.9739545471049432 0 +5217 6.974999999995389 0.02604545289498315 0 +5218 2.825000000000005 0.9739545471050822 0 +5219 7.193471495397268 0.8934483274717101 0 +5220 9.704269535639236 0.5526728003463384 0 +5221 8.12081619368867 0.6410339583540789 0 +5222 6.929253938687003 0.64042097808191 0 +5223 2.211941449029532 0.09150631611389798 0 +5224 7.557655866553962 0.9048717009972466 0 +5225 3.910494317629371 0.09112380601355574 0 +5226 0.2980444207061307 0.454372672796132 0 +5227 5.103016629483064 0.2369821150599964 0 +5228 8.844790080044399 0.08419809208670374 0 +5229 1.296527907368538 0.9093723236265833 0 +5230 4.862127653290869 0.4216988945185822 0 +5231 1.873089920072843 0.4005610274335549 0 +5232 7.926892787779284 0.5995076371507594 0 +5233 7.590681598117947 0.0903860346402393 0 +5234 9.289686850172151 0.361095768533833 0 +5235 6.569150101418354 0.1862917314995795 0 +5236 1.036379754899257 0.6492550218237241 0 +5237 3.473373873620266 0.1460469689235405 0 +5238 1.105496547602886 0.3155203593896739 0 +5239 9.402468789541841 0.3175658198817492 0 +5240 4.787373767199693 0.9662790927620195 0 +5241 5.494410118220586 0.9167617633965978 0 +5242 3.521970224175509 0.2652213596375004 0 +5243 6.78971912174846 0.467605759775893 0 +5244 4.229565284310579 0.6953723743418999 0 +5245 2.80023071406287 0.5185258538983722 0 +5246 3.447239058779993 0.518059871432804 0 +5247 0.7531946292480202 0.4215450576262703 0 +5248 2.816837441718559 0.6882805842783039 0 +5249 8.403240143417346 0.5289838726184622 0 +5250 5.017410273266225 0.6605157447738675 0 +5251 4.208083475938393 0.9080729291036117 0 +5252 0.8840315363506294 0.5137413639738051 0 +5253 2.427517528228043 0.02949102435836268 0 +5254 7.372465043314078 0.9705073153108443 0 +5255 2.310128944725139 0.9048513917191376 0 +5256 5.954271766888034 0.833985796501943 0 +5257 6.503736045084825 0.8347680117445443 0 +5258 8.753736045084676 0.1652319882554807 0 +5259 6.506451874609579 0.1635184899335754 0 +5260 5.4065167507804 0.1635873651261336 0 +5261 5.956791398713177 0.165113160597503 0 +5262 8.96173263990578 0.9667121558197515 0 +5263 0.8318480784365742 0.3460106010067318 0 +5264 4.766887531448259 0.1016978649845782 0 +5265 2.225329283125456 0.9711892067108923 0 +5266 7.574999999996329 0.02578029536014626 0 +5267 8.811892945725207 0.4576132132312229 0 +5268 4.677960777888218 0.8270957713199865 0 +5269 0.4870939843485013 0.07972636610488283 0 +5270 9.723075424665897 0.9696147444997938 0 +5271 9.723065555487905 0.03033941778102538 0 +5272 9.303529159136954 0.3226028692822312 0 +5273 0.5043322725205207 0.8313669745546359 0 +5274 8.792771332932316 0.5388090982611549 0 +5275 9.15489509935197 0.3468849355868329 0 +5276 9.502667976463103 0.08939826149626219 0 +5277 1.786211839601848 0.1157153508833774 0 +5278 4.131863741604845 0.4390034220364086 0 +5279 3.741945188545109 0.5149070023849631 0 +5280 2.273760545809536 0.5326113557499518 0 +5281 7.526235240448825 0.4672671438289895 0 +5282 9.16774594065855 0.7554811842428908 0 +5283 3.89091188903795 0.6920029701288669 0 +5284 0.3172900654889783 0.2073145967120385 0 +5285 1.106738926786456 0.6470362742604133 0 +5286 2.310742780361894 0.6873125159055733 0 +5287 0.9939007945647431 0.3118491906055703 0 +5288 0.3919297997619894 0.913181749941136 0 +5289 2.465007136647178 0.3629366120278129 0 +5290 4.858527127463819 0.03476095089209974 0 +5291 7.901570928101811 0.3458134223363263 0 +5292 0.8006464072169169 0.7688557028045225 0 +5293 4.61182341482748 0.5451568058570931 0 +5294 6.657804784715053 0.4307847343076275 0 +5295 6.592565377540988 0.4380809409224458 0 +5296 3.406867245876116 0.7255550563665275 0 +5297 9.23239254143531 0.9021115709138987 0 +5298 2.597352275405785 0.8090414797438999 0 +5299 0.4474051440849159 0.6342917338110365 0 +5300 1.712654159557123 0.3536833908836245 0 +5301 2.893010139121588 0.3437234998803593 0 +5302 6.181158306126851 0.6371055545768843 0 +5303 5.358967377270869 0.7066020978324629 0 +5304 3.479445641376071 0.2575587508025328 0 +5305 0.9972069639119741 0.1867555714894059 0 +5306 9.589284315241539 0.7942322254327916 0 +5307 0.7411036171043515 0.4882471090067912 0 +5308 0.4260857638529251 0.9708842780893991 0 +5309 1.643724739599596 0.5224377782444579 0 +5310 4.659094961831244 0.6518527005782818 0 +5311 1.672609723860475 0.2351197001309341 0 +5312 5.494305788276598 0.39130825564693 0 +5313 8.743012616118799 0.4285641171670878 0 +5314 4.101475839239257 0.5245460079198929 0 +5315 9.229257151362155 0.2007804164667104 0 +5316 0.2877484756000891 0.08076932594327285 0 +5317 4.570251392032454 0.5612632601971547 0 +5318 3.946007370656725 0.3503376908566362 0 +5319 9.641763617569802 0.2450631663031701 0 +5320 6.597509873373237 0.9117543402753163 0 +5321 9.406680173274486 0.1737379290671185 0 +5322 6.594630592093398 0.08190320589707806 0 +5323 1.835614782434062 0.1630579413166721 0 +5324 0.33987509901309 0.9658432144451841 0 +5325 4.92898309555402 0.1219273968080765 0 +5326 8.061779504893247 0.1721886726832319 0 +5327 3.238210509101557 0.1232015246302381 0 +5328 7.693770372582369 0.8472735039823747 0 +5329 2.103886513952175 0.1543048439501196 0 +5330 4.506575382746956 0.7079145978018493 0 +5331 7.153015378398721 0.3631388013192097 0 +5332 1.903015378394879 0.6368611986779734 0 +5333 3.585870843312132 0.6764283943075099 0 +5334 2.664711723945424 0.6768461406555333 0 +5335 2.005579879787091 0.5189419584768377 0 +5336 7.794366362808823 0.4810733747591929 0 +5337 7.257384658949765 0.4806040711548711 0 +5338 5.512029915920369 0.7904793149668614 0 +5339 8.43790955937085 0.7897482309769358 0 +5340 2.339705967850013 0.08720169533622417 0 +5341 7.460294032145667 0.9127983046638701 0 +5342 6.044544591661918 0.08174314068187057 0 +5343 5.494524814910637 0.08169156092813586 0 +5344 0.5700555186088474 0.3402994918135884 0 +5345 7.524785404794978 0.1905118724249263 0 +5346 8.148704695521696 0.1402320984276318 0 +5347 7.857816227110013 0.4863163442672548 0 +5348 1.942183772887103 0.5136836557329877 0 +5349 9.171166351948672 0.7986513053693113 0 +5350 1.777403293888337 0.3072501254095289 0 +5351 8.292564698646663 0.3839770417820347 0 +5352 4.108113585789023 0.1382584095783649 0 +5353 8.498444144386401 0.4669241065314896 0 +5354 5.601498669136422 0.3786075267695184 0 +5355 2.228452891257687 0.1602622709524011 0 +5356 7.571547108738281 0.8397377290476221 0 +5357 3.92845289125875 0.1602622709528048 0 +5358 1.831162211765161 0.2727075096876907 0 +5359 3.961435548959206 0.5981345582047872 0 +5360 3.962071628997936 0.6345246262053852 0 +5361 3.374999999992812 0.0252545613186351 0 +5362 2.324999999999999 0.9747477406511419 0 +5363 7.474999999996172 0.02525225934884498 0 +5364 5.566937852382351 0.6002918616397022 0 +5365 2.643524552042089 0.9138714240364614 0 +5366 0.9727564435243047 0.9719805428959265 0 +5367 6.567629408592817 0.8186793740420168 0 +5368 6.994245767042883 0.5934227296021678 0 +5369 8.050274039146096 0.5918158030008559 0 +5370 0.1434850457250269 0.7312325247833699 0 +5371 9.859315904368501 0.2624130912862179 0 +5372 9.828632127141509 0.7320332406580344 0 +5373 0.1661885659923887 0.2724300478853384 0 +5374 0.7809591987083483 0.1203305515016041 0 +5375 8.331668342488991 0.2850265078935631 0 +5376 1.905456041673904 0.9168080527294421 0 +5377 7.155456041672561 0.08319194727010755 0 +5378 7.971169534305693 0.7249333432935063 0 +5379 6.521559291113391 0.6096447011519952 0 +5380 1.394957565018542 0.5131166017613222 0 +5381 1.357782462606894 0.5255252284659532 0 +5382 4.684929955646268 0.5396176245470022 0 +5383 7.319327067559374 0.2476165954564935 0 +5384 0.9446149733699863 0.4665755848693958 0 +5385 1.294920837685269 0.5545793863570431 0 +5386 4.383388629405832 0.08250581057238336 0 +5387 0.2752005337254705 0.6686535947294937 0 +5388 8.590664362416421 0.7063119304033237 0 +5389 7.079019189701547 0.5426897707228137 0 +5390 2.216570461268943 0.8375618458912103 0 +5391 4.308469760513203 0.4987072374386244 0 +5392 4.749289057398861 0.5188290730471402 0 +5393 7.889060810444306 0.2298929027082631 0 +5394 4.240512608625841 0.4919354338997147 0 +5395 5.317049402593732 0.03104204046133895 0 +5396 5.865181272356719 0.03195412890318961 0 +5397 6.415057162542113 0.03204899066521547 0 +5398 8.665057162543029 0.03204899066568995 0 +5399 6.415104359048979 0.9680857053991614 0 +5400 5.865181272358544 0.9680458710960086 0 +5401 5.420873567214272 0.911621205503603 0 +5402 1.251849152936285 0.503518147917106 0 +5403 6.004779879398498 0.689590137114126 0 +5404 9.076897205644617 0.4047440561315863 0 +5405 1.302886133968276 0.6184187958557862 0 +5406 1.574268230054201 0.7363113154328539 0 +5407 5.431389190964421 0.4358943539280283 0 +5408 9.62359830505191 0.7274441273920709 0 +5409 1.235312833153848 0.1470706380704994 0 +5410 9.650028543102769 0.700088534342628 0 +5411 3.467017368198885 0.9155118982276278 0 +5412 9.106546634721502 0.5576980744714589 0 +5413 3.196248697693924 0.06507240476996952 0 +5414 2.238072752826715 0.5490539537925477 0 +5415 7.561926685338281 0.4509298461510347 0 +5416 3.9384600914276 0.5426347490032941 0 +5417 2.945825331629905 0.442274640615306 0 +5418 9.232154690126857 0.2437627217964675 0 +5419 2.703195875829863 0.2352253446414983 0 +5420 2.718622588313248 0.2667259958442457 0 +$EndNodes +$Elements +10420 +1 15 2 2 1 1 +2 15 2 3 3 3 +3 1 2 1 2 2 205 +4 1 2 1 2 205 206 +5 1 2 1 2 206 207 +6 1 2 1 2 207 208 +7 1 2 1 2 208 3 +8 1 2 1 3 3 209 +9 1 2 1 3 209 210 +10 1 2 1 3 210 211 +11 1 2 1 3 211 212 +12 1 2 1 3 212 213 +13 1 2 1 3 213 214 +14 1 2 1 3 214 215 +15 1 2 1 3 215 216 +16 1 2 1 3 216 217 +17 1 2 1 3 217 218 +18 1 2 1 3 218 219 +19 1 2 1 3 219 220 +20 1 2 1 3 220 221 +21 1 2 1 3 221 222 +22 1 2 1 3 222 4 +23 2 2 4 8 1497 4168 1810 +24 2 2 4 8 747 1810 4168 +25 2 2 4 8 1007 1835 2457 +26 2 2 4 8 660 2077 3009 +27 2 2 4 8 898 1940 2083 +28 2 2 4 8 464 2135 4144 +29 2 2 4 8 927 2073 2047 +30 2 2 4 8 928 2048 2072 +31 2 2 4 8 533 1733 2788 +32 2 2 4 8 1729 1165 3150 +33 2 2 4 8 1166 3149 1728 +34 2 2 4 8 932 1818 2348 +35 2 2 4 8 933 1819 2349 +36 2 2 4 8 633 1938 3061 +37 2 2 4 8 1229 3061 1938 +38 2 2 4 8 634 1939 3062 +39 2 2 4 8 1231 3062 1939 +40 2 2 4 8 95 4275 2251 +41 2 2 4 8 489 2949 2371 +42 2 2 4 8 464 4144 4491 +43 2 2 4 8 1438 3691 1929 +44 2 2 4 8 593 3153 2185 +45 2 2 4 8 594 2186 3154 +46 2 2 4 8 619 2409 1836 +47 2 2 4 8 744 4155 1723 +48 2 2 4 8 23 24 1918 +49 2 2 4 8 822 2900 2046 +50 2 2 4 8 900 3614 1756 +51 2 2 4 8 1055 2851 1669 +52 2 2 4 8 829 3686 2515 +53 2 2 4 8 1272 2912 3035 +54 2 2 4 8 942 2530 1734 +55 2 2 4 8 624 1734 2530 +56 2 2 4 8 839 2280 1964 +57 2 2 4 8 988 1964 2280 +58 2 2 4 8 723 3521 2540 +59 2 2 4 8 725 3522 2541 +60 2 2 4 8 660 3009 2429 +61 2 2 4 8 1137 1680 2454 +62 2 2 4 8 528 2927 1874 +63 2 2 4 8 1167 1874 2927 +64 2 2 4 8 1046 1803 5081 +65 2 2 4 8 931 2355 1817 +66 2 2 4 8 745 2465 1724 +67 2 2 4 8 945 1724 2465 +68 2 2 4 8 1047 1811 5099 +69 2 2 4 8 586 5098 1812 +70 2 2 4 8 1299 1867 3675 +71 2 2 4 8 1172 2317 1914 +72 2 2 4 8 869 1914 2317 +73 2 2 4 8 1662 4449 967 +74 2 2 4 8 914 2416 2175 +75 2 2 4 8 465 2529 1889 +76 2 2 4 8 652 1723 2644 +77 2 2 4 8 549 1859 2169 +78 2 2 4 8 550 1860 2170 +79 2 2 4 8 548 1858 2171 +80 2 2 4 8 638 3503 2783 +81 2 2 4 8 637 2782 3502 +82 2 2 4 8 606 4259 2235 +83 2 2 4 8 4226 2235 4259 +84 2 2 4 8 1798 4795 4778 +85 2 2 4 8 1799 4796 4779 +86 2 2 4 8 794 3040 1918 +87 2 2 4 8 1220 1918 3040 +88 2 2 4 8 1439 2383 2741 +89 2 2 4 8 962 2741 2383 +90 2 2 4 8 1783 2282 4579 +91 2 2 4 8 888 2264 1926 +92 2 2 4 8 1224 1926 2264 +93 2 2 4 8 685 1865 3859 +94 2 2 4 8 486 3119 2273 +95 2 2 4 8 2086 977 2269 +96 2 2 4 8 2086 2269 1051 +97 2 2 4 8 2740 1337 2886 +98 2 2 4 8 470 3301 3180 +99 2 2 4 8 481 3179 3300 +100 2 2 4 8 2431 4497 3894 +101 2 2 4 8 1624 2893 1122 +102 2 2 4 8 1834 4753 4614 +103 2 2 4 8 1257 2631 2506 +104 2 2 4 8 1169 2506 2631 +105 2 2 4 8 1624 1122 3442 +106 2 2 4 8 1021 3089 3480 +107 2 2 4 8 866 2486 2485 +108 2 2 4 8 1315 2485 2486 +109 2 2 4 8 482 3516 3672 +110 2 2 4 8 484 3517 3673 +111 2 2 4 8 924 4559 1726 +112 2 2 4 8 925 1727 4560 +113 2 2 4 8 934 1820 2368 +114 2 2 4 8 935 1821 2369 +115 2 2 4 8 1586 3156 4550 +116 2 2 4 8 1341 2181 2660 +117 2 2 4 8 648 2660 2181 +118 2 2 4 8 1342 2180 2659 +119 2 2 4 8 650 2659 2180 +120 2 2 4 8 560 1965 2400 +121 2 2 4 8 1180 2565 2548 +122 2 2 4 8 1140 2199 2533 +123 2 2 4 8 1033 2533 2199 +124 2 2 4 8 1031 2532 2200 +125 2 2 4 8 1139 2200 2532 +126 2 2 4 8 1138 2201 2531 +127 2 2 4 8 1032 2531 2201 +128 2 2 4 8 1497 1810 2587 +129 2 2 4 8 566 2355 1743 +130 2 2 4 8 421 2068 3465 +131 2 2 4 8 1431 1744 2961 +132 2 2 4 8 557 2406 1959 +133 2 2 4 8 1231 1939 4975 +134 2 2 4 8 1229 1938 4974 +135 2 2 4 8 616 5175 3209 +136 2 2 4 8 2273 3119 4033 +137 2 2 4 8 463 4579 2282 +138 2 2 4 8 470 2445 3301 +139 2 2 4 8 481 3300 2444 +140 2 2 4 8 2567 3807 5205 +141 2 2 4 8 2568 3808 5206 +142 2 2 4 8 1798 2190 4795 +143 2 2 4 8 1799 2191 4796 +144 2 2 4 8 768 1752 3344 +145 2 2 4 8 769 3345 1753 +146 2 2 4 8 681 2434 3265 +147 2 2 4 8 2509 4505 4022 +148 2 2 4 8 1079 1653 2624 +149 2 2 4 8 465 2020 2529 +150 2 2 4 8 543 2097 2119 +151 2 2 4 8 2097 978 2119 +152 2 2 4 8 2515 3686 1579 +153 2 2 4 8 1834 4614 2557 +154 2 2 4 8 2918 4184 3371 +155 2 2 4 8 614 2003 3529 +156 2 2 4 8 496 3708 1750 +157 2 2 4 8 1276 1750 3708 +158 2 2 4 8 2652 4760 3442 +159 2 2 4 8 1218 2319 2645 +160 2 2 4 8 622 2645 2319 +161 2 2 4 8 1219 2646 2320 +162 2 2 4 8 623 2320 2646 +163 2 2 4 8 528 1874 3229 +164 2 2 4 8 993 2652 2992 +165 2 2 4 8 1257 1786 3458 +166 2 2 4 8 757 3458 1786 +167 2 2 4 8 925 5248 1948 +168 2 2 4 8 1073 1947 3374 +169 2 2 4 8 1287 3374 1947 +170 2 2 4 8 549 2214 1859 +171 2 2 4 8 550 2215 1860 +172 2 2 4 8 924 2072 2048 +173 2 2 4 8 925 2047 2073 +174 2 2 4 8 842 1658 2633 +175 2 2 4 8 2371 2949 3843 +176 2 2 4 8 1276 3911 1750 +177 2 2 4 8 736 1647 4499 +178 2 2 4 8 734 4500 1648 +179 2 2 4 8 621 1930 2363 +180 2 2 4 8 1036 3703 2968 +181 2 2 4 8 548 2219 1858 +182 2 2 4 8 593 2864 3153 +183 2 2 4 8 594 3154 2863 +184 2 2 4 8 35 36 1880 +185 2 2 4 8 924 1797 4863 +186 2 2 4 8 1316 3807 2567 +187 2 2 4 8 1317 3808 2568 +188 2 2 4 8 51 52 2012 +189 2 2 4 8 272 273 2013 +190 2 2 4 8 1104 4297 1768 +191 2 2 4 8 1105 4296 1769 +192 2 2 4 8 444 2191 2504 +193 2 2 4 8 453 2190 2505 +194 2 2 4 8 736 3021 1647 +195 2 2 4 8 1385 3859 1865 +196 2 2 4 8 943 2509 4022 +197 2 2 4 8 1318 2918 3371 +198 2 2 4 8 599 2553 2157 +199 2 2 4 8 920 3634 1763 +200 2 2 4 8 604 3723 2022 +201 2 2 4 8 839 1807 2280 +202 2 2 4 8 2279 3403 4436 +203 2 2 4 8 1060 2999 3119 +204 2 2 4 8 582 5129 4441 +205 2 2 4 8 570 1768 2348 +206 2 2 4 8 572 1769 2349 +207 2 2 4 8 573 1765 2368 +208 2 2 4 8 574 1764 2369 +209 2 2 4 8 725 2541 4303 +210 2 2 4 8 723 2540 4304 +211 2 2 4 8 946 2464 1764 +212 2 2 4 8 2102 2400 915 +213 2 2 4 8 1078 2257 2224 +214 2 2 4 8 1077 2223 2256 +215 2 2 4 8 915 2256 2223 +216 2 2 4 8 918 2224 2257 +217 2 2 4 8 1099 1743 4229 +218 2 2 4 8 2085 1131 4258 +219 2 2 4 8 869 3216 1914 +220 2 2 4 8 870 3217 1915 +221 2 2 4 8 647 2652 3442 +222 2 2 4 8 2139 4219 3362 +223 2 2 4 8 2140 4221 3363 +224 2 2 4 8 1198 2240 2665 +225 2 2 4 8 829 2665 2240 +226 2 2 4 8 1702 2520 890 +227 2 2 4 8 2003 3482 3529 +228 2 2 4 8 925 2073 5248 +229 2 2 4 8 1384 1947 3857 +230 2 2 4 8 1188 3314 1735 +231 2 2 4 8 1796 3643 4469 +232 2 2 4 8 1975 3209 5175 +233 2 2 4 8 687 1850 3860 +234 2 2 4 8 1850 1387 3860 +235 2 2 4 8 1479 2603 3071 +236 2 2 4 8 705 3071 2603 +237 2 2 4 8 872 3491 2010 +238 2 2 4 8 690 1937 2615 +239 2 2 4 8 1889 2529 4280 +240 2 2 4 8 949 2593 2399 +241 2 2 4 8 620 1927 2354 +242 2 2 4 8 1248 2395 2225 +243 2 2 4 8 843 1951 4539 +244 2 2 4 8 844 1952 4540 +245 2 2 4 8 531 4219 2139 +246 2 2 4 8 532 4221 2140 +247 2 2 4 8 686 1846 2476 +248 2 2 4 8 653 1724 2616 +249 2 2 4 8 1039 1842 2272 +250 2 2 4 8 918 2262 2669 +251 2 2 4 8 994 2634 1748 +252 2 2 4 8 995 2635 1749 +253 2 2 4 8 744 1791 4155 +254 2 2 4 8 980 1713 3432 +255 2 2 4 8 1674 1126 2608 +256 2 2 4 8 533 2559 1733 +257 2 2 4 8 1047 5099 2153 +258 2 2 4 8 586 2154 5098 +259 2 2 4 8 1567 3829 1921 +260 2 2 4 8 754 1785 3309 +261 2 2 4 8 1012 2010 3888 +262 2 2 4 8 1136 2848 1903 +263 2 2 4 8 632 1903 2848 +264 2 2 4 8 627 1960 2697 +265 2 2 4 8 1112 2697 1960 +266 2 2 4 8 1734 4046 2387 +267 2 2 4 8 864 2387 4046 +268 2 2 4 8 1046 5081 2152 +269 2 2 4 8 877 1892 3248 +270 2 2 4 8 1011 2401 2188 +271 2 2 4 8 1110 2188 2401 +272 2 2 4 8 825 1858 4158 +273 2 2 4 8 671 2985 4149 +274 2 2 4 8 672 2984 4148 +275 2 2 4 8 3039 595 3296 +276 2 2 4 8 639 4312 1794 +277 2 2 4 8 583 2137 3548 +278 2 2 4 8 629 2539 3370 +279 2 2 4 8 78 3598 1694 +280 2 2 4 8 1702 890 3234 +281 2 2 4 8 883 2288 3287 +282 2 2 4 8 884 2289 3288 +283 2 2 4 8 1351 3504 2432 +284 2 2 4 8 825 1877 3750 +285 2 2 4 8 914 3403 2279 +286 2 2 4 8 2095 989 2468 +287 2 2 4 8 2095 2468 1196 +288 2 2 4 8 870 2409 1967 +289 2 2 4 8 1209 1967 2409 +290 2 2 4 8 1951 2688 4539 +291 2 2 4 8 1952 2689 4540 +292 2 2 4 8 870 1967 3217 +293 2 2 4 8 1343 2774 2658 +294 2 2 4 8 981 2658 2774 +295 2 2 4 8 1342 2659 2773 +296 2 2 4 8 982 2773 2659 +297 2 2 4 8 983 2772 2660 +298 2 2 4 8 1341 2660 2772 +299 2 2 4 8 1166 2736 2253 +300 2 2 4 8 1331 2706 2037 +301 2 2 4 8 1332 2707 2038 +302 2 2 4 8 861 2480 1899 +303 2 2 4 8 862 1898 2479 +304 2 2 4 8 642 3716 1766 +305 2 2 4 8 730 2803 3671 +306 2 2 4 8 34 1637 3032 +307 2 2 4 8 1048 2367 1962 +308 2 2 4 8 1135 1962 2367 +309 2 2 4 8 945 2616 1724 +310 2 2 4 8 2432 3504 4330 +311 2 2 4 8 762 4180 2019 +312 2 2 4 8 1582 2019 4180 +313 2 2 4 8 1394 2004 2634 +314 2 2 4 8 1395 2005 2635 +315 2 2 4 8 600 2156 3377 +316 2 2 4 8 1048 2174 2175 +317 2 2 4 8 914 2175 2174 +318 2 2 4 8 1710 4471 3215 +319 2 2 4 8 616 2431 3894 +320 2 2 4 8 825 4124 1858 +321 2 2 4 8 947 2428 1765 +322 2 2 4 8 2336 5129 582 +323 2 2 4 8 798 2292 2022 +324 2 2 4 8 94 95 2251 +325 2 2 4 8 595 2583 3296 +326 2 2 4 8 1211 1869 3346 +327 2 2 4 8 646 2193 3002 +328 2 2 4 8 1263 3002 2193 +329 2 2 4 8 1123 2000 2393 +330 2 2 4 8 1060 2393 2000 +331 2 2 4 8 900 3958 1754 +332 2 2 4 8 1288 2429 3009 +333 2 2 4 8 638 2579 3503 +334 2 2 4 8 637 3502 2578 +335 2 2 4 8 907 3615 2971 +336 2 2 4 8 34 4231 1637 +337 2 2 4 8 629 3370 2907 +338 2 2 4 8 900 1756 3958 +339 2 2 4 8 880 2029 3951 +340 2 2 4 8 881 2030 3950 +341 2 2 4 8 911 2032 2374 +342 2 2 4 8 912 2373 2031 +343 2 2 4 8 1675 2971 3615 +344 2 2 4 8 731 2804 3691 +345 2 2 4 8 563 2740 2886 +346 2 2 4 8 497 3942 1808 +347 2 2 4 8 930 2427 1816 +348 2 2 4 8 459 1922 3168 +349 2 2 4 8 1238 3168 1922 +350 2 2 4 8 665 3635 3139 +351 2 2 4 8 875 3133 2049 +352 2 2 4 8 842 3350 1658 +353 2 2 4 8 1165 2663 2252 +354 2 2 4 8 78 1694 3101 +355 2 2 4 8 1311 2211 3399 +356 2 2 4 8 1310 2210 3398 +357 2 2 4 8 1312 3400 2209 +358 2 2 4 8 668 3256 2164 +359 2 2 4 8 1027 2563 2550 +360 2 2 4 8 1228 2550 2563 +361 2 2 4 8 1414 2525 3749 +362 2 2 4 8 583 3548 2257 +363 2 2 4 8 869 2317 1835 +364 2 2 4 8 748 3304 1777 +365 2 2 4 8 750 3306 1778 +366 2 2 4 8 477 1913 3513 +367 2 2 4 8 1299 3939 1867 +368 2 2 4 8 596 1872 2457 +369 2 2 4 8 598 1873 2458 +370 2 2 4 8 759 1780 2417 +371 2 2 4 8 2461 3851 4176 +372 2 2 4 8 1091 4190 1765 +373 2 2 4 8 1092 4189 1764 +374 2 2 4 8 731 3637 2804 +375 2 2 4 8 730 3638 2803 +376 2 2 4 8 653 3778 1724 +377 2 2 4 8 420 421 3465 +378 2 2 4 8 612 1642 2937 +379 2 2 4 8 611 1643 2936 +380 2 2 4 8 872 3237 3491 +381 2 2 4 8 968 2247 2152 +382 2 2 4 8 1047 2153 2248 +383 2 2 4 8 969 2248 2153 +384 2 2 4 8 1046 2152 2247 +385 2 2 4 8 1045 2154 2246 +386 2 2 4 8 967 2246 2154 +387 2 2 4 8 1056 3105 2890 +388 2 2 4 8 611 3472 1643 +389 2 2 4 8 652 3777 1723 +390 2 2 4 8 612 3067 1642 +391 2 2 4 8 1542 3840 1977 +392 2 2 4 8 1543 3841 1976 +393 2 2 4 8 1110 2035 2545 +394 2 2 4 8 1042 5046 1826 +395 2 2 4 8 781 2849 3597 +396 2 2 4 8 734 1648 2943 +397 2 2 4 8 753 1722 2574 +398 2 2 4 8 923 2786 1981 +399 2 2 4 8 737 3786 4942 +400 2 2 4 8 1113 4673 1751 +401 2 2 4 8 1438 4088 3691 +402 2 2 4 8 492 2053 3707 +403 2 2 4 8 482 3672 2449 +404 2 2 4 8 484 3673 2450 +405 2 2 4 8 35 1880 4231 +406 2 2 4 8 958 2238 2745 +407 2 2 4 8 908 3600 2972 +408 2 2 4 8 906 1922 2360 +409 2 2 4 8 460 2361 1924 +410 2 2 4 8 461 2362 1923 +411 2 2 4 8 525 3675 1867 +412 2 2 4 8 1023 3947 1784 +413 2 2 4 8 901 5385 2062 +414 2 2 4 8 1579 3686 3889 +415 2 2 4 8 688 1936 3456 +416 2 2 4 8 1292 3456 1936 +417 2 2 4 8 2062 5385 1979 +418 2 2 4 8 760 4469 3643 +419 2 2 4 8 1207 1652 5121 +420 2 2 4 8 1082 2952 2842 +421 2 2 4 8 1079 2887 1653 +422 2 2 4 8 1296 2129 2353 +423 2 2 4 8 535 1757 2944 +424 2 2 4 8 998 2189 2221 +425 2 2 4 8 1042 2221 2189 +426 2 2 4 8 1024 1777 5203 +427 2 2 4 8 684 3857 1947 +428 2 2 4 8 4206 3247 4702 +429 2 2 4 8 1160 2304 1934 +430 2 2 4 8 1161 1933 2305 +431 2 2 4 8 1774 3247 4206 +432 2 2 4 8 910 5142 2036 +433 2 2 4 8 1781 4550 3156 +434 2 2 4 8 1207 3036 1652 +435 2 2 4 8 698 3634 4597 +436 2 2 4 8 1048 1962 4961 +437 2 2 4 8 1130 2724 2045 +438 2 2 4 8 651 2045 2724 +439 2 2 4 8 971 1743 2544 +440 2 2 4 8 724 3746 4501 +441 2 2 4 8 1251 2739 1679 +442 2 2 4 8 1617 4700 2613 +443 2 2 4 8 851 1932 2273 +444 2 2 4 8 1664 2972 3600 +445 2 2 4 8 895 2044 5045 +446 2 2 4 8 968 2548 2565 +447 2 2 4 8 466 2294 1935 +448 2 2 4 8 626 3143 2089 +449 2 2 4 8 653 2341 3778 +450 2 2 4 8 1221 2595 1994 +451 2 2 4 8 2062 1979 5402 +452 2 2 4 8 2022 3723 4602 +453 2 2 4 8 2107 3026 3369 +454 2 2 4 8 877 3248 2012 +455 2 2 4 8 878 3249 2013 +456 2 2 4 8 942 1822 2473 +457 2 2 4 8 349 3185 1736 +458 2 2 4 8 162 3184 1735 +459 2 2 4 8 982 1671 3170 +460 2 2 4 8 983 1672 3171 +461 2 2 4 8 996 1791 2682 +462 2 2 4 8 771 2931 3668 +463 2 2 4 8 2172 3161 4387 +464 2 2 4 8 2036 5142 2380 +465 2 2 4 8 920 1763 4004 +466 2 2 4 8 884 3288 4944 +467 2 2 4 8 883 3287 4943 +468 2 2 4 8 1055 1669 2953 +469 2 2 4 8 2077 3666 3009 +470 2 2 4 8 1145 1770 4580 +471 2 2 4 8 1144 1771 4581 +472 2 2 4 8 1024 2487 2816 +473 2 2 4 8 1272 2816 2487 +474 2 2 4 8 888 1926 3970 +475 2 2 4 8 2083 639 3969 +476 2 2 4 8 448 1831 2627 +477 2 2 4 8 1000 2244 2302 +478 2 2 4 8 1078 2302 2244 +479 2 2 4 8 999 2301 2243 +480 2 2 4 8 1077 2243 2301 +481 2 2 4 8 1001 2303 2245 +482 2 2 4 8 1076 2245 2303 +483 2 2 4 8 944 1783 4579 +484 2 2 4 8 469 5020 1944 +485 2 2 4 8 468 1945 5021 +486 2 2 4 8 1037 2494 1773 +487 2 2 4 8 1038 2495 1772 +488 2 2 4 8 924 4863 2072 +489 2 2 4 8 1696 3668 2931 +490 2 2 4 8 482 2324 1973 +491 2 2 4 8 951 1973 2324 +492 2 2 4 8 950 1972 2325 +493 2 2 4 8 484 2325 1972 +494 2 2 4 8 1617 4292 3849 +495 2 2 4 8 443 3038 1754 +496 2 2 4 8 963 2830 2467 +497 2 2 4 8 965 2466 2829 +498 2 2 4 8 821 2909 3654 +499 2 2 4 8 744 1723 3781 +500 2 2 4 8 1012 3888 4480 +501 2 2 4 8 499 3822 3990 +502 2 2 4 8 501 3823 3991 +503 2 2 4 8 1273 2220 2446 +504 2 2 4 8 615 2446 2220 +505 2 2 4 8 794 4746 1766 +506 2 2 4 8 476 2318 2903 +507 2 2 4 8 1036 2699 3703 +508 2 2 4 8 855 4338 2577 +509 2 2 4 8 1159 4993 1665 +510 2 2 4 8 903 2001 4346 +511 2 2 4 8 905 3851 2461 +512 2 2 4 8 2107 1116 3026 +513 2 2 4 8 1248 3224 2395 +514 2 2 4 8 902 2614 1969 +515 2 2 4 8 588 2198 2044 +516 2 2 4 8 2341 3390 3778 +517 2 2 4 8 1662 967 3226 +518 2 2 4 8 215 2037 2925 +519 2 2 4 8 433 2038 2926 +520 2 2 4 8 1113 2222 3655 +521 2 2 4 8 805 4360 1887 +522 2 2 4 8 806 4361 1888 +523 2 2 4 8 1026 1779 5120 +524 2 2 4 8 750 1778 5119 +525 2 2 4 8 745 1724 3783 +526 2 2 4 8 922 1935 2294 +527 2 2 4 8 2044 2198 5045 +528 2 2 4 8 84 2600 5190 +529 2 2 4 8 1617 2613 4292 +530 2 2 4 8 1154 2399 2593 +531 2 2 4 8 202 3129 1933 +532 2 2 4 8 225 1934 3130 +533 2 2 4 8 616 3209 2431 +534 2 2 4 8 1010 1790 5141 +535 2 2 4 8 737 2910 3786 +536 2 2 4 8 694 2987 2346 +537 2 2 4 8 1279 2346 2987 +538 2 2 4 8 991 1934 2304 +539 2 2 4 8 990 2305 1933 +540 2 2 4 8 952 1866 4706 +541 2 2 4 8 923 1981 3592 +542 2 2 4 8 1203 3162 2543 +543 2 2 4 8 1205 3166 2542 +544 2 2 4 8 636 1891 2618 +545 2 2 4 8 1050 2618 1891 +546 2 2 4 8 1159 1665 3932 +547 2 2 4 8 1902 3344 3447 +548 2 2 4 8 603 1785 5114 +549 2 2 4 8 1010 4280 2529 +550 2 2 4 8 600 3377 2565 +551 2 2 4 8 976 1863 2521 +552 2 2 4 8 605 3721 2051 +553 2 2 4 8 658 1841 5118 +554 2 2 4 8 869 5255 3216 +555 2 2 4 8 544 2628 2387 +556 2 2 4 8 449 2306 4759 +557 2 2 4 8 2306 4720 4759 +558 2 2 4 8 472 2479 1898 +559 2 2 4 8 474 1899 2480 +560 2 2 4 8 972 2538 1768 +561 2 2 4 8 974 2539 1769 +562 2 2 4 8 1129 1739 4208 +563 2 2 4 8 676 2750 2065 +564 2 2 4 8 1784 2577 4338 +565 2 2 4 8 879 5225 1893 +566 2 2 4 8 1149 1894 5224 +567 2 2 4 8 877 5223 1892 +568 2 2 4 8 561 2426 1964 +569 2 2 4 8 1354 2486 3729 +570 2 2 4 8 499 3990 2560 +571 2 2 4 8 501 3991 2561 +572 2 2 4 8 1294 3849 4292 +573 2 2 4 8 497 1931 3942 +574 2 2 4 8 2053 3975 3707 +575 2 2 4 8 768 2923 2100 +576 2 2 4 8 769 2099 2922 +577 2 2 4 8 2099 1364 2922 +578 2 2 4 8 2100 2923 1365 +579 2 2 4 8 982 4011 1671 +580 2 2 4 8 983 4012 1672 +581 2 2 4 8 2145 2763 979 +582 2 2 4 8 52 3478 2012 +583 2 2 4 8 273 3479 2013 +584 2 2 4 8 1567 4897 3829 +585 2 2 4 8 671 4149 2706 +586 2 2 4 8 672 4148 2707 +587 2 2 4 8 2211 4270 3399 +588 2 2 4 8 2210 4269 3398 +589 2 2 4 8 2209 3400 4271 +590 2 2 4 8 1723 4155 2644 +591 2 2 4 8 1261 2686 2576 +592 2 2 4 8 1002 2576 2686 +593 2 2 4 8 688 2656 1936 +594 2 2 4 8 1431 2961 3471 +595 2 2 4 8 880 3951 2494 +596 2 2 4 8 881 3950 2495 +597 2 2 4 8 565 2527 1881 +598 2 2 4 8 1881 2527 999 +599 2 2 4 8 585 2933 2514 +600 2 2 4 8 1136 1903 2922 +601 2 2 4 8 769 2922 1903 +602 2 2 4 8 768 1902 2923 +603 2 2 4 8 1137 2923 1902 +604 2 2 4 8 2003 1201 2266 +605 2 2 4 8 2501 3667 3984 +606 2 2 4 8 807 3913 1992 +607 2 2 4 8 1449 1992 3913 +608 2 2 4 8 808 3912 1993 +609 2 2 4 8 1448 1993 3912 +610 2 2 4 8 888 2872 1928 +611 2 2 4 8 611 2503 3219 +612 2 2 4 8 1259 4614 4753 +613 2 2 4 8 1494 3480 3089 +614 2 2 4 8 900 3920 3614 +615 2 2 4 8 914 4919 2416 +616 2 2 4 8 1031 2588 2645 +617 2 2 4 8 1185 2530 2473 +618 2 2 4 8 942 2473 2530 +619 2 2 4 8 469 2878 1954 +620 2 2 4 8 669 2407 3159 +621 2 2 4 8 1380 3159 2407 +622 2 2 4 8 670 2408 3160 +623 2 2 4 8 1381 3160 2408 +624 2 2 4 8 928 4654 1863 +625 2 2 4 8 927 1864 4655 +626 2 2 4 8 674 2751 1798 +627 2 2 4 8 673 2752 1799 +628 2 2 4 8 3065 2297 4116 +629 2 2 4 8 535 3917 1757 +630 2 2 4 8 475 3403 2174 +631 2 2 4 8 444 1839 2507 +632 2 2 4 8 453 1840 2508 +633 2 2 4 8 951 2316 1958 +634 2 2 4 8 1735 3314 3981 +635 2 2 4 8 848 2788 1733 +636 2 2 4 8 867 3740 2410 +637 2 2 4 8 1589 2410 3740 +638 2 2 4 8 458 3228 2517 +639 2 2 4 8 1455 2517 3228 +640 2 2 4 8 469 2073 5020 +641 2 2 4 8 468 5021 2072 +642 2 2 4 8 2745 2238 4511 +643 2 2 4 8 741 2827 3829 +644 2 2 4 8 743 2828 3828 +645 2 2 4 8 1255 3161 2172 +646 2 2 4 8 917 2790 1917 +647 2 2 4 8 1111 1917 2790 +648 2 2 4 8 934 2312 3028 +649 2 2 4 8 935 2313 3027 +650 2 2 4 8 2052 3530 3570 +651 2 2 4 8 767 1873 2542 +652 2 2 4 8 1205 2542 1873 +653 2 2 4 8 766 1872 2543 +654 2 2 4 8 1203 2543 1872 +655 2 2 4 8 777 3567 1741 +656 2 2 4 8 778 3566 1742 +657 2 2 4 8 2392 4061 3416 +658 2 2 4 8 635 3063 2116 +659 2 2 4 8 907 2114 3061 +660 2 2 4 8 908 2115 3062 +661 2 2 4 8 552 3920 2027 +662 2 2 4 8 927 1942 4809 +663 2 2 4 8 832 1943 4808 +664 2 2 4 8 1674 3223 1126 +665 2 2 4 8 832 4808 1945 +666 2 2 4 8 1354 3763 2486 +667 2 2 4 8 1251 1679 3293 +668 2 2 4 8 1232 2354 1925 +669 2 2 4 8 887 1925 2354 +670 2 2 4 8 2825 3840 740 +671 2 2 4 8 742 2826 3841 +672 2 2 4 8 738 2824 3839 +673 2 2 4 8 1173 3231 1856 +674 2 2 4 8 1172 3230 1857 +675 2 2 4 8 835 1687 2899 +676 2 2 4 8 915 2223 4289 +677 2 2 4 8 1285 2950 1677 +678 2 2 4 8 887 2354 1927 +679 2 2 4 8 4206 4702 1455 +680 2 2 4 8 1137 3294 1680 +681 2 2 4 8 1331 4228 2706 +682 2 2 4 8 1170 3447 3344 +683 2 2 4 8 1094 5215 2165 +684 2 2 4 8 1858 2219 4158 +685 2 2 4 8 2543 3162 4145 +686 2 2 4 8 2542 3166 4146 +687 2 2 4 8 559 4910 2316 +688 2 2 4 8 1958 2316 4910 +689 2 2 4 8 952 4706 1959 +690 2 2 4 8 978 2775 2119 +691 2 2 4 8 1274 1740 3776 +692 2 2 4 8 2165 5215 2294 +693 2 2 4 8 778 3092 1907 +694 2 2 4 8 1193 1907 3092 +695 2 2 4 8 777 3091 1908 +696 2 2 4 8 1192 1908 3091 +697 2 2 4 8 2825 740 3789 +698 2 2 4 8 742 3790 2826 +699 2 2 4 8 741 3788 2827 +700 2 2 4 8 762 2019 5168 +701 2 2 4 8 459 2360 1922 +702 2 2 4 8 908 1923 2362 +703 2 2 4 8 907 1924 2361 +704 2 2 4 8 832 2947 1685 +705 2 2 4 8 996 4155 1791 +706 2 2 4 8 467 5152 1848 +707 2 2 4 8 346 2839 1916 +708 2 2 4 8 958 2358 1982 +709 2 2 4 8 625 1982 2358 +710 2 2 4 8 902 5167 2061 +711 2 2 4 8 870 1915 5233 +712 2 2 4 8 830 1683 5053 +713 2 2 4 8 834 1688 5052 +714 2 2 4 8 23 1918 3343 +715 2 2 4 8 498 3625 3471 +716 2 2 4 8 98 2120 97 +717 2 2 4 8 1148 1824 3122 +718 2 2 4 8 1149 1825 3123 +719 2 2 4 8 1147 1823 3121 +720 2 2 4 8 1213 2234 3142 +721 2 2 4 8 1215 2235 3141 +722 2 2 4 8 1217 2236 3140 +723 2 2 4 8 570 1718 2930 +724 2 2 4 8 3513 1913 4407 +725 2 2 4 8 1285 1677 3181 +726 2 2 4 8 1183 2297 3065 +727 2 2 4 8 1013 1740 2980 +728 2 2 4 8 996 2644 4155 +729 2 2 4 8 927 5020 2073 +730 2 2 4 8 928 2072 5021 +731 2 2 4 8 448 2481 1831 +732 2 2 4 8 1092 1764 4344 +733 2 2 4 8 1095 2166 5155 +734 2 2 4 8 1415 3119 2999 +735 2 2 4 8 491 3128 2129 +736 2 2 4 8 898 3748 1940 +737 2 2 4 8 903 4346 4031 +738 2 2 4 8 639 2596 3969 +739 2 2 4 8 218 2290 2647 +740 2 2 4 8 436 2291 2648 +741 2 2 4 8 940 2239 2734 +742 2 2 4 8 925 4560 2047 +743 2 2 4 8 924 2048 4559 +744 2 2 4 8 487 4867 3682 +745 2 2 4 8 1796 4216 3643 +746 2 2 4 8 1207 2022 2292 +747 2 2 4 8 1007 2477 1835 +748 2 2 4 8 607 3530 2052 +749 2 2 4 8 451 1957 2703 +750 2 2 4 8 709 2283 3290 +751 2 2 4 8 2223 2594 4289 +752 2 2 4 8 668 3935 3256 +753 2 2 4 8 191 2275 3338 +754 2 2 4 8 2166 2287 5155 +755 2 2 4 8 626 2331 3143 +756 2 2 4 8 425 2288 3588 +757 2 2 4 8 208 2289 3589 +758 2 2 4 8 219 3590 2290 +759 2 2 4 8 437 3591 2291 +760 2 2 4 8 644 5405 3850 +761 2 2 4 8 1319 3212 1993 +762 2 2 4 8 1320 3213 1992 +763 2 2 4 8 1113 3655 2743 +764 2 2 4 8 97 2120 2692 +765 2 2 4 8 973 4487 4356 +766 2 2 4 8 488 2087 2852 +767 2 2 4 8 2087 1174 2852 +768 2 2 4 8 607 2146 3382 +769 2 2 4 8 690 3541 1937 +770 2 2 4 8 1293 1937 3541 +771 2 2 4 8 1091 1765 4187 +772 2 2 4 8 937 3494 2344 +773 2 2 4 8 936 2343 3493 +774 2 2 4 8 737 4942 2877 +775 2 2 4 8 1425 3664 2485 +776 2 2 4 8 689 2672 1971 +777 2 2 4 8 2019 2575 5168 +778 2 2 4 8 834 3585 1688 +779 2 2 4 8 973 2470 4487 +780 2 2 4 8 308 309 2230 +781 2 2 4 8 298 2229 297 +782 2 2 4 8 175 2228 174 +783 2 2 4 8 130 2227 129 +784 2 2 4 8 118 119 2226 +785 2 2 4 8 835 4073 1687 +786 2 2 4 8 830 3873 1683 +787 2 2 4 8 832 1685 3874 +788 2 2 4 8 2991 3647 4652 +789 2 2 4 8 902 2061 2614 +790 2 2 4 8 2083 4312 639 +791 2 2 4 8 651 2724 2023 +792 2 2 4 8 957 2381 2907 +793 2 2 4 8 1178 1970 2589 +794 2 2 4 8 920 1877 4158 +795 2 2 4 8 927 4655 1942 +796 2 2 4 8 962 4798 2196 +797 2 2 4 8 1104 2352 2325 +798 2 2 4 8 950 2325 2352 +799 2 2 4 8 2262 4629 2669 +800 2 2 4 8 2085 4258 1535 +801 2 2 4 8 1112 1960 2364 +802 2 2 4 8 1050 2729 3719 +803 2 2 4 8 1050 3719 3625 +804 2 2 4 8 2061 5167 5405 +805 2 2 4 8 477 5303 1913 +806 2 2 4 8 1108 2358 2329 +807 2 2 4 8 958 2329 2358 +808 2 2 4 8 975 2569 1864 +809 2 2 4 8 1363 2842 2952 +810 2 2 4 8 1042 2189 5046 +811 2 2 4 8 611 3219 3472 +812 2 2 4 8 659 2794 1775 +813 2 2 4 8 318 4608 1985 +814 2 2 4 8 1216 2327 3335 +815 2 2 4 8 1214 2326 3334 +816 2 2 4 8 1209 1887 3359 +817 2 2 4 8 1208 1888 3358 +818 2 2 4 8 444 2504 1839 +819 2 2 4 8 453 2505 1840 +820 2 2 4 8 1127 2973 3880 +821 2 2 4 8 895 2293 2044 +822 2 2 4 8 473 1949 5388 +823 2 2 4 8 2387 2628 4016 +824 2 2 4 8 465 1889 2430 +825 2 2 4 8 639 1794 4639 +826 2 2 4 8 794 1918 4693 +827 2 2 4 8 994 1748 3807 +828 2 2 4 8 995 1749 3808 +829 2 2 4 8 928 4808 4654 +830 2 2 4 8 1542 4740 3840 +831 2 2 4 8 1543 4741 3841 +832 2 2 4 8 822 4552 2900 +833 2 2 4 8 1118 1831 4868 +834 2 2 4 8 1321 1897 2513 +835 2 2 4 8 557 4706 4781 +836 2 2 4 8 962 2383 4798 +837 2 2 4 8 878 5224 3249 +838 2 2 4 8 1612 3787 3010 +839 2 2 4 8 1257 3445 1786 +840 2 2 4 8 1047 2452 1878 +841 2 2 4 8 162 1735 3631 +842 2 2 4 8 349 1736 3630 +843 2 2 4 8 927 4809 5020 +844 2 2 4 8 978 2212 4948 +845 2 2 4 8 979 2213 4947 +846 2 2 4 8 1013 2730 1740 +847 2 2 4 8 1863 4654 2521 +848 2 2 4 8 1548 3597 2849 +849 2 2 4 8 1804 5126 2065 +850 2 2 4 8 810 2065 5126 +851 2 2 4 8 802 4112 1745 +852 2 2 4 8 1776 4235 2796 +853 2 2 4 8 952 2041 2308 +854 2 2 4 8 753 5136 1722 +855 2 2 4 8 1012 5104 2010 +856 2 2 4 8 656 2796 4235 +857 2 2 4 8 888 3970 2159 +858 2 2 4 8 1557 3461 3007 +859 2 2 4 8 425 426 2288 +860 2 2 4 8 208 3 2289 +861 2 2 4 8 218 219 2290 +862 2 2 4 8 436 437 2291 +863 2 2 4 8 764 4803 4327 +864 2 2 4 8 1099 3940 1743 +865 2 2 4 8 970 4173 4557 +866 2 2 4 8 1149 3123 1894 +867 2 2 4 8 1204 5111 1871 +868 2 2 4 8 925 1948 3480 +869 2 2 4 8 191 192 2275 +870 2 2 4 8 952 1974 5012 +871 2 2 4 8 1558 3087 4262 +872 2 2 4 8 948 1999 2351 +873 2 2 4 8 978 4948 2412 +874 2 2 4 8 979 4947 2411 +875 2 2 4 8 308 2230 4380 +876 2 2 4 8 297 2229 4381 +877 2 2 4 8 175 4382 2228 +878 2 2 4 8 130 4383 2227 +879 2 2 4 8 119 4384 2226 +880 2 2 4 8 923 2233 2786 +881 2 2 4 8 534 1961 2875 +882 2 2 4 8 25 3432 1713 +883 2 2 4 8 1222 1868 3404 +884 2 2 4 8 879 2206 5225 +885 2 2 4 8 1149 5224 2207 +886 2 2 4 8 877 2205 5223 +887 2 2 4 8 1151 1795 3090 +888 2 2 4 8 946 2334 2015 +889 2 2 4 8 923 3592 2179 +890 2 2 4 8 556 2521 4654 +891 2 2 4 8 2336 917 3048 +892 2 2 4 8 2336 3048 1295 +893 2 2 4 8 500 1806 3208 +894 2 2 4 8 2078 1182 2585 +895 2 2 4 8 946 4210 2334 +896 2 2 4 8 2395 3961 3740 +897 2 2 4 8 633 3864 1938 +898 2 2 4 8 634 3865 1939 +899 2 2 4 8 618 2263 2477 +900 2 2 4 8 607 3382 2940 +901 2 2 4 8 761 1782 3766 +902 2 2 4 8 1139 2703 1761 +903 2 2 4 8 603 2413 2234 +904 2 2 4 8 189 190 2159 +905 2 2 4 8 924 4115 1797 +906 2 2 4 8 825 4823 4124 +907 2 2 4 8 1359 3235 4671 +908 2 2 4 8 744 3842 1791 +909 2 2 4 8 1296 1791 3842 +910 2 2 4 8 557 4781 2011 +911 2 2 4 8 1124 1760 3954 +912 2 2 4 8 1125 1839 4846 +913 2 2 4 8 1124 1840 4845 +914 2 2 4 8 31 2179 30 +915 2 2 4 8 1061 2370 3833 +916 2 2 4 8 1585 3833 2370 +917 2 2 4 8 588 2587 1810 +918 2 2 4 8 937 2574 3494 +919 2 2 4 8 936 3493 2573 +920 2 2 4 8 764 1834 2557 +921 2 2 4 8 1062 2371 3221 +922 2 2 4 8 1364 3221 2371 +923 2 2 4 8 1063 3222 2372 +924 2 2 4 8 1365 2372 3222 +925 2 2 4 8 1021 1954 2413 +926 2 2 4 8 573 2668 3323 +927 2 2 4 8 1543 3323 2668 +928 2 2 4 8 500 4165 1806 +929 2 2 4 8 1893 5190 2600 +930 2 2 4 8 1077 2301 2223 +931 2 2 4 8 477 2223 2301 +932 2 2 4 8 1078 2224 2302 +933 2 2 4 8 473 2302 2224 +934 2 2 4 8 497 1808 4171 +935 2 2 4 8 920 4502 1877 +936 2 2 4 8 574 3322 1764 +937 2 2 4 8 947 1765 3323 +938 2 2 4 8 476 3048 1917 +939 2 2 4 8 1132 1876 4406 +940 2 2 4 8 333 334 1987 +941 2 2 4 8 1791 3821 2682 +942 2 2 4 8 959 4507 2041 +943 2 2 4 8 1218 2645 2588 +944 2 2 4 8 875 2834 3133 +945 2 2 4 8 735 2732 3326 +946 2 2 4 8 1566 3326 2732 +947 2 2 4 8 1332 3626 2707 +948 2 2 4 8 799 2326 2051 +949 2 2 4 8 1214 2051 2326 +950 2 2 4 8 800 2327 2052 +951 2 2 4 8 1216 2052 2327 +952 2 2 4 8 1943 4654 4808 +953 2 2 4 8 1259 2992 2652 +954 2 2 4 8 4210 5198 2334 +955 2 2 4 8 693 1738 2792 +956 2 2 4 8 948 4306 4212 +957 2 2 4 8 2417 4657 4453 +958 2 2 4 8 1249 2662 3224 +959 2 2 4 8 913 3526 2278 +960 2 2 4 8 2278 3526 4437 +961 2 2 4 8 615 2264 2498 +962 2 2 4 8 1312 2209 3274 +963 2 2 4 8 507 3274 2209 +964 2 2 4 8 963 3907 2830 +965 2 2 4 8 1104 1768 4007 +966 2 2 4 8 689 1971 3546 +967 2 2 4 8 1290 3546 1971 +968 2 2 4 8 2231 3163 4161 +969 2 2 4 8 757 1786 4006 +970 2 2 4 8 1204 3163 2231 +971 2 2 4 8 706 1885 3272 +972 2 2 4 8 1577 3272 1885 +973 2 2 4 8 707 1886 3273 +974 2 2 4 8 1578 3273 1886 +975 2 2 4 8 980 3381 1713 +976 2 2 4 8 1768 4297 2348 +977 2 2 4 8 1769 4296 2349 +978 2 2 4 8 1582 3274 2019 +979 2 2 4 8 467 3883 2287 +980 2 2 4 8 592 2468 3187 +981 2 2 4 8 863 2599 4269 +982 2 2 4 8 865 4271 2598 +983 2 2 4 8 894 3667 2501 +984 2 2 4 8 1710 3215 4520 +985 2 2 4 8 944 3481 1783 +986 2 2 4 8 1363 3315 3708 +987 2 2 4 8 580 2056 2548 +988 2 2 4 8 318 319 4608 +989 2 2 4 8 1383 2890 3105 +990 2 2 4 8 948 2351 4306 +991 2 2 4 8 934 3028 3720 +992 2 2 4 8 935 3027 3722 +993 2 2 4 8 971 3279 1743 +994 2 2 4 8 1677 4067 2590 +995 2 2 4 8 419 3465 2095 +996 2 2 4 8 759 2417 4453 +997 2 2 4 8 2504 2191 4773 +998 2 2 4 8 2505 2190 4774 +999 2 2 4 8 1399 2918 2784 +1000 2 2 4 8 558 4890 1998 +1001 2 2 4 8 1686 1998 4890 +1002 2 2 4 8 643 2042 2595 +1003 2 2 4 8 1072 2595 2042 +1004 2 2 4 8 1262 2623 2704 +1005 2 2 4 8 1171 2704 2623 +1006 2 2 4 8 1267 2737 1904 +1007 2 2 4 8 952 5012 2041 +1008 2 2 4 8 1104 2325 2309 +1009 2 2 4 8 484 2309 2325 +1010 2 2 4 8 482 2310 2324 +1011 2 2 4 8 1105 2324 2310 +1012 2 2 4 8 3426 5102 2954 +1013 2 2 4 8 2097 2597 1187 +1014 2 2 4 8 1255 2856 2415 +1015 2 2 4 8 1090 2415 2856 +1016 2 2 4 8 1611 3021 3785 +1017 2 2 4 8 1431 4577 1744 +1018 2 2 4 8 1297 3265 2434 +1019 2 2 4 8 1223 4700 3081 +1020 2 2 4 8 570 3134 1718 +1021 2 2 4 8 1708 2835 3560 +1022 2 2 4 8 540 3560 2835 +1023 2 2 4 8 1709 3561 2836 +1024 2 2 4 8 539 2836 3561 +1025 2 2 4 8 946 2015 2464 +1026 2 2 4 8 764 2557 4803 +1027 2 2 4 8 802 1745 4534 +1028 2 2 4 8 2108 3277 1225 +1029 2 2 4 8 1014 1861 2547 +1030 2 2 4 8 2051 3721 4766 +1031 2 2 4 8 970 4557 2469 +1032 2 2 4 8 1146 1717 2993 +1033 2 2 4 8 693 2784 2918 +1034 2 2 4 8 791 1856 4199 +1035 2 2 4 8 790 1857 4198 +1036 2 2 4 8 776 3798 1816 +1037 2 2 4 8 775 3797 1817 +1038 2 2 4 8 779 1820 3800 +1039 2 2 4 8 780 1821 3799 +1040 2 2 4 8 280 2642 2996 +1041 2 2 4 8 263 2995 2641 +1042 2 2 4 8 59 2640 2994 +1043 2 2 4 8 951 1958 4782 +1044 2 2 4 8 952 1959 4783 +1045 2 2 4 8 42 3031 2675 +1046 2 2 4 8 576 1751 4512 +1047 2 2 4 8 466 2165 2294 +1048 2 2 4 8 8 2311 3977 +1049 2 2 4 8 1011 4744 5249 +1050 2 2 4 8 665 3139 2432 +1051 2 2 4 8 1351 2432 3139 +1052 2 2 4 8 2055 3850 5405 +1053 2 2 4 8 25 1713 3938 +1054 2 2 4 8 1014 2711 1861 +1055 2 2 4 8 2108 4163 3277 +1056 2 2 4 8 1846 4875 2476 +1057 2 2 4 8 915 2400 4881 +1058 2 2 4 8 1111 2239 5379 +1059 2 2 4 8 641 2298 2844 +1060 2 2 4 8 803 2180 3423 +1061 2 2 4 8 1342 3423 2180 +1062 2 2 4 8 1341 3422 2181 +1063 2 2 4 8 804 2181 3422 +1064 2 2 4 8 870 5233 2216 +1065 2 2 4 8 965 2829 3996 +1066 2 2 4 8 1849 3759 1295 +1067 2 2 4 8 716 3759 1849 +1068 2 2 4 8 2738 3903 4669 +1069 2 2 4 8 1249 2679 3550 +1070 2 2 4 8 1665 3872 3764 +1071 2 2 4 8 554 2031 2373 +1072 2 2 4 8 556 2374 2032 +1073 2 2 4 8 1277 4598 3357 +1074 2 2 4 8 1877 3168 3750 +1075 2 2 4 8 2679 3564 3550 +1076 2 2 4 8 2239 2331 5379 +1077 2 2 4 8 951 4782 1973 +1078 2 2 4 8 952 4783 1974 +1079 2 2 4 8 2056 1180 2548 +1080 2 2 4 8 498 2698 3625 +1081 2 2 4 8 916 2118 3527 +1082 2 2 4 8 986 2006 2886 +1083 2 2 4 8 1115 2727 2063 +1084 2 2 4 8 796 2063 2727 +1085 2 2 4 8 953 4197 3398 +1086 2 2 4 8 955 4196 3399 +1087 2 2 4 8 1439 2039 4201 +1088 2 2 4 8 1009 2039 3000 +1089 2 2 4 8 17 18 2168 +1090 2 2 4 8 1527 2251 4275 +1091 2 2 4 8 1879 4671 3235 +1092 2 2 4 8 658 5118 2244 +1093 2 2 4 8 2755 3741 4696 +1094 2 2 4 8 1556 2392 3416 +1095 2 2 4 8 555 2036 2380 +1096 2 2 4 8 777 1818 3567 +1097 2 2 4 8 778 1819 3566 +1098 2 2 4 8 1023 1784 4338 +1099 2 2 4 8 487 3003 4867 +1100 2 2 4 8 943 2029 3368 +1101 2 2 4 8 944 2030 3367 +1102 2 2 4 8 773 2571 1867 +1103 2 2 4 8 1236 3478 1951 +1104 2 2 4 8 1237 3479 1952 +1105 2 2 4 8 1146 4160 1717 +1106 2 2 4 8 500 3208 3676 +1107 2 2 4 8 829 2515 5071 +1108 2 2 4 8 1577 1885 4489 +1109 2 2 4 8 1578 1886 4490 +1110 2 2 4 8 473 2329 4311 +1111 2 2 4 8 467 2287 2166 +1112 2 2 4 8 1887 4360 2718 +1113 2 2 4 8 1888 4361 2719 +1114 2 2 4 8 1257 3458 2631 +1115 2 2 4 8 948 2553 1999 +1116 2 2 4 8 975 1864 2578 +1117 2 2 4 8 976 2579 1863 +1118 2 2 4 8 1091 2391 4049 +1119 2 2 4 8 1651 4049 2391 +1120 2 2 4 8 1650 4050 2390 +1121 2 2 4 8 1092 2390 4050 +1122 2 2 4 8 570 2930 1768 +1123 2 2 4 8 473 5388 2302 +1124 2 2 4 8 1270 3754 1884 +1125 2 2 4 8 1937 3847 2615 +1126 2 2 4 8 462 2029 4578 +1127 2 2 4 8 944 4579 2030 +1128 2 2 4 8 627 3782 2352 +1129 2 2 4 8 950 4707 1972 +1130 2 2 4 8 624 5291 1734 +1131 2 2 4 8 2327 3892 3335 +1132 2 2 4 8 2326 3893 3334 +1133 2 2 4 8 895 2590 4067 +1134 2 2 4 8 1172 1914 3230 +1135 2 2 4 8 977 4639 2733 +1136 2 2 4 8 867 3943 2225 +1137 2 2 4 8 552 4277 3920 +1138 2 2 4 8 1485 3743 5072 +1139 2 2 4 8 736 2556 3785 +1140 2 2 4 8 572 3348 1769 +1141 2 2 4 8 2253 2736 3689 +1142 2 2 4 8 2745 4311 2329 +1143 2 2 4 8 666 2064 4345 +1144 2 2 4 8 502 3426 2954 +1145 2 2 4 8 8 3977 7 +1146 2 2 4 8 2287 3883 2924 +1147 2 2 4 8 620 5349 1927 +1148 2 2 4 8 2612 3844 3907 +1149 2 2 4 8 848 1733 4107 +1150 2 2 4 8 942 1734 4016 +1151 2 2 4 8 70 71 2133 +1152 2 2 4 8 4566 5121 3457 +1153 2 2 4 8 2157 2553 3912 +1154 2 2 4 8 675 2545 1897 +1155 2 2 4 8 1587 3749 2525 +1156 2 2 4 8 533 3811 2559 +1157 2 2 4 8 949 1999 2593 +1158 2 2 4 8 1359 4562 3235 +1159 2 2 4 8 485 2733 2265 +1160 2 2 4 8 475 3849 3403 +1161 2 2 4 8 587 3175 3082 +1162 2 2 4 8 582 3174 3083 +1163 2 2 4 8 885 2647 2290 +1164 2 2 4 8 886 2648 2291 +1165 2 2 4 8 1485 5072 2947 +1166 2 2 4 8 443 1754 3644 +1167 2 2 4 8 610 1778 4432 +1168 2 2 4 8 609 4433 1779 +1169 2 2 4 8 1130 2045 2838 +1170 2 2 4 8 787 2838 2045 +1171 2 2 4 8 1966 3216 5255 +1172 2 2 4 8 1270 1884 3768 +1173 2 2 4 8 644 3850 2680 +1174 2 2 4 8 1274 3565 1740 +1175 2 2 4 8 1228 2618 2698 +1176 2 2 4 8 1233 2296 2341 +1177 2 2 4 8 54 2688 5253 +1178 2 2 4 8 275 2689 5254 +1179 2 2 4 8 477 2301 5303 +1180 2 2 4 8 465 5027 2020 +1181 2 2 4 8 603 4392 1785 +1182 2 2 4 8 2364 5138 5089 +1183 2 2 4 8 950 1998 4707 +1184 2 2 4 8 1424 1995 4204 +1185 2 2 4 8 1612 3010 5228 +1186 2 2 4 8 747 4168 2721 +1187 2 2 4 8 517 3844 2612 +1188 2 2 4 8 621 5315 1928 +1189 2 2 4 8 1024 5203 2487 +1190 2 2 4 8 1391 2746 3648 +1191 2 2 4 8 1392 2747 3649 +1192 2 2 4 8 693 2965 1738 +1193 2 2 4 8 476 2903 3386 +1194 2 2 4 8 724 2797 3746 +1195 2 2 4 8 726 2798 3747 +1196 2 2 4 8 560 3206 1965 +1197 2 2 4 8 959 2041 2558 +1198 2 2 4 8 2129 3128 4431 +1199 2 2 4 8 1070 1788 2935 +1200 2 2 4 8 562 3665 2007 +1201 2 2 4 8 1355 1937 5160 +1202 2 2 4 8 1356 5159 1936 +1203 2 2 4 8 2631 3458 4876 +1204 2 2 4 8 1179 2461 2621 +1205 2 2 4 8 493 2621 2461 +1206 2 2 4 8 1586 4941 3156 +1207 2 2 4 8 562 2007 4918 +1208 2 2 4 8 1691 4918 2007 +1209 2 2 4 8 969 2654 2248 +1210 2 2 4 8 970 2469 1982 +1211 2 2 4 8 973 1983 2470 +1212 2 2 4 8 580 2548 2152 +1213 2 2 4 8 610 2811 1778 +1214 2 2 4 8 1026 2812 1779 +1215 2 2 4 8 609 1779 2812 +1216 2 2 4 8 599 2157 3226 +1217 2 2 4 8 2515 1941 5071 +1218 2 2 4 8 1705 4269 2599 +1219 2 2 4 8 1704 2598 4271 +1220 2 2 4 8 925 3905 1727 +1221 2 2 4 8 481 4419 1851 +1222 2 2 4 8 470 1854 4417 +1223 2 2 4 8 755 4332 4636 +1224 2 2 4 8 42 43 3031 +1225 2 2 4 8 2308 2041 4507 +1226 2 2 4 8 924 1726 4159 +1227 2 2 4 8 557 1959 4706 +1228 2 2 4 8 1099 3994 2359 +1229 2 2 4 8 945 2465 2725 +1230 2 2 4 8 2283 3963 3290 +1231 2 2 4 8 1130 1800 2724 +1232 2 2 4 8 1277 2674 4598 +1233 2 2 4 8 1272 2487 2912 +1234 2 2 4 8 628 4042 2308 +1235 2 2 4 8 1003 1970 5040 +1236 2 2 4 8 1011 5249 2401 +1237 2 2 4 8 986 2476 4875 +1238 2 2 4 8 580 2416 2056 +1239 2 2 4 8 902 3396 5167 +1240 2 2 4 8 1743 2355 4229 +1241 2 2 4 8 759 3815 1780 +1242 2 2 4 8 867 2395 3740 +1243 2 2 4 8 1000 2626 1882 +1244 2 2 4 8 568 1882 2626 +1245 2 2 4 8 857 2353 2129 +1246 2 2 4 8 1070 2898 1788 +1247 2 2 4 8 1230 2961 1744 +1248 2 2 4 8 2608 3259 5252 +1249 2 2 4 8 2084 4555 4314 +1250 2 2 4 8 343 344 2138 +1251 2 2 4 8 1213 3142 2769 +1252 2 2 4 8 1215 3141 2770 +1253 2 2 4 8 1217 3140 2771 +1254 2 2 4 8 279 280 2996 +1255 2 2 4 8 263 264 2995 +1256 2 2 4 8 58 59 2994 +1257 2 2 4 8 957 1850 2791 +1258 2 2 4 8 1166 1728 4343 +1259 2 2 4 8 1208 1966 5255 +1260 2 2 4 8 1729 4239 1165 +1261 2 2 4 8 717 2379 3035 +1262 2 2 4 8 1573 2559 3811 +1263 2 2 4 8 543 4159 2522 +1264 2 2 4 8 1822 4650 2473 +1265 2 2 4 8 1250 2023 2451 +1266 2 2 4 8 1260 2616 2617 +1267 2 2 4 8 945 2617 2616 +1268 2 2 4 8 469 3470 2878 +1269 2 2 4 8 662 2682 3821 +1270 2 2 4 8 1662 2191 4449 +1271 2 2 4 8 444 4449 2191 +1272 2 2 4 8 454 1862 4058 +1273 2 2 4 8 610 2160 2829 +1274 2 2 4 8 609 2830 2161 +1275 2 2 4 8 849 2028 3796 +1276 2 2 4 8 922 3507 1935 +1277 2 2 4 8 152 5145 2718 +1278 2 2 4 8 373 5146 2719 +1279 2 2 4 8 169 170 2142 +1280 2 2 4 8 356 357 2141 +1281 2 2 4 8 1267 2978 2737 +1282 2 2 4 8 528 3229 4025 +1283 2 2 4 8 1804 5138 2364 +1284 2 2 4 8 543 2580 4159 +1285 2 2 4 8 1040 1814 2925 +1286 2 2 4 8 1041 1813 2926 +1287 2 2 4 8 821 4070 2909 +1288 2 2 4 8 1071 3007 3461 +1289 2 2 4 8 1049 1890 2596 +1290 2 2 4 8 1937 3108 5160 +1291 2 2 4 8 1936 5159 3107 +1292 2 2 4 8 884 3153 2289 +1293 2 2 4 8 1282 2289 3153 +1294 2 2 4 8 885 2290 3154 +1295 2 2 4 8 1283 3154 2290 +1296 2 2 4 8 1067 1767 3052 +1297 2 2 4 8 1003 4957 4701 +1298 2 2 4 8 954 2058 2418 +1299 2 2 4 8 953 2419 2057 +1300 2 2 4 8 955 2420 2059 +1301 2 2 4 8 807 4778 4795 +1302 2 2 4 8 808 4779 4796 +1303 2 2 4 8 627 2538 2915 +1304 2 2 4 8 569 2630 1883 +1305 2 2 4 8 1001 1883 2630 +1306 2 2 4 8 1249 3550 2662 +1307 2 2 4 8 1594 2662 3550 +1308 2 2 4 8 601 2464 2015 +1309 2 2 4 8 547 3905 2499 +1310 2 2 4 8 1558 4587 3087 +1311 2 2 4 8 805 1887 4405 +1312 2 2 4 8 806 1888 4404 +1313 2 2 4 8 618 2477 4644 +1314 2 2 4 8 1413 2423 3653 +1315 2 2 4 8 1412 2422 3654 +1316 2 2 4 8 2477 4401 4644 +1317 2 2 4 8 592 3187 2969 +1318 2 2 4 8 649 3285 1761 +1319 2 2 4 8 1139 1761 3285 +1320 2 2 4 8 1010 5141 2397 +1321 2 2 4 8 1188 1735 3184 +1322 2 2 4 8 2085 575 4484 +1323 2 2 4 8 1024 3037 1777 +1324 2 2 4 8 879 1893 2600 +1325 2 2 4 8 547 2523 3905 +1326 2 2 4 8 1864 2569 4655 +1327 2 2 4 8 454 4058 1870 +1328 2 2 4 8 1358 3106 1971 +1329 2 2 4 8 4201 2039 5361 +1330 2 2 4 8 467 2303 5152 +1331 2 2 4 8 627 2697 3782 +1332 2 2 4 8 628 4507 1983 +1333 2 2 4 8 984 1963 4762 +1334 2 2 4 8 985 4763 1965 +1335 2 2 4 8 1760 4441 5129 +1336 2 2 4 8 483 2473 4650 +1337 2 2 4 8 2554 3784 5151 +1338 2 2 4 8 685 2822 1865 +1339 2 2 4 8 637 3733 2047 +1340 2 2 4 8 638 2048 3732 +1341 2 2 4 8 755 4636 2550 +1342 2 2 4 8 1575 4303 2541 +1343 2 2 4 8 1576 4304 2540 +1344 2 2 4 8 1129 3262 1739 +1345 2 2 4 8 2053 1369 2792 +1346 2 2 4 8 140 141 2132 +1347 2 2 4 8 362 2131 361 +1348 2 2 4 8 847 5121 4566 +1349 2 2 4 8 1050 2698 2618 +1350 2 2 4 8 1030 4810 3826 +1351 2 2 4 8 454 1870 4613 +1352 2 2 4 8 585 2531 2933 +1353 2 2 4 8 724 3678 2797 +1354 2 2 4 8 628 2475 4042 +1355 2 2 4 8 754 3089 1785 +1356 2 2 4 8 564 2238 4369 +1357 2 2 4 8 554 4655 2569 +1358 2 2 4 8 560 2400 2102 +1359 2 2 4 8 1384 2885 1947 +1360 2 2 4 8 31 3645 2179 +1361 2 2 4 8 2524 3908 4127 +1362 2 2 4 8 777 1741 3091 +1363 2 2 4 8 778 1742 3092 +1364 2 2 4 8 1113 2988 4673 +1365 2 2 4 8 19 20 2208 +1366 2 2 4 8 1010 3490 1790 +1367 2 2 4 8 1099 2881 3994 +1368 2 2 4 8 900 1754 3038 +1369 2 2 4 8 1037 1773 3438 +1370 2 2 4 8 1038 1772 3437 +1371 2 2 4 8 65 66 2112 +1372 2 2 4 8 286 287 2110 +1373 2 2 4 8 256 257 2111 +1374 2 2 4 8 1208 3358 1966 +1375 2 2 4 8 1209 3359 1967 +1376 2 2 4 8 469 5248 2073 +1377 2 2 4 8 784 4008 1823 +1378 2 2 4 8 786 4010 1824 +1379 2 2 4 8 785 4009 1825 +1380 2 2 4 8 1335 2540 3521 +1381 2 2 4 8 1334 2541 3522 +1382 2 2 4 8 460 2567 2361 +1383 2 2 4 8 461 2568 2362 +1384 2 2 4 8 887 2744 1925 +1385 2 2 4 8 1230 1744 4849 +1386 2 2 4 8 1098 2360 2414 +1387 2 2 4 8 459 2414 2360 +1388 2 2 4 8 566 1743 3279 +1389 2 2 4 8 984 4762 1988 +1390 2 2 4 8 985 1990 4763 +1391 2 2 4 8 368 3017 2651 +1392 2 2 4 8 147 3018 2650 +1393 2 2 4 8 385 2649 3016 +1394 2 2 4 8 1700 2730 4202 +1395 2 2 4 8 1204 2231 5111 +1396 2 2 4 8 940 2331 2239 +1397 2 2 4 8 810 5126 1960 +1398 2 2 4 8 625 2849 2610 +1399 2 2 4 8 684 2871 1844 +1400 2 2 4 8 1170 3215 4471 +1401 2 2 4 8 581 2691 2153 +1402 2 2 4 8 576 3158 1751 +1403 2 2 4 8 1113 1751 3158 +1404 2 2 4 8 729 3981 3314 +1405 2 2 4 8 2225 3943 3675 +1406 2 2 4 8 875 2489 2488 +1407 2 2 4 8 1344 2488 2489 +1408 2 2 4 8 1052 5138 4318 +1409 2 2 4 8 990 2864 2305 +1410 2 2 4 8 991 2304 2863 +1411 2 2 4 8 977 2733 2218 +1412 2 2 4 8 1536 3880 2973 +1413 2 2 4 8 737 4014 2910 +1414 2 2 4 8 1145 2920 1770 +1415 2 2 4 8 1144 2919 1771 +1416 2 2 4 8 973 2609 1983 +1417 2 2 4 8 970 1982 2610 +1418 2 2 4 8 768 3372 1752 +1419 2 2 4 8 769 1753 3373 +1420 2 2 4 8 972 1768 2930 +1421 2 2 4 8 557 2118 2406 +1422 2 2 4 8 651 2023 3336 +1423 2 2 4 8 1250 3336 2023 +1424 2 2 4 8 1686 4840 1998 +1425 2 2 4 8 920 4004 4502 +1426 2 2 4 8 496 1750 3176 +1427 2 2 4 8 1016 3741 2755 +1428 2 2 4 8 1026 5120 2438 +1429 2 2 4 8 750 5119 2437 +1430 2 2 4 8 516 2847 2789 +1431 2 2 4 8 920 4158 2219 +1432 2 2 4 8 4103 2523 4645 +1433 2 2 4 8 603 5114 2413 +1434 2 2 4 8 405 3953 2389 +1435 2 2 4 8 1039 4622 1842 +1436 2 2 4 8 692 3094 1829 +1437 2 2 4 8 698 4597 2753 +1438 2 2 4 8 597 1871 2664 +1439 2 2 4 8 664 2182 3238 +1440 2 2 4 8 1121 2316 2333 +1441 2 2 4 8 951 2333 2316 +1442 2 2 4 8 1703 2721 4168 +1443 2 2 4 8 558 4053 2394 +1444 2 2 4 8 1630 2394 4053 +1445 2 2 4 8 1124 4441 1760 +1446 2 2 4 8 2087 873 2433 +1447 2 2 4 8 869 1835 4104 +1448 2 2 4 8 1067 3350 1767 +1449 2 2 4 8 685 1845 2977 +1450 2 2 4 8 1046 2796 1803 +1451 2 2 4 8 2054 1286 3501 +1452 2 2 4 8 495 2054 3501 +1453 2 2 4 8 866 2485 3664 +1454 2 2 4 8 595 2028 2516 +1455 2 2 4 8 649 1761 3103 +1456 2 2 4 8 898 4084 3748 +1457 2 2 4 8 642 1766 4659 +1458 2 2 4 8 404 405 2389 +1459 2 2 4 8 451 2532 2058 +1460 2 2 4 8 1031 2058 2532 +1461 2 2 4 8 1222 4395 1868 +1462 2 2 4 8 2118 4964 3527 +1463 2 2 4 8 506 4442 4376 +1464 2 2 4 8 1866 4781 4706 +1465 2 2 4 8 636 2563 3662 +1466 2 2 4 8 1794 2733 4639 +1467 2 2 4 8 987 1991 4683 +1468 2 2 4 8 986 1989 4684 +1469 2 2 4 8 1021 3480 1948 +1470 2 2 4 8 872 2010 5104 +1471 2 2 4 8 739 3010 3787 +1472 2 2 4 8 1030 2526 4810 +1473 2 2 4 8 599 1999 2553 +1474 2 2 4 8 1047 2795 1811 +1475 2 2 4 8 561 1964 4859 +1476 2 2 4 8 724 4501 2484 +1477 2 2 4 8 472 2276 2479 +1478 2 2 4 8 474 2480 2277 +1479 2 2 4 8 794 1766 3040 +1480 2 2 4 8 977 2218 2982 +1481 2 2 4 8 1212 2982 2218 +1482 2 2 4 8 599 3226 2330 +1483 2 2 4 8 1101 3035 2912 +1484 2 2 4 8 908 2972 1923 +1485 2 2 4 8 953 2602 4197 +1486 2 2 4 8 955 2604 4196 +1487 2 2 4 8 907 2971 1924 +1488 2 2 4 8 772 3995 2040 +1489 2 2 4 8 1424 2040 3995 +1490 2 2 4 8 581 2192 2691 +1491 2 2 4 8 1750 3911 2699 +1492 2 2 4 8 906 2963 1922 +1493 2 2 4 8 1042 1826 4349 +1494 2 2 4 8 1870 4926 5364 +1495 2 2 4 8 687 1847 3227 +1496 2 2 4 8 1869 4953 3346 +1497 2 2 4 8 355 2025 4223 +1498 2 2 4 8 168 2026 4224 +1499 2 2 4 8 1296 3821 1791 +1500 2 2 4 8 2252 2663 3769 +1501 2 2 4 8 987 4683 2007 +1502 2 2 4 8 986 4684 2006 +1503 2 2 4 8 2064 3624 4345 +1504 2 2 4 8 734 2555 4500 +1505 2 2 4 8 736 4499 2556 +1506 2 2 4 8 2105 1003 5040 +1507 2 2 4 8 635 3679 3063 +1508 2 2 4 8 652 2433 3777 +1509 2 2 4 8 1003 3791 3728 +1510 2 2 4 8 916 5016 2118 +1511 2 2 4 8 84 85 2600 +1512 2 2 4 8 534 2875 5402 +1513 2 2 4 8 288 3245 3440 +1514 2 2 4 8 1323 2789 2847 +1515 2 2 4 8 920 4965 3634 +1516 2 2 4 8 564 4369 2469 +1517 2 2 4 8 445 2570 2589 +1518 2 2 4 8 1178 2589 2570 +1519 2 2 4 8 1486 3283 2665 +1520 2 2 4 8 1198 2665 3283 +1521 2 2 4 8 1075 3647 2991 +1522 2 2 4 8 1765 4190 2368 +1523 2 2 4 8 1764 4189 2369 +1524 2 2 4 8 704 1879 4812 +1525 2 2 4 8 1083 2667 2126 +1526 2 2 4 8 1084 2668 2124 +1527 2 2 4 8 1167 3064 1874 +1528 2 2 4 8 2571 4731 4952 +1529 2 2 4 8 2089 4600 795 +1530 2 2 4 8 2089 1626 4600 +1531 2 2 4 8 658 3914 1841 +1532 2 2 4 8 488 2852 1800 +1533 2 2 4 8 946 1764 3322 +1534 2 2 4 8 573 3323 1765 +1535 2 2 4 8 1391 2560 2746 +1536 2 2 4 8 1392 2561 2747 +1537 2 2 4 8 608 2908 1855 +1538 2 2 4 8 1337 1862 2806 +1539 2 2 4 8 1580 2637 3060 +1540 2 2 4 8 1103 3060 2637 +1541 2 2 4 8 1868 4302 3404 +1542 2 2 4 8 571 4261 2134 +1543 2 2 4 8 1210 2943 2204 +1544 2 2 4 8 967 4449 2246 +1545 2 2 4 8 453 2247 4450 +1546 2 2 4 8 2084 4314 840 +1547 2 2 4 8 1236 1951 2817 +1548 2 2 4 8 843 2817 1951 +1549 2 2 4 8 844 2818 1952 +1550 2 2 4 8 1237 1952 2818 +1551 2 2 4 8 717 3035 2760 +1552 2 2 4 8 874 2341 2296 +1553 2 2 4 8 482 3182 2310 +1554 2 2 4 8 484 3183 2309 +1555 2 2 4 8 1931 4701 4957 +1556 2 2 4 8 2522 4031 5122 +1557 2 2 4 8 1752 2455 3344 +1558 2 2 4 8 1753 3345 2456 +1559 2 2 4 8 743 4094 2828 +1560 2 2 4 8 738 4095 2824 +1561 2 2 4 8 577 2269 2982 +1562 2 2 4 8 773 4731 2571 +1563 2 2 4 8 645 1884 3754 +1564 2 2 4 8 580 2175 2416 +1565 2 2 4 8 320 1787 4608 +1566 2 2 4 8 1066 2204 2471 +1567 2 2 4 8 568 2471 2204 +1568 2 2 4 8 486 1969 2614 +1569 2 2 4 8 2105 4957 1003 +1570 2 2 4 8 964 2908 2453 +1571 2 2 4 8 899 5230 3148 +1572 2 2 4 8 442 2201 4475 +1573 2 2 4 8 450 2199 4473 +1574 2 2 4 8 1073 2680 1896 +1575 2 2 4 8 770 3890 2195 +1576 2 2 4 8 1478 2195 3890 +1577 2 2 4 8 394 4208 3466 +1578 2 2 4 8 1120 3352 2985 +1579 2 2 4 8 1119 3351 2984 +1580 2 2 4 8 1032 5348 2057 +1581 2 2 4 8 1033 5347 2059 +1582 2 2 4 8 761 3766 4001 +1583 2 2 4 8 1024 1935 4806 +1584 2 2 4 8 462 4578 5286 +1585 2 2 4 8 708 2586 2392 +1586 2 2 4 8 957 2907 4026 +1587 2 2 4 8 789 1916 4185 +1588 2 2 4 8 575 2351 4484 +1589 2 2 4 8 470 4417 1988 +1590 2 2 4 8 480 1989 4420 +1591 2 2 4 8 481 1991 4419 +1592 2 2 4 8 479 1990 4418 +1593 2 2 4 8 748 1777 3037 +1594 2 2 4 8 886 3126 2187 +1595 2 2 4 8 1951 5253 2688 +1596 2 2 4 8 1952 5254 2689 +1597 2 2 4 8 636 3662 2787 +1598 2 2 4 8 867 2225 2395 +1599 2 2 4 8 1049 1865 2822 +1600 2 2 4 8 919 3908 2524 +1601 2 2 4 8 1072 1994 2595 +1602 2 2 4 8 1703 3406 3198 +1603 2 2 4 8 563 4958 2279 +1604 2 2 4 8 1226 2575 2019 +1605 2 2 4 8 218 2647 217 +1606 2 2 4 8 435 436 2648 +1607 2 2 4 8 773 3939 2163 +1608 2 2 4 8 506 2002 4442 +1609 2 2 4 8 1691 2007 4850 +1610 2 2 4 8 1695 4815 3331 +1611 2 2 4 8 640 3499 2299 +1612 2 2 4 8 2279 4958 4919 +1613 2 2 4 8 2086 639 4639 +1614 2 2 4 8 1298 3889 3686 +1615 2 2 4 8 599 2593 1999 +1616 2 2 4 8 1589 3043 2410 +1617 2 2 4 8 1617 3081 4700 +1618 2 2 4 8 560 4843 3206 +1619 2 2 4 8 628 1983 2609 +1620 2 2 4 8 903 4031 2522 +1621 2 2 4 8 625 2610 1982 +1622 2 2 4 8 1220 3343 1918 +1623 2 2 4 8 2088 872 5104 +1624 2 2 4 8 1105 1769 4341 +1625 2 2 4 8 1451 2026 4452 +1626 2 2 4 8 1450 2025 4451 +1627 2 2 4 8 510 3903 2738 +1628 2 2 4 8 621 4460 1930 +1629 2 2 4 8 1017 2836 2683 +1630 2 2 4 8 1018 2684 2835 +1631 2 2 4 8 339 340 2347 +1632 2 2 4 8 2201 4390 4475 +1633 2 2 4 8 2199 4389 4473 +1634 2 2 4 8 851 2690 1932 +1635 2 2 4 8 1003 2396 3791 +1636 2 2 4 8 736 3785 3021 +1637 2 2 4 8 1771 2701 4581 +1638 2 2 4 8 1770 2700 4580 +1639 2 2 4 8 772 3768 1884 +1640 2 2 4 8 595 2516 2187 +1641 2 2 4 8 1064 2187 2516 +1642 2 2 4 8 659 1775 3488 +1643 2 2 4 8 687 2791 1850 +1644 2 2 4 8 905 3104 3851 +1645 2 2 4 8 761 3571 1782 +1646 2 2 4 8 1944 5020 4809 +1647 2 2 4 8 1306 5252 3259 +1648 2 2 4 8 862 4353 1898 +1649 2 2 4 8 861 1899 4352 +1650 2 2 4 8 953 2057 2906 +1651 2 2 4 8 955 2059 2905 +1652 2 2 4 8 954 2904 2058 +1653 2 2 4 8 677 2493 3611 +1654 2 2 4 8 1201 3198 3406 +1655 2 2 4 8 586 1812 4549 +1656 2 2 4 8 1870 5364 2452 +1657 2 2 4 8 998 3820 2054 +1658 2 2 4 8 974 1769 3348 +1659 2 2 4 8 553 4064 4065 +1660 2 2 4 8 553 4065 2388 +1661 2 2 4 8 660 2768 3999 +1662 2 2 4 8 862 4478 3201 +1663 2 2 4 8 1835 5390 2457 +1664 2 2 4 8 207 2376 206 +1665 2 2 4 8 423 424 2375 +1666 2 2 4 8 220 221 2377 +1667 2 2 4 8 438 439 2378 +1668 2 2 4 8 1611 5241 3021 +1669 2 2 4 8 368 369 3017 +1670 2 2 4 8 148 3018 147 +1671 2 2 4 8 384 385 3016 +1672 2 2 4 8 608 2356 2497 +1673 2 2 4 8 1739 3466 4208 +1674 2 2 4 8 976 4102 3503 +1675 2 2 4 8 1021 1948 4524 +1676 2 2 4 8 458 4204 1995 +1677 2 2 4 8 639 3281 2596 +1678 2 2 4 8 733 3877 2880 +1679 2 2 4 8 2433 3609 3777 +1680 2 2 4 8 620 2382 5349 +1681 2 2 4 8 2035 4396 2545 +1682 2 2 4 8 139 3448 3242 +1683 2 2 4 8 776 1816 3694 +1684 2 2 4 8 775 1817 3693 +1685 2 2 4 8 777 3695 1818 +1686 2 2 4 8 778 3696 1819 +1687 2 2 4 8 779 3697 1820 +1688 2 2 4 8 780 3698 1821 +1689 2 2 4 8 887 1927 4409 +1690 2 2 4 8 2492 1766 4746 +1691 2 2 4 8 883 2184 4034 +1692 2 2 4 8 2298 4076 2844 +1693 2 2 4 8 1208 5255 2263 +1694 2 2 4 8 911 2374 4880 +1695 2 2 4 8 494 2756 2398 +1696 2 2 4 8 1184 2398 2756 +1697 2 2 4 8 1021 4524 1954 +1698 2 2 4 8 1210 4813 1843 +1699 2 2 4 8 1013 4202 2730 +1700 2 2 4 8 1009 3000 2346 +1701 2 2 4 8 446 3034 2268 +1702 2 2 4 8 1340 3764 3872 +1703 2 2 4 8 735 5151 3784 +1704 2 2 4 8 533 2788 2462 +1705 2 2 4 8 483 2558 5012 +1706 2 2 4 8 2041 5012 2558 +1707 2 2 4 8 417 3311 1953 +1708 2 2 4 8 642 2024 2592 +1709 2 2 4 8 837 3068 2056 +1710 2 2 4 8 2056 3068 1180 +1711 2 2 4 8 761 2108 4938 +1712 2 2 4 8 1376 2632 2502 +1713 2 2 4 8 1037 2169 2494 +1714 2 2 4 8 1038 2170 2495 +1715 2 2 4 8 1318 1946 5002 +1716 2 2 4 8 1919 2962 4595 +1717 2 2 4 8 975 3070 1950 +1718 2 2 4 8 2107 2787 1116 +1719 2 2 4 8 2107 636 2787 +1720 2 2 4 8 657 2795 1878 +1721 2 2 4 8 1047 1878 2795 +1722 2 2 4 8 474 2820 1899 +1723 2 2 4 8 472 1898 2819 +1724 2 2 4 8 562 4851 3665 +1725 2 2 4 8 956 3642 3606 +1726 2 2 4 8 788 3315 2405 +1727 2 2 4 8 1363 2405 3315 +1728 2 2 4 8 2085 4106 1131 +1729 2 2 4 8 1520 2902 2180 +1730 2 2 4 8 1521 2901 2181 +1731 2 2 4 8 850 3238 2182 +1732 2 2 4 8 1427 3671 2803 +1733 2 2 4 8 469 1954 4524 +1734 2 2 4 8 1818 5258 2348 +1735 2 2 4 8 1819 5259 2349 +1736 2 2 4 8 561 2232 2426 +1737 2 2 4 8 682 1904 2737 +1738 2 2 4 8 332 2793 3120 +1739 2 2 4 8 1850 2847 1387 +1740 2 2 4 8 768 3344 1902 +1741 2 2 4 8 769 1903 3345 +1742 2 2 4 8 1288 3009 3019 +1743 2 2 4 8 1512 3019 3009 +1744 2 2 4 8 1307 2259 2633 +1745 2 2 4 8 842 2633 2259 +1746 2 2 4 8 1831 2481 4868 +1747 2 2 4 8 907 3061 3615 +1748 2 2 4 8 624 2582 2420 +1749 2 2 4 8 453 4450 5143 +1750 2 2 4 8 475 4961 1962 +1751 2 2 4 8 621 2363 5315 +1752 2 2 4 8 1211 2203 2720 +1753 2 2 4 8 2062 5402 2875 +1754 2 2 4 8 18 3816 2168 +1755 2 2 4 8 608 3178 2453 +1756 2 2 4 8 214 215 2925 +1757 2 2 4 8 432 433 2926 +1758 2 2 4 8 908 3062 3600 +1759 2 2 4 8 1385 1865 2846 +1760 2 2 4 8 1148 3266 1824 +1761 2 2 4 8 786 1824 3266 +1762 2 2 4 8 1149 3267 1825 +1763 2 2 4 8 785 1825 3267 +1764 2 2 4 8 2118 5016 2406 +1765 2 2 4 8 586 2255 5072 +1766 2 2 4 8 1004 1955 4113 +1767 2 2 4 8 1005 1956 4114 +1768 2 2 4 8 802 1957 4112 +1769 2 2 4 8 1560 2985 3352 +1770 2 2 4 8 1559 2984 3351 +1771 2 2 4 8 1265 1950 3644 +1772 2 2 4 8 443 3644 1950 +1773 2 2 4 8 1964 3444 4859 +1774 2 2 4 8 1532 2027 3197 +1775 2 2 4 8 2655 3996 3846 +1776 2 2 4 8 2657 3997 3845 +1777 2 2 4 8 1181 2192 3069 +1778 2 2 4 8 482 2449 3182 +1779 2 2 4 8 484 2450 3183 +1780 2 2 4 8 2494 2169 5414 +1781 2 2 4 8 2495 2170 5415 +1782 2 2 4 8 1394 2634 3990 +1783 2 2 4 8 1395 2635 3991 +1784 2 2 4 8 455 5177 1890 +1785 2 2 4 8 159 2766 5087 +1786 2 2 4 8 380 2767 5088 +1787 2 2 4 8 1032 2201 5348 +1788 2 2 4 8 1033 2199 5347 +1789 2 2 4 8 1031 2200 2588 +1790 2 2 4 8 880 2494 5414 +1791 2 2 4 8 881 2495 5415 +1792 2 2 4 8 444 2507 2246 +1793 2 2 4 8 453 2508 2247 +1794 2 2 4 8 1546 4595 2962 +1795 2 2 4 8 1887 2718 5145 +1796 2 2 4 8 1888 2719 5146 +1797 2 2 4 8 904 2002 5083 +1798 2 2 4 8 903 5082 2001 +1799 2 2 4 8 1068 2692 2120 +1800 2 2 4 8 989 2068 4264 +1801 2 2 4 8 990 2066 4265 +1802 2 2 4 8 991 4266 2067 +1803 2 2 4 8 992 4267 2069 +1804 2 2 4 8 865 3819 2209 +1805 2 2 4 8 1256 3543 2666 +1806 2 2 4 8 1554 2666 3543 +1807 2 2 4 8 498 3471 2961 +1808 2 2 4 8 791 4090 1856 +1809 2 2 4 8 790 4089 1857 +1810 2 2 4 8 665 2233 3635 +1811 2 2 4 8 2335 5062 4864 +1812 2 2 4 8 885 3627 2647 +1813 2 2 4 8 590 2634 2004 +1814 2 2 4 8 591 2635 2005 +1815 2 2 4 8 6 3977 2069 +1816 2 2 4 8 608 2497 3178 +1817 2 2 4 8 745 3827 2465 +1818 2 2 4 8 1554 2465 3827 +1819 2 2 4 8 477 2109 2594 +1820 2 2 4 8 538 3239 2078 +1821 2 2 4 8 671 4228 2150 +1822 2 2 4 8 1096 2361 2567 +1823 2 2 4 8 1097 2362 2568 +1824 2 2 4 8 447 3286 2502 +1825 2 2 4 8 1376 2502 3286 +1826 2 2 4 8 1376 3656 2632 +1827 2 2 4 8 1696 4989 2414 +1828 2 2 4 8 1979 5167 3396 +1829 2 2 4 8 1690 2416 4919 +1830 2 2 4 8 1817 2355 5257 +1831 2 2 4 8 466 1935 2816 +1832 2 2 4 8 1181 5407 2192 +1833 2 2 4 8 480 4420 4676 +1834 2 2 4 8 479 4418 4677 +1835 2 2 4 8 1499 3894 4497 +1836 2 2 4 8 1503 4387 3161 +1837 2 2 4 8 1426 3691 2804 +1838 2 2 4 8 1567 1921 4355 +1839 2 2 4 8 1308 2639 2168 +1840 2 2 4 8 658 1912 3914 +1841 2 2 4 8 1337 4083 1862 +1842 2 2 4 8 957 4026 1850 +1843 2 2 4 8 1102 5183 2028 +1844 2 2 4 8 677 3611 4099 +1845 2 2 4 8 868 2726 2074 +1846 2 2 4 8 2124 2668 5261 +1847 2 2 4 8 2126 2667 5260 +1848 2 2 4 8 2255 4880 5072 +1849 2 2 4 8 1023 2765 3947 +1850 2 2 4 8 320 3225 1787 +1851 2 2 4 8 1182 3101 4018 +1852 2 2 4 8 1641 4552 3735 +1853 2 2 4 8 2106 993 2992 +1854 2 2 4 8 654 2293 2950 +1855 2 2 4 8 1259 2652 2678 +1856 2 2 4 8 647 2678 2652 +1857 2 2 4 8 706 3011 1885 +1858 2 2 4 8 707 3012 1886 +1859 2 2 4 8 877 2012 5340 +1860 2 2 4 8 878 2013 5341 +1861 2 2 4 8 419 420 3465 +1862 2 2 4 8 813 2624 2194 +1863 2 2 4 8 941 4781 2475 +1864 2 2 4 8 1866 2475 4781 +1865 2 2 4 8 10 3041 2155 +1866 2 2 4 8 1686 2137 4840 +1867 2 2 4 8 833 4840 2137 +1868 2 2 4 8 1031 5026 2058 +1869 2 2 4 8 1032 2057 5024 +1870 2 2 4 8 1033 2059 5025 +1871 2 2 4 8 189 2159 3970 +1872 2 2 4 8 1066 2471 2929 +1873 2 2 4 8 716 1849 4248 +1874 2 2 4 8 850 2254 3238 +1875 2 2 4 8 645 2952 1884 +1876 2 2 4 8 1082 1884 2952 +1877 2 2 4 8 1881 2813 1057 +1878 2 2 4 8 1058 2814 1882 +1879 2 2 4 8 1059 1883 2815 +1880 2 2 4 8 773 2163 3651 +1881 2 2 4 8 1836 2409 4841 +1882 2 2 4 8 870 4841 2409 +1883 2 2 4 8 1407 3139 3635 +1884 2 2 4 8 692 1829 2964 +1885 2 2 4 8 1085 2731 2125 +1886 2 2 4 8 925 3480 2499 +1887 2 2 4 8 949 4484 1999 +1888 2 2 4 8 2061 1123 4842 +1889 2 2 4 8 246 247 2250 +1890 2 2 4 8 251 252 2249 +1891 2 2 4 8 1624 3810 3930 +1892 2 2 4 8 663 2729 2671 +1893 2 2 4 8 1247 2671 2729 +1894 2 2 4 8 540 3170 3200 +1895 2 2 4 8 1671 3200 3170 +1896 2 2 4 8 1670 3169 3201 +1897 2 2 4 8 539 3201 3169 +1898 2 2 4 8 1338 2472 2791 +1899 2 2 4 8 931 1817 3797 +1900 2 2 4 8 930 1816 3798 +1901 2 2 4 8 934 3800 1820 +1902 2 2 4 8 935 3799 1821 +1903 2 2 4 8 2504 4846 1839 +1904 2 2 4 8 2505 4845 1840 +1905 2 2 4 8 1076 2552 2255 +1906 2 2 4 8 911 2255 2552 +1907 2 2 4 8 1516 4314 4555 +1908 2 2 4 8 1691 4850 2136 +1909 2 2 4 8 838 2136 4850 +1910 2 2 4 8 464 5360 2135 +1911 2 2 4 8 628 2308 4507 +1912 2 2 4 8 1187 4030 3185 +1913 2 2 4 8 1152 5041 4386 +1914 2 2 4 8 967 2154 3743 +1915 2 2 4 8 909 2335 4864 +1916 2 2 4 8 1176 5015 1916 +1917 2 2 4 8 451 3354 1957 +1918 2 2 4 8 196 197 2623 +1919 2 2 4 8 1009 3312 2039 +1920 2 2 4 8 455 1890 2821 +1921 2 2 4 8 1049 2821 1890 +1922 2 2 4 8 655 2395 3224 +1923 2 2 4 8 894 2501 2500 +1924 2 2 4 8 1336 2500 2501 +1925 2 2 4 8 943 3368 2509 +1926 2 2 4 8 944 3367 2510 +1927 2 2 4 8 476 1917 2881 +1928 2 2 4 8 1581 3676 3208 +1929 2 2 4 8 640 2520 3499 +1930 2 2 4 8 825 4158 1877 +1931 2 2 4 8 1287 1947 2885 +1932 2 2 4 8 1752 3372 2945 +1933 2 2 4 8 1753 2946 3373 +1934 2 2 4 8 1016 2025 3298 +1935 2 2 4 8 1015 2026 3299 +1936 2 2 4 8 864 2211 3738 +1937 2 2 4 8 863 2210 3737 +1938 2 2 4 8 70 2133 3131 +1939 2 2 4 8 212 2261 4024 +1940 2 2 4 8 430 2260 4023 +1941 2 2 4 8 494 2167 2681 +1942 2 2 4 8 845 3749 2619 +1943 2 2 4 8 1587 2619 3749 +1944 2 2 4 8 2145 3280 696 +1945 2 2 4 8 196 2623 3452 +1946 2 2 4 8 1876 2696 4406 +1947 2 2 4 8 703 3259 2608 +1948 2 2 4 8 450 4473 3355 +1949 2 2 4 8 442 4475 3356 +1950 2 2 4 8 2214 4518 3621 +1951 2 2 4 8 2215 4519 3622 +1952 2 2 4 8 1389 2657 3340 +1953 2 2 4 8 518 2655 3846 +1954 2 2 4 8 1186 2014 3411 +1955 2 2 4 8 787 2075 2838 +1956 2 2 4 8 520 2657 3845 +1957 2 2 4 8 1955 3355 4473 +1958 2 2 4 8 1956 3356 4475 +1959 2 2 4 8 971 3608 2144 +1960 2 2 4 8 956 3606 4977 +1961 2 2 4 8 944 4399 3481 +1962 2 2 4 8 1463 3785 2556 +1963 2 2 4 8 1461 3784 2554 +1964 2 2 4 8 571 2470 4261 +1965 2 2 4 8 942 3974 1822 +1966 2 2 4 8 639 3072 3281 +1967 2 2 4 8 968 2152 2548 +1968 2 2 4 8 2027 4290 3197 +1969 2 2 4 8 949 2399 4106 +1970 2 2 4 8 1936 2656 3848 +1971 2 2 4 8 829 2240 3686 +1972 2 2 4 8 1697 4236 2666 +1973 2 2 4 8 1281 3187 2375 +1974 2 2 4 8 989 2375 3187 +1975 2 2 4 8 1894 3249 5224 +1976 2 2 4 8 1579 3889 2799 +1977 2 2 4 8 188 1926 3332 +1978 2 2 4 8 1409 2804 3637 +1979 2 2 4 8 1410 2803 3638 +1980 2 2 4 8 1147 3751 1823 +1981 2 2 4 8 1151 3364 1795 +1982 2 2 4 8 2192 5407 2691 +1983 2 2 4 8 2510 4506 4399 +1984 2 2 4 8 1130 3512 1800 +1985 2 2 4 8 657 3492 2813 +1986 2 2 4 8 1821 5260 2369 +1987 2 2 4 8 1820 5261 2368 +1988 2 2 4 8 1291 3978 2534 +1989 2 2 4 8 911 2552 2166 +1990 2 2 4 8 1262 2704 4085 +1991 2 2 4 8 3040 1766 3716 +1992 2 2 4 8 674 1798 3213 +1993 2 2 4 8 673 1799 3212 +1994 2 2 4 8 1689 4881 2400 +1995 2 2 4 8 397 2590 4921 +1996 2 2 4 8 467 1848 3883 +1997 2 2 4 8 2202 3948 3776 +1998 2 2 4 8 1601 4501 3746 +1999 2 2 4 8 1938 3864 2817 +2000 2 2 4 8 1939 3865 2818 +2001 2 2 4 8 573 5261 2668 +2002 2 2 4 8 574 5260 2667 +2003 2 2 4 8 1399 2784 1961 +2004 2 2 4 8 1736 3185 4030 +2005 2 2 4 8 202 203 3129 +2006 2 2 4 8 224 225 3130 +2007 2 2 4 8 991 3130 1934 +2008 2 2 4 8 990 1933 3129 +2009 2 2 4 8 1247 4443 4697 +2010 2 2 4 8 488 1800 3512 +2011 2 2 4 8 1526 4380 2230 +2012 2 2 4 8 1525 4381 2229 +2013 2 2 4 8 1524 2228 4382 +2014 2 2 4 8 1523 2227 4383 +2015 2 2 4 8 1522 2226 4384 +2016 2 2 4 8 684 1844 3857 +2017 2 2 4 8 685 3859 1845 +2018 2 2 4 8 686 3858 1846 +2019 2 2 4 8 687 3860 1847 +2020 2 2 4 8 904 2523 4103 +2021 2 2 4 8 1168 2737 2978 +2022 2 2 4 8 1472 4652 3647 +2023 2 2 4 8 1042 3395 2221 +2024 2 2 4 8 657 3553 2243 +2025 2 2 4 8 658 2244 3554 +2026 2 2 4 8 659 3555 2245 +2027 2 2 4 8 1045 2246 2507 +2028 2 2 4 8 1046 2247 2508 +2029 2 2 4 8 1143 2479 2276 +2030 2 2 4 8 1144 2277 2480 +2031 2 2 4 8 1666 3655 4985 +2032 2 2 4 8 1262 4085 3199 +2033 2 2 4 8 625 4653 2849 +2034 2 2 4 8 944 2510 4399 +2035 2 2 4 8 2145 3292 2763 +2036 2 2 4 8 861 2919 2480 +2037 2 2 4 8 998 2221 3820 +2038 2 2 4 8 998 3937 2189 +2039 2 2 4 8 1833 4376 4442 +2040 2 2 4 8 1960 5126 2364 +2041 2 2 4 8 188 3970 1926 +2042 2 2 4 8 2109 1106 2594 +2043 2 2 4 8 1009 3157 2258 +2044 2 2 4 8 1428 2160 4610 +2045 2 2 4 8 1429 4609 2161 +2046 2 2 4 8 1674 3646 2584 +2047 2 2 4 8 986 2886 2476 +2048 2 2 4 8 840 4314 2023 +2049 2 2 4 8 1134 4650 1822 +2050 2 2 4 8 565 3575 2876 +2051 2 2 4 8 1647 2876 3575 +2052 2 2 4 8 1695 3331 5314 +2053 2 2 4 8 998 2054 3607 +2054 2 2 4 8 477 2594 2223 +2055 2 2 4 8 659 3488 2815 +2056 2 2 4 8 552 2027 4505 +2057 2 2 4 8 1532 4505 2027 +2058 2 2 4 8 667 2993 2488 +2059 2 2 4 8 1239 2214 3621 +2060 2 2 4 8 1242 2215 3622 +2061 2 2 4 8 1060 2000 4678 +2062 2 2 4 8 1024 2816 1935 +2063 2 2 4 8 1694 4018 3101 +2064 2 2 4 8 456 1919 5394 +2065 2 2 4 8 733 2880 4194 +2066 2 2 4 8 1041 3172 1813 +2067 2 2 4 8 1040 3173 1814 +2068 2 2 4 8 250 1968 4169 +2069 2 2 4 8 843 1938 2817 +2070 2 2 4 8 844 1939 2818 +2071 2 2 4 8 1081 2681 2167 +2072 2 2 4 8 588 1810 3736 +2073 2 2 4 8 1004 4113 4243 +2074 2 2 4 8 1005 4114 4245 +2075 2 2 4 8 1037 3438 1885 +2076 2 2 4 8 1038 3437 1886 +2077 2 2 4 8 1134 1822 4410 +2078 2 2 4 8 1850 4026 2847 +2079 2 2 4 8 527 2973 2492 +2080 2 2 4 8 454 3964 1862 +2081 2 2 4 8 839 3420 1807 +2082 2 2 4 8 2020 3936 2529 +2083 2 2 4 8 705 2603 4282 +2084 2 2 4 8 976 2570 4102 +2085 2 2 4 8 1255 2415 2845 +2086 2 2 4 8 646 2241 2739 +2087 2 2 4 8 1007 4945 2281 +2088 2 2 4 8 1008 4946 2282 +2089 2 2 4 8 1042 2040 5310 +2090 2 2 4 8 1023 4338 2050 +2091 2 2 4 8 570 2348 5258 +2092 2 2 4 8 572 2349 5259 +2093 2 2 4 8 2847 4026 1323 +2094 2 2 4 8 644 2680 3374 +2095 2 2 4 8 677 2780 2493 +2096 2 2 4 8 1199 2493 2780 +2097 2 2 4 8 1779 3305 5120 +2098 2 2 4 8 2617 4895 4322 +2099 2 2 4 8 747 3262 1810 +2100 2 2 4 8 2281 4945 3965 +2101 2 2 4 8 2282 4946 3966 +2102 2 2 4 8 912 5060 2373 +2103 2 2 4 8 3492 3933 2813 +2104 2 2 4 8 1893 5225 3121 +2105 2 2 4 8 1892 5223 3122 +2106 2 2 4 8 108 2323 107 +2107 2 2 4 8 782 3793 1839 +2108 2 2 4 8 783 3794 1840 +2109 2 2 4 8 3069 2192 4916 +2110 2 2 4 8 932 3567 1818 +2111 2 2 4 8 933 3566 1819 +2112 2 2 4 8 1487 3829 2827 +2113 2 2 4 8 1490 3828 2828 +2114 2 2 4 8 642 2831 2024 +2115 2 2 4 8 1425 2662 3771 +2116 2 2 4 8 650 2180 2902 +2117 2 2 4 8 648 2181 2901 +2118 2 2 4 8 2108 2620 4938 +2119 2 2 4 8 515 4260 2874 +2120 2 2 4 8 2108 1225 2620 +2121 2 2 4 8 940 2734 3540 +2122 2 2 4 8 637 2578 3733 +2123 2 2 4 8 638 3732 2579 +2124 2 2 4 8 635 5352 3679 +2125 2 2 4 8 475 1962 4397 +2126 2 2 4 8 1281 3588 2288 +2127 2 2 4 8 1282 3589 2289 +2128 2 2 4 8 1283 2290 3590 +2129 2 2 4 8 1284 2291 3591 +2130 2 2 4 8 807 4795 2156 +2131 2 2 4 8 1661 2156 4795 +2132 2 2 4 8 1662 2157 4796 +2133 2 2 4 8 808 4796 2157 +2134 2 2 4 8 1160 2945 3372 +2135 2 2 4 8 1161 3373 2946 +2136 2 2 4 8 2145 696 5326 +2137 2 2 4 8 1859 5414 2169 +2138 2 2 4 8 1860 5415 2170 +2139 2 2 4 8 1858 5416 2171 +2140 2 2 4 8 247 2661 2250 +2141 2 2 4 8 1245 3338 2275 +2142 2 2 4 8 1875 2874 4260 +2143 2 2 4 8 1849 1206 3054 +2144 2 2 4 8 980 3432 2425 +2145 2 2 4 8 1321 4028 1897 +2146 2 2 4 8 675 1897 4028 +2147 2 2 4 8 705 4282 3727 +2148 2 2 4 8 2538 3795 2915 +2149 2 2 4 8 911 4775 2032 +2150 2 2 4 8 1881 1057 3575 +2151 2 2 4 8 1058 1882 3577 +2152 2 2 4 8 1059 3576 1883 +2153 2 2 4 8 1748 5205 3807 +2154 2 2 4 8 1749 5206 3808 +2155 2 2 4 8 1345 1981 2786 +2156 2 2 4 8 927 3733 1864 +2157 2 2 4 8 928 1863 3732 +2158 2 2 4 8 2632 4097 3872 +2159 2 2 4 8 1040 2037 2706 +2160 2 2 4 8 1041 2038 2707 +2161 2 2 4 8 992 2069 3977 +2162 2 2 4 8 2864 990 4350 +2163 2 2 4 8 991 2863 4351 +2164 2 2 4 8 704 4671 1879 +2165 2 2 4 8 1066 1968 3282 +2166 2 2 4 8 333 1987 2793 +2167 2 2 4 8 1613 3788 3050 +2168 2 2 4 8 773 1867 3939 +2169 2 2 4 8 1221 1994 4032 +2170 2 2 4 8 1491 3839 2824 +2171 2 2 4 8 2826 1488 3841 +2172 2 2 4 8 2825 1489 3840 +2173 2 2 4 8 902 3931 3396 +2174 2 2 4 8 904 5083 2176 +2175 2 2 4 8 903 2177 5082 +2176 2 2 4 8 1785 4392 3309 +2177 2 2 4 8 54 55 2688 +2178 2 2 4 8 275 276 2689 +2179 2 2 4 8 494 2681 2756 +2180 2 2 4 8 1247 2756 2681 +2181 2 2 4 8 566 5257 2355 +2182 2 2 4 8 726 3941 2798 +2183 2 2 4 8 170 3149 2142 +2184 2 2 4 8 357 3150 2141 +2185 2 2 4 8 473 4311 1949 +2186 2 2 4 8 1610 4942 3786 +2187 2 2 4 8 912 2165 4237 +2188 2 2 4 8 1118 3658 1831 +2189 2 2 4 8 784 1823 3751 +2190 2 2 4 8 866 3729 2486 +2191 2 2 4 8 19 2208 3816 +2192 2 2 4 8 846 3232 2421 +2193 2 2 4 8 1304 2421 3232 +2194 2 2 4 8 2015 4977 3606 +2195 2 2 4 8 756 2113 2629 +2196 2 2 4 8 621 1928 2872 +2197 2 2 4 8 1009 2133 3312 +2198 2 2 4 8 2534 3978 3587 +2199 2 2 4 8 490 2666 4236 +2200 2 2 4 8 859 2696 4595 +2201 2 2 4 8 1919 4595 2696 +2202 2 2 4 8 1316 2567 3135 +2203 2 2 4 8 460 3135 2567 +2204 2 2 4 8 461 3137 2568 +2205 2 2 4 8 1317 2568 3137 +2206 2 2 4 8 2748 4099 3810 +2207 2 2 4 8 1074 2081 5250 +2208 2 2 4 8 516 2789 4481 +2209 2 2 4 8 615 3333 2446 +2210 2 2 4 8 2108 4001 1418 +2211 2 2 4 8 761 4001 2108 +2212 2 2 4 8 2815 3488 3952 +2213 2 2 4 8 782 1839 3669 +2214 2 2 4 8 783 1840 3670 +2215 2 2 4 8 1122 3707 3635 +2216 2 2 4 8 1804 4318 5138 +2217 2 2 4 8 2088 1012 3286 +2218 2 2 4 8 1798 2751 4774 +2219 2 2 4 8 1799 2752 4773 +2220 2 2 4 8 640 2299 2606 +2221 2 2 4 8 1094 2606 2299 +2222 2 2 4 8 2076 4634 845 +2223 2 2 4 8 1921 4481 2789 +2224 2 2 4 8 521 3001 4415 +2225 2 2 4 8 1052 2481 5138 +2226 2 2 4 8 1022 2328 3032 +2227 2 2 4 8 1043 2782 2176 +2228 2 2 4 8 1044 2177 2783 +2229 2 2 4 8 36 3080 1880 +2230 2 2 4 8 1880 3080 1169 +2231 2 2 4 8 1009 2346 3157 +2232 2 2 4 8 534 4368 1961 +2233 2 2 4 8 1209 4405 1887 +2234 2 2 4 8 1208 4404 1888 +2235 2 2 4 8 764 3604 1834 +2236 2 2 4 8 1203 1872 3510 +2237 2 2 4 8 596 3510 1872 +2238 2 2 4 8 1205 1873 3511 +2239 2 2 4 8 598 3511 1873 +2240 2 2 4 8 579 2588 2200 +2241 2 2 4 8 565 2074 4997 +2242 2 2 4 8 410 1984 3366 +2243 2 2 4 8 598 2607 2216 +2244 2 2 4 8 1439 3000 2039 +2245 2 2 4 8 1329 2503 3515 +2246 2 2 4 8 2082 1188 3477 +2247 2 2 4 8 2088 5104 1012 +2248 2 2 4 8 2079 1125 3955 +2249 2 2 4 8 2080 1124 3954 +2250 2 2 4 8 832 1945 2862 +2251 2 2 4 8 2095 1196 4255 +2252 2 2 4 8 1495 3656 3813 +2253 2 2 4 8 1338 2791 3623 +2254 2 2 4 8 1132 3973 1876 +2255 2 2 4 8 1028 3918 2384 +2256 2 2 4 8 1029 2385 3919 +2257 2 2 4 8 2735 4662 5029 +2258 2 2 4 8 1619 3654 2422 +2259 2 2 4 8 1618 3653 2423 +2260 2 2 4 8 1424 3218 1995 +2261 2 2 4 8 868 2241 2726 +2262 2 2 4 8 1287 2885 2738 +2263 2 2 4 8 510 2738 2885 +2264 2 2 4 8 2653 4354 5150 +2265 2 2 4 8 2684 4444 2835 +2266 2 2 4 8 2683 2836 4445 +2267 2 2 4 8 583 3726 2188 +2268 2 2 4 8 720 2653 5150 +2269 2 2 4 8 1809 4517 2774 +2270 2 2 4 8 1125 3669 1839 +2271 2 2 4 8 1124 3670 1840 +2272 2 2 4 8 1729 3150 4729 +2273 2 2 4 8 1728 3149 4730 +2274 2 2 4 8 1638 4500 2555 +2275 2 2 4 8 1639 2556 4499 +2276 2 2 4 8 1414 4260 2525 +2277 2 2 4 8 681 3911 2434 +2278 2 2 4 8 1320 4029 3213 +2279 2 2 4 8 1319 4027 3212 +2280 2 2 4 8 152 2718 151 +2281 2 2 4 8 372 373 2719 +2282 2 2 4 8 1061 5370 2148 +2283 2 2 4 8 1062 5371 2149 +2284 2 2 4 8 885 5372 2150 +2285 2 2 4 8 886 5373 2151 +2286 2 2 4 8 397 398 2590 +2287 2 2 4 8 1016 2755 2025 +2288 2 2 4 8 1015 2754 2026 +2289 2 2 4 8 2825 3789 1469 +2290 2 2 4 8 1468 2826 3790 +2291 2 2 4 8 1467 2827 3788 +2292 2 2 4 8 1920 4415 3001 +2293 2 2 4 8 588 4678 2000 +2294 2 2 4 8 2399 2892 4106 +2295 2 2 4 8 644 3374 3155 +2296 2 2 4 8 475 2174 4961 +2297 2 2 4 8 2119 2775 3303 +2298 2 2 4 8 1167 2927 2049 +2299 2 2 4 8 1039 4627 2034 +2300 2 2 4 8 658 2814 3525 +2301 2 2 4 8 1016 3298 2141 +2302 2 2 4 8 1015 3299 2142 +2303 2 2 4 8 1076 2303 5207 +2304 2 2 4 8 520 3340 2657 +2305 2 2 4 8 575 3741 2252 +2306 2 2 4 8 571 3704 2253 +2307 2 2 4 8 1597 3999 2768 +2308 2 2 4 8 1413 4082 2423 +2309 2 2 4 8 1412 4081 2422 +2310 2 2 4 8 559 2316 2734 +2311 2 2 4 8 1687 5016 2403 +2312 2 2 4 8 655 3224 2662 +2313 2 2 4 8 340 4357 2347 +2314 2 2 4 8 1160 1934 4055 +2315 2 2 4 8 1161 4054 1933 +2316 2 2 4 8 1935 3507 4806 +2317 2 2 4 8 1971 2672 3855 +2318 2 2 4 8 1229 2960 3615 +2319 2 2 4 8 1675 3615 2960 +2320 2 2 4 8 708 3392 2034 +2321 2 2 4 8 989 4264 2375 +2322 2 2 4 8 990 4265 2376 +2323 2 2 4 8 991 2377 4266 +2324 2 2 4 8 992 2378 4267 +2325 2 2 4 8 1628 3936 2625 +2326 2 2 4 8 792 2625 3936 +2327 2 2 4 8 2003 3328 1201 +2328 2 2 4 8 614 3328 2003 +2329 2 2 4 8 1550 2807 3394 +2330 2 2 4 8 891 1954 2878 +2331 2 2 4 8 1042 4349 2040 +2332 2 2 4 8 1234 3896 3529 +2333 2 2 4 8 1235 3530 3897 +2334 2 2 4 8 619 1836 3431 +2335 2 2 4 8 899 3148 2823 +2336 2 2 4 8 1072 4003 1994 +2337 2 2 4 8 26 27 2425 +2338 2 2 4 8 2096 1118 3960 +2339 2 2 4 8 868 2676 4276 +2340 2 2 4 8 1037 1885 3011 +2341 2 2 4 8 1038 1886 3012 +2342 2 2 4 8 1462 3786 2910 +2343 2 2 4 8 1061 2184 5370 +2344 2 2 4 8 1062 2185 5371 +2345 2 2 4 8 885 2186 5372 +2346 2 2 4 8 886 2187 5373 +2347 2 2 4 8 703 3641 3407 +2348 2 2 4 8 574 2369 5260 +2349 2 2 4 8 573 2368 5261 +2350 2 2 4 8 886 4400 3126 +2351 2 2 4 8 734 4131 2555 +2352 2 2 4 8 526 2217 2968 +2353 2 2 4 8 1055 1980 2841 +2354 2 2 4 8 75 2383 74 +2355 2 2 4 8 1055 2953 1980 +2356 2 2 4 8 938 2275 2948 +2357 2 2 4 8 1363 3708 2842 +2358 2 2 4 8 408 1994 4003 +2359 2 2 4 8 228 229 2455 +2360 2 2 4 8 198 199 2456 +2361 2 2 4 8 1210 1843 4620 +2362 2 2 4 8 1173 1856 4090 +2363 2 2 4 8 1172 1857 4089 +2364 2 2 4 8 1075 1904 3042 +2365 2 2 4 8 460 2271 3135 +2366 2 2 4 8 1239 3135 2271 +2367 2 2 4 8 781 3904 2849 +2368 2 2 4 8 1056 4662 2735 +2369 2 2 4 8 1075 2991 1904 +2370 2 2 4 8 33 2328 32 +2371 2 2 4 8 1425 2485 4553 +2372 2 2 4 8 767 4424 1873 +2373 2 2 4 8 766 4423 1872 +2374 2 2 4 8 1627 3851 3104 +2375 2 2 4 8 1412 3654 2909 +2376 2 2 4 8 1013 2980 2138 +2377 2 2 4 8 919 2875 1961 +2378 2 2 4 8 1135 2879 1962 +2379 2 2 4 8 2062 4466 1199 +2380 2 2 4 8 1607 3638 2888 +2381 2 2 4 8 1036 3008 2098 +2382 2 2 4 8 1856 2766 4199 +2383 2 2 4 8 1857 2767 4198 +2384 2 2 4 8 1070 2168 2639 +2385 2 2 4 8 487 2486 3763 +2386 2 2 4 8 1117 2745 4511 +2387 2 2 4 8 578 2490 3151 +2388 2 2 4 8 1849 3386 1206 +2389 2 2 4 8 1849 1295 3752 +2390 2 2 4 8 2184 2969 4034 +2391 2 2 4 8 1121 2734 2316 +2392 2 2 4 8 622 2418 2645 +2393 2 2 4 8 623 2646 2419 +2394 2 2 4 8 587 2512 3175 +2395 2 2 4 8 582 2511 3174 +2396 2 2 4 8 481 1851 3179 +2397 2 2 4 8 470 3180 1854 +2398 2 2 4 8 1081 2183 2671 +2399 2 2 4 8 663 2671 2183 +2400 2 2 4 8 998 3607 4203 +2401 2 2 4 8 1082 3430 1884 +2402 2 2 4 8 88 4379 2014 +2403 2 2 4 8 1550 3394 5022 +2404 2 2 4 8 1685 4880 2374 +2405 2 2 4 8 525 1867 3780 +2406 2 2 4 8 1204 1871 3547 +2407 2 2 4 8 597 3547 1871 +2408 2 2 4 8 1195 3831 1905 +2409 2 2 4 8 888 4313 2872 +2410 2 2 4 8 1856 5087 2766 +2411 2 2 4 8 1857 5088 2767 +2412 2 2 4 8 679 2962 2674 +2413 2 2 4 8 1275 2674 2962 +2414 2 2 4 8 878 5341 2339 +2415 2 2 4 8 877 5340 2338 +2416 2 2 4 8 596 2457 5390 +2417 2 2 4 8 1687 2403 5069 +2418 2 2 4 8 1061 2148 3573 +2419 2 2 4 8 1062 2149 3574 +2420 2 2 4 8 1145 2762 2430 +2421 2 2 4 8 1151 3361 1855 +2422 2 2 4 8 608 1855 3361 +2423 2 2 4 8 1073 1896 3025 +2424 2 2 4 8 1764 2464 4344 +2425 2 2 4 8 2147 1441 4619 +2426 2 2 4 8 1074 5250 2195 +2427 2 2 4 8 627 2915 1960 +2428 2 2 4 8 2065 2750 4318 +2429 2 2 4 8 1151 1855 3364 +2430 2 2 4 8 1549 4597 3634 +2431 2 2 4 8 2125 2731 5259 +2432 2 2 4 8 494 5105 2167 +2433 2 2 4 8 1915 3231 5233 +2434 2 2 4 8 588 2044 4678 +2435 2 2 4 8 981 2774 4517 +2436 2 2 4 8 555 4728 2036 +2437 2 2 4 8 965 2615 3847 +2438 2 2 4 8 952 4042 1866 +2439 2 2 4 8 1201 3406 2266 +2440 2 2 4 8 481 4447 1991 +2441 2 2 4 8 1231 2954 3600 +2442 2 2 4 8 1664 3600 2954 +2443 2 2 4 8 3039 3796 2028 +2444 2 2 4 8 684 1947 3057 +2445 2 2 4 8 1789 3679 5352 +2446 2 2 4 8 192 2948 2275 +2447 2 2 4 8 2503 4530 3515 +2448 2 2 4 8 1520 2180 4472 +2449 2 2 4 8 1521 2181 4474 +2450 2 2 4 8 1832 3481 4399 +2451 2 2 4 8 2008 4386 5041 +2452 2 2 4 8 2465 4153 2725 +2453 2 2 4 8 250 3282 1968 +2454 2 2 4 8 1128 2491 2831 +2455 2 2 4 8 997 2587 2913 +2456 2 2 4 8 99 100 2442 +2457 2 2 4 8 646 2911 2241 +2458 2 2 4 8 2241 2911 1153 +2459 2 2 4 8 1039 2171 4622 +2460 2 2 4 8 600 2785 2156 +2461 2 2 4 8 1348 3319 2535 +2462 2 2 4 8 673 2535 3319 +2463 2 2 4 8 674 2536 3321 +2464 2 2 4 8 1350 3321 2536 +2465 2 2 4 8 675 2537 3320 +2466 2 2 4 8 1349 3320 2537 +2467 2 2 4 8 1940 3148 5230 +2468 2 2 4 8 1326 3051 3049 +2469 2 2 4 8 2075 4686 2838 +2470 2 2 4 8 1561 3278 2981 +2471 2 2 4 8 709 2981 3278 +2472 2 2 4 8 1123 2913 2000 +2473 2 2 4 8 456 5211 1919 +2474 2 2 4 8 2814 3934 3525 +2475 2 2 4 8 1777 3304 4616 +2476 2 2 4 8 1614 3790 3059 +2477 2 2 4 8 1615 3789 3058 +2478 2 2 4 8 715 2534 3066 +2479 2 2 4 8 470 1988 4482 +2480 2 2 4 8 1151 4017 4656 +2481 2 2 4 8 1224 2046 4038 +2482 2 2 4 8 1458 4121 3770 +2483 2 2 4 8 560 2102 5067 +2484 2 2 4 8 1080 2020 5027 +2485 2 2 4 8 657 2243 3552 +2486 2 2 4 8 659 2245 3551 +2487 2 2 4 8 680 2101 2764 +2488 2 2 4 8 1660 2143 4949 +2489 2 2 4 8 811 4949 2143 +2490 2 2 4 8 1076 5207 2552 +2491 2 2 4 8 1647 2460 4499 +2492 2 2 4 8 1648 4500 2459 +2493 2 2 4 8 580 4606 2175 +2494 2 2 4 8 1063 3250 5372 +2495 2 2 4 8 1064 3251 5373 +2496 2 2 4 8 682 3042 1904 +2497 2 2 4 8 1605 2896 3524 +2498 2 2 4 8 167 168 4224 +2499 2 2 4 8 354 355 4223 +2500 2 2 4 8 2019 3274 5383 +2501 2 2 4 8 985 4418 1990 +2502 2 2 4 8 987 4419 1991 +2503 2 2 4 8 986 4420 1989 +2504 2 2 4 8 984 1988 4417 +2505 2 2 4 8 1399 1961 4368 +2506 2 2 4 8 2516 2028 5183 +2507 2 2 4 8 1088 2749 4040 +2508 2 2 4 8 1066 2929 1968 +2509 2 2 4 8 239 3401 4605 +2510 2 2 4 8 1765 2428 4187 +2511 2 2 4 8 4443 1891 4697 +2512 2 2 4 8 1271 2179 3645 +2513 2 2 4 8 2150 4228 3627 +2514 2 2 4 8 1047 2248 4613 +2515 2 2 4 8 1036 2098 5023 +2516 2 2 4 8 206 2376 4265 +2517 2 2 4 8 423 2375 4264 +2518 2 2 4 8 221 4266 2377 +2519 2 2 4 8 439 4267 2378 +2520 2 2 4 8 1049 5210 1865 +2521 2 2 4 8 883 5370 2184 +2522 2 2 4 8 1064 5373 2187 +2523 2 2 4 8 2209 3819 5096 +2524 2 2 4 8 1870 2452 4613 +2525 2 2 4 8 1278 2802 2846 +2526 2 2 4 8 511 2846 2802 +2527 2 2 4 8 114 2717 113 +2528 2 2 4 8 124 125 2716 +2529 2 2 4 8 135 136 2715 +2530 2 2 4 8 180 181 2714 +2531 2 2 4 8 291 292 2712 +2532 2 2 4 8 302 303 2713 +2533 2 2 4 8 969 2153 2691 +2534 2 2 4 8 1416 2474 3595 +2535 2 2 4 8 496 3595 2474 +2536 2 2 4 8 21 4091 3518 +2537 2 2 4 8 1274 3776 3948 +2538 2 2 4 8 728 3524 2896 +2539 2 2 4 8 589 4989 4681 +2540 2 2 4 8 541 3171 3337 +2541 2 2 4 8 1672 3337 3171 +2542 2 2 4 8 868 2074 4920 +2543 2 2 4 8 499 2560 3421 +2544 2 2 4 8 1391 3421 2560 +2545 2 2 4 8 1392 3424 2561 +2546 2 2 4 8 501 2561 3424 +2547 2 2 4 8 452 2966 4705 +2548 2 2 4 8 897 2584 3646 +2549 2 2 4 8 917 1917 3048 +2550 2 2 4 8 487 2515 3003 +2551 2 2 4 8 2515 1579 3003 +2552 2 2 4 8 1712 2562 3540 +2553 2 2 4 8 1074 2195 2894 +2554 2 2 4 8 989 3465 2068 +2555 2 2 4 8 1023 2050 3079 +2556 2 2 4 8 2026 2754 4452 +2557 2 2 4 8 2755 4451 2025 +2558 2 2 4 8 730 2888 3638 +2559 2 2 4 8 1125 4440 3955 +2560 2 2 4 8 988 4105 5234 +2561 2 2 4 8 1042 2517 3395 +2562 2 2 4 8 922 2518 3507 +2563 2 2 4 8 1088 4040 5401 +2564 2 2 4 8 1508 2800 4243 +2565 2 2 4 8 1507 2801 4245 +2566 2 2 4 8 544 2082 2763 +2567 2 2 4 8 165 166 2411 +2568 2 2 4 8 352 353 2412 +2569 2 2 4 8 1145 2404 2762 +2570 2 2 4 8 910 2762 2404 +2571 2 2 4 8 966 2613 4700 +2572 2 2 4 8 2055 5405 5167 +2573 2 2 4 8 1388 3339 2612 +2574 2 2 4 8 517 2612 3339 +2575 2 2 4 8 211 212 4024 +2576 2 2 4 8 429 430 4023 +2577 2 2 4 8 811 1897 4396 +2578 2 2 4 8 2061 4842 2614 +2579 2 2 4 8 626 2089 2934 +2580 2 2 4 8 1653 3514 3657 +2581 2 2 4 8 1145 2430 2920 +2582 2 2 4 8 557 2011 4558 +2583 2 2 4 8 254 3446 4813 +2584 2 2 4 8 988 2280 4105 +2585 2 2 4 8 2960 3676 5209 +2586 2 2 4 8 1965 4043 2400 +2587 2 2 4 8 421 4884 2068 +2588 2 2 4 8 6 2069 4885 +2589 2 2 4 8 2265 2733 4191 +2590 2 2 4 8 1128 2621 2491 +2591 2 2 4 8 493 2491 2621 +2592 2 2 4 8 1294 4436 3403 +2593 2 2 4 8 1296 2353 3821 +2594 2 2 4 8 2150 5372 3250 +2595 2 2 4 8 2151 5373 3251 +2596 2 2 4 8 846 1876 3973 +2597 2 2 4 8 1801 4286 2870 +2598 2 2 4 8 343 2138 2980 +2599 2 2 4 8 2106 2748 993 +2600 2 2 4 8 2101 1067 2764 +2601 2 2 4 8 1679 4276 2676 +2602 2 2 4 8 549 2169 3269 +2603 2 2 4 8 550 2170 3270 +2604 2 2 4 8 1211 4078 1869 +2605 2 2 4 8 1067 2389 2764 +2606 2 2 4 8 1408 2764 2389 +2607 2 2 4 8 990 3129 2066 +2608 2 2 4 8 991 2067 3130 +2609 2 2 4 8 572 5259 2731 +2610 2 2 4 8 998 4203 3937 +2611 2 2 4 8 929 2632 3872 +2612 2 2 4 8 1941 3763 4172 +2613 2 2 4 8 1221 4300 2595 +2614 2 2 4 8 664 1980 2953 +2615 2 2 4 8 898 3969 1890 +2616 2 2 4 8 497 3053 1931 +2617 2 2 4 8 1326 5319 2350 +2618 2 2 4 8 141 4071 2132 +2619 2 2 4 8 362 4072 2131 +2620 2 2 4 8 2095 3465 989 +2621 2 2 4 8 406 407 2636 +2622 2 2 4 8 789 3929 1916 +2623 2 2 4 8 1983 4507 4261 +2624 2 2 4 8 983 2285 2772 +2625 2 2 4 8 982 2284 2773 +2626 2 2 4 8 1129 4208 3014 +2627 2 2 4 8 458 1995 4371 +2628 2 2 4 8 1118 4448 3960 +2629 2 2 4 8 1959 2406 4073 +2630 2 2 4 8 846 3636 1876 +2631 2 2 4 8 811 3774 1897 +2632 2 2 4 8 905 2321 3104 +2633 2 2 4 8 851 2237 2690 +2634 2 2 4 8 813 5073 5174 +2635 2 2 4 8 1676 5065 2694 +2636 2 2 4 8 2160 3073 4610 +2637 2 2 4 8 2161 4609 3074 +2638 2 2 4 8 665 2786 2233 +2639 2 2 4 8 1497 4669 3903 +2640 2 2 4 8 1090 4663 5175 +2641 2 2 4 8 1816 2427 5256 +2642 2 2 4 8 1461 3440 3245 +2643 2 2 4 8 918 2669 2224 +2644 2 2 4 8 2240 4904 3686 +2645 2 2 4 8 771 2297 2931 +2646 2 2 4 8 1044 2392 2586 +2647 2 2 4 8 447 2617 4322 +2648 2 2 4 8 597 3436 2581 +2649 2 2 4 8 1152 4386 3117 +2650 2 2 4 8 1999 4484 2351 +2651 2 2 4 8 468 2072 4863 +2652 2 2 4 8 454 2248 2654 +2653 2 2 4 8 24 3938 1918 +2654 2 2 4 8 1354 4172 3763 +2655 2 2 4 8 548 2171 3528 +2656 2 2 4 8 1589 4867 3043 +2657 2 2 4 8 1843 4813 3446 +2658 2 2 4 8 1318 4077 1946 +2659 2 2 4 8 498 4715 3616 +2660 2 2 4 8 1053 4774 2751 +2661 2 2 4 8 1054 4773 2752 +2662 2 2 4 8 1178 3394 1970 +2663 2 2 4 8 1267 1904 3875 +2664 2 2 4 8 1065 2250 2661 +2665 2 2 4 8 334 3302 1987 +2666 2 2 4 8 1053 2505 4774 +2667 2 2 4 8 1054 2504 4773 +2668 2 2 4 8 812 2898 2009 +2669 2 2 4 8 1074 1980 3660 +2670 2 2 4 8 657 1878 3492 +2671 2 2 4 8 1152 2779 3055 +2672 2 2 4 8 1347 3055 2779 +2673 2 2 4 8 2498 2264 4378 +2674 2 2 4 8 813 5174 2624 +2675 2 2 4 8 589 2759 4989 +2676 2 2 4 8 1408 2389 3953 +2677 2 2 4 8 1415 2999 3580 +2678 2 2 4 8 159 160 2766 +2679 2 2 4 8 380 381 2767 +2680 2 2 4 8 1073 3057 1947 +2681 2 2 4 8 849 4582 2028 +2682 2 2 4 8 1778 3306 4432 +2683 2 2 4 8 1779 4433 3305 +2684 2 2 4 8 1155 3131 2133 +2685 2 2 4 8 542 2870 4286 +2686 2 2 4 8 1880 1169 3427 +2687 2 2 4 8 2087 4934 1174 +2688 2 2 4 8 1036 2217 3008 +2689 2 2 4 8 910 2036 4504 +2690 2 2 4 8 579 2200 5389 +2691 2 2 4 8 1432 3746 2797 +2692 2 2 4 8 1433 3747 2798 +2693 2 2 4 8 632 4411 1903 +2694 2 2 4 8 1359 3197 4290 +2695 2 2 4 8 890 3993 3234 +2696 2 2 4 8 1827 5249 4744 +2697 2 2 4 8 992 3977 2311 +2698 2 2 4 8 1673 4001 3766 +2699 2 2 4 8 346 347 2839 +2700 2 2 4 8 696 5346 4263 +2701 2 2 4 8 647 2366 3989 +2702 2 2 4 8 1453 2438 3560 +2703 2 2 4 8 1454 3561 2437 +2704 2 2 4 8 1060 3119 2393 +2705 2 2 4 8 1002 2686 3761 +2706 2 2 4 8 967 3743 4747 +2707 2 2 4 8 943 4578 2029 +2708 2 2 4 8 696 2754 5346 +2709 2 2 4 8 565 1881 3575 +2710 2 2 4 8 568 3577 1882 +2711 2 2 4 8 569 1883 3576 +2712 2 2 4 8 1620 4317 2629 +2713 2 2 4 8 443 1950 3070 +2714 2 2 4 8 1098 2414 4989 +2715 2 2 4 8 969 4370 2654 +2716 2 2 4 8 898 1890 3341 +2717 2 2 4 8 664 3238 3853 +2718 2 2 4 8 839 1964 4272 +2719 2 2 4 8 1000 1882 3554 +2720 2 2 4 8 1881 999 3553 +2721 2 2 4 8 1001 3555 1883 +2722 2 2 4 8 577 3156 2269 +2723 2 2 4 8 772 1884 3430 +2724 2 2 4 8 697 3648 2746 +2725 2 2 4 8 699 3649 2747 +2726 2 2 4 8 1543 1976 4211 +2727 2 2 4 8 1542 1977 4210 +2728 2 2 4 8 1194 3531 1906 +2729 2 2 4 8 1193 3532 1907 +2730 2 2 4 8 1192 3535 1908 +2731 2 2 4 8 1190 1909 3533 +2732 2 2 4 8 1191 1910 3534 +2733 2 2 4 8 2686 4287 3761 +2734 2 2 4 8 1050 1891 4443 +2735 2 2 4 8 2012 3478 5340 +2736 2 2 4 8 2013 3479 5341 +2737 2 2 4 8 500 3676 2960 +2738 2 2 4 8 1186 3659 2014 +2739 2 2 4 8 704 4812 2463 +2740 2 2 4 8 909 4864 2232 +2741 2 2 4 8 1198 2690 2237 +2742 2 2 4 8 1080 4496 2020 +2743 2 2 4 8 1080 2021 4496 +2744 2 2 4 8 1308 2168 3816 +2745 2 2 4 8 2234 2413 4638 +2746 2 2 4 8 1440 2723 3382 +2747 2 2 4 8 1164 3382 2723 +2748 2 2 4 8 656 2367 3497 +2749 2 2 4 8 694 5237 4241 +2750 2 2 4 8 1698 2592 5374 +2751 2 2 4 8 694 2741 5237 +2752 2 2 4 8 1103 4063 1986 +2753 2 2 4 8 1307 3580 2259 +2754 2 2 4 8 654 2259 3580 +2755 2 2 4 8 468 4414 1945 +2756 2 2 4 8 1292 1936 3107 +2757 2 2 4 8 1293 3108 1937 +2758 2 2 4 8 3513 4407 1264 +2759 2 2 4 8 205 4265 4882 +2760 2 2 4 8 222 4883 4266 +2761 2 2 4 8 422 4264 4884 +2762 2 2 4 8 440 4885 4267 +2763 2 2 4 8 993 2748 3810 +2764 2 2 4 8 1137 1902 3294 +2765 2 2 4 8 631 3294 1902 +2766 2 2 4 8 1506 2598 3145 +2767 2 2 4 8 1505 3146 2599 +2768 2 2 4 8 958 1982 4369 +2769 2 2 4 8 1117 1949 4311 +2770 2 2 4 8 636 3468 1891 +2771 2 2 4 8 321 322 2551 +2772 2 2 4 8 3088 5125 5309 +2773 2 2 4 8 1895 4705 2966 +2774 2 2 4 8 1698 5374 4896 +2775 2 2 4 8 17 2168 2935 +2776 2 2 4 8 780 3539 1905 +2777 2 2 4 8 1195 1905 3539 +2778 2 2 4 8 779 3538 1906 +2779 2 2 4 8 1194 1906 3538 +2780 2 2 4 8 1190 3537 1909 +2781 2 2 4 8 776 1910 3536 +2782 2 2 4 8 775 1909 3537 +2783 2 2 4 8 1191 3536 1910 +2784 2 2 4 8 2562 4705 5042 +2785 2 2 4 8 228 2455 5270 +2786 2 2 4 8 199 5271 2456 +2787 2 2 4 8 604 3603 2162 +2788 2 2 4 8 2101 4923 1067 +2789 2 2 4 8 912 2031 4776 +2790 2 2 4 8 1095 2032 4775 +2791 2 2 4 8 964 4412 2908 +2792 2 2 4 8 862 3201 4353 +2793 2 2 4 8 1533 2388 3071 +2794 2 2 4 8 2104 5220 1269 +2795 2 2 4 8 1887 5145 3359 +2796 2 2 4 8 1888 5146 3358 +2797 2 2 4 8 451 2058 2904 +2798 2 2 4 8 485 2172 3020 +2799 2 2 4 8 598 2458 2607 +2800 2 2 4 8 2350 5319 2949 +2801 2 2 4 8 1502 4103 4645 +2802 2 2 4 8 996 2682 2268 +2803 2 2 4 8 1056 2307 3105 +2804 2 2 4 8 391 392 2357 +2805 2 2 4 8 1042 5310 2517 +2806 2 2 4 8 448 2627 2365 +2807 2 2 4 8 450 5347 2199 +2808 2 2 4 8 442 5348 2201 +2809 2 2 4 8 595 2187 3126 +2810 2 2 4 8 329 330 2577 +2811 2 2 4 8 2103 5226 1268 +2812 2 2 4 8 485 2218 2733 +2813 2 2 4 8 605 2051 3412 +2814 2 2 4 8 1214 3412 2051 +2815 2 2 4 8 65 2112 4037 +2816 2 2 4 8 286 2110 4035 +2817 2 2 4 8 257 4036 2111 +2818 2 2 4 8 461 1923 3854 +2819 2 2 4 8 460 1924 3717 +2820 2 2 4 8 1240 3717 1924 +2821 2 2 4 8 536 3148 1940 +2822 2 2 4 8 959 4261 4507 +2823 2 2 4 8 859 4878 2315 +2824 2 2 4 8 1047 4613 2452 +2825 2 2 4 8 1925 4605 3401 +2826 2 2 4 8 741 3050 3788 +2827 2 2 4 8 2054 4994 1286 +2828 2 2 4 8 1585 2838 4686 +2829 2 2 4 8 1151 3090 4017 +2830 2 2 4 8 780 1905 4569 +2831 2 2 4 8 779 1906 4570 +2832 2 2 4 8 778 1907 4571 +2833 2 2 4 8 777 1908 4572 +2834 2 2 4 8 776 4574 1910 +2835 2 2 4 8 775 4573 1909 +2836 2 2 4 8 467 2166 5207 +2837 2 2 4 8 1467 3242 3448 +2838 2 2 4 8 2101 1298 3193 +2839 2 2 4 8 1111 3994 1917 +2840 2 2 4 8 1072 2042 2916 +2841 2 2 4 8 1347 2779 2197 +2842 2 2 4 8 809 2197 2779 +2843 2 2 4 8 1040 2925 2037 +2844 2 2 4 8 1041 2926 2038 +2845 2 2 4 8 2083 1940 5230 +2846 2 2 4 8 984 3088 1963 +2847 2 2 4 8 1166 2142 3149 +2848 2 2 4 8 1165 2141 3150 +2849 2 2 4 8 631 1902 3447 +2850 2 2 4 8 1110 4771 2035 +2851 2 2 4 8 1093 5066 4780 +2852 2 2 4 8 1115 2306 4252 +2853 2 2 4 8 2066 4882 4265 +2854 2 2 4 8 2067 4266 4883 +2855 2 2 4 8 2068 4884 4264 +2856 2 2 4 8 2069 4267 4885 +2857 2 2 4 8 2241 1153 2726 +2858 2 2 4 8 803 4472 2180 +2859 2 2 4 8 804 4474 2181 +2860 2 2 4 8 486 3549 1969 +2861 2 2 4 8 210 211 3435 +2862 2 2 4 8 428 429 3434 +2863 2 2 4 8 1080 3147 2021 +2864 2 2 4 8 955 2905 2604 +2865 2 2 4 8 953 2906 2602 +2866 2 2 4 8 954 2603 2904 +2867 2 2 4 8 1029 3919 3464 +2868 2 2 4 8 1028 3463 3918 +2869 2 2 4 8 637 2176 2782 +2870 2 2 4 8 638 2783 2177 +2871 2 2 4 8 720 3060 1986 +2872 2 2 4 8 1039 2272 4627 +2873 2 2 4 8 658 3525 1912 +2874 2 2 4 8 2211 4951 3738 +2875 2 2 4 8 2210 4950 3737 +2876 2 2 4 8 1725 4921 2590 +2877 2 2 4 8 1176 1916 3929 +2878 2 2 4 8 492 4127 2053 +2879 2 2 4 8 2053 4127 1369 +2880 2 2 4 8 1946 2965 5002 +2881 2 2 4 8 1564 4717 2114 +2882 2 2 4 8 633 2114 4717 +2883 2 2 4 8 634 2115 4718 +2884 2 2 4 8 1563 4718 2115 +2885 2 2 4 8 657 2813 3553 +2886 2 2 4 8 658 3554 2814 +2887 2 2 4 8 659 2815 3555 +2888 2 2 4 8 525 3349 2225 +2889 2 2 4 8 1248 2225 3349 +2890 2 2 4 8 497 3065 4116 +2891 2 2 4 8 1228 2563 2618 +2892 2 2 4 8 565 2876 2074 +2893 2 2 4 8 2074 2876 1088 +2894 2 2 4 8 715 3066 2776 +2895 2 2 4 8 1695 2315 4878 +2896 2 2 4 8 1808 4323 4615 +2897 2 2 4 8 1007 2281 4401 +2898 2 2 4 8 1571 4401 2281 +2899 2 2 4 8 559 2734 2239 +2900 2 2 4 8 1353 3416 4061 +2901 2 2 4 8 593 2185 3221 +2902 2 2 4 8 594 3222 2186 +2903 2 2 4 8 567 5256 2427 +2904 2 2 4 8 687 3227 3623 +2905 2 2 4 8 346 1916 5015 +2906 2 2 4 8 1438 1929 3819 +2907 2 2 4 8 891 4638 1954 +2908 2 2 4 8 1856 3231 5087 +2909 2 2 4 8 1857 3230 5088 +2910 2 2 4 8 1355 4426 2466 +2911 2 2 4 8 1356 2467 4425 +2912 2 2 4 8 1062 3419 2371 +2913 2 2 4 8 1061 3418 2370 +2914 2 2 4 8 638 2177 5333 +2915 2 2 4 8 637 5334 2176 +2916 2 2 4 8 1224 3332 1926 +2917 2 2 4 8 1082 2842 2474 +2918 2 2 4 8 1451 3280 2411 +2919 2 2 4 8 979 2411 3280 +2920 2 2 4 8 1290 1971 3106 +2921 2 2 4 8 994 3807 2746 +2922 2 2 4 8 995 3808 2747 +2923 2 2 4 8 1240 1924 4364 +2924 2 2 4 8 1546 2962 3365 +2925 2 2 4 8 679 3365 2962 +2926 2 2 4 8 1305 3237 2549 +2927 2 2 4 8 872 2549 3237 +2928 2 2 4 8 1594 3771 2662 +2929 2 2 4 8 584 2701 2533 +2930 2 2 4 8 1140 2533 2701 +2931 2 2 4 8 1138 2531 2700 +2932 2 2 4 8 585 2700 2531 +2933 2 2 4 8 875 2049 4618 +2934 2 2 4 8 1103 1986 3060 +2935 2 2 4 8 1238 1922 4611 +2936 2 2 4 8 417 1953 4556 +2937 2 2 4 8 632 5065 4085 +2938 2 2 4 8 2064 4780 5066 +2939 2 2 4 8 798 4137 2292 +2940 2 2 4 8 746 3404 4302 +2941 2 2 4 8 485 3020 2218 +2942 2 2 4 8 451 2703 2532 +2943 2 2 4 8 1139 2532 2703 +2944 2 2 4 8 195 2130 4483 +2945 2 2 4 8 1232 1925 3401 +2946 2 2 4 8 1952 3479 5254 +2947 2 2 4 8 1951 3478 5253 +2948 2 2 4 8 888 1928 4378 +2949 2 2 4 8 1226 2019 5383 +2950 2 2 4 8 2757 5205 5213 +2951 2 2 4 8 5206 5214 2758 +2952 2 2 4 8 1096 5205 2757 +2953 2 2 4 8 1097 5206 2758 +2954 2 2 4 8 1355 3847 1937 +2955 2 2 4 8 1356 1936 3848 +2956 2 2 4 8 202 1933 4054 +2957 2 2 4 8 225 4055 1934 +2958 2 2 4 8 865 2833 3819 +2959 2 2 4 8 832 3874 1943 +2960 2 2 4 8 1102 2028 4582 +2961 2 2 4 8 721 2679 2873 +2962 2 2 4 8 1249 2873 2679 +2963 2 2 4 8 764 1996 3604 +2964 2 2 4 8 1227 3604 1996 +2965 2 2 4 8 1100 2761 4248 +2966 2 2 4 8 4200 3084 5062 +2967 2 2 4 8 564 2203 3284 +2968 2 2 4 8 1388 2612 2656 +2969 2 2 4 8 1389 2613 2657 +2970 2 2 4 8 576 4512 2300 +2971 2 2 4 8 1527 4831 2251 +2972 2 2 4 8 1390 2615 2655 +2973 2 2 4 8 2098 1277 3176 +2974 2 2 4 8 1853 4676 4420 +2975 2 2 4 8 1852 4677 4418 +2976 2 2 4 8 471 2622 3106 +2977 2 2 4 8 1290 3106 2622 +2978 2 2 4 8 410 4251 1984 +2979 2 2 4 8 930 2572 2879 +2980 2 2 4 8 506 3277 4163 +2981 2 2 4 8 1985 3731 1251 +2982 2 2 4 8 1117 3871 1949 +2983 2 2 4 8 316 3293 4604 +2984 2 2 4 8 2853 3307 1730 +2985 2 2 4 8 6 7 3977 +2986 2 2 4 8 1093 3436 2664 +2987 2 2 4 8 522 2500 3428 +2988 2 2 4 8 1336 3428 2500 +2989 2 2 4 8 1683 2373 5060 +2990 2 2 4 8 614 3529 2941 +2991 2 2 4 8 1598 2941 3529 +2992 2 2 4 8 1599 3530 2940 +2993 2 2 4 8 607 2940 3530 +2994 2 2 4 8 692 2632 3656 +2995 2 2 4 8 788 2434 3315 +2996 2 2 4 8 1276 3315 2434 +2997 2 2 4 8 1762 4502 4004 +2998 2 2 4 8 1014 2547 4150 +2999 2 2 4 8 2076 845 4770 +3000 2 2 4 8 672 2707 3626 +3001 2 2 4 8 2023 4314 2451 +3002 2 2 4 8 710 3369 3026 +3003 2 2 4 8 1793 3616 4715 +3004 2 2 4 8 810 1960 4188 +3005 2 2 4 8 4121 4219 2447 +3006 2 2 4 8 4120 4221 2448 +3007 2 2 4 8 490 3998 2372 +3008 2 2 4 8 1279 5131 2346 +3009 2 2 4 8 793 3779 1930 +3010 2 2 4 8 1310 3714 2210 +3011 2 2 4 8 504 2210 3714 +3012 2 2 4 8 505 2211 3715 +3013 2 2 4 8 1311 3715 2211 +3014 2 2 4 8 756 4291 2113 +3015 2 2 4 8 1452 2113 4291 +3016 2 2 4 8 592 2184 3833 +3017 2 2 4 8 629 2333 2687 +3018 2 2 4 8 1606 3637 2897 +3019 2 2 4 8 1063 3998 3250 +3020 2 2 4 8 1837 2889 4081 +3021 2 2 4 8 1838 2890 4082 +3022 2 2 4 8 846 2421 3636 +3023 2 2 4 8 1372 3636 2421 +3024 2 2 4 8 1095 4421 2032 +3025 2 2 4 8 1093 4780 3436 +3026 2 2 4 8 1768 2538 4007 +3027 2 2 4 8 1108 2329 5007 +3028 2 2 4 8 1202 2135 3263 +3029 2 2 4 8 1300 3082 3175 +3030 2 2 4 8 1301 3083 3174 +3031 2 2 4 8 2076 1232 4092 +3032 2 2 4 8 985 1965 3206 +3033 2 2 4 8 554 3015 2031 +3034 2 2 4 8 792 2693 2625 +3035 2 2 4 8 1837 4661 2889 +3036 2 2 4 8 1838 4662 2890 +3037 2 2 4 8 793 1930 3610 +3038 2 2 4 8 448 5089 5138 +3039 2 2 4 8 47 5092 2809 +3040 2 2 4 8 268 5093 2810 +3041 2 2 4 8 81 5094 2808 +3042 2 2 4 8 558 5075 2262 +3043 2 2 4 8 1707 2262 5075 +3044 2 2 4 8 1755 4660 5287 +3045 2 2 4 8 512 2695 2334 +3046 2 2 4 8 1116 4416 2251 +3047 2 2 4 8 1196 1953 3311 +3048 2 2 4 8 802 3881 1957 +3049 2 2 4 8 535 4238 2702 +3050 2 2 4 8 536 1940 3748 +3051 2 2 4 8 1659 3519 3078 +3052 2 2 4 8 1260 3078 3519 +3053 2 2 4 8 1652 4551 3924 +3054 2 2 4 8 637 2047 4560 +3055 2 2 4 8 638 4559 2048 +3056 2 2 4 8 1122 2893 3707 +3057 2 2 4 8 923 5409 2233 +3058 2 2 4 8 1103 5290 2386 +3059 2 2 4 8 1640 3846 3619 +3060 2 2 4 8 1638 3618 3844 +3061 2 2 4 8 975 1950 4233 +3062 2 2 4 8 624 2420 5291 +3063 2 2 4 8 581 2153 5099 +3064 2 2 4 8 1045 5098 2154 +3065 2 2 4 8 1396 2797 3678 +3066 2 2 4 8 1348 2878 3470 +3067 2 2 4 8 666 2202 3776 +3068 2 2 4 8 731 2897 3637 +3069 2 2 4 8 1715 2868 3306 +3070 2 2 4 8 1714 3305 2867 +3071 2 2 4 8 2866 3304 1716 +3072 2 2 4 8 1665 2611 3872 +3073 2 2 4 8 788 3467 1987 +3074 2 2 4 8 2074 2726 4997 +3075 2 2 4 8 770 2195 5250 +3076 2 2 4 8 747 2721 4179 +3077 2 2 4 8 1182 2196 4041 +3078 2 2 4 8 2232 4864 2426 +3079 2 2 4 8 1078 2967 2257 +3080 2 2 4 8 506 3085 2002 +3081 2 2 4 8 910 2267 2762 +3082 2 2 4 8 1056 2735 2307 +3083 2 2 4 8 643 3043 2042 +3084 2 2 4 8 1114 2042 3043 +3085 2 2 4 8 691 4292 2613 +3086 2 2 4 8 1061 3573 4932 +3087 2 2 4 8 1062 3574 4925 +3088 2 2 4 8 919 1961 3908 +3089 2 2 4 8 1308 3816 2208 +3090 2 2 4 8 843 3578 1938 +3091 2 2 4 8 844 3579 1939 +3092 2 2 4 8 1100 4248 3054 +3093 2 2 4 8 469 1944 3470 +3094 2 2 4 8 902 1969 3931 +3095 2 2 4 8 1004 3355 1955 +3096 2 2 4 8 1005 3356 1956 +3097 2 2 4 8 1890 5177 3341 +3098 2 2 4 8 580 2152 5081 +3099 2 2 4 8 595 3039 2028 +3100 2 2 4 8 1459 4120 4066 +3101 2 2 4 8 957 2791 2472 +3102 2 2 4 8 2165 3391 4237 +3103 2 2 4 8 1090 2265 2823 +3104 2 2 4 8 105 3692 4395 +3105 2 2 4 8 1197 2268 4319 +3106 2 2 4 8 1698 3518 4091 +3107 2 2 4 8 1265 4394 1950 +3108 2 2 4 8 1079 3225 2551 +3109 2 2 4 8 740 3058 3789 +3110 2 2 4 8 742 3059 3790 +3111 2 2 4 8 513 2673 3450 +3112 2 2 4 8 1419 3450 2673 +3113 2 2 4 8 556 2032 4498 +3114 2 2 4 8 1580 3029 2442 +3115 2 2 4 8 452 4705 2562 +3116 2 2 4 8 480 4122 1989 +3117 2 2 4 8 479 4123 1990 +3118 2 2 4 8 485 5140 2172 +3119 2 2 4 8 916 2403 5016 +3120 2 2 4 8 211 4024 3435 +3121 2 2 4 8 429 4023 3434 +3122 2 2 4 8 1206 3971 3067 +3123 2 2 4 8 836 3069 4916 +3124 2 2 4 8 929 2611 3078 +3125 2 2 4 8 2446 3333 4218 +3126 2 2 4 8 1035 2498 5315 +3127 2 2 4 8 2498 1928 5315 +3128 2 2 4 8 1206 2903 3971 +3129 2 2 4 8 2993 4724 2488 +3130 2 2 4 8 751 4985 3655 +3131 2 2 4 8 588 2000 4247 +3132 2 2 4 8 2673 4250 4412 +3133 2 2 4 8 929 2502 2632 +3134 2 2 4 8 580 5081 4606 +3135 2 2 4 8 1551 3475 2332 +3136 2 2 4 8 581 5182 2192 +3137 2 2 4 8 1689 2192 5182 +3138 2 2 4 8 1196 3835 1953 +3139 2 2 4 8 784 2033 4817 +3140 2 2 4 8 1095 2298 2807 +3141 2 2 4 8 1068 2120 4898 +3142 2 2 4 8 939 2365 4692 +3143 2 2 4 8 1486 3407 3641 +3144 2 2 4 8 1448 4515 1993 +3145 2 2 4 8 1449 4516 1992 +3146 2 2 4 8 78 79 3598 +3147 2 2 4 8 38 2506 37 +3148 2 2 4 8 612 4554 2728 +3149 2 2 4 8 1219 2514 2933 +3150 2 2 4 8 485 2265 2856 +3151 2 2 4 8 3204 5203 4616 +3152 2 2 4 8 907 4321 2114 +3153 2 2 4 8 908 4320 2115 +3154 2 2 4 8 852 3172 2139 +3155 2 2 4 8 853 3173 2140 +3156 2 2 4 8 1157 2867 3305 +3157 2 2 4 8 1158 3306 2868 +3158 2 2 4 8 1156 3304 2866 +3159 2 2 4 8 886 2151 4249 +3160 2 2 4 8 2266 3406 4051 +3161 2 2 4 8 636 2618 2563 +3162 2 2 4 8 708 2034 4373 +3163 2 2 4 8 1080 5027 2267 +3164 2 2 4 8 683 2435 3514 +3165 2 2 4 8 605 2939 3721 +3166 2 2 4 8 1645 3721 2939 +3167 2 2 4 8 604 2938 3723 +3168 2 2 4 8 1644 3723 2938 +3169 2 2 4 8 1254 3657 3514 +3170 2 2 4 8 1108 2669 4629 +3171 2 2 4 8 666 5068 2064 +3172 2 2 4 8 1652 3036 4551 +3173 2 2 4 8 503 4161 3163 +3174 2 2 4 8 619 4217 2409 +3175 2 2 4 8 963 3848 2656 +3176 2 2 4 8 629 4341 2539 +3177 2 2 4 8 1222 3443 4395 +3178 2 2 4 8 108 4690 2323 +3179 2 2 4 8 2746 3807 4521 +3180 2 2 4 8 2747 3808 4522 +3181 2 2 4 8 1066 3282 2249 +3182 2 2 4 8 1592 5158 2685 +3183 2 2 4 8 325 2332 4299 +3184 2 2 4 8 607 2052 3474 +3185 2 2 4 8 1216 3474 2052 +3186 2 2 4 8 509 2989 4969 +3187 2 2 4 8 514 2990 4970 +3188 2 2 4 8 1358 1971 3855 +3189 2 2 4 8 2061 5186 1123 +3190 2 2 4 8 1440 2132 4071 +3191 2 2 4 8 1441 2131 4072 +3192 2 2 4 8 2109 4976 1106 +3193 2 2 4 8 1507 4518 2801 +3194 2 2 4 8 1508 4519 2800 +3195 2 2 4 8 2086 1051 4503 +3196 2 2 4 8 524 3207 2106 +3197 2 2 4 8 2106 3207 1168 +3198 2 2 4 8 1074 3660 2081 +3199 2 2 4 8 961 3255 4727 +3200 2 2 4 8 868 4920 2676 +3201 2 2 4 8 988 3444 1964 +3202 2 2 4 8 612 4981 4554 +3203 2 2 4 8 1641 4714 4047 +3204 2 2 4 8 1243 3120 2793 +3205 2 2 4 8 1534 3614 3920 +3206 2 2 4 8 958 2745 2329 +3207 2 2 4 8 2420 5034 5291 +3208 2 2 4 8 2077 1102 4582 +3209 2 2 4 8 956 2695 2591 +3210 2 2 4 8 1740 2730 3776 +3211 2 2 4 8 1435 2899 3976 +3212 2 2 4 8 1386 2591 2695 +3213 2 2 4 8 1197 2921 2705 +3214 2 2 4 8 1337 2476 2886 +3215 2 2 4 8 1127 2601 2605 +3216 2 2 4 8 1128 2605 2601 +3217 2 2 4 8 692 3656 3094 +3218 2 2 4 8 813 2194 5200 +3219 2 2 4 8 1263 5200 2194 +3220 2 2 4 8 1263 2193 5200 +3221 2 2 4 8 2853 1162 3307 +3222 2 2 4 8 1733 3125 4107 +3223 2 2 4 8 1034 2497 5349 +3224 2 2 4 8 2497 1927 5349 +3225 2 2 4 8 1743 3940 2544 +3226 2 2 4 8 1209 2127 4405 +3227 2 2 4 8 1208 2128 4404 +3228 2 2 4 8 2778 1711 4799 +3229 2 2 4 8 2899 5069 3976 +3230 2 2 4 8 2685 5158 2837 +3231 2 2 4 8 4551 2802 4941 +3232 2 2 4 8 1712 3540 5295 +3233 2 2 4 8 654 3580 2999 +3234 2 2 4 8 1144 2480 2919 +3235 2 2 4 8 100 4689 2442 +3236 2 2 4 8 1507 3621 4518 +3237 2 2 4 8 1508 3622 4519 +3238 2 2 4 8 1696 2414 3668 +3239 2 2 4 8 1584 2319 4538 +3240 2 2 4 8 1003 3728 1970 +3241 2 2 4 8 558 1998 4053 +3242 2 2 4 8 964 2672 2673 +3243 2 2 4 8 1419 2673 2672 +3244 2 2 4 8 408 4032 1994 +3245 2 2 4 8 1246 3296 2311 +3246 2 2 4 8 992 2311 3296 +3247 2 2 4 8 1430 4037 2112 +3248 2 2 4 8 2110 1428 4035 +3249 2 2 4 8 2111 4036 1429 +3250 2 2 4 8 917 2295 2790 +3251 2 2 4 8 584 5069 2403 +3252 2 2 4 8 1169 4743 1996 +3253 2 2 4 8 1458 3159 4121 +3254 2 2 4 8 1459 3160 4120 +3255 2 2 4 8 856 2183 3125 +3256 2 2 4 8 2085 4723 575 +3257 2 2 4 8 2085 1535 4723 +3258 2 2 4 8 2105 5040 2844 +3259 2 2 4 8 641 2844 5040 +3260 2 2 4 8 772 2040 4349 +3261 2 2 4 8 1322 5275 2519 +3262 2 2 4 8 2074 1088 5401 +3263 2 2 4 8 330 4531 2577 +3264 2 2 4 8 873 4121 2447 +3265 2 2 4 8 874 4120 2448 +3266 2 2 4 8 906 4205 2116 +3267 2 2 4 8 86 3005 4147 +3268 2 2 4 8 2466 4426 2811 +3269 2 2 4 8 2467 2812 4425 +3270 2 2 4 8 1345 4787 1981 +3271 2 2 4 8 886 4249 2648 +3272 2 2 4 8 1495 3813 2643 +3273 2 2 4 8 1963 3088 5309 +3274 2 2 4 8 912 4776 2165 +3275 2 2 4 8 1095 4775 2166 +3276 2 2 4 8 482 1973 3516 +3277 2 2 4 8 484 1972 3517 +3278 2 2 4 8 355 3298 2025 +3279 2 2 4 8 168 3299 2026 +3280 2 2 4 8 446 3564 3034 +3281 2 2 4 8 1472 3057 3025 +3282 2 2 4 8 1073 3025 3057 +3283 2 2 4 8 682 2021 3147 +3284 2 2 4 8 1093 2242 5066 +3285 2 2 4 8 2076 2928 4634 +3286 2 2 4 8 1218 4538 2319 +3287 2 2 4 8 1147 3121 5225 +3288 2 2 4 8 1148 3122 5223 +3289 2 2 4 8 586 4549 2255 +3290 2 2 4 8 581 4548 2256 +3291 2 2 4 8 720 1986 4967 +3292 2 2 4 8 876 2981 4048 +3293 2 2 4 8 1043 2176 5083 +3294 2 2 4 8 1044 5082 2177 +3295 2 2 4 8 635 2116 4832 +3296 2 2 4 8 899 2823 2265 +3297 2 2 4 8 29 3592 1981 +3298 2 2 4 8 1872 4423 2457 +3299 2 2 4 8 1873 4424 2458 +3300 2 2 4 8 822 3735 4552 +3301 2 2 4 8 1668 2711 4952 +3302 2 2 4 8 1169 1996 3427 +3303 2 2 4 8 764 3427 1996 +3304 2 2 4 8 1731 3308 2854 +3305 2 2 4 8 1732 3309 2855 +3306 2 2 4 8 1059 2889 4661 +3307 2 2 4 8 1056 2890 4662 +3308 2 2 4 8 1783 3572 2282 +3309 2 2 4 8 1390 2655 3640 +3310 2 2 4 8 1089 2121 3093 +3311 2 2 4 8 1707 2528 3730 +3312 2 2 4 8 1420 4057 2976 +3313 2 2 4 8 2471 3639 2929 +3314 2 2 4 8 1103 2637 5290 +3315 2 2 4 8 950 5313 1998 +3316 2 2 4 8 939 4692 2528 +3317 2 2 4 8 689 3491 2672 +3318 2 2 4 8 1419 2672 3491 +3319 2 2 4 8 494 2398 2743 +3320 2 2 4 8 1113 2743 2398 +3321 2 2 4 8 1975 5175 4663 +3322 2 2 4 8 947 4462 2428 +3323 2 2 4 8 1351 5013 3504 +3324 2 2 4 8 1916 2839 4185 +3325 2 2 4 8 590 2004 3375 +3326 2 2 4 8 591 2005 3376 +3327 2 2 4 8 922 2294 5215 +3328 2 2 4 8 1188 4182 2213 +3329 2 2 4 8 1187 4183 2212 +3330 2 2 4 8 1868 4395 3692 +3331 2 2 4 8 1221 3366 1984 +3332 2 2 4 8 476 2881 2318 +3333 2 2 4 8 453 5143 2190 +3334 2 2 4 8 10 11 3041 +3335 2 2 4 8 951 5095 2333 +3336 2 2 4 8 922 5215 2299 +3337 2 2 4 8 756 2629 4317 +3338 2 2 4 8 641 2807 2298 +3339 2 2 4 8 322 4178 2551 +3340 2 2 4 8 1179 2621 2843 +3341 2 2 4 8 310 3244 3484 +3342 2 2 4 8 299 3246 3483 +3343 2 2 4 8 128 3486 3241 +3344 2 2 4 8 117 3487 3240 +3345 2 2 4 8 2104 1120 3186 +3346 2 2 4 8 1450 4223 2025 +3347 2 2 4 8 1451 4224 2026 +3348 2 2 4 8 1247 4697 2756 +3349 2 2 4 8 1497 2587 4669 +3350 2 2 4 8 524 2106 2992 +3351 2 2 4 8 1420 4130 4057 +3352 2 2 4 8 2098 3008 679 +3353 2 2 4 8 921 5155 2287 +3354 2 2 4 8 675 2917 2545 +3355 2 2 4 8 1676 2694 3815 +3356 2 2 4 8 577 2982 3562 +3357 2 2 4 8 1159 3049 3051 +3358 2 2 4 8 2147 4619 3102 +3359 2 2 4 8 1143 2402 2869 +3360 2 2 4 8 579 2869 2402 +3361 2 2 4 8 1296 3824 2129 +3362 2 2 4 8 491 2129 3824 +3363 2 2 4 8 74 2383 4201 +3364 2 2 4 8 807 1992 4778 +3365 2 2 4 8 808 1993 4779 +3366 2 2 4 8 2528 4692 4653 +3367 2 2 4 8 1150 3883 4257 +3368 2 2 4 8 1384 4140 2266 +3369 2 2 4 8 544 4391 2082 +3370 2 2 4 8 2082 4391 1437 +3371 2 2 4 8 1090 5175 2415 +3372 2 2 4 8 578 3151 4200 +3373 2 2 4 8 776 5180 3798 +3374 2 2 4 8 775 5181 3797 +3375 2 2 4 8 779 3800 5178 +3376 2 2 4 8 780 3799 5179 +3377 2 2 4 8 29 1981 4787 +3378 2 2 4 8 921 2298 5155 +3379 2 2 4 8 562 2278 4413 +3380 2 2 4 8 1538 4413 2278 +3381 2 2 4 8 1168 3207 3385 +3382 2 2 4 8 1058 2459 2884 +3383 2 2 4 8 1057 2883 2460 +3384 2 2 4 8 1634 2702 4238 +3385 2 2 4 8 1074 4802 1980 +3386 2 2 4 8 1106 4976 2182 +3387 2 2 4 8 1369 4909 2792 +3388 2 2 4 8 1331 2647 3627 +3389 2 2 4 8 1087 2123 3291 +3390 2 2 4 8 1299 2163 3939 +3391 2 2 4 8 604 2162 4986 +3392 2 2 4 8 1395 5328 2005 +3393 2 2 4 8 1394 5329 2004 +3394 2 2 4 8 1421 2821 2822 +3395 2 2 4 8 1049 2822 2821 +3396 2 2 4 8 476 3752 3048 +3397 2 2 4 8 1985 1251 3711 +3398 2 2 4 8 1893 3121 5190 +3399 2 2 4 8 1892 3122 5191 +3400 2 2 4 8 1894 3123 5192 +3401 2 2 4 8 3022 4511 4971 +3402 2 2 4 8 788 1987 3834 +3403 2 2 4 8 971 4467 3608 +3404 2 2 4 8 1297 2008 3265 +3405 2 2 4 8 664 3660 1980 +3406 2 2 4 8 51 2012 3248 +3407 2 2 4 8 272 2013 3249 +3408 2 2 4 8 1474 3260 3387 +3409 2 2 4 8 1475 3261 3388 +3410 2 2 4 8 910 4504 2267 +3411 2 2 4 8 629 2687 4341 +3412 2 2 4 8 1162 3047 3957 +3413 2 2 4 8 1070 2935 2168 +3414 2 2 4 8 2346 5131 3157 +3415 2 2 4 8 1496 2118 4558 +3416 2 2 4 8 557 4558 2118 +3417 2 2 4 8 513 4250 2673 +3418 2 2 4 8 1115 2063 3144 +3419 2 2 4 8 906 2360 4205 +3420 2 2 4 8 1330 3930 3810 +3421 2 2 4 8 323 324 2891 +3422 2 2 4 8 1747 4243 4113 +3423 2 2 4 8 1746 4245 4114 +3424 2 2 4 8 1146 4674 2024 +3425 2 2 4 8 1755 5287 3310 +3426 2 2 4 8 904 4442 2002 +3427 2 2 4 8 1707 3730 4629 +3428 2 2 4 8 336 2008 3925 +3429 2 2 4 8 349 350 3185 +3430 2 2 4 8 163 3184 162 +3431 2 2 4 8 2103 1119 3194 +3432 2 2 4 8 2105 5165 4957 +3433 2 2 4 8 2043 5234 4105 +3434 2 2 4 8 2003 2266 5406 +3435 2 2 4 8 559 4594 2295 +3436 2 2 4 8 860 2482 2920 +3437 2 2 4 8 861 2483 2919 +3438 2 2 4 8 917 5061 2295 +3439 2 2 4 8 1688 2295 5061 +3440 2 2 4 8 318 1985 3711 +3441 2 2 4 8 473 2224 5007 +3442 2 2 4 8 602 5203 3204 +3443 2 2 4 8 508 4081 2889 +3444 2 2 4 8 519 4082 2890 +3445 2 2 4 8 2101 3889 1298 +3446 2 2 4 8 680 3889 2101 +3447 2 2 4 8 1670 3201 4478 +3448 2 2 4 8 1221 1984 3651 +3449 2 2 4 8 1809 2774 3927 +3450 2 2 4 8 1126 4262 3087 +3451 2 2 4 8 1164 2854 3308 +3452 2 2 4 8 1163 2855 3309 +3453 2 2 4 8 1064 5154 3251 +3454 2 2 4 8 2404 5199 5142 +3455 2 2 4 8 2086 4639 977 +3456 2 2 4 8 608 2453 2908 +3457 2 2 4 8 1090 2856 2265 +3458 2 2 4 8 2263 4104 2477 +3459 2 2 4 8 1135 2307 4621 +3460 2 2 4 8 1624 3442 4760 +3461 2 2 4 8 1108 5007 2669 +3462 2 2 4 8 2581 3436 4202 +3463 2 2 4 8 2204 2943 4209 +3464 2 2 4 8 1978 4969 2989 +3465 2 2 4 8 1976 4970 2990 +3466 2 2 4 8 1269 5220 3783 +3467 2 2 4 8 1751 2986 4512 +3468 2 2 4 8 46 47 2809 +3469 2 2 4 8 268 2810 267 +3470 2 2 4 8 80 81 2808 +3471 2 2 4 8 2089 3143 1626 +3472 2 2 4 8 862 2479 3459 +3473 2 2 4 8 1320 1992 3629 +3474 2 2 4 8 1319 1993 3628 +3475 2 2 4 8 2166 2552 5207 +3476 2 2 4 8 889 5165 3233 +3477 2 2 4 8 2492 2973 4632 +3478 2 2 4 8 2430 5350 2920 +3479 2 2 4 8 1176 3177 5015 +3480 2 2 4 8 1455 3395 2517 +3481 2 2 4 8 1167 2049 5344 +3482 2 2 4 8 1133 2120 3214 +3483 2 2 4 8 1271 3124 2179 +3484 2 2 4 8 923 2179 3124 +3485 2 2 4 8 583 2967 3726 +3486 2 2 4 8 1227 1996 3706 +3487 2 2 4 8 1598 3529 3896 +3488 2 2 4 8 1599 3897 3530 +3489 2 2 4 8 664 3118 2182 +3490 2 2 4 8 1448 3912 2553 +3491 2 2 4 8 404 2389 3052 +3492 2 2 4 8 657 3552 2795 +3493 2 2 4 8 659 3551 2794 +3494 2 2 4 8 455 2841 4802 +3495 2 2 4 8 910 2404 5142 +3496 2 2 4 8 1748 2634 5213 +3497 2 2 4 8 1749 2635 5214 +3498 2 2 4 8 1233 2341 3451 +3499 2 2 4 8 1752 5270 2455 +3500 2 2 4 8 1753 2456 5271 +3501 2 2 4 8 1424 4204 2040 +3502 2 2 4 8 1235 3570 3530 +3503 2 2 4 8 809 4002 2197 +3504 2 2 4 8 531 2139 4825 +3505 2 2 4 8 532 2140 4826 +3506 2 2 4 8 1162 2941 3307 +3507 2 2 4 8 1164 3308 2940 +3508 2 2 4 8 1268 5226 3781 +3509 2 2 4 8 685 2977 3680 +3510 2 2 4 8 1246 5208 2155 +3511 2 2 4 8 1532 4022 4505 +3512 2 2 4 8 2071 1173 4090 +3513 2 2 4 8 2070 1172 4089 +3514 2 2 4 8 1297 3925 2008 +3515 2 2 4 8 2547 3336 4150 +3516 2 2 4 8 1115 4252 2727 +3517 2 2 4 8 1064 2436 5154 +3518 2 2 4 8 797 5364 4926 +3519 2 2 4 8 589 2033 4403 +3520 2 2 4 8 809 2202 4002 +3521 2 2 4 8 656 3497 2796 +3522 2 2 4 8 2077 5284 1102 +3523 2 2 4 8 1686 3548 2137 +3524 2 2 4 8 626 5379 2331 +3525 2 2 4 8 2086 3072 639 +3526 2 2 4 8 965 2655 2615 +3527 2 2 4 8 963 2656 2612 +3528 2 2 4 8 966 2657 2613 +3529 2 2 4 8 1492 4615 4323 +3530 2 2 4 8 1267 2780 2978 +3531 2 2 4 8 677 2978 2780 +3532 2 2 4 8 1415 4033 3119 +3533 2 2 4 8 455 4802 2895 +3534 2 2 4 8 592 2969 2184 +3535 2 2 4 8 889 3233 4323 +3536 2 2 4 8 1674 2584 5384 +3537 2 2 4 8 2365 2627 4692 +3538 2 2 4 8 1970 3728 2589 +3539 2 2 4 8 575 4723 3741 +3540 2 2 4 8 1331 2037 4721 +3541 2 2 4 8 1332 2038 4722 +3542 2 2 4 8 1807 2519 5275 +3543 2 2 4 8 1862 3964 2806 +3544 2 2 4 8 1339 2806 3964 +3545 2 2 4 8 1792 2676 4920 +3546 2 2 4 8 1452 4291 2908 +3547 2 2 4 8 1855 2908 4291 +3548 2 2 4 8 828 2053 5238 +3549 2 2 4 8 1196 3311 4255 +3550 2 2 4 8 1022 3032 4803 +3551 2 2 4 8 1573 4167 2559 +3552 2 2 4 8 856 2559 4167 +3553 2 2 4 8 688 3144 2063 +3554 2 2 4 8 490 4236 3998 +3555 2 2 4 8 2023 2724 3830 +3556 2 2 4 8 1224 3593 2046 +3557 2 2 4 8 822 2046 3593 +3558 2 2 4 8 964 3855 2672 +3559 2 2 4 8 1930 3779 2363 +3560 2 2 4 8 336 4386 2008 +3561 2 2 4 8 1662 3226 2157 +3562 2 2 4 8 600 2428 2785 +3563 2 2 4 8 571 4748 3704 +3564 2 2 4 8 316 317 3293 +3565 2 2 4 8 848 4107 5134 +3566 2 2 4 8 511 2802 4551 +3567 2 2 4 8 401 4567 2173 +3568 2 2 4 8 765 2231 4164 +3569 2 2 4 8 1417 4164 2231 +3570 2 2 4 8 2366 3124 3989 +3571 2 2 4 8 1048 4961 2174 +3572 2 2 4 8 812 2009 3906 +3573 2 2 4 8 2160 3923 2829 +3574 2 2 4 8 2830 3922 2161 +3575 2 2 4 8 626 2359 5379 +3576 2 2 4 8 1504 2397 3498 +3577 2 2 4 8 1154 4414 2399 +3578 2 2 4 8 960 3236 4853 +3579 2 2 4 8 1062 4925 3419 +3580 2 2 4 8 1572 4322 4895 +3581 2 2 4 8 880 3368 2029 +3582 2 2 4 8 881 3367 2030 +3583 2 2 4 8 1919 2696 5394 +3584 2 2 4 8 784 3751 2033 +3585 2 2 4 8 1105 5095 2324 +3586 2 2 4 8 1117 4511 3022 +3587 2 2 4 8 593 2305 2864 +3588 2 2 4 8 594 2863 2304 +3589 2 2 4 8 633 3061 2114 +3590 2 2 4 8 634 3062 2115 +3591 2 2 4 8 906 2116 3063 +3592 2 2 4 8 1061 4932 3418 +3593 2 2 4 8 669 2148 3023 +3594 2 2 4 8 670 2149 3024 +3595 2 2 4 8 1102 3128 2436 +3596 2 2 4 8 987 2007 3665 +3597 2 2 4 8 863 4827 2599 +3598 2 2 4 8 865 2598 4828 +3599 2 2 4 8 1064 5183 2436 +3600 2 2 4 8 1093 3915 2242 +3601 2 2 4 8 691 3801 3255 +3602 2 2 4 8 1805 3255 3801 +3603 2 2 4 8 1081 4107 3125 +3604 2 2 4 8 577 4862 3156 +3605 2 2 4 8 2010 3491 3888 +3606 2 2 4 8 689 3888 3491 +3607 2 2 4 8 1036 2968 2217 +3608 2 2 4 8 1535 4696 3741 +3609 2 2 4 8 1513 3606 3642 +3610 2 2 4 8 690 3802 3236 +3611 2 2 4 8 1802 3236 3802 +3612 2 2 4 8 1069 3020 2172 +3613 2 2 4 8 2914 4871 4305 +3614 2 2 4 8 519 2423 4082 +3615 2 2 4 8 508 2422 4081 +3616 2 2 4 8 850 2182 4976 +3617 2 2 4 8 1964 2426 4272 +3618 2 2 4 8 2405 4588 3500 +3619 2 2 4 8 4212 4927 1978 +3620 2 2 4 8 113 2717 4459 +3621 2 2 4 8 124 2716 4458 +3622 2 2 4 8 135 2715 4457 +3623 2 2 4 8 180 2714 4456 +3624 2 2 4 8 292 4455 2712 +3625 2 2 4 8 303 4454 2713 +3626 2 2 4 8 975 3502 3070 +3627 2 2 4 8 620 2354 4240 +3628 2 2 4 8 1618 2423 4554 +3629 2 2 4 8 1100 4554 2423 +3630 2 2 4 8 1276 3708 3315 +3631 2 2 4 8 1028 2649 3463 +3632 2 2 4 8 1377 3463 2649 +3633 2 2 4 8 1379 2650 3464 +3634 2 2 4 8 1029 3464 2650 +3635 2 2 4 8 937 3897 2574 +3636 2 2 4 8 936 2573 3896 +3637 2 2 4 8 507 2209 5096 +3638 2 2 4 8 1173 5233 3231 +3639 2 2 4 8 601 2015 3606 +3640 2 2 4 8 904 2176 4912 +3641 2 2 4 8 903 4911 2177 +3642 2 2 4 8 1039 2034 3392 +3643 2 2 4 8 2430 2762 5300 +3644 2 2 4 8 88 2014 3659 +3645 2 2 4 8 603 3102 4392 +3646 2 2 4 8 1464 2555 4131 +3647 2 2 4 8 571 2134 4748 +3648 2 2 4 8 1824 5092 3122 +3649 2 2 4 8 1825 5093 3123 +3650 2 2 4 8 1823 5094 3121 +3651 2 2 4 8 934 4190 2312 +3652 2 2 4 8 935 4189 2313 +3653 2 2 4 8 2082 3477 2763 +3654 2 2 4 8 1351 3389 5013 +3655 2 2 4 8 1804 2065 4318 +3656 2 2 4 8 2438 4725 3560 +3657 2 2 4 8 2437 3561 4726 +3658 2 2 4 8 1146 2993 2340 +3659 2 2 4 8 667 2340 2993 +3660 2 2 4 8 462 3951 2029 +3661 2 2 4 8 1499 2462 2788 +3662 2 2 4 8 2103 3351 1119 +3663 2 2 4 8 2104 3352 1120 +3664 2 2 4 8 654 2999 2293 +3665 2 2 4 8 2071 4358 1173 +3666 2 2 4 8 1128 2601 2843 +3667 2 2 4 8 601 2390 4344 +3668 2 2 4 8 1817 5257 3693 +3669 2 2 4 8 1816 5256 3694 +3670 2 2 4 8 1818 3695 5258 +3671 2 2 4 8 1820 3697 5261 +3672 2 2 4 8 1821 3698 5260 +3673 2 2 4 8 1819 3696 5259 +3674 2 2 4 8 338 4933 3117 +3675 2 2 4 8 604 2022 3603 +3676 2 2 4 8 1207 3603 2022 +3677 2 2 4 8 675 3320 2917 +3678 2 2 4 8 1877 5318 3168 +3679 2 2 4 8 480 2312 4049 +3680 2 2 4 8 479 2313 4050 +3681 2 2 4 8 1227 2625 2693 +3682 2 2 4 8 840 2023 3830 +3683 2 2 4 8 1914 5265 3230 +3684 2 2 4 8 1915 5266 3231 +3685 2 2 4 8 1100 2423 3261 +3686 2 2 4 8 1101 2422 3260 +3687 2 2 4 8 1589 3682 4867 +3688 2 2 4 8 2094 789 5135 +3689 2 2 4 8 1122 2233 5409 +3690 2 2 4 8 1107 2525 3295 +3691 2 2 4 8 682 5115 2021 +3692 2 2 4 8 1218 2588 4232 +3693 2 2 4 8 642 2605 2831 +3694 2 2 4 8 1692 5062 3084 +3695 2 2 4 8 906 4849 2963 +3696 2 2 4 8 589 3469 2033 +3697 2 2 4 8 2564 4021 3657 +3698 2 2 4 8 1546 2283 4595 +3699 2 2 4 8 859 4595 2283 +3700 2 2 4 8 1352 3967 3235 +3701 2 2 4 8 1879 3235 3967 +3702 2 2 4 8 600 2391 4187 +3703 2 2 4 8 798 2022 4602 +3704 2 2 4 8 2435 4742 3514 +3705 2 2 4 8 1641 3196 4714 +3706 2 2 4 8 1064 2516 5183 +3707 2 2 4 8 1128 2843 2621 +3708 2 2 4 8 2098 679 4510 +3709 2 2 4 8 1146 2024 4869 +3710 2 2 4 8 1848 4257 3883 +3711 2 2 4 8 930 2879 2427 +3712 2 2 4 8 1135 2427 2879 +3713 2 2 4 8 1293 4437 3526 +3714 2 2 4 8 1099 2318 2881 +3715 2 2 4 8 1081 2671 2681 +3716 2 2 4 8 1247 2681 2671 +3717 2 2 4 8 1144 5369 2277 +3718 2 2 4 8 1143 2276 5368 +3719 2 2 4 8 2062 2875 4466 +3720 2 2 4 8 921 2287 2924 +3721 2 2 4 8 1824 2809 5092 +3722 2 2 4 8 1825 2810 5093 +3723 2 2 4 8 1823 2808 5094 +3724 2 2 4 8 1111 4594 2239 +3725 2 2 4 8 2101 3193 4923 +3726 2 2 4 8 980 4326 2432 +3727 2 2 4 8 583 2257 2967 +3728 2 2 4 8 994 2746 2560 +3729 2 2 4 8 995 2747 2561 +3730 2 2 4 8 837 2056 4166 +3731 2 2 4 8 688 2063 4268 +3732 2 2 4 8 1624 3930 2893 +3733 2 2 4 8 522 3428 2805 +3734 2 2 4 8 1422 2805 3428 +3735 2 2 4 8 2079 3669 1125 +3736 2 2 4 8 2080 3670 1124 +3737 2 2 4 8 4107 2167 5134 +3738 2 2 4 8 1079 5174 3225 +3739 2 2 4 8 648 2482 4012 +3740 2 2 4 8 650 2483 4011 +3741 2 2 4 8 537 3079 5268 +3742 2 2 4 8 344 3177 2138 +3743 2 2 4 8 1133 4898 2120 +3744 2 2 4 8 1236 5340 3478 +3745 2 2 4 8 1237 5341 3479 +3746 2 2 4 8 1350 3672 3516 +3747 2 2 4 8 1349 3673 3517 +3748 2 2 4 8 1265 3643 4216 +3749 2 2 4 8 1322 3984 3667 +3750 2 2 4 8 533 2462 3297 +3751 2 2 4 8 709 3290 2981 +3752 2 2 4 8 1519 2981 3290 +3753 2 2 4 8 1824 4010 2809 +3754 2 2 4 8 1825 4009 2810 +3755 2 2 4 8 1823 4008 2808 +3756 2 2 4 8 610 4432 3073 +3757 2 2 4 8 609 3074 4433 +3758 2 2 4 8 595 3126 2583 +3759 2 2 4 8 2096 3658 1118 +3760 2 2 4 8 1700 5068 2730 +3761 2 2 4 8 1480 3837 2602 +3762 2 2 4 8 706 2602 3837 +3763 2 2 4 8 1481 3838 2604 +3764 2 2 4 8 707 2604 3838 +3765 2 2 4 8 1623 2323 4690 +3766 2 2 4 8 1597 4431 3128 +3767 2 2 4 8 1183 2931 2297 +3768 2 2 4 8 1086 3134 2122 +3769 2 2 4 8 610 3073 2160 +3770 2 2 4 8 609 2161 3074 +3771 2 2 4 8 2060 1132 5278 +3772 2 2 4 8 889 4957 5165 +3773 2 2 4 8 1385 2292 4137 +3774 2 2 4 8 931 2903 2318 +3775 2 2 4 8 33 3032 2328 +3776 2 2 4 8 600 4187 2428 +3777 2 2 4 8 1150 4241 4052 +3778 2 2 4 8 192 193 2948 +3779 2 2 4 8 774 3325 2496 +3780 2 2 4 8 610 2466 2811 +3781 2 2 4 8 609 2812 2467 +3782 2 2 4 8 931 2318 4229 +3783 2 2 4 8 3358 5362 1966 +3784 2 2 4 8 1967 3359 5363 +3785 2 2 4 8 962 2078 3239 +3786 2 2 4 8 265 266 2974 +3787 2 2 4 8 44 45 2975 +3788 2 2 4 8 1197 3046 3327 +3789 2 2 4 8 77 78 3101 +3790 2 2 4 8 1263 2194 3685 +3791 2 2 4 8 530 3685 2194 +3792 2 2 4 8 1155 2133 4667 +3793 2 2 4 8 1775 2794 4935 +3794 2 2 4 8 907 2361 4321 +3795 2 2 4 8 908 2362 4320 +3796 2 2 4 8 518 3640 2655 +3797 2 2 4 8 195 3452 2130 +3798 2 2 4 8 977 2982 2269 +3799 2 2 4 8 934 2368 4190 +3800 2 2 4 8 935 2369 4189 +3801 2 2 4 8 2082 1437 4363 +3802 2 2 4 8 1400 2753 2840 +3803 2 2 4 8 1776 2796 4936 +3804 2 2 4 8 959 4468 2134 +3805 2 2 4 8 2428 4462 2785 +3806 2 2 4 8 932 4297 2309 +3807 2 2 4 8 933 4296 2310 +3808 2 2 4 8 2251 4831 3026 +3809 2 2 4 8 1032 2646 2933 +3810 2 2 4 8 1219 2933 2646 +3811 2 2 4 8 215 4721 2037 +3812 2 2 4 8 433 4722 2038 +3813 2 2 4 8 1273 3735 2220 +3814 2 2 4 8 822 2220 3735 +3815 2 2 4 8 2135 5359 3263 +3816 2 2 4 8 1292 3527 4964 +3817 2 2 4 8 1511 3327 3046 +3818 2 2 4 8 1067 3052 2389 +3819 2 2 4 8 14 2158 3612 +3820 2 2 4 8 901 2062 4074 +3821 2 2 4 8 1983 4261 2470 +3822 2 2 4 8 2436 4075 5154 +3823 2 2 4 8 251 2249 3282 +3824 2 2 4 8 603 2147 3102 +3825 2 2 4 8 1243 2405 3500 +3826 2 2 4 8 601 4344 2464 +3827 2 2 4 8 1689 4916 2192 +3828 2 2 4 8 1416 3313 2474 +3829 2 2 4 8 765 5111 2231 +3830 2 2 4 8 626 3940 2359 +3831 2 2 4 8 1903 4411 3345 +3832 2 2 4 8 2333 5095 2687 +3833 2 2 4 8 1430 2112 4465 +3834 2 2 4 8 821 4465 2112 +3835 2 2 4 8 1727 2523 4912 +3836 2 2 4 8 904 4912 2523 +3837 2 2 4 8 903 2522 4911 +3838 2 2 4 8 1726 4911 2522 +3839 2 2 4 8 1568 2805 4157 +3840 2 2 4 8 796 4631 2063 +3841 2 2 4 8 1411 4176 3851 +3842 2 2 4 8 926 2443 4995 +3843 2 2 4 8 1710 4995 2443 +3844 2 2 4 8 1114 4143 2042 +3845 2 2 4 8 871 3702 2208 +3846 2 2 4 8 1308 2208 3702 +3847 2 2 4 8 480 4049 4122 +3848 2 2 4 8 479 4050 4123 +3849 2 2 4 8 962 4308 2078 +3850 2 2 4 8 1681 4203 3607 +3851 2 2 4 8 1348 3470 3077 +3852 2 2 4 8 791 5085 2071 +3853 2 2 4 8 790 5086 2070 +3854 2 2 4 8 1254 2564 3657 +3855 2 2 4 8 2078 2585 3586 +3856 2 2 4 8 1315 3740 3961 +3857 2 2 4 8 931 4229 2355 +3858 2 2 4 8 2491 4869 2831 +3859 2 2 4 8 1806 4601 3993 +3860 2 2 4 8 1253 4284 4115 +3861 2 2 4 8 2682 4319 2268 +3862 2 2 4 8 1094 2165 4776 +3863 2 2 4 8 911 2166 4775 +3864 2 2 4 8 610 2829 2466 +3865 2 2 4 8 609 2467 2830 +3866 2 2 4 8 3033 4132 4184 +3867 2 2 4 8 4169 1968 4305 +3868 2 2 4 8 828 3975 2053 +3869 2 2 4 8 1245 2275 3462 +3870 2 2 4 8 938 3462 2275 +3871 2 2 4 8 3029 5150 4879 +3872 2 2 4 8 1786 3445 5103 +3873 2 2 4 8 1123 2439 2913 +3874 2 2 4 8 524 4753 3605 +3875 2 2 4 8 800 2052 3570 +3876 2 2 4 8 98 3214 2120 +3877 2 2 4 8 1110 2401 4771 +3878 2 2 4 8 696 3280 4452 +3879 2 2 4 8 2082 3314 1188 +3880 2 2 4 8 787 2045 3700 +3881 2 2 4 8 651 3701 2045 +3882 2 2 4 8 627 2352 4007 +3883 2 2 4 8 447 2088 3286 +3884 2 2 4 8 1426 2804 3211 +3885 2 2 4 8 805 3211 2804 +3886 2 2 4 8 1427 2803 3210 +3887 2 2 4 8 806 3210 2803 +3888 2 2 4 8 1430 2322 4529 +3889 2 2 4 8 660 2429 4283 +3890 2 2 4 8 555 5309 5125 +3891 2 2 4 8 1016 2141 4640 +3892 2 2 4 8 1015 2142 4641 +3893 2 2 4 8 1000 2302 5388 +3894 2 2 4 8 826 3683 2270 +3895 2 2 4 8 1112 2364 5089 +3896 2 2 4 8 1112 5089 2365 +3897 2 2 4 8 2014 4332 3411 +3898 2 2 4 8 1399 3033 4184 +3899 2 2 4 8 1116 2251 3026 +3900 2 2 4 8 1267 3205 2780 +3901 2 2 4 8 1089 4541 2121 +3902 2 2 4 8 1086 2122 4543 +3903 2 2 4 8 1085 2125 4544 +3904 2 2 4 8 1083 2126 4546 +3905 2 2 4 8 1084 2124 4545 +3906 2 2 4 8 1087 4542 2123 +3907 2 2 4 8 1249 3224 2873 +3908 2 2 4 8 2111 1429 4495 +3909 2 2 4 8 2110 4494 1428 +3910 2 2 4 8 932 2348 4297 +3911 2 2 4 8 933 2349 4296 +3912 2 2 4 8 495 3607 2054 +3913 2 2 4 8 2587 4247 2913 +3914 2 2 4 8 488 5387 2087 +3915 2 2 4 8 1262 3452 2623 +3916 2 2 4 8 447 4322 2088 +3917 2 2 4 8 450 3355 5336 +3918 2 2 4 8 442 3356 5335 +3919 2 2 4 8 451 5337 3354 +3920 2 2 4 8 1620 2629 5212 +3921 2 2 4 8 625 2358 3730 +3922 2 2 4 8 1028 2384 2896 +3923 2 2 4 8 1029 2897 2385 +3924 2 2 4 8 927 2047 3733 +3925 2 2 4 8 928 3732 2048 +3926 2 2 4 8 1266 4844 2777 +3927 2 2 4 8 502 3927 2774 +3928 2 2 4 8 2094 5116 1176 +3929 2 2 4 8 707 3838 3012 +3930 2 2 4 8 706 3837 3011 +3931 2 2 4 8 2420 2582 5025 +3932 2 2 4 8 629 2907 2381 +3933 2 2 4 8 1580 2442 4689 +3934 2 2 4 8 994 3990 2634 +3935 2 2 4 8 995 3991 2635 +3936 2 2 4 8 67 3405 3439 +3937 2 2 4 8 526 3330 2217 +3938 2 2 4 8 2293 4067 2950 +3939 2 2 4 8 799 2051 4766 +3940 2 2 4 8 496 2474 2842 +3941 2 2 4 8 598 4358 2071 +3942 2 2 4 8 515 2874 3568 +3943 2 2 4 8 762 3572 3481 +3944 2 2 4 8 1783 3481 3572 +3945 2 2 4 8 1133 3029 4879 +3946 2 2 4 8 1212 2218 4665 +3947 2 2 4 8 1193 3092 3384 +3948 2 2 4 8 1192 3091 3383 +3949 2 2 4 8 3077 3470 4754 +3950 2 2 4 8 504 4950 2210 +3951 2 2 4 8 505 4951 2211 +3952 2 2 4 8 2060 3973 1132 +3953 2 2 4 8 468 2892 2399 +3954 2 2 4 8 2070 4253 1172 +3955 2 2 4 8 1106 2182 3118 +3956 2 2 4 8 1348 2535 2878 +3957 2 2 4 8 891 2878 2535 +3958 2 2 4 8 2062 1199 4074 +3959 2 2 4 8 1669 2851 5067 +3960 2 2 4 8 1692 4864 5062 +3961 2 2 4 8 663 2421 3719 +3962 2 2 4 8 2097 1187 4328 +3963 2 2 4 8 1010 2397 4280 +3964 2 2 4 8 1504 4280 2397 +3965 2 2 4 8 1072 2636 4003 +3966 2 2 4 8 1641 3454 4552 +3967 2 2 4 8 1358 4329 3106 +3968 2 2 4 8 14 4583 2158 +3969 2 2 4 8 1210 3347 4813 +3970 2 2 4 8 1234 3529 3482 +3971 2 2 4 8 489 2350 2949 +3972 2 2 4 8 771 4101 2297 +3973 2 2 4 8 1403 2297 4101 +3974 2 2 4 8 769 3373 2099 +3975 2 2 4 8 2099 3373 1161 +3976 2 2 4 8 2100 1160 3372 +3977 2 2 4 8 768 2100 3372 +3978 2 2 4 8 1081 3125 2183 +3979 2 2 4 8 817 4672 2229 +3980 2 2 4 8 1525 2229 4672 +3981 2 2 4 8 1457 2849 3904 +3982 2 2 4 8 331 332 3120 +3983 2 2 4 8 1439 4201 2383 +3984 2 2 4 8 971 2144 4633 +3985 2 2 4 8 459 3168 5318 +3986 2 2 4 8 1725 5229 3014 +3987 2 2 4 8 2097 3601 2597 +3988 2 2 4 8 1441 4533 2131 +3989 2 2 4 8 1440 4532 2132 +3990 2 2 4 8 687 3623 2791 +3991 2 2 4 8 1514 2449 4226 +3992 2 2 4 8 892 4226 2449 +3993 2 2 4 8 662 3821 2353 +3994 2 2 4 8 1398 2675 3569 +3995 2 2 4 8 1019 3569 2675 +3996 2 2 4 8 1068 4512 2986 +3997 2 2 4 8 1122 5409 2366 +3998 2 2 4 8 996 2268 3034 +3999 2 2 4 8 2075 1196 4750 +4000 2 2 4 8 791 2071 4090 +4001 2 2 4 8 790 2070 4089 +4002 2 2 4 8 708 4373 2586 +4003 2 2 4 8 1411 2834 4176 +4004 2 2 4 8 1078 2244 5118 +4005 2 2 4 8 598 2071 3511 +4006 2 2 4 8 417 418 3311 +4007 2 2 4 8 2100 4118 1160 +4008 2 2 4 8 2099 1161 4117 +4009 2 2 4 8 2091 3384 606 +4010 2 2 4 8 2092 3383 613 +4011 2 2 4 8 1414 2880 3877 +4012 2 2 4 8 941 4561 4781 +4013 2 2 4 8 1215 3413 2235 +4014 2 2 4 8 606 2235 3413 +4015 2 2 4 8 613 2236 3414 +4016 2 2 4 8 1217 3414 2236 +4017 2 2 4 8 531 3351 2103 +4018 2 2 4 8 532 3352 2104 +4019 2 2 4 8 676 2065 3992 +4020 2 2 4 8 1541 4179 2721 +4021 2 2 4 8 810 4937 2065 +4022 2 2 4 8 1466 2828 4094 +4023 2 2 4 8 1470 2824 4095 +4024 2 2 4 8 854 2286 4865 +4025 2 2 4 8 1595 4865 2286 +4026 2 2 4 8 648 5231 4959 +4027 2 2 4 8 650 5232 4960 +4028 2 2 4 8 1008 5345 2458 +4029 2 2 4 8 2078 4308 1182 +4030 2 2 4 8 941 2306 4561 +4031 2 2 4 8 1544 4927 4212 +4032 2 2 4 8 1460 2909 4070 +4033 2 2 4 8 1012 3813 3286 +4034 2 2 4 8 2091 606 3413 +4035 2 2 4 8 2092 613 3414 +4036 2 2 4 8 537 3937 3079 +4037 2 2 4 8 2094 1176 3929 +4038 2 2 4 8 857 2129 4431 +4039 2 2 4 8 419 2095 4255 +4040 2 2 4 8 885 3154 2186 +4041 2 2 4 8 838 3257 2136 +4042 2 2 4 8 538 4761 3239 +4043 2 2 4 8 1377 5137 3463 +4044 2 2 4 8 695 4258 2865 +4045 2 2 4 8 1185 3006 3203 +4046 2 2 4 8 102 2637 101 +4047 2 2 4 8 563 2886 4958 +4048 2 2 4 8 2006 4958 2886 +4049 2 2 4 8 1662 4796 2191 +4050 2 2 4 8 1815 4626 4031 +4051 2 2 4 8 932 2309 3183 +4052 2 2 4 8 933 2310 3182 +4053 2 2 4 8 1328 3619 3846 +4054 2 2 4 8 1327 3844 3618 +4055 2 2 4 8 1150 2987 4241 +4056 2 2 4 8 1020 2870 2484 +4057 2 2 4 8 538 2078 3586 +4058 2 2 4 8 2107 3369 1184 +4059 2 2 4 8 1691 2136 3613 +4060 2 2 4 8 478 2778 4799 +4061 2 2 4 8 2102 915 4289 +4062 2 2 4 8 249 250 4169 +4063 2 2 4 8 1219 3393 2514 +4064 2 2 4 8 947 3323 4211 +4065 2 2 4 8 1957 3881 2703 +4066 2 2 4 8 1574 2577 4531 +4067 2 2 4 8 2075 3835 1196 +4068 2 2 4 8 90 91 2638 +4069 2 2 4 8 86 87 3005 +4070 2 2 4 8 1423 4170 2609 +4071 2 2 4 8 1089 3111 2713 +4072 2 2 4 8 1087 3112 2712 +4073 2 2 4 8 1086 2714 3113 +4074 2 2 4 8 1085 2715 3114 +4075 2 2 4 8 1084 2716 3115 +4076 2 2 4 8 1083 2717 3116 +4077 2 2 4 8 454 2654 3964 +4078 2 2 4 8 324 325 4299 +4079 2 2 4 8 1393 5102 3426 +4080 2 2 4 8 849 2155 5316 +4081 2 2 4 8 1159 3051 4993 +4082 2 2 4 8 1013 2138 5204 +4083 2 2 4 8 71 3312 2133 +4084 2 2 4 8 1134 2882 4263 +4085 2 2 4 8 632 3049 5065 +4086 2 2 4 8 684 3792 2871 +4087 2 2 4 8 1009 4667 2133 +4088 2 2 4 8 852 2139 3362 +4089 2 2 4 8 853 2140 3363 +4090 2 2 4 8 653 3451 2341 +4091 2 2 4 8 1116 3004 4416 +4092 2 2 4 8 1471 3385 3207 +4093 2 2 4 8 671 2150 3250 +4094 2 2 4 8 672 2151 3251 +4095 2 2 4 8 2777 4844 3127 +4096 2 2 4 8 648 4012 2660 +4097 2 2 4 8 650 4011 2659 +4098 2 2 4 8 712 5196 4435 +4099 2 2 4 8 1798 4774 2190 +4100 2 2 4 8 1799 4773 2191 +4101 2 2 4 8 1506 3145 4758 +4102 2 2 4 8 1505 4757 3146 +4103 2 2 4 8 306 307 2959 +4104 2 2 4 8 295 296 2958 +4105 2 2 4 8 176 177 2957 +4106 2 2 4 8 132 2956 131 +4107 2 2 4 8 120 121 2955 +4108 2 2 4 8 2301 999 5303 +4109 2 2 4 8 2050 5268 3079 +4110 2 2 4 8 583 4814 2137 +4111 2 2 4 8 814 2226 4708 +4112 2 2 4 8 1522 4708 2226 +4113 2 2 4 8 815 2227 4709 +4114 2 2 4 8 1523 4709 2227 +4115 2 2 4 8 1524 4710 2228 +4116 2 2 4 8 823 2228 4710 +4117 2 2 4 8 1526 2230 4711 +4118 2 2 4 8 819 4711 2230 +4119 2 2 4 8 1647 3021 2876 +4120 2 2 4 8 694 2346 3000 +4121 2 2 4 8 2820 4128 1899 +4122 2 2 4 8 1898 4129 2819 +4123 2 2 4 8 1220 5144 4091 +4124 2 2 4 8 1244 2345 3700 +4125 2 2 4 8 997 2913 2439 +4126 2 2 4 8 480 3028 2312 +4127 2 2 4 8 479 3027 2313 +4128 2 2 4 8 356 2141 3298 +4129 2 2 4 8 169 2142 3299 +4130 2 2 4 8 1762 2414 5318 +4131 2 2 4 8 459 5318 2414 +4132 2 2 4 8 1835 2317 5390 +4133 2 2 4 8 2123 3693 5257 +4134 2 2 4 8 2121 3694 5256 +4135 2 2 4 8 2122 5258 3695 +4136 2 2 4 8 2124 5261 3697 +4137 2 2 4 8 2126 5260 3698 +4138 2 2 4 8 2125 5259 3696 +4139 2 2 4 8 652 3402 2433 +4140 2 2 4 8 816 4532 2146 +4141 2 2 4 8 824 4533 2147 +4142 2 2 4 8 1440 2146 4532 +4143 2 2 4 8 2147 4533 1441 +4144 2 2 4 8 662 2353 3064 +4145 2 2 4 8 1805 4727 3255 +4146 2 2 4 8 820 2161 3922 +4147 2 2 4 8 818 3923 2160 +4148 2 2 4 8 882 3263 5359 +4149 2 2 4 8 2097 4328 978 +4150 2 2 4 8 247 248 2661 +4151 2 2 4 8 190 3338 2159 +4152 2 2 4 8 1245 2159 3338 +4153 2 2 4 8 265 2974 4592 +4154 2 2 4 8 1438 3819 2833 +4155 2 2 4 8 2145 979 3280 +4156 2 2 4 8 443 4562 3038 +4157 2 2 4 8 2107 1184 3468 +4158 2 2 4 8 2107 3468 636 +4159 2 2 4 8 531 2103 4220 +4160 2 2 4 8 532 2104 4222 +4161 2 2 4 8 660 3999 2077 +4162 2 2 4 8 719 5037 3988 +4163 2 2 4 8 161 162 3631 +4164 2 2 4 8 348 349 3630 +4165 2 2 4 8 1482 2551 4178 +4166 2 2 4 8 1660 3380 2143 +4167 2 2 4 8 1207 5121 3275 +4168 2 2 4 8 2076 4770 1232 +4169 2 2 4 8 2099 4174 1364 +4170 2 2 4 8 2100 1365 4175 +4171 2 2 4 8 1498 3623 3227 +4172 2 2 4 8 1234 4646 3180 +4173 2 2 4 8 939 3900 2365 +4174 2 2 4 8 1234 3482 4646 +4175 2 2 4 8 581 5099 4548 +4176 2 2 4 8 1261 4847 2113 +4177 2 2 4 8 2145 1258 3292 +4178 2 2 4 8 38 3445 2506 +4179 2 2 4 8 26 2425 3432 +4180 2 2 4 8 535 2944 5307 +4181 2 2 4 8 1595 3957 3047 +4182 2 2 4 8 564 5008 2238 +4183 2 2 4 8 1261 2576 4984 +4184 2 2 4 8 1668 4751 2711 +4185 2 2 4 8 1165 4640 2141 +4186 2 2 4 8 1166 4641 2142 +4187 2 2 4 8 1223 3081 2572 +4188 2 2 4 8 475 2572 3081 +4189 2 2 4 8 1175 2332 3475 +4190 2 2 4 8 1220 4091 3343 +4191 2 2 4 8 820 4495 2161 +4192 2 2 4 8 1429 2161 4495 +4193 2 2 4 8 818 2160 4494 +4194 2 2 4 8 1428 4494 2160 +4195 2 2 4 8 407 4003 2636 +4196 2 2 4 8 1842 3757 2272 +4197 2 2 4 8 997 2439 4886 +4198 2 2 4 8 787 3835 2075 +4199 2 2 4 8 1658 4923 3193 +4200 2 2 4 8 1558 2424 3371 +4201 2 2 4 8 2941 4273 3307 +4202 2 2 4 8 2940 3308 4274 +4203 2 2 4 8 446 2268 3327 +4204 2 2 4 8 1197 3327 2268 +4205 2 2 4 8 774 3371 4184 +4206 2 2 4 8 88 89 4379 +4207 2 2 4 8 543 3601 2097 +4208 2 2 4 8 1759 3955 4440 +4209 2 2 4 8 588 3736 2198 +4210 2 2 4 8 287 3440 2110 +4211 2 2 4 8 256 2111 3441 +4212 2 2 4 8 66 3439 2112 +4213 2 2 4 8 1545 3556 3667 +4214 2 2 4 8 1062 3221 2185 +4215 2 2 4 8 486 2273 3549 +4216 2 2 4 8 1037 3269 2169 +4217 2 2 4 8 1038 3270 2170 +4218 2 2 4 8 1210 2249 3347 +4219 2 2 4 8 1211 3346 2250 +4220 2 2 4 8 252 3347 2249 +4221 2 2 4 8 246 2250 3346 +4222 2 2 4 8 1733 2559 3125 +4223 2 2 4 8 1457 3568 2874 +4224 2 2 4 8 1529 2458 4424 +4225 2 2 4 8 1528 2457 4423 +4226 2 2 4 8 892 3141 2235 +4227 2 2 4 8 893 3140 2236 +4228 2 2 4 8 891 3142 2234 +4229 2 2 4 8 1105 2687 5095 +4230 2 2 4 8 1226 3545 2575 +4231 2 2 4 8 919 3611 2493 +4232 2 2 4 8 2509 3368 1657 +4233 2 2 4 8 2510 3367 1656 +4234 2 2 4 8 1128 2831 2605 +4235 2 2 4 8 1640 3619 2554 +4236 2 2 4 8 1638 2555 3618 +4237 2 2 4 8 1135 5403 2307 +4238 2 2 4 8 938 2948 4657 +4239 2 2 4 8 2307 2735 4621 +4240 2 2 4 8 1113 3158 2222 +4241 2 2 4 8 1136 3843 2949 +4242 2 2 4 8 2084 840 3652 +4243 2 2 4 8 426 3287 2288 +4244 2 2 4 8 3 3288 2289 +4245 2 2 4 8 1167 2921 3064 +4246 2 2 4 8 2083 3969 898 +4247 2 2 4 8 648 2901 5231 +4248 2 2 4 8 650 2902 5232 +4249 2 2 4 8 1113 2398 2988 +4250 2 2 4 8 939 2394 3900 +4251 2 2 4 8 602 2912 2487 +4252 2 2 4 8 4169 4305 1530 +4253 2 2 4 8 2415 3910 2845 +4254 2 2 4 8 2494 3951 1773 +4255 2 2 4 8 2495 3950 1772 +4256 2 2 4 8 668 2164 5263 +4257 2 2 4 8 1030 2888 2526 +4258 2 2 4 8 1107 3295 2776 +4259 2 2 4 8 1123 5186 2439 +4260 2 2 4 8 483 3006 2473 +4261 2 2 4 8 1299 3599 2163 +4262 2 2 4 8 643 2163 3599 +4263 2 2 4 8 1453 4128 2438 +4264 2 2 4 8 1025 4129 2437 +4265 2 2 4 8 1026 2438 4128 +4266 2 2 4 8 1454 2437 4129 +4267 2 2 4 8 626 2544 3940 +4268 2 2 4 8 913 5368 2276 +4269 2 2 4 8 916 2277 5369 +4270 2 2 4 8 848 3983 2788 +4271 2 2 4 8 1911 3117 4933 +4272 2 2 4 8 114 3116 2717 +4273 2 2 4 8 125 3115 2716 +4274 2 2 4 8 136 3114 2715 +4275 2 2 4 8 181 3113 2714 +4276 2 2 4 8 302 2713 3111 +4277 2 2 4 8 291 2712 3112 +4278 2 2 4 8 1495 3094 3656 +4279 2 2 4 8 856 3125 2559 +4280 2 2 4 8 2088 4861 872 +4281 2 2 4 8 640 2606 2951 +4282 2 2 4 8 1177 2951 2606 +4283 2 2 4 8 1608 4147 3005 +4284 2 2 4 8 508 3387 3260 +4285 2 2 4 8 519 3388 3261 +4286 2 2 4 8 668 2843 2601 +4287 2 2 4 8 919 2524 3611 +4288 2 2 4 8 2089 795 4119 +4289 2 2 4 8 1048 2175 4606 +4290 2 2 4 8 1841 3914 3726 +4291 2 2 4 8 140 2132 3448 +4292 2 2 4 8 361 2131 3449 +4293 2 2 4 8 1122 2366 3442 +4294 2 2 4 8 1103 2440 4063 +4295 2 2 4 8 2087 3770 873 +4296 2 2 4 8 360 3449 3409 +4297 2 2 4 8 477 3513 2109 +4298 2 2 4 8 1403 2396 3053 +4299 2 2 4 8 1484 3680 2977 +4300 2 2 4 8 1695 5314 2315 +4301 2 2 4 8 1020 2994 2640 +4302 2 2 4 8 1017 2996 2642 +4303 2 2 4 8 1018 2641 2995 +4304 2 2 4 8 971 2544 4467 +4305 2 2 4 8 2098 4510 1277 +4306 2 2 4 8 1440 3382 2146 +4307 2 2 4 8 2094 3929 789 +4308 2 2 4 8 1052 4868 2481 +4309 2 2 4 8 1159 2694 5065 +4310 2 2 4 8 1304 3719 2421 +4311 2 2 4 8 2458 5345 2607 +4312 2 2 4 8 1177 2606 4584 +4313 2 2 4 8 1252 2644 3034 +4314 2 2 4 8 996 3034 2644 +4315 2 2 4 8 528 2489 2927 +4316 2 2 4 8 1557 3007 5153 +4317 2 2 4 8 1661 3377 2156 +4318 2 2 4 8 486 4842 2393 +4319 2 2 4 8 1028 3016 2649 +4320 2 2 4 8 1029 2650 3018 +4321 2 2 4 8 1030 2651 3017 +4322 2 2 4 8 1358 2453 3178 +4323 2 2 4 8 2108 1418 4163 +4324 2 2 4 8 44 2975 4642 +4325 2 2 4 8 1019 2675 3031 +4326 2 2 4 8 1052 2490 4868 +4327 2 2 4 8 2295 4594 2790 +4328 2 2 4 8 1202 3331 4815 +4329 2 2 4 8 1150 5304 2924 +4330 2 2 4 8 2224 2669 5007 +4331 2 2 4 8 583 2188 3289 +4332 2 2 4 8 629 4192 2333 +4333 2 2 4 8 590 5213 2634 +4334 2 2 4 8 591 5214 2635 +4335 2 2 4 8 794 4693 3381 +4336 2 2 4 8 959 2558 4468 +4337 2 2 4 8 1358 3855 2453 +4338 2 2 4 8 964 2453 3855 +4339 2 2 4 8 1457 2610 2849 +4340 2 2 4 8 627 4007 2538 +4341 2 2 4 8 1418 4000 2463 +4342 2 2 4 8 704 2463 4000 +4343 2 2 4 8 625 3730 2528 +4344 2 2 4 8 569 2258 3157 +4345 2 2 4 8 258 259 2709 +4346 2 2 4 8 284 285 2710 +4347 2 2 4 8 64 2708 63 +4348 2 2 4 8 554 2569 3015 +4349 2 2 4 8 1177 3015 2569 +4350 2 2 4 8 897 4687 3256 +4351 2 2 4 8 2164 3256 4687 +4352 2 2 4 8 1435 2582 4691 +4353 2 2 4 8 1045 4935 2794 +4354 2 2 4 8 1134 4263 4477 +4355 2 2 4 8 1133 2300 4898 +4356 2 2 4 8 1758 3960 4448 +4357 2 2 4 8 663 2183 4301 +4358 2 2 4 8 1150 4052 5304 +4359 2 2 4 8 2103 1268 4220 +4360 2 2 4 8 2104 1269 4222 +4361 2 2 4 8 695 4696 4258 +4362 2 2 4 8 1094 2299 5215 +4363 2 2 4 8 1208 4366 2128 +4364 2 2 4 8 1046 4936 2796 +4365 2 2 4 8 1154 2862 4414 +4366 2 2 4 8 466 3391 2165 +4367 2 2 4 8 385 4295 2649 +4368 2 2 4 8 147 2650 4294 +4369 2 2 4 8 368 2651 4293 +4370 2 2 4 8 620 3030 2382 +4371 2 2 4 8 1022 3690 2328 +4372 2 2 4 8 1271 2328 3690 +4373 2 2 4 8 1637 4327 4803 +4374 2 2 4 8 957 5294 2381 +4375 2 2 4 8 1712 2381 5294 +4376 2 2 4 8 1051 2269 3156 +4377 2 2 4 8 1209 4217 2127 +4378 2 2 4 8 1272 3035 2379 +4379 2 2 4 8 855 2577 5048 +4380 2 2 4 8 468 4863 5296 +4381 2 2 4 8 649 3086 2314 +4382 2 2 4 8 1564 2114 4755 +4383 2 2 4 8 1563 2115 4756 +4384 2 2 4 8 96 97 2692 +4385 2 2 4 8 855 3324 4338 +4386 2 2 4 8 2050 4338 3324 +4387 2 2 4 8 1221 3651 2163 +4388 2 2 4 8 1957 3354 4112 +4389 2 2 4 8 1006 4112 3354 +4390 2 2 4 8 959 2134 4261 +4391 2 2 4 8 1737 3218 4130 +4392 2 2 4 8 821 2112 4070 +4393 2 2 4 8 1982 2469 4369 +4394 2 2 4 8 859 2315 4406 +4395 2 2 4 8 630 3283 3087 +4396 2 2 4 8 1486 3087 3283 +4397 2 2 4 8 1135 2367 5403 +4398 2 2 4 8 847 2323 4983 +4399 2 2 4 8 1623 4983 2323 +4400 2 2 4 8 1065 3284 2203 +4401 2 2 4 8 2106 1168 4230 +4402 2 2 4 8 602 2322 4968 +4403 2 2 4 8 1619 4968 2322 +4404 2 2 4 8 1213 3473 2234 +4405 2 2 4 8 603 2234 3473 +4406 2 2 4 8 1834 3605 4753 +4407 2 2 4 8 205 206 4265 +4408 2 2 4 8 422 423 4264 +4409 2 2 4 8 221 222 4266 +4410 2 2 4 8 439 440 4267 +4411 2 2 4 8 4176 2834 4839 +4412 2 2 4 8 1218 4232 3257 +4413 2 2 4 8 1617 3849 3081 +4414 2 2 4 8 1285 3739 2173 +4415 2 2 4 8 870 2216 4841 +4416 2 2 4 8 914 2174 3403 +4417 2 2 4 8 1035 5006 2498 +4418 2 2 4 8 1688 3083 5052 +4419 2 2 4 8 1683 3082 5053 +4420 2 2 4 8 1110 2545 2917 +4421 2 2 4 8 1831 3658 3597 +4422 2 2 4 8 781 3597 3658 +4423 2 2 4 8 1533 4506 2388 +4424 2 2 4 8 553 2388 4506 +4425 2 2 4 8 467 5207 2303 +4426 2 2 4 8 1688 3585 2295 +4427 2 2 4 8 635 4832 2441 +4428 2 2 4 8 1285 2173 3968 +4429 2 2 4 8 1023 3079 2742 +4430 2 2 4 8 972 4157 2805 +4431 2 2 4 8 578 4448 2490 +4432 2 2 4 8 749 5120 3305 +4433 2 2 4 8 1198 3283 2690 +4434 2 2 4 8 603 3473 2147 +4435 2 2 4 8 607 3474 2146 +4436 2 2 4 8 194 195 4483 +4437 2 2 4 8 1946 4628 5076 +4438 2 2 4 8 340 341 4357 +4439 2 2 4 8 1261 2113 3856 +4440 2 2 4 8 1326 3049 2848 +4441 2 2 4 8 63 2708 2866 +4442 2 2 4 8 259 2867 2709 +4443 2 2 4 8 284 2710 2868 +4444 2 2 4 8 263 2641 4213 +4445 2 2 4 8 59 4215 2640 +4446 2 2 4 8 280 4214 2642 +4447 2 2 4 8 1032 2933 2531 +4448 2 2 4 8 645 3500 4588 +4449 2 2 4 8 2853 3047 1162 +4450 2 2 4 8 1452 4250 2113 +4451 2 2 4 8 1227 2693 3605 +4452 2 2 4 8 1501 5122 4031 +4453 2 2 4 8 1920 4356 4992 +4454 2 2 4 8 1221 4032 3366 +4455 2 2 4 8 1302 5353 2917 +4456 2 2 4 8 2018 3718 4385 +4457 2 2 4 8 1725 3014 4921 +4458 2 2 4 8 619 3545 4217 +4459 2 2 4 8 2127 4217 3545 +4460 2 2 4 8 1025 2819 4129 +4461 2 2 4 8 1026 4128 2820 +4462 2 2 4 8 1213 3581 3188 +4463 2 2 4 8 1215 3582 3190 +4464 2 2 4 8 1827 5004 2727 +4465 2 2 4 8 796 2727 5004 +4466 2 2 4 8 412 413 2711 +4467 2 2 4 8 3092 4680 3384 +4468 2 2 4 8 3091 4679 3383 +4469 2 2 4 8 1054 4846 2504 +4470 2 2 4 8 1053 4845 2505 +4471 2 2 4 8 1302 3289 5353 +4472 2 2 4 8 1496 4964 2118 +4473 2 2 4 8 1053 2511 4845 +4474 2 2 4 8 1054 2512 4846 +4475 2 2 4 8 142 143 2723 +4476 2 2 4 8 363 364 2722 +4477 2 2 4 8 629 2381 4192 +4478 2 2 4 8 1019 2685 2837 +4479 2 2 4 8 1387 2327 4138 +4480 2 2 4 8 799 4139 2326 +4481 2 2 4 8 800 4138 2327 +4482 2 2 4 8 1386 2326 4139 +4483 2 2 4 8 626 2934 2544 +4484 2 2 4 8 1795 5147 3090 +4485 2 2 4 8 2664 4096 5139 +4486 2 2 4 8 622 2319 3145 +4487 2 2 4 8 623 3146 2320 +4488 2 2 4 8 143 2854 2723 +4489 2 2 4 8 364 2855 2722 +4490 2 2 4 8 543 2119 4630 +4491 2 2 4 8 982 2659 4011 +4492 2 2 4 8 983 2660 4012 +4493 2 2 4 8 188 189 3970 +4494 2 2 4 8 523 4893 2694 +4495 2 2 4 8 1780 2694 4893 +4496 2 2 4 8 1463 3484 3244 +4497 2 2 4 8 1462 3483 3246 +4498 2 2 4 8 1468 3241 3486 +4499 2 2 4 8 1469 3240 3487 +4500 2 2 4 8 1315 2486 3682 +4501 2 2 4 8 487 3682 2486 +4502 2 2 4 8 240 3401 239 +4503 2 2 4 8 1004 4243 2800 +4504 2 2 4 8 1005 4245 2801 +4505 2 2 4 8 703 2608 3641 +4506 2 2 4 8 1017 2642 3632 +4507 2 2 4 8 1362 3632 2642 +4508 2 2 4 8 1018 3633 2641 +4509 2 2 4 8 1361 2641 3633 +4510 2 2 4 8 1355 2466 3847 +4511 2 2 4 8 965 3847 2466 +4512 2 2 4 8 963 2467 3848 +4513 2 2 4 8 1356 3848 2467 +4514 2 2 4 8 767 2542 4490 +4515 2 2 4 8 1578 4490 2542 +4516 2 2 4 8 1577 4489 2543 +4517 2 2 4 8 766 2543 4489 +4518 2 2 4 8 461 2270 5003 +4519 2 2 4 8 1100 3261 2761 +4520 2 2 4 8 1101 3260 2760 +4521 2 2 4 8 1683 3873 2373 +4522 2 2 4 8 1685 2374 3874 +4523 2 2 4 8 888 2159 4313 +4524 2 2 4 8 1095 5155 2298 +4525 2 2 4 8 2515 3763 1941 +4526 2 2 4 8 1309 3238 2254 +4527 2 2 4 8 1069 2172 4387 +4528 2 2 4 8 922 2299 3499 +4529 2 2 4 8 1396 2861 3578 +4530 2 2 4 8 1397 2860 3579 +4531 2 2 4 8 1570 2282 3572 +4532 2 2 4 8 1571 2281 3571 +4533 2 2 4 8 1133 3214 2442 +4534 2 2 4 8 549 3269 5108 +4535 2 2 4 8 550 3270 5109 +4536 2 2 4 8 103 3443 2386 +4537 2 2 4 8 1413 2910 4014 +4538 2 2 4 8 669 3573 2148 +4539 2 2 4 8 670 3574 2149 +4540 2 2 4 8 4167 4900 1693 +4541 2 2 4 8 1687 4073 2406 +4542 2 2 4 8 712 3453 5196 +4543 2 2 4 8 1149 2207 3376 +4544 2 2 4 8 1513 2654 4370 +4545 2 2 4 8 811 2143 4170 +4546 2 2 4 8 76 2196 4798 +4547 2 2 4 8 1185 2473 3006 +4548 2 2 4 8 643 2410 3043 +4549 2 2 4 8 1132 2315 3762 +4550 2 2 4 8 166 4648 2411 +4551 2 2 4 8 353 4647 2412 +4552 2 2 4 8 407 408 4003 +4553 2 2 4 8 1831 3597 2627 +4554 2 2 4 8 1001 5152 2303 +4555 2 2 4 8 1397 2798 3941 +4556 2 2 4 8 1257 2506 3445 +4557 2 2 4 8 763 3699 3104 +4558 2 2 4 8 1627 3104 3699 +4559 2 2 4 8 1479 2904 2603 +4560 2 2 4 8 1480 2602 2906 +4561 2 2 4 8 1481 2604 2905 +4562 2 2 4 8 1011 3726 3914 +4563 2 2 4 8 1124 2511 4441 +4564 2 2 4 8 587 4440 2512 +4565 2 2 4 8 1133 2442 3029 +4566 2 2 4 8 833 2137 4195 +4567 2 2 4 8 1697 2666 3827 +4568 2 2 4 8 714 2914 4305 +4569 2 2 4 8 561 4765 2232 +4570 2 2 4 8 351 4948 2212 +4571 2 2 4 8 164 4947 2213 +4572 2 2 4 8 2044 2293 5106 +4573 2 2 4 8 575 2252 3769 +4574 2 2 4 8 1039 3528 2171 +4575 2 2 4 8 401 2173 3739 +4576 2 2 4 8 1252 4193 3617 +4577 2 2 4 8 1221 2163 4300 +4578 2 2 4 8 885 2150 3627 +4579 2 2 4 8 672 3626 2151 +4580 2 2 4 8 1141 3145 2319 +4581 2 2 4 8 1142 2320 3146 +4582 2 2 4 8 2441 4832 5063 +4583 2 2 4 8 642 4659 2605 +4584 2 2 4 8 915 4881 2256 +4585 2 2 4 8 911 4880 2255 +4586 2 2 4 8 1127 3880 2601 +4587 2 2 4 8 1288 3612 2158 +4588 2 2 4 8 700 5289 3614 +4589 2 2 4 8 940 3143 2331 +4590 2 2 4 8 708 5197 3392 +4591 2 2 4 8 490 2372 3756 +4592 2 2 4 8 872 4861 2549 +4593 2 2 4 8 982 5043 2284 +4594 2 2 4 8 983 5044 2285 +4595 2 2 4 8 1077 3552 2243 +4596 2 2 4 8 1076 3551 2245 +4597 2 2 4 8 599 2330 4019 +4598 2 2 4 8 680 4143 2799 +4599 2 2 4 8 1202 4144 2135 +4600 2 2 4 8 515 2525 4260 +4601 2 2 4 8 1859 2214 4907 +4602 2 2 4 8 1860 2215 4908 +4603 2 2 4 8 2145 5326 1258 +4604 2 2 4 8 719 2979 5037 +4605 2 2 4 8 1640 3326 5110 +4606 2 2 4 8 1689 2400 4043 +4607 2 2 4 8 382 383 3013 +4608 2 2 4 8 1871 4096 2664 +4609 2 2 4 8 558 2262 4890 +4610 2 2 4 8 1324 3027 3378 +4611 2 2 4 8 1325 3028 3379 +4612 2 2 4 8 32 2328 3645 +4613 2 2 4 8 1271 3645 2328 +4614 2 2 4 8 552 2509 4903 +4615 2 2 4 8 2509 1657 4903 +4616 2 2 4 8 553 2510 4902 +4617 2 2 4 8 2510 1656 4902 +4618 2 2 4 8 1539 3011 3837 +4619 2 2 4 8 1540 3012 3838 +4620 2 2 4 8 4140 5406 2266 +4621 2 2 4 8 1407 3707 3975 +4622 2 2 4 8 860 2920 5350 +4623 2 2 4 8 1161 2305 4117 +4624 2 2 4 8 1160 4118 2304 +4625 2 2 4 8 874 3390 2341 +4626 2 2 4 8 598 2216 4358 +4627 2 2 4 8 718 2221 3395 +4628 2 2 4 8 1684 3898 2380 +4629 2 2 4 8 1325 3720 3028 +4630 2 2 4 8 1324 3722 3027 +4631 2 2 4 8 1182 4308 2196 +4632 2 2 4 8 937 2344 3745 +4633 2 2 4 8 936 3744 2343 +4634 2 2 4 8 1224 4038 3332 +4635 2 2 4 8 1009 2258 4667 +4636 2 2 4 8 392 4056 2357 +4637 2 2 4 8 2217 3330 5244 +4638 2 2 4 8 1346 3229 2768 +4639 2 2 4 8 857 2768 3229 +4640 2 2 4 8 913 2402 5368 +4641 2 2 4 8 916 5369 2403 +4642 2 2 4 8 682 3147 3042 +4643 2 2 4 8 1555 3042 3147 +4644 2 2 4 8 1289 2379 3758 +4645 2 2 4 8 717 3758 2379 +4646 2 2 4 8 1014 4952 2711 +4647 2 2 4 8 8 3460 2311 +4648 2 2 4 8 643 4300 2163 +4649 2 2 4 8 561 2643 4765 +4650 2 2 4 8 698 2396 4109 +4651 2 2 4 8 1403 4109 2396 +4652 2 2 4 8 1071 2840 2753 +4653 2 2 4 8 1435 3203 2899 +4654 2 2 4 8 923 3124 2366 +4655 2 2 4 8 1288 2158 4162 +4656 2 2 4 8 2195 4362 2894 +4657 2 2 4 8 1253 4630 3303 +4658 2 2 4 8 2105 2844 5165 +4659 2 2 4 8 2119 3303 4630 +4660 2 2 4 8 923 2366 5409 +4661 2 2 4 8 586 3743 2154 +4662 2 2 4 8 1241 3854 4156 +4663 2 2 4 8 30 2179 3592 +4664 2 2 4 8 1797 4115 4284 +4665 2 2 4 8 1078 5118 2967 +4666 2 2 4 8 17 2935 16 +4667 2 2 4 8 391 2357 4279 +4668 2 2 4 8 1164 2723 2854 +4669 2 2 4 8 1163 2722 2855 +4670 2 2 4 8 1165 2252 4640 +4671 2 2 4 8 1166 2253 4641 +4672 2 2 4 8 457 2424 3223 +4673 2 2 4 8 816 3191 2827 +4674 2 2 4 8 1487 2827 3191 +4675 2 2 4 8 815 3190 2826 +4676 2 2 4 8 2826 3190 1488 +4677 2 2 4 8 1490 2828 3192 +4678 2 2 4 8 2825 814 3189 +4679 2 2 4 8 2825 3189 1489 +4680 2 2 4 8 823 3192 2828 +4681 2 2 4 8 1491 2824 3188 +4682 2 2 4 8 824 3188 2824 +4683 2 2 4 8 677 2748 4230 +4684 2 2 4 8 818 4069 2554 +4685 2 2 4 8 820 2555 4068 +4686 2 2 4 8 1461 2554 4069 +4687 2 2 4 8 1464 4068 2555 +4688 2 2 4 8 2778 5418 1711 +4689 2 2 4 8 1240 4385 3718 +4690 2 2 4 8 1418 2463 3085 +4691 2 2 4 8 1761 3881 4807 +4692 2 2 4 8 649 2314 5185 +4693 2 2 4 8 312 313 2749 +4694 2 2 4 8 979 3477 2213 +4695 2 2 4 8 849 3796 2155 +4696 2 2 4 8 1246 2155 3796 +4697 2 2 4 8 1376 3813 3656 +4698 2 2 4 8 1570 4978 2282 +4699 2 2 4 8 1008 2282 4978 +4700 2 2 4 8 1419 3491 3237 +4701 2 2 4 8 10 2155 5208 +4702 2 2 4 8 656 5403 2367 +4703 2 2 4 8 188 3332 187 +4704 2 2 4 8 1245 4313 2159 +4705 2 2 4 8 2578 1864 3733 +4706 2 2 4 8 1863 2579 3732 +4707 2 2 4 8 816 2146 5031 +4708 2 2 4 8 824 2147 5030 +4709 2 2 4 8 520 2883 3340 +4710 2 2 4 8 517 3339 2884 +4711 2 2 4 8 1371 3340 2883 +4712 2 2 4 8 1370 2884 3339 +4713 2 2 4 8 1188 2213 3477 +4714 2 2 4 8 1156 2866 2708 +4715 2 2 4 8 1157 2709 2867 +4716 2 2 4 8 1158 2868 2710 +4717 2 2 4 8 978 4328 2212 +4718 2 2 4 8 457 2584 3753 +4719 2 2 4 8 1357 3753 2584 +4720 2 2 4 8 1626 5042 4705 +4721 2 2 4 8 667 4643 2639 +4722 2 2 4 8 341 3565 4357 +4723 2 2 4 8 1678 2431 3209 +4724 2 2 4 8 337 338 3117 +4725 2 2 4 8 1343 3426 2774 +4726 2 2 4 8 501 3424 2773 +4727 2 2 4 8 1342 2773 3424 +4728 2 2 4 8 502 2774 3426 +4729 2 2 4 8 499 3421 2772 +4730 2 2 4 8 1341 2772 3421 +4731 2 2 4 8 631 3447 2443 +4732 2 2 4 8 409 410 3366 +4733 2 2 4 8 862 3459 2314 +4734 2 2 4 8 895 5045 2590 +4735 2 2 4 8 1725 2590 5045 +4736 2 2 4 8 2090 4784 3412 +4737 2 2 4 8 602 3204 2322 +4738 2 2 4 8 647 3989 2678 +4739 2 2 4 8 744 3194 3842 +4740 2 2 4 8 1699 3842 3194 +4741 2 2 4 8 807 2156 3913 +4742 2 2 4 8 808 2157 3912 +4743 2 2 4 8 486 2393 3119 +4744 2 2 4 8 549 4518 2214 +4745 2 2 4 8 550 4519 2215 +4746 2 2 4 8 1744 2963 4849 +4747 2 2 4 8 1146 2340 4674 +4748 2 2 4 8 1697 3827 3186 +4749 2 2 4 8 745 3186 3827 +4750 2 2 4 8 1675 3959 2971 +4751 2 2 4 8 700 2971 3959 +4752 2 2 4 8 1309 2254 4021 +4753 2 2 4 8 530 4021 2254 +4754 2 2 4 8 1182 4041 3101 +4755 2 2 4 8 1081 2167 4107 +4756 2 2 4 8 343 2980 342 +4757 2 2 4 8 294 3533 5399 +4758 2 2 4 8 305 3534 5400 +4759 2 2 4 8 178 5398 3535 +4760 2 2 4 8 133 5397 3532 +4761 2 2 4 8 122 5396 3531 +4762 2 2 4 8 812 3906 2429 +4763 2 2 4 8 1346 2429 3906 +4764 2 2 4 8 596 4253 3510 +4765 2 2 4 8 2070 3510 4253 +4766 2 2 4 8 1255 2172 5140 +4767 2 2 4 8 713 4130 3218 +4768 2 2 4 8 324 4299 2891 +4769 2 2 4 8 1065 2203 4463 +4770 2 2 4 8 1066 4464 2204 +4771 2 2 4 8 1307 2633 3866 +4772 2 2 4 8 562 4918 2278 +4773 2 2 4 8 914 2279 4919 +4774 2 2 4 8 1553 3250 3998 +4775 2 2 4 8 20 3518 2208 +4776 2 2 4 8 832 2862 3417 +4777 2 2 4 8 1737 5317 3218 +4778 2 2 4 8 118 2226 3487 +4779 2 2 4 8 129 2227 3486 +4780 2 2 4 8 174 2228 3485 +4781 2 2 4 8 298 3483 2229 +4782 2 2 4 8 309 3484 2230 +4783 2 2 4 8 442 2906 5348 +4784 2 2 4 8 450 2905 5347 +4785 2 2 4 8 2098 3176 5023 +4786 2 2 4 8 1189 5244 3330 +4787 2 2 4 8 3326 2144 5110 +4788 2 2 4 8 2611 4435 3078 +4789 2 2 4 8 605 3412 4784 +4790 2 2 4 8 468 5296 2892 +4791 2 2 4 8 319 320 4608 +4792 2 2 4 8 1483 4194 2880 +4793 2 2 4 8 646 3002 2911 +4794 2 2 4 8 1264 2911 3002 +4795 2 2 4 8 788 2405 3467 +4796 2 2 4 8 1243 3467 2405 +4797 2 2 4 8 294 295 3533 +4798 2 2 4 8 305 306 3534 +4799 2 2 4 8 178 3535 177 +4800 2 2 4 8 132 133 3532 +4801 2 2 4 8 121 122 3531 +4802 2 2 4 8 1199 4887 4074 +4803 2 2 4 8 691 2613 3801 +4804 2 2 4 8 1389 3801 2613 +4805 2 2 4 8 1473 2871 3792 +4806 2 2 4 8 332 333 2793 +4807 2 2 4 8 483 5012 3006 +4808 2 2 4 8 690 2615 3802 +4809 2 2 4 8 1390 3802 2615 +4810 2 2 4 8 876 4790 2981 +4811 2 2 4 8 1274 3948 2347 +4812 2 2 4 8 1302 2917 3320 +4813 2 2 4 8 674 3321 2751 +4814 2 2 4 8 1300 2752 3319 +4815 2 2 4 8 673 3319 2752 +4816 2 2 4 8 1301 2751 3321 +4817 2 2 4 8 879 3557 2206 +4818 2 2 4 8 877 3558 2205 +4819 2 2 4 8 2507 1839 3793 +4820 2 2 4 8 2508 1840 3794 +4821 2 2 4 8 646 4039 2193 +4822 2 2 4 8 1802 4853 3236 +4823 2 2 4 8 114 115 3116 +4824 2 2 4 8 125 126 3115 +4825 2 2 4 8 136 137 3114 +4826 2 2 4 8 181 182 3113 +4827 2 2 4 8 301 302 3111 +4828 2 2 4 8 290 291 3112 +4829 2 2 4 8 1140 4389 2199 +4830 2 2 4 8 1138 4390 2201 +4831 2 2 4 8 614 2286 3328 +4832 2 2 4 8 967 2330 3226 +4833 2 2 4 8 403 404 3052 +4834 2 2 4 8 2574 3897 4988 +4835 2 2 4 8 2573 4987 3896 +4836 2 2 4 8 680 2916 4143 +4837 2 2 4 8 1584 5056 2319 +4838 2 2 4 8 891 2234 4638 +4839 2 2 4 8 548 3528 5153 +4840 2 2 4 8 856 3772 2183 +4841 2 2 4 8 1244 5324 2345 +4842 2 2 4 8 2117 4074 4887 +4843 2 2 4 8 1198 2237 4637 +4844 2 2 4 8 1211 4463 2203 +4845 2 2 4 8 1210 2204 4464 +4846 2 2 4 8 567 2427 4621 +4847 2 2 4 8 2057 5348 2906 +4848 2 2 4 8 2059 5347 2905 +4849 2 2 4 8 1400 2589 3728 +4850 2 2 4 8 974 2789 3370 +4851 2 2 4 8 1323 3370 2789 +4852 2 2 4 8 1827 2727 4252 +4853 2 2 4 8 1179 3152 2461 +4854 2 2 4 8 905 2461 3152 +4855 2 2 4 8 1499 2788 3983 +4856 2 2 4 8 962 2196 4308 +4857 2 2 4 8 1616 2435 3132 +4858 2 2 4 8 1266 3132 2435 +4859 2 2 4 8 1106 4289 2594 +4860 2 2 4 8 1347 2968 3703 +4861 2 2 4 8 530 2194 4278 +4862 2 2 4 8 1519 4048 2981 +4863 2 2 4 8 2654 4888 3964 +4864 2 2 4 8 529 4637 2237 +4865 2 2 4 8 1286 3476 2979 +4866 2 2 4 8 1456 2979 3476 +4867 2 2 4 8 571 2253 3689 +4868 2 2 4 8 556 4498 2521 +4869 2 2 4 8 1550 2521 4498 +4870 2 2 4 8 1493 3993 4601 +4871 2 2 4 8 1352 3502 2782 +4872 2 2 4 8 1353 2783 3503 +4873 2 2 4 8 512 2334 5198 +4874 2 2 4 8 563 2279 4877 +4875 2 2 4 8 1011 2188 3726 +4876 2 2 4 8 37 2506 3080 +4877 2 2 4 8 1169 3080 2506 +4878 2 2 4 8 1954 4638 2413 +4879 2 2 4 8 508 2889 3387 +4880 2 2 4 8 1382 3387 2889 +4881 2 2 4 8 519 2890 3388 +4882 2 2 4 8 1383 3388 2890 +4883 2 2 4 8 2497 2356 4409 +4884 2 2 4 8 666 4345 2202 +4885 2 2 4 8 759 3199 3815 +4886 2 2 4 8 1676 3815 3199 +4887 2 2 4 8 486 2614 4842 +4888 2 2 4 8 1721 5137 2573 +4889 2 2 4 8 752 2573 5137 +4890 2 2 4 8 107 2323 3870 +4891 2 2 4 8 1425 4553 2662 +4892 2 2 4 8 1306 3259 3917 +4893 2 2 4 8 1757 3917 3259 +4894 2 2 4 8 686 2591 3858 +4895 2 2 4 8 1386 3858 2591 +4896 2 2 4 8 1580 5264 3029 +4897 2 2 4 8 490 3756 2454 +4898 2 2 4 8 660 4283 2768 +4899 2 2 4 8 529 2240 4637 +4900 2 2 4 8 385 386 4295 +4901 2 2 4 8 146 147 4294 +4902 2 2 4 8 367 368 4293 +4903 2 2 4 8 1663 2983 5097 +4904 2 2 4 8 1333 4008 2850 +4905 2 2 4 8 920 2219 4965 +4906 2 2 4 8 1110 5353 2188 +4907 2 2 4 8 1574 5028 2342 +4908 2 2 4 8 1987 3302 3834 +4909 2 2 4 8 615 2220 3594 +4910 2 2 4 8 822 3593 2220 +4911 2 2 4 8 1628 2529 3936 +4912 2 2 4 8 1347 2197 4281 +4913 2 2 4 8 859 2283 4878 +4914 2 2 4 8 2162 3603 3275 +4915 2 2 4 8 1061 3833 2184 +4916 2 2 4 8 1261 4984 3258 +4917 2 2 4 8 1554 4153 2465 +4918 2 2 4 8 1690 4919 4958 +4919 2 2 4 8 1327 2830 3907 +4920 2 2 4 8 832 3417 2947 +4921 2 2 4 8 1187 2212 4328 +4922 2 2 4 8 948 5017 2553 +4923 2 2 4 8 666 2730 5068 +4924 2 2 4 8 844 2798 3579 +4925 2 2 4 8 1397 3579 2798 +4926 2 2 4 8 843 2797 3578 +4927 2 2 4 8 1396 3578 2797 +4928 2 2 4 8 1198 4637 2240 +4929 2 2 4 8 1008 3431 5345 +4930 2 2 4 8 1679 4604 3293 +4931 2 2 4 8 584 2403 4581 +4932 2 2 4 8 585 2404 4580 +4933 2 2 4 8 1663 4354 2983 +4934 2 2 4 8 868 4276 2241 +4935 2 2 4 8 1417 3353 2586 +4936 2 2 4 8 2549 4861 5074 +4937 2 2 4 8 1258 2628 3292 +4938 2 2 4 8 544 3292 2628 +4939 2 2 4 8 1167 2705 2921 +4940 2 2 4 8 1633 4944 3288 +4941 2 2 4 8 1632 4943 3287 +4942 2 2 4 8 1897 2545 4396 +4943 2 2 4 8 1324 4602 3723 +4944 2 2 4 8 491 2436 3128 +4945 2 2 4 8 559 2295 4910 +4946 2 2 4 8 974 4355 2789 +4947 2 2 4 8 1921 2789 4355 +4948 2 2 4 8 1781 3156 4862 +4949 2 2 4 8 1974 3006 5012 +4950 2 2 4 8 1830 3617 4193 +4951 2 2 4 8 1474 2760 3260 +4952 2 2 4 8 1475 2761 3261 +4953 2 2 4 8 454 4613 2248 +4954 2 2 4 8 890 3523 3208 +4955 2 2 4 8 1581 3208 3523 +4956 2 2 4 8 2307 5403 3105 +4957 2 2 4 8 656 3105 5403 +4958 2 2 4 8 1239 3684 2214 +4959 2 2 4 8 1242 3683 2215 +4960 2 2 4 8 1134 2558 4650 +4961 2 2 4 8 614 5176 2286 +4962 2 2 4 8 581 2256 5182 +4963 2 2 4 8 2203 3806 2720 +4964 2 2 4 8 1273 3196 3735 +4965 2 2 4 8 1641 3735 3196 +4966 2 2 4 8 865 2209 4271 +4967 2 2 4 8 863 4269 2210 +4968 2 2 4 8 864 4270 2211 +4969 2 2 4 8 1923 4156 3854 +4970 2 2 4 8 809 5251 5149 +4971 2 2 4 8 1325 4766 3721 +4972 2 2 4 8 559 2239 4594 +4973 2 2 4 8 1141 3713 2444 +4974 2 2 4 8 1142 2445 3712 +4975 2 2 4 8 1109 3661 2496 +4976 2 2 4 8 1478 4362 2195 +4977 2 2 4 8 1235 3179 3570 +4978 2 2 4 8 35 4231 34 +4979 2 2 4 8 1177 4584 3015 +4980 2 2 4 8 3071 2388 3949 +4981 2 2 4 8 2624 4278 2194 +4982 2 2 4 8 299 300 3246 +4983 2 2 4 8 310 311 3244 +4984 2 2 4 8 288 289 3245 +4985 2 2 4 8 183 184 3243 +4986 2 2 4 8 138 139 3242 +4987 2 2 4 8 127 128 3241 +4988 2 2 4 8 116 117 3240 +4989 2 2 4 8 892 2449 3672 +4990 2 2 4 8 893 2450 3673 +4991 2 2 4 8 937 3745 2444 +4992 2 2 4 8 936 2445 3744 +4993 2 2 4 8 918 5173 2262 +4994 2 2 4 8 719 3988 2894 +4995 2 2 4 8 1588 2894 3988 +4996 2 2 4 8 2432 4326 3681 +4997 2 2 4 8 456 3809 5211 +4998 2 2 4 8 838 4538 3257 +4999 2 2 4 8 1160 4055 2945 +5000 2 2 4 8 1161 2946 4054 +5001 2 2 4 8 951 2324 5095 +5002 2 2 4 8 568 2204 4209 +5003 2 2 4 8 1369 4127 3908 +5004 2 2 4 8 1773 3951 4833 +5005 2 2 4 8 1772 3950 4834 +5006 2 2 4 8 1476 3295 3568 +5007 2 2 4 8 1716 3304 3805 +5008 2 2 4 8 748 3805 3304 +5009 2 2 4 8 749 3305 3803 +5010 2 2 4 8 1714 3803 3305 +5011 2 2 4 8 750 3804 3306 +5012 2 2 4 8 1715 3306 3804 +5013 2 2 4 8 1855 4291 3364 +5014 2 2 4 8 1280 3066 2534 +5015 2 2 4 8 76 4041 2196 +5016 2 2 4 8 1576 2540 3508 +5017 2 2 4 8 1575 2541 3509 +5018 2 2 4 8 1276 2434 3911 +5019 2 2 4 8 2001 3353 4346 +5020 2 2 4 8 503 4346 3353 +5021 2 2 4 8 1000 3554 2244 +5022 2 2 4 8 999 2243 3553 +5023 2 2 4 8 1001 2245 3555 +5024 2 2 4 8 1769 2539 4341 +5025 2 2 4 8 856 4167 2998 +5026 2 2 4 8 1693 2998 4167 +5027 2 2 4 8 1608 5132 2441 +5028 2 2 4 8 838 4256 4538 +5029 2 2 4 8 1386 2695 3893 +5030 2 2 4 8 874 2448 3390 +5031 2 2 4 8 555 2380 5309 +5032 2 2 4 8 564 3806 2203 +5033 2 2 4 8 1224 2264 3594 +5034 2 2 4 8 615 3594 2264 +5035 2 2 4 8 1225 3544 2620 +5036 2 2 4 8 351 2212 4183 +5037 2 2 4 8 164 2213 4182 +5038 2 2 4 8 1622 2638 4636 +5039 2 2 4 8 262 263 4213 +5040 2 2 4 8 60 4215 59 +5041 2 2 4 8 280 281 4214 +5042 2 2 4 8 644 3155 2439 +5043 2 2 4 8 2011 4781 4561 +5044 2 2 4 8 1175 4299 2332 +5045 2 2 4 8 703 3407 4172 +5046 2 2 4 8 1941 4172 3407 +5047 2 2 4 8 2336 1295 5129 +5048 2 2 4 8 1556 4793 2392 +5049 2 2 4 8 708 2392 4793 +5050 2 2 4 8 1141 2319 5056 +5051 2 2 4 8 1219 2320 5054 +5052 2 2 4 8 1142 5055 2320 +5053 2 2 4 8 1122 3635 2233 +5054 2 2 4 8 752 3863 3307 +5055 2 2 4 8 1730 3307 3863 +5056 2 2 4 8 754 3309 3861 +5057 2 2 4 8 1732 3861 3309 +5058 2 2 4 8 1731 3862 3308 +5059 2 2 4 8 753 3308 3862 +5060 2 2 4 8 62 63 2866 +5061 2 2 4 8 259 260 2867 +5062 2 2 4 8 283 284 2868 +5063 2 2 4 8 684 3057 3792 +5064 2 2 4 8 525 2225 3675 +5065 2 2 4 8 1139 3876 2200 +5066 2 2 4 8 2850 4008 4422 +5067 2 2 4 8 547 2499 4342 +5068 2 2 4 8 2499 1494 4342 +5069 2 2 4 8 930 3195 2572 +5070 2 2 4 8 1223 2572 3195 +5071 2 2 4 8 918 2257 3548 +5072 2 2 4 8 1111 2790 4594 +5073 2 2 4 8 913 2278 5148 +5074 2 2 4 8 1033 4685 2533 +5075 2 2 4 8 452 2562 5169 +5076 2 2 4 8 1712 5169 2562 +5077 2 2 4 8 1613 3050 5322 +5078 2 2 4 8 1350 4695 3075 +5079 2 2 4 8 1349 4694 3076 +5080 2 2 4 8 665 3681 2786 +5081 2 2 4 8 1211 2250 4463 +5082 2 2 4 8 1210 4464 2249 +5083 2 2 4 8 1133 4879 2300 +5084 2 2 4 8 1460 3439 3405 +5085 2 2 4 8 630 3087 4587 +5086 2 2 4 8 809 3948 2202 +5087 2 2 4 8 592 3833 4686 +5088 2 2 4 8 814 4333 2226 +5089 2 2 4 8 815 4334 2227 +5090 2 2 4 8 823 4337 2228 +5091 2 2 4 8 817 2229 4335 +5092 2 2 4 8 819 2230 4336 +5093 2 2 4 8 1707 4629 2262 +5094 2 2 4 8 873 3609 2433 +5095 2 2 4 8 681 3265 3055 +5096 2 2 4 8 701 3895 3869 +5097 2 2 4 8 2060 3869 3895 +5098 2 2 4 8 871 2208 4896 +5099 2 2 4 8 677 4230 2978 +5100 2 2 4 8 574 5123 3322 +5101 2 2 4 8 1226 5383 3276 +5102 2 2 4 8 488 3512 2370 +5103 2 2 4 8 1547 4151 2742 +5104 2 2 4 8 711 2742 4151 +5105 2 2 4 8 1472 3792 3057 +5106 2 2 4 8 984 4872 2871 +5107 2 2 4 8 1844 2871 4872 +5108 2 2 4 8 1866 4042 2475 +5109 2 2 4 8 1231 2860 2954 +5110 2 2 4 8 502 2954 2860 +5111 2 2 4 8 1208 2263 4366 +5112 2 2 4 8 364 365 2855 +5113 2 2 4 8 144 2854 143 +5114 2 2 4 8 1576 3508 3822 +5115 2 2 4 8 1575 3509 3823 +5116 2 2 4 8 2544 2934 4467 +5117 2 2 4 8 890 2520 3523 +5118 2 2 4 8 1074 2894 2895 +5119 2 2 4 8 1588 2895 2894 +5120 2 2 4 8 1623 2970 4288 +5121 2 2 4 8 896 2431 5293 +5122 2 2 4 8 1678 5293 2431 +5123 2 2 4 8 1321 2513 5130 +5124 2 2 4 8 2780 3205 4887 +5125 2 2 4 8 4173 1565 4557 +5126 2 2 4 8 618 3544 4366 +5127 2 2 4 8 2128 4366 3544 +5128 2 2 4 8 1229 2861 2960 +5129 2 2 4 8 500 2960 2861 +5130 2 2 4 8 548 4152 2219 +5131 2 2 4 8 444 2246 4449 +5132 2 2 4 8 968 4450 2247 +5133 2 2 4 8 1547 3079 3937 +5134 2 2 4 8 1304 3471 3625 +5135 2 2 4 8 718 3820 2221 +5136 2 2 4 8 1239 2271 3684 +5137 2 2 4 8 827 3684 2271 +5138 2 2 4 8 873 2447 3609 +5139 2 2 4 8 1076 2255 4549 +5140 2 2 4 8 1077 2256 4548 +5141 2 2 4 8 1590 4444 2684 +5142 2 2 4 8 1591 2683 4445 +5143 2 2 4 8 1234 3180 3301 +5144 2 2 4 8 1235 3300 3179 +5145 2 2 4 8 809 2779 5251 +5146 2 2 4 8 1739 3262 4179 +5147 2 2 4 8 1066 2249 4464 +5148 2 2 4 8 1065 4463 2250 +5149 2 2 4 8 473 5007 2329 +5150 2 2 4 8 1807 5164 2280 +5151 2 2 4 8 913 2276 3526 +5152 2 2 4 8 916 3527 2277 +5153 2 2 4 8 851 4635 2237 +5154 2 2 4 8 1155 2942 4824 +5155 2 2 4 8 1501 4031 4626 +5156 2 2 4 8 940 3540 2562 +5157 2 2 4 8 1649 2877 3093 +5158 2 2 4 8 1861 2711 5308 +5159 2 2 4 8 1146 2491 4160 +5160 2 2 4 8 370 371 3045 +5161 2 2 4 8 150 3044 149 +5162 2 2 4 8 1514 3182 2449 +5163 2 2 4 8 1515 3183 2450 +5164 2 2 4 8 1322 2519 3984 +5165 2 2 4 8 1275 3809 3271 +5166 2 2 4 8 1693 3271 3809 +5167 2 2 4 8 4170 5184 2609 +5168 2 2 4 8 958 4369 2238 +5169 2 2 4 8 1491 3188 3581 +5170 2 2 4 8 1488 3190 3582 +5171 2 2 4 8 1172 4253 2317 +5172 2 2 4 8 1593 4453 4657 +5173 2 2 4 8 2643 4480 4765 +5174 2 2 4 8 2514 1684 5199 +5175 2 2 4 8 585 2514 5199 +5176 2 2 4 8 2513 1897 3774 +5177 2 2 4 8 2336 5061 917 +5178 2 2 4 8 1264 3002 3264 +5179 2 2 4 8 229 3215 2455 +5180 2 2 4 8 94 2251 4416 +5181 2 2 4 8 1970 3394 5040 +5182 2 2 4 8 556 5246 2374 +5183 2 2 4 8 554 2373 5245 +5184 2 2 4 8 1101 2760 3035 +5185 2 2 4 8 893 2236 4752 +5186 2 2 4 8 2148 5370 4943 +5187 2 2 4 8 2149 5371 4944 +5188 2 2 4 8 545 4819 2832 +5189 2 2 4 8 103 2386 5290 +5190 2 2 4 8 981 3169 4699 +5191 2 2 4 8 529 4904 2240 +5192 2 2 4 8 1246 2311 3460 +5193 2 2 4 8 1417 2231 4161 +5194 2 2 4 8 1651 3068 4990 +5195 2 2 4 8 3069 4991 1650 +5196 2 2 4 8 1162 3957 2941 +5197 2 2 4 8 1052 3151 2490 +5198 2 2 4 8 865 4828 2833 +5199 2 2 4 8 1188 3184 4182 +5200 2 2 4 8 1187 3185 4183 +5201 2 2 4 8 542 4286 2518 +5202 2 2 4 8 1477 2518 4286 +5203 2 2 4 8 2336 582 5079 +5204 2 2 4 8 608 3361 2356 +5205 2 2 4 8 1109 4461 3549 +5206 2 2 4 8 756 3364 4291 +5207 2 2 4 8 530 2254 3685 +5208 2 2 4 8 12 13 3019 +5209 2 2 4 8 685 3680 2822 +5210 2 2 4 8 1421 2822 3680 +5211 2 2 4 8 1314 2261 4136 +5212 2 2 4 8 1313 2260 4133 +5213 2 2 4 8 2418 5026 2645 +5214 2 2 4 8 2419 2646 5024 +5215 2 2 4 8 545 2832 4651 +5216 2 2 4 8 1027 4636 2638 +5217 2 2 4 8 755 2550 4141 +5218 2 2 4 8 25 26 3432 +5219 2 2 4 8 1019 2837 3569 +5220 2 2 4 8 99 2442 3214 +5221 2 2 4 8 892 2235 4226 +5222 2 2 4 8 613 4227 2236 +5223 2 2 4 8 794 3381 4746 +5224 2 2 4 8 1153 2527 4997 +5225 2 2 4 8 1283 2863 3154 +5226 2 2 4 8 2864 1282 3153 +5227 2 2 4 8 1350 3516 4695 +5228 2 2 4 8 1349 3517 4694 +5229 2 2 4 8 846 3973 4788 +5230 2 2 4 8 3006 4860 3203 +5231 2 2 4 8 1143 5368 2402 +5232 2 2 4 8 978 2412 5411 +5233 2 2 4 8 667 4045 2340 +5234 2 2 4 8 792 4315 2693 +5235 2 2 4 8 1536 3935 3880 +5236 2 2 4 8 529 2237 3866 +5237 2 2 4 8 1080 2267 4504 +5238 2 2 4 8 1684 5142 5199 +5239 2 2 4 8 1087 3291 2732 +5240 2 2 4 8 989 3187 2468 +5241 2 2 4 8 1164 2940 3382 +5242 2 2 4 8 2056 2416 4166 +5243 2 2 4 8 892 3672 2536 +5244 2 2 4 8 893 3673 2537 +5245 2 2 4 8 1995 3218 5317 +5246 2 2 4 8 1548 2849 4653 +5247 2 2 4 8 1197 4319 2921 +5248 2 2 4 8 508 3260 2422 +5249 2 2 4 8 519 3261 2423 +5250 2 2 4 8 1053 3174 2511 +5251 2 2 4 8 1054 3175 2512 +5252 2 2 4 8 1574 2342 5048 +5253 2 2 4 8 909 2232 3962 +5254 2 2 4 8 1106 4811 4289 +5255 2 2 4 8 2138 3177 5204 +5256 2 2 4 8 852 3362 2407 +5257 2 2 4 8 853 3363 2408 +5258 2 2 4 8 939 2528 5274 +5259 2 2 4 8 1707 5274 2528 +5260 2 2 4 8 388 389 2853 +5261 2 2 4 8 930 3798 3195 +5262 2 2 4 8 1643 3195 3798 +5263 2 2 4 8 600 4963 2391 +5264 2 2 4 8 601 4962 2390 +5265 2 2 4 8 2015 2334 4977 +5266 2 2 4 8 255 3441 3446 +5267 2 2 4 8 570 5258 3134 +5268 2 2 4 8 1721 3463 5137 +5269 2 2 4 8 1170 2455 3215 +5270 2 2 4 8 1489 3189 3334 +5271 2 2 4 8 1214 3334 3189 +5272 2 2 4 8 1487 3191 3335 +5273 2 2 4 8 1216 3335 3191 +5274 2 2 4 8 2241 4276 2739 +5275 2 2 4 8 1505 2343 4757 +5276 2 2 4 8 1506 4758 2344 +5277 2 2 4 8 1493 3234 3993 +5278 2 2 4 8 1330 3810 4099 +5279 2 2 4 8 1651 4990 4122 +5280 2 2 4 8 1650 4991 4123 +5281 2 2 4 8 1020 2640 3775 +5282 2 2 4 8 1360 3775 2640 +5283 2 2 4 8 1034 3178 2497 +5284 2 2 4 8 726 2683 4408 +5285 2 2 4 8 1591 4408 2683 +5286 2 2 4 8 2941 3957 5176 +5287 2 2 4 8 999 2527 4688 +5288 2 2 4 8 1340 3872 4097 +5289 2 2 4 8 1807 3420 2519 +5290 2 2 4 8 1303 2519 3420 +5291 2 2 4 8 1750 2699 5023 +5292 2 2 4 8 1036 5023 2699 +5293 2 2 4 8 850 4800 2254 +5294 2 2 4 8 888 4378 2264 +5295 2 2 4 8 905 5247 2321 +5296 2 2 4 8 460 3717 2271 +5297 2 2 4 8 827 2271 3718 +5298 2 2 4 8 1559 4148 2984 +5299 2 2 4 8 1560 4149 2985 +5300 2 2 4 8 1841 2967 5118 +5301 2 2 4 8 1762 4004 3668 +5302 2 2 4 8 576 2300 5097 +5303 2 2 4 8 1357 2584 3256 +5304 2 2 4 8 897 3256 2584 +5305 2 2 4 8 926 3258 2443 +5306 2 2 4 8 2692 4891 4275 +5307 2 2 4 8 1241 2270 3854 +5308 2 2 4 8 618 4366 2263 +5309 2 2 4 8 1619 2322 4889 +5310 2 2 4 8 1241 3899 2270 +5311 2 2 4 8 1518 3748 4084 +5312 2 2 4 8 383 4526 3013 +5313 2 2 4 8 1246 3460 5208 +5314 2 2 4 8 2151 3626 4249 +5315 2 2 4 8 261 262 3252 +5316 2 2 4 8 282 3253 281 +5317 2 2 4 8 61 3254 60 +5318 2 2 4 8 649 3103 2658 +5319 2 2 4 8 1369 3908 2784 +5320 2 2 4 8 1961 2784 3908 +5321 2 2 4 8 1455 4702 3395 +5322 2 2 4 8 1189 3330 3290 +5323 2 2 4 8 1519 3290 3330 +5324 2 2 4 8 34 3032 33 +5325 2 2 4 8 569 3832 2258 +5326 2 2 4 8 654 4488 2259 +5327 2 2 4 8 416 2345 5324 +5328 2 2 4 8 2267 5027 5300 +5329 2 2 4 8 1804 2364 5126 +5330 2 2 4 8 2514 3393 5009 +5331 2 2 4 8 1233 3453 2350 +5332 2 2 4 8 1520 4473 4389 +5333 2 2 4 8 1521 4475 4390 +5334 2 2 4 8 1352 3070 3502 +5335 2 2 4 8 1176 5204 3177 +5336 2 2 4 8 1762 3668 2414 +5337 2 2 4 8 1801 2870 3775 +5338 2 2 4 8 1827 4252 5249 +5339 2 2 4 8 941 4720 2306 +5340 2 2 4 8 545 3493 2343 +5341 2 2 4 8 546 2344 3494 +5342 2 2 4 8 430 3868 2260 +5343 2 2 4 8 212 3867 2261 +5344 2 2 4 8 863 3737 2832 +5345 2 2 4 8 1436 2832 3737 +5346 2 2 4 8 2582 3429 4691 +5347 2 2 4 8 488 2370 3418 +5348 2 2 4 8 1168 3385 2737 +5349 2 2 4 8 489 2371 3419 +5350 2 2 4 8 1470 3409 3449 +5351 2 2 4 8 896 2462 4497 +5352 2 2 4 8 1499 4497 2462 +5353 2 2 4 8 2086 4503 3072 +5354 2 2 4 8 788 3834 2434 +5355 2 2 4 8 1297 2434 3834 +5356 2 2 4 8 1493 2484 4372 +5357 2 2 4 8 1969 3549 4461 +5358 2 2 4 8 2439 3155 4886 +5359 2 2 4 8 1530 4305 4871 +5360 2 2 4 8 1171 3602 2456 +5361 2 2 4 8 1284 2583 3126 +5362 2 2 4 8 663 4301 2421 +5363 2 2 4 8 448 2365 5089 +5364 2 2 4 8 647 3442 2366 +5365 2 2 4 8 2778 3556 1545 +5366 2 2 4 8 1380 2407 3362 +5367 2 2 4 8 1381 2408 3363 +5368 2 2 4 8 854 4979 2286 +5369 2 2 4 8 1677 2590 4367 +5370 2 2 4 8 842 2259 3968 +5371 2 2 4 8 366 367 3316 +5372 2 2 4 8 145 146 3317 +5373 2 2 4 8 386 387 3318 +5374 2 2 4 8 937 2444 3300 +5375 2 2 4 8 936 3301 2445 +5376 2 2 4 8 1812 5098 2794 +5377 2 2 4 8 1045 2794 5098 +5378 2 2 4 8 461 3854 2270 +5379 2 2 4 8 1684 2380 5142 +5380 2 2 4 8 1048 3497 2367 +5381 2 2 4 8 645 2342 3500 +5382 2 2 4 8 1280 2382 4537 +5383 2 2 4 8 1538 2278 4437 +5384 2 2 4 8 1416 3595 3357 +5385 2 2 4 8 424 3588 2375 +5386 2 2 4 8 1281 2375 3588 +5387 2 2 4 8 1284 3591 2378 +5388 2 2 4 8 1283 3590 2377 +5389 2 2 4 8 438 2378 3591 +5390 2 2 4 8 220 2377 3590 +5391 2 2 4 8 207 3589 2376 +5392 2 2 4 8 1282 2376 3589 +5393 2 2 4 8 1566 2732 5367 +5394 2 2 4 8 649 2658 3086 +5395 2 2 4 8 1314 4024 2261 +5396 2 2 4 8 1313 4023 2260 +5397 2 2 4 8 899 2265 4191 +5398 2 2 4 8 622 3145 2598 +5399 2 2 4 8 623 2599 3146 +5400 2 2 4 8 895 4067 2293 +5401 2 2 4 8 401 402 4567 +5402 2 2 4 8 1551 4870 3475 +5403 2 2 4 8 966 3219 2503 +5404 2 2 4 8 4226 4259 1514 +5405 2 2 4 8 1107 2776 3066 +5406 2 2 4 8 826 2270 3899 +5407 2 2 4 8 339 2347 4933 +5408 2 2 4 8 1233 4670 2296 +5409 2 2 4 8 635 3342 5352 +5410 2 2 4 8 1693 4900 3271 +5411 2 2 4 8 1653 2887 3514 +5412 2 2 4 8 754 4015 3089 +5413 2 2 4 8 2397 4786 3498 +5414 2 2 4 8 250 251 3282 +5415 2 2 4 8 1639 3845 3765 +5416 2 2 4 8 1033 5025 2582 +5417 2 2 4 8 56 57 3109 +5418 2 2 4 8 277 278 3110 +5419 2 2 4 8 1384 2266 4051 +5420 2 2 4 8 1932 5285 2273 +5421 2 2 4 8 841 5076 4628 +5422 2 2 4 8 1197 2705 3046 +5423 2 2 4 8 1083 3058 2667 +5424 2 2 4 8 1084 3059 2668 +5425 2 2 4 8 1378 2651 3826 +5426 2 2 4 8 1030 3826 2651 +5427 2 2 4 8 1345 2425 3814 +5428 2 2 4 8 27 3814 2425 +5429 2 2 4 8 1476 2776 3295 +5430 2 2 4 8 1318 3371 2424 +5431 2 2 4 8 747 4179 3262 +5432 2 2 4 8 1155 4824 5413 +5433 2 2 4 8 474 2277 5221 +5434 2 2 4 8 472 5222 2276 +5435 2 2 4 8 1502 2526 4439 +5436 2 2 4 8 1222 2386 3443 +5437 2 2 4 8 1103 2386 5156 +5438 2 2 4 8 1223 3219 4700 +5439 2 2 4 8 635 2441 3342 +5440 2 2 4 8 1703 3198 2721 +5441 2 2 4 8 886 2291 4400 +5442 2 2 4 8 599 4019 2593 +5443 2 2 4 8 1554 3827 2666 +5444 2 2 4 8 1186 3005 3659 +5445 2 2 4 8 851 2273 4033 +5446 2 2 4 8 1625 3148 3916 +5447 2 2 4 8 1373 3524 2857 +5448 2 2 4 8 728 2857 3524 +5449 2 2 4 8 2633 5047 3866 +5450 2 2 4 8 678 3046 2705 +5451 2 2 4 8 1100 3054 2728 +5452 2 2 4 8 1206 2728 3054 +5453 2 2 4 8 883 4034 2288 +5454 2 2 4 8 1281 2288 4034 +5455 2 2 4 8 1115 4561 2306 +5456 2 2 4 8 1889 5350 2430 +5457 2 2 4 8 806 4404 5100 +5458 2 2 4 8 805 4405 5101 +5459 2 2 4 8 909 3979 2335 +5460 2 2 4 8 1322 3667 3556 +5461 2 2 4 8 1043 3967 2782 +5462 2 2 4 8 1175 3475 2777 +5463 2 2 4 8 399 3181 4367 +5464 2 2 4 8 967 4747 2330 +5465 2 2 4 8 1319 2769 3142 +5466 2 2 4 8 1320 2770 3141 +5467 2 2 4 8 1321 2771 3140 +5468 2 2 4 8 1328 3996 2829 +5469 2 2 4 8 321 2551 3225 +5470 2 2 4 8 1561 4491 4144 +5471 2 2 4 8 1234 3301 3896 +5472 2 2 4 8 1235 3897 3300 +5473 2 2 4 8 2498 5006 3333 +5474 2 2 4 8 1496 3144 3456 +5475 2 2 4 8 688 3456 3144 +5476 2 2 4 8 1380 4219 4121 +5477 2 2 4 8 1381 4221 4120 +5478 2 2 4 8 1170 3344 2455 +5479 2 2 4 8 1171 2456 3345 +5480 2 2 4 8 2322 3204 4529 +5481 2 2 4 8 463 2282 3966 +5482 2 2 4 8 512 3893 2695 +5483 2 2 4 8 1665 4993 2611 +5484 2 2 4 8 712 2611 4993 +5485 2 2 4 8 1700 3436 4780 +5486 2 2 4 8 1407 3635 3707 +5487 2 2 4 8 1089 3093 2877 +5488 2 2 4 8 1750 5023 3176 +5489 2 2 4 8 1546 3963 2283 +5490 2 2 4 8 586 5072 3743 +5491 2 2 4 8 709 4225 2283 +5492 2 2 4 8 1001 2630 4377 +5493 2 2 4 8 1595 2286 3957 +5494 2 2 4 8 1365 4623 2372 +5495 2 2 4 8 1411 3133 2834 +5496 2 2 4 8 1179 2843 5263 +5497 2 2 4 8 1184 5193 2398 +5498 2 2 4 8 1277 3357 3595 +5499 2 2 4 8 971 4633 3279 +5500 2 2 4 8 546 4820 2344 +5501 2 2 4 8 1506 2344 4820 +5502 2 2 4 8 1505 4819 2343 +5503 2 2 4 8 545 2343 4819 +5504 2 2 4 8 981 4517 3169 +5505 2 2 4 8 1890 3969 2596 +5506 2 2 4 8 1676 4085 5065 +5507 2 2 4 8 1232 3401 4092 +5508 2 2 4 8 1167 5344 2705 +5509 2 2 4 8 852 5090 3172 +5510 2 2 4 8 853 5091 3173 +5511 2 2 4 8 1085 3050 2731 +5512 2 2 4 8 1550 5022 2521 +5513 2 2 4 8 585 5199 2404 +5514 2 2 4 8 1622 4636 4332 +5515 2 2 4 8 976 2521 3709 +5516 2 2 4 8 2162 3275 4983 +5517 2 2 4 8 847 4983 3275 +5518 2 2 4 8 1206 3067 2728 +5519 2 2 4 8 612 2728 3067 +5520 2 2 4 8 925 2499 3905 +5521 2 2 4 8 1284 4400 2291 +5522 2 2 4 8 1770 5231 2700 +5523 2 2 4 8 1138 2700 5231 +5524 2 2 4 8 1140 2701 5232 +5525 2 2 4 8 1771 5232 2701 +5526 2 2 4 8 1269 3390 2448 +5527 2 2 4 8 897 2702 4687 +5528 2 2 4 8 1634 4687 2702 +5529 2 2 4 8 1385 4005 2292 +5530 2 2 4 8 342 2980 5107 +5531 2 2 4 8 938 2417 4309 +5532 2 2 4 8 1436 4087 2384 +5533 2 2 4 8 1438 2385 4088 +5534 2 2 4 8 624 2530 3429 +5535 2 2 4 8 1207 2292 5227 +5536 2 2 4 8 42 2675 4402 +5537 2 2 4 8 1400 3728 3791 +5538 2 2 4 8 1159 3932 2694 +5539 2 2 4 8 3179 4866 3570 +5540 2 2 4 8 1422 3795 2805 +5541 2 2 4 8 972 2805 3795 +5542 2 2 4 8 526 2968 4281 +5543 2 2 4 8 1117 4311 2745 +5544 2 2 4 8 1985 5073 3731 +5545 2 2 4 8 1109 2496 3325 +5546 2 2 4 8 1343 2658 3103 +5547 2 2 4 8 465 2430 5300 +5548 2 2 4 8 185 2900 4599 +5549 2 2 4 8 1639 3765 2556 +5550 2 2 4 8 1975 4664 3209 +5551 2 2 4 8 858 3209 4664 +5552 2 2 4 8 3039 3296 1246 +5553 2 2 4 8 1222 5156 2386 +5554 2 2 4 8 651 2547 3701 +5555 2 2 4 8 698 2753 3791 +5556 2 2 4 8 1400 3791 2753 +5557 2 2 4 8 2572 4397 2879 +5558 2 2 4 8 1869 4194 3505 +5559 2 2 4 8 1511 3046 4100 +5560 2 2 4 8 1326 2350 4777 +5561 2 2 4 8 615 2498 3333 +5562 2 2 4 8 1717 2834 4724 +5563 2 2 4 8 875 4724 2834 +5564 2 2 4 8 1810 3262 3736 +5565 2 2 4 8 1129 3736 3262 +5566 2 2 4 8 515 3295 2525 +5567 2 2 4 8 2482 4959 2920 +5568 2 2 4 8 2483 4960 2919 +5569 2 2 4 8 226 227 2945 +5570 2 2 4 8 200 201 2946 +5571 2 2 4 8 1291 2534 3760 +5572 2 2 4 8 715 3760 2534 +5573 2 2 4 8 1272 2379 3584 +5574 2 2 4 8 1788 2898 5269 +5575 2 2 4 8 961 4972 3255 +5576 2 2 4 8 874 2296 4066 +5577 2 2 4 8 2122 3134 5258 +5578 2 2 4 8 1660 4759 4720 +5579 2 2 4 8 1403 4116 2297 +5580 2 2 4 8 871 2340 3702 +5581 2 2 4 8 877 2338 4704 +5582 2 2 4 8 878 2339 4703 +5583 2 2 4 8 921 4076 2298 +5584 2 2 4 8 2837 5323 3569 +5585 2 2 4 8 1330 2524 3930 +5586 2 2 4 8 492 3930 2524 +5587 2 2 4 8 306 2959 3534 +5588 2 2 4 8 295 2958 3533 +5589 2 2 4 8 177 3535 2957 +5590 2 2 4 8 132 3532 2956 +5591 2 2 4 8 121 3531 2955 +5592 2 2 4 8 1195 4288 2970 +5593 2 2 4 8 2357 4865 4279 +5594 2 2 4 8 1273 2446 3812 +5595 2 2 4 8 894 3812 2446 +5596 2 2 4 8 2498 4378 1928 +5597 2 2 4 8 527 3310 2973 +5598 2 2 4 8 1013 5204 2581 +5599 2 2 4 8 558 2394 5075 +5600 2 2 4 8 1345 2786 3681 +5601 2 2 4 8 969 5407 2566 +5602 2 2 4 8 941 2475 3380 +5603 2 2 4 8 997 4669 2587 +5604 2 2 4 8 593 4117 2305 +5605 2 2 4 8 594 2304 4118 +5606 2 2 4 8 974 3370 2539 +5607 2 2 4 8 184 185 4599 +5608 2 2 4 8 449 4252 2306 +5609 2 2 4 8 166 167 4648 +5610 2 2 4 8 353 354 4647 +5611 2 2 4 8 1166 4343 2736 +5612 2 2 4 8 1233 2350 4670 +5613 2 2 4 8 664 2953 3118 +5614 2 2 4 8 536 3916 3148 +5615 2 2 4 8 847 4566 2323 +5616 2 2 4 8 1195 2970 3831 +5617 2 2 4 8 325 3921 2332 +5618 2 2 4 8 1165 4239 2663 +5619 2 2 4 8 567 4621 2735 +5620 2 2 4 8 1176 5116 2581 +5621 2 2 4 8 1650 2390 5035 +5622 2 2 4 8 1651 2391 5036 +5623 2 2 4 8 1104 2309 4297 +5624 2 2 4 8 1105 2310 4296 +5625 2 2 4 8 1132 4406 2315 +5626 2 2 4 8 871 4674 2340 +5627 2 2 4 8 972 3795 2538 +5628 2 2 4 8 1569 4992 4356 +5629 2 2 4 8 1278 2846 5210 +5630 2 2 4 8 2846 1865 5210 +5631 2 2 4 8 676 3992 2501 +5632 2 2 4 8 1336 2501 3992 +5633 2 2 4 8 952 2308 4042 +5634 2 2 4 8 1630 5267 2394 +5635 2 2 4 8 960 4905 3236 +5636 2 2 4 8 784 4817 3056 +5637 2 2 4 8 1483 3505 4194 +5638 2 2 4 8 1680 5408 2454 +5639 2 2 4 8 572 5235 3348 +5640 2 2 4 8 1075 2997 3647 +5641 2 2 4 8 1473 3647 2997 +5642 2 2 4 8 1878 2452 5364 +5643 2 2 4 8 731 3691 4088 +5644 2 2 4 8 695 3303 2775 +5645 2 2 4 8 1547 2742 3079 +5646 2 2 4 8 645 3754 2342 +5647 2 2 4 8 976 3709 2570 +5648 2 2 4 8 1232 4240 2354 +5649 2 2 4 8 1171 3345 4411 +5650 2 2 4 8 985 2977 4873 +5651 2 2 4 8 1845 4873 2977 +5652 2 2 4 8 2639 4643 3710 +5653 2 2 4 8 859 4406 2696 +5654 2 2 4 8 1672 2482 5358 +5655 2 2 4 8 860 5358 2482 +5656 2 2 4 8 1196 2468 4750 +5657 2 2 4 8 110 2970 109 +5658 2 2 4 8 819 2556 3765 +5659 2 2 4 8 3027 4677 3378 +5660 2 2 4 8 3028 4676 3379 +5661 2 2 4 8 1430 4465 2322 +5662 2 2 4 8 2693 4207 3605 +5663 2 2 4 8 1169 2631 4743 +5664 2 2 4 8 1091 4049 2312 +5665 2 2 4 8 1092 4050 2313 +5666 2 2 4 8 1655 4124 4823 +5667 2 2 4 8 1101 5201 2422 +5668 2 2 4 8 1619 2422 5201 +5669 2 2 4 8 1091 2312 4190 +5670 2 2 4 8 1092 2313 4189 +5671 2 2 4 8 1685 5072 4880 +5672 2 2 4 8 1153 4997 2726 +5673 2 2 4 8 1568 4714 2805 +5674 2 2 4 8 465 5300 5027 +5675 2 2 4 8 1522 2955 3879 +5676 2 2 4 8 1194 3879 2955 +5677 2 2 4 8 1526 3878 2959 +5678 2 2 4 8 1191 2959 3878 +5679 2 2 4 8 399 400 3181 +5680 2 2 4 8 1544 4212 4306 +5681 2 2 4 8 624 3429 2582 +5682 2 2 4 8 1386 3893 2326 +5683 2 2 4 8 1387 3892 2327 +5684 2 2 4 8 1671 2483 5378 +5685 2 2 4 8 861 5378 2483 +5686 2 2 4 8 862 2314 4478 +5687 2 2 4 8 1395 3991 3823 +5688 2 2 4 8 1394 3990 3822 +5689 2 2 4 8 489 4670 2350 +5690 2 2 4 8 1209 2409 4217 +5691 2 2 4 8 544 2763 3292 +5692 2 2 4 8 924 4159 2580 +5693 2 2 4 8 1787 3225 5174 +5694 2 2 4 8 968 2565 3377 +5695 2 2 4 8 1108 3730 2358 +5696 2 2 4 8 683 4712 3127 +5697 2 2 4 8 2060 4788 3973 +5698 2 2 4 8 1463 2556 4336 +5699 2 2 4 8 819 4336 2556 +5700 2 2 4 8 771 3668 4004 +5701 2 2 4 8 1375 2858 4185 +5702 2 2 4 8 600 2565 4963 +5703 2 2 4 8 601 2566 4962 +5704 2 2 4 8 651 3336 2547 +5705 2 2 4 8 724 2484 4601 +5706 2 2 4 8 1493 4601 2484 +5707 2 2 4 8 1225 3277 3210 +5708 2 2 4 8 1427 3210 3277 +5709 2 2 4 8 1226 3276 3211 +5710 2 2 4 8 1426 3211 3276 +5711 2 2 4 8 857 4431 2768 +5712 2 2 4 8 1597 2768 4431 +5713 2 2 4 8 950 2352 3782 +5714 2 2 4 8 1021 2413 5114 +5715 2 2 4 8 1876 4298 5394 +5716 2 2 4 8 2861 4974 3578 +5717 2 2 4 8 3579 2860 4975 +5718 2 2 4 8 1551 2332 3921 +5719 2 2 4 8 2216 2607 4841 +5720 2 2 4 8 719 2894 4362 +5721 2 2 4 8 1401 3674 2850 +5722 2 2 4 8 722 2850 3674 +5723 2 2 4 8 1778 2811 5119 +5724 2 2 4 8 258 2709 4036 +5725 2 2 4 8 285 4035 2710 +5726 2 2 4 8 64 4037 2708 +5727 2 2 4 8 632 2704 4411 +5728 2 2 4 8 1088 2876 3021 +5729 2 2 4 8 913 3613 2402 +5730 2 2 4 8 584 4581 2701 +5731 2 2 4 8 585 4580 2700 +5732 2 2 4 8 643 3599 2410 +5733 2 2 4 8 676 3984 2519 +5734 2 2 4 8 1059 4661 3576 +5735 2 2 4 8 857 4649 2353 +5736 2 2 4 8 101 2637 4689 +5737 2 2 4 8 1099 4229 2318 +5738 2 2 4 8 1308 4045 2639 +5739 2 2 4 8 1614 3059 5342 +5740 2 2 4 8 1615 3058 5343 +5741 2 2 4 8 1052 4318 2750 +5742 2 2 4 8 992 4797 2378 +5743 2 2 4 8 975 4233 2569 +5744 2 2 4 8 1486 2665 3407 +5745 2 2 4 8 966 2503 3997 +5746 2 2 4 8 1329 3997 2503 +5747 2 2 4 8 1945 4414 2862 +5748 2 2 4 8 1310 3398 4197 +5749 2 2 4 8 1311 3399 4196 +5750 2 2 4 8 589 4403 5357 +5751 2 2 4 8 416 4556 2345 +5752 2 2 4 8 887 5297 2744 +5753 2 2 4 8 1843 3446 4131 +5754 2 2 4 8 1464 4131 3446 +5755 2 2 4 8 641 5040 3394 +5756 2 2 4 8 1057 2460 5338 +5757 2 2 4 8 1058 5339 2459 +5758 2 2 4 8 1647 5338 2460 +5759 2 2 4 8 1648 2459 5339 +5760 2 2 4 8 510 4051 3406 +5761 2 2 4 8 549 2801 4518 +5762 2 2 4 8 550 2800 4519 +5763 2 2 4 8 992 3296 2583 +5764 2 2 4 8 2997 5064 4728 +5765 2 2 4 8 1815 4031 4346 +5766 2 2 4 8 1473 3088 2871 +5767 2 2 4 8 984 2871 3088 +5768 2 2 4 8 653 2616 3519 +5769 2 2 4 8 1260 3519 2616 +5770 2 2 4 8 1687 2406 5016 +5771 2 2 4 8 919 2493 4466 +5772 2 2 4 8 2347 5149 4933 +5773 2 2 4 8 1580 4689 2637 +5774 2 2 4 8 1143 3459 2479 +5775 2 2 4 8 579 2402 5194 +5776 2 2 4 8 1108 4629 3730 +5777 2 2 4 8 1637 4803 3032 +5778 2 2 4 8 1357 3256 3935 +5779 2 2 4 8 1368 3639 2471 +5780 2 2 4 8 1668 4952 4731 +5781 2 2 4 8 1020 3775 2870 +5782 2 2 4 8 679 3008 3365 +5783 2 2 4 8 560 5067 2851 +5784 2 2 4 8 710 2988 3369 +5785 2 2 4 8 2624 1653 4278 +5786 2 2 4 8 526 3415 3330 +5787 2 2 4 8 1519 3330 3415 +5788 2 2 4 8 655 2485 3961 +5789 2 2 4 8 1315 3961 2485 +5790 2 2 4 8 1611 4738 2749 +5791 2 2 4 8 530 3657 4021 +5792 2 2 4 8 1666 4985 3734 +5793 2 2 4 8 1182 4018 2585 +5794 2 2 4 8 1373 2857 4198 +5795 2 2 4 8 1374 2859 4199 +5796 2 2 4 8 1025 5119 2811 +5797 2 2 4 8 1121 2333 4192 +5798 2 2 4 8 1183 3469 2931 +5799 2 2 4 8 2053 2792 5238 +5800 2 2 4 8 939 5274 2394 +5801 2 2 4 8 1530 4871 2661 +5802 2 2 4 8 443 3070 3235 +5803 2 2 4 8 1352 3235 3070 +5804 2 2 4 8 1388 2656 4268 +5805 2 2 4 8 389 390 3047 +5806 2 2 4 8 1049 2596 3281 +5807 2 2 4 8 1372 2421 4301 +5808 2 2 4 8 1309 4154 3853 +5809 2 2 4 8 2081 3853 4154 +5810 2 2 4 8 75 4798 2383 +5811 2 2 4 8 2089 4119 2934 +5812 2 2 4 8 1919 5211 2962 +5813 2 2 4 8 2357 4056 4658 +5814 2 2 4 8 515 3568 3295 +5815 2 2 4 8 1044 2783 4061 +5816 2 2 4 8 893 4752 2450 +5817 2 2 4 8 1515 2450 4752 +5818 2 2 4 8 1274 2347 4357 +5819 2 2 4 8 1255 2845 3161 +5820 2 2 4 8 751 3161 2845 +5821 2 2 4 8 817 2910 3653 +5822 2 2 4 8 1413 3653 2910 +5823 2 2 4 8 1171 2623 3602 +5824 2 2 4 8 1756 3614 5289 +5825 2 2 4 8 1603 4592 2974 +5826 2 2 4 8 1402 5209 3676 +5827 2 2 4 8 884 5371 3153 +5828 2 2 4 8 2185 3153 5371 +5829 2 2 4 8 389 3047 2853 +5830 2 2 4 8 632 2848 3049 +5831 2 2 4 8 956 4977 2695 +5832 2 2 4 8 1429 4036 2709 +5833 2 2 4 8 1428 2710 4035 +5834 2 2 4 8 1430 2708 4037 +5835 2 2 4 8 1608 2441 5195 +5836 2 2 4 8 395 396 3014 +5837 2 2 4 8 1123 2393 4842 +5838 2 2 4 8 1102 2436 5183 +5839 2 2 4 8 973 5375 2609 +5840 2 2 4 8 644 2439 5186 +5841 2 2 4 8 2077 3999 5284 +5842 2 2 4 8 867 2410 3943 +5843 2 2 4 8 1185 3429 2530 +5844 2 2 4 8 2575 3545 4446 +5845 2 2 4 8 2499 3480 1494 +5846 2 2 4 8 1511 4100 3699 +5847 2 2 4 8 1567 2731 4897 +5848 2 2 4 8 2678 3989 3690 +5849 2 2 4 8 2253 3704 4641 +5850 2 2 4 8 1015 4641 3704 +5851 2 2 4 8 1364 2371 3843 +5852 2 2 4 8 410 411 4251 +5853 2 2 4 8 1404 2858 3705 +5854 2 2 4 8 727 3705 2858 +5855 2 2 4 8 578 5412 4448 +5856 2 2 4 8 1104 4007 2352 +5857 2 2 4 8 2218 3020 4665 +5858 2 2 4 8 2092 4710 4514 +5859 2 2 4 8 2091 4709 4513 +5860 2 2 4 8 1112 2365 3900 +5861 2 2 4 8 953 5033 2419 +5862 2 2 4 8 954 2418 5032 +5863 2 2 4 8 955 5034 2420 +5864 2 2 4 8 1625 2823 3148 +5865 2 2 4 8 755 4141 4764 +5866 2 2 4 8 2156 2785 3913 +5867 2 2 4 8 2058 5026 2418 +5868 2 2 4 8 2057 2419 5024 +5869 2 2 4 8 2059 2420 5025 +5870 2 2 4 8 1187 2597 4030 +5871 2 2 4 8 1103 5156 2440 +5872 2 2 4 8 1099 2359 3940 +5873 2 2 4 8 926 2629 4847 +5874 2 2 4 8 1318 2424 4077 +5875 2 2 4 8 457 4077 2424 +5876 2 2 4 8 575 4306 2351 +5877 2 2 4 8 1250 2451 3780 +5878 2 2 4 8 1416 4057 3313 +5879 2 2 4 8 352 2412 4948 +5880 2 2 4 8 165 2411 4947 +5881 2 2 4 8 1008 4978 3431 +5882 2 2 4 8 512 3334 3893 +5883 2 2 4 8 516 3335 3892 +5884 2 2 4 8 720 4967 2653 +5885 2 2 4 8 2128 5100 4404 +5886 2 2 4 8 2127 5101 4405 +5887 2 2 4 8 1297 3834 3302 +5888 2 2 4 8 1268 3609 2447 +5889 2 2 4 8 1175 2777 3127 +5890 2 2 4 8 1896 2680 3850 +5891 2 2 4 8 1195 2938 4986 +5892 2 2 4 8 1569 4356 4487 +5893 2 2 4 8 1380 3362 4219 +5894 2 2 4 8 1381 3363 4221 +5895 2 2 4 8 1020 4501 2994 +5896 2 2 4 8 1704 5331 2598 +5897 2 2 4 8 622 2598 5331 +5898 2 2 4 8 623 5332 2599 +5899 2 2 4 8 1705 2599 5332 +5900 2 2 4 8 1191 4785 2936 +5901 2 2 4 8 1194 2939 4784 +5902 2 2 4 8 1190 4732 2937 +5903 2 2 4 8 1534 3920 4277 +5904 2 2 4 8 1562 2759 3557 +5905 2 2 4 8 1564 2757 3558 +5906 2 2 4 8 1563 2758 3559 +5907 2 2 4 8 698 3791 2396 +5908 2 2 4 8 1206 3386 2903 +5909 2 2 4 8 1200 4460 2546 +5910 2 2 4 8 1527 4275 4891 +5911 2 2 4 8 198 2456 3602 +5912 2 2 4 8 938 4309 2546 +5913 2 2 4 8 1254 3596 2564 +5914 2 2 4 8 770 2564 3596 +5915 2 2 4 8 1025 2437 5119 +5916 2 2 4 8 535 2702 3917 +5917 2 2 4 8 447 3563 2617 +5918 2 2 4 8 1260 2617 3563 +5919 2 2 4 8 1585 2370 4563 +5920 2 2 4 8 897 3646 2702 +5921 2 2 4 8 1306 2702 3646 +5922 2 2 4 8 547 2526 4645 +5923 2 2 4 8 1502 4645 2526 +5924 2 2 4 8 1616 3132 3891 +5925 2 2 4 8 495 3891 3132 +5926 2 2 4 8 1052 2750 3151 +5927 2 2 4 8 729 3724 2859 +5928 2 2 4 8 1406 2859 3724 +5929 2 2 4 8 1405 2857 3725 +5930 2 2 4 8 728 3725 2857 +5931 2 2 4 8 1335 4010 2540 +5932 2 2 4 8 786 2540 4010 +5933 2 2 4 8 785 2541 4009 +5934 2 2 4 8 1334 4009 2541 +5935 2 2 4 8 713 4698 3313 +5936 2 2 4 8 1997 3313 4698 +5937 2 2 4 8 1417 2586 4373 +5938 2 2 4 8 1303 3151 2750 +5939 2 2 4 8 534 3396 3033 +5940 2 2 4 8 1367 3033 3396 +5941 2 2 4 8 1574 5048 2577 +5942 2 2 4 8 1987 3467 2793 +5943 2 2 4 8 665 2432 3681 +5944 2 2 4 8 2732 3291 5367 +5945 2 2 4 8 1096 4321 2361 +5946 2 2 4 8 1097 4320 2362 +5947 2 2 4 8 1222 5325 5156 +5948 2 2 4 8 1436 2384 4651 +5949 2 2 4 8 1254 3514 4742 +5950 2 2 4 8 1702 3499 2520 +5951 2 2 4 8 1438 4666 2385 +5952 2 2 4 8 854 2721 3198 +5953 2 2 4 8 1053 2751 3174 +5954 2 2 4 8 1054 2752 3175 +5955 2 2 4 8 1407 4093 3139 +5956 2 2 4 8 1477 3507 2518 +5957 2 2 4 8 1010 5311 3490 +5958 2 2 4 8 3127 4712 4285 +5959 2 2 4 8 1098 4205 2360 +5960 2 2 4 8 1063 2372 3998 +5961 2 2 4 8 1717 4724 2993 +5962 2 2 4 8 1090 2823 4663 +5963 2 2 4 8 938 2546 3462 +5964 2 2 4 8 1651 4122 4049 +5965 2 2 4 8 1650 4123 4050 +5966 2 2 4 8 1082 5330 3430 +5967 2 2 4 8 969 2691 5407 +5968 2 2 4 8 96 2692 4275 +5969 2 2 4 8 1280 5282 2382 +5970 2 2 4 8 1298 3686 4904 +5971 2 2 4 8 370 3045 4528 +5972 2 2 4 8 149 3044 4527 +5973 2 2 4 8 1289 5301 2379 +5974 2 2 4 8 1530 2661 4749 +5975 2 2 4 8 1284 2378 4797 +5976 2 2 4 8 564 3284 5008 +5977 2 2 4 8 802 4807 3881 +5978 2 2 4 8 1353 3503 4102 +5979 2 2 4 8 1301 3174 2751 +5980 2 2 4 8 1300 3175 2752 +5981 2 2 4 8 1652 3457 5121 +5982 2 2 4 8 1283 2377 4351 +5983 2 2 4 8 1282 4350 2376 +5984 2 2 4 8 1201 4979 3198 +5985 2 2 4 8 2252 3741 4640 +5986 2 2 4 8 1016 4640 3741 +5987 2 2 4 8 1319 3628 2769 +5988 2 2 4 8 509 2769 3628 +5989 2 2 4 8 514 2770 3629 +5990 2 2 4 8 1320 3629 2770 +5991 2 2 4 8 447 2502 3563 +5992 2 2 4 8 2148 4943 3023 +5993 2 2 4 8 3024 2149 4944 +5994 2 2 4 8 991 4351 2377 +5995 2 2 4 8 990 2376 4350 +5996 2 2 4 8 1006 3949 2388 +5997 2 2 4 8 1464 3446 3441 +5998 2 2 4 8 1911 4933 5149 +5999 2 2 4 8 4210 1977 5198 +6000 2 2 4 8 470 3712 2445 +6001 2 2 4 8 481 2444 3713 +6002 2 2 4 8 363 2722 4072 +6003 2 2 4 8 1441 4072 2722 +6004 2 2 4 8 142 2723 4071 +6005 2 2 4 8 1440 4071 2723 +6006 2 2 4 8 1713 3381 4693 +6007 2 2 4 8 1667 4656 4017 +6008 2 2 4 8 1089 4942 3111 +6009 2 2 4 8 413 5308 2711 +6010 2 2 4 8 1394 3822 3508 +6011 2 2 4 8 1395 3823 3509 +6012 2 2 4 8 1129 3014 5229 +6013 2 2 4 8 1669 3118 2953 +6014 2 2 4 8 1204 3165 3163 +6015 2 2 4 8 1404 3163 3165 +6016 2 2 4 8 1405 3162 3164 +6017 2 2 4 8 1203 3164 3162 +6018 2 2 4 8 1406 3166 3167 +6019 2 2 4 8 1205 3167 3166 +6020 2 2 4 8 697 3136 3621 +6021 2 2 4 8 699 3138 3622 +6022 2 2 4 8 786 3508 2540 +6023 2 2 4 8 785 3509 2541 +6024 2 2 4 8 587 5417 4440 +6025 2 2 4 8 662 3064 2921 +6026 2 2 4 8 1734 2387 4016 +6027 2 2 4 8 232 4719 2670 +6028 2 2 4 8 1643 3472 3195 +6029 2 2 4 8 1895 2966 4853 +6030 2 2 4 8 960 4853 2966 +6031 2 2 4 8 466 2816 3584 +6032 2 2 4 8 1593 4657 2948 +6033 2 2 4 8 655 3961 2395 +6034 2 2 4 8 1712 5295 2381 +6035 2 2 4 8 590 3375 5355 +6036 2 2 4 8 591 3376 5356 +6037 2 2 4 8 1142 3744 2445 +6038 2 2 4 8 1141 2444 3745 +6039 2 2 4 8 527 2492 5305 +6040 2 2 4 8 1095 2807 4421 +6041 2 2 4 8 2113 4847 2629 +6042 2 2 4 8 1366 3624 4048 +6043 2 2 4 8 1484 2977 3206 +6044 2 2 4 8 985 3206 2977 +6045 2 2 4 8 1630 3782 2697 +6046 2 2 4 8 2031 4584 4776 +6047 2 2 4 8 1201 3328 4979 +6048 2 2 4 8 1450 5411 2412 +6049 2 2 4 8 2087 2433 4934 +6050 2 2 4 8 1600 4642 2975 +6051 2 2 4 8 2285 4059 2772 +6052 2 2 4 8 2284 4060 2773 +6053 2 2 4 8 1509 4065 4064 +6054 2 2 4 8 545 4651 3918 +6055 2 2 4 8 2384 3918 4651 +6056 2 2 4 8 661 2549 5074 +6057 2 2 4 8 542 2518 5419 +6058 2 2 4 8 922 5420 2518 +6059 2 2 4 8 1006 2388 4065 +6060 2 2 4 8 103 104 3443 +6061 2 2 4 8 197 3602 2623 +6062 2 2 4 8 839 4272 3084 +6063 2 2 4 8 1692 3084 4272 +6064 2 2 4 8 1677 4367 3181 +6065 2 2 4 8 544 2387 4391 +6066 2 2 4 8 1420 3297 4130 +6067 2 2 4 8 1737 4130 3297 +6068 2 2 4 8 845 2880 3749 +6069 2 2 4 8 1414 3749 2880 +6070 2 2 4 8 1044 4061 2392 +6071 2 2 4 8 1471 2693 4315 +6072 2 2 4 8 2440 5156 5325 +6073 2 2 4 8 1200 4893 2932 +6074 2 2 4 8 1465 2900 4552 +6075 2 2 4 8 864 5393 2387 +6076 2 2 4 8 452 4917 2966 +6077 2 2 4 8 1086 3010 3134 +6078 2 2 4 8 1718 3134 3010 +6079 2 2 4 8 2314 5010 5185 +6080 2 2 4 8 676 2519 5404 +6081 2 2 4 8 1721 2573 3493 +6082 2 2 4 8 1722 3494 2574 +6083 2 2 4 8 1092 4344 2390 +6084 2 2 4 8 490 2454 5410 +6085 2 2 4 8 1031 2645 5026 +6086 2 2 4 8 1032 5024 2646 +6087 2 2 4 8 1091 4187 2391 +6088 2 2 4 8 546 3919 4666 +6089 2 2 4 8 2385 4666 3919 +6090 2 2 4 8 42 4402 41 +6091 2 2 4 8 1329 3845 3997 +6092 2 2 4 8 167 4224 4648 +6093 2 2 4 8 354 4223 4647 +6094 2 2 4 8 1328 3846 3996 +6095 2 2 4 8 623 2419 5332 +6096 2 2 4 8 622 5331 2418 +6097 2 2 4 8 1145 4580 2404 +6098 2 2 4 8 2009 4177 4025 +6099 2 2 4 8 1543 2668 4741 +6100 2 2 4 8 1542 2667 4740 +6101 2 2 4 8 1582 3727 3274 +6102 2 2 4 8 1312 3274 3727 +6103 2 2 4 8 4173 1875 4716 +6104 2 2 4 8 631 2443 4984 +6105 2 2 4 8 1330 3611 2524 +6106 2 2 4 8 1310 3272 3714 +6107 2 2 4 8 1577 3714 3272 +6108 2 2 4 8 1578 3715 3273 +6109 2 2 4 8 1311 3273 3715 +6110 2 2 4 8 1137 2454 3756 +6111 2 2 4 8 2173 5133 3968 +6112 2 2 4 8 1451 2411 4648 +6113 2 2 4 8 1450 2412 4647 +6114 2 2 4 8 426 427 3287 +6115 2 2 4 8 209 3288 3 +6116 2 2 4 8 1280 2534 3587 +6117 2 2 4 8 812 5269 2898 +6118 2 2 4 8 545 3918 3493 +6119 2 2 4 8 546 3494 3919 +6120 2 2 4 8 1780 3815 2694 +6121 2 2 4 8 975 2578 3502 +6122 2 2 4 8 976 3503 2579 +6123 2 2 4 8 578 4200 5062 +6124 2 2 4 8 2093 4711 3515 +6125 2 2 4 8 819 3515 4711 +6126 2 2 4 8 737 2877 4576 +6127 2 2 4 8 1649 4576 2877 +6128 2 2 4 8 1003 4701 2396 +6129 2 2 4 8 468 2399 4414 +6130 2 2 4 8 1718 3010 4586 +6131 2 2 4 8 739 4586 3010 +6132 2 2 4 8 841 5287 4660 +6133 2 2 4 8 2205 5355 3375 +6134 2 2 4 8 2207 5356 3376 +6135 2 2 4 8 1000 4479 2626 +6136 2 2 4 8 602 2487 5203 +6137 2 2 4 8 938 4657 2417 +6138 2 2 4 8 2462 4617 3297 +6139 2 2 4 8 2339 3865 4718 +6140 2 2 4 8 2338 3864 4717 +6141 2 2 4 8 14 3612 13 +6142 2 2 4 8 1649 5029 4662 +6143 2 2 4 8 634 4718 3865 +6144 2 2 4 8 633 4717 3864 +6145 2 2 4 8 1780 5321 2417 +6146 2 2 4 8 1266 2435 4844 +6147 2 2 4 8 37 3080 36 +6148 2 2 4 8 1227 3706 2625 +6149 2 2 4 8 1876 3636 4298 +6150 2 2 4 8 789 3165 5135 +6151 2 2 4 8 2853 1730 5216 +6152 2 2 4 8 774 4132 3325 +6153 2 2 4 8 1316 3135 3136 +6154 2 2 4 8 1239 3136 3135 +6155 2 2 4 8 1242 3138 3137 +6156 2 2 4 8 1317 3137 3138 +6157 2 2 4 8 852 2407 4133 +6158 2 2 4 8 669 4134 2407 +6159 2 2 4 8 670 4135 2408 +6160 2 2 4 8 853 2408 4136 +6161 2 2 4 8 1784 4939 2577 +6162 2 2 4 8 329 2577 4939 +6163 2 2 4 8 1213 2769 3581 +6164 2 2 4 8 1215 2770 3582 +6165 2 2 4 8 521 3583 2771 +6166 2 2 4 8 15 4583 14 +6167 2 2 4 8 1576 4059 4304 +6168 2 2 4 8 2285 4304 4059 +6169 2 2 4 8 1575 4060 4303 +6170 2 2 4 8 2284 4303 4060 +6171 2 2 4 8 683 4844 2435 +6172 2 2 4 8 1721 3493 3918 +6173 2 2 4 8 1722 3919 3494 +6174 2 2 4 8 1586 4551 4941 +6175 2 2 4 8 593 3221 4174 +6176 2 2 4 8 594 4175 3222 +6177 2 2 4 8 1350 3075 3321 +6178 2 2 4 8 1301 3321 3075 +6179 2 2 4 8 1302 3320 3076 +6180 2 2 4 8 1349 3076 3320 +6181 2 2 4 8 1348 3077 3319 +6182 2 2 4 8 1300 3319 3077 +6183 2 2 4 8 527 5013 3310 +6184 2 2 4 8 1063 5372 3222 +6185 2 2 4 8 3222 5372 2186 +6186 2 2 4 8 1363 4588 2405 +6187 2 2 4 8 1416 3357 2976 +6188 2 2 4 8 1636 5139 4096 +6189 2 2 4 8 873 3770 4121 +6190 2 2 4 8 1093 5139 3915 +6191 2 2 4 8 1533 4399 4506 +6192 2 2 4 8 1065 2914 3284 +6193 2 2 4 8 1596 3284 2914 +6194 2 2 4 8 1752 2945 5270 +6195 2 2 4 8 1753 5271 2946 +6196 2 2 4 8 1107 5127 2525 +6197 2 2 4 8 1587 2525 5127 +6198 2 2 4 8 327 3947 2765 +6199 2 2 4 8 1035 5418 2778 +6200 2 2 4 8 730 3671 4439 +6201 2 2 4 8 448 5138 2481 +6202 2 2 4 8 312 2749 4738 +6203 2 2 4 8 1329 3765 3845 +6204 2 2 4 8 232 2670 4098 +6205 2 2 4 8 1625 4663 2823 +6206 2 2 4 8 457 3753 4077 +6207 2 2 4 8 1946 4077 3753 +6208 2 2 4 8 2335 3979 5124 +6209 2 2 4 8 173 3485 3410 +6210 2 2 4 8 3671 5298 4439 +6211 2 2 4 8 1874 4649 3229 +6212 2 2 4 8 857 3229 4649 +6213 2 2 4 8 287 288 3440 +6214 2 2 4 8 255 256 3441 +6215 2 2 4 8 66 67 3439 +6216 2 2 4 8 1623 4690 2970 +6217 2 2 4 8 235 236 3090 +6218 2 2 4 8 1690 4166 2416 +6219 2 2 4 8 4185 2858 4767 +6220 2 2 4 8 1407 3975 4093 +6221 2 2 4 8 2123 4542 3693 +6222 2 2 4 8 1442 3693 4542 +6223 2 2 4 8 1443 3694 4541 +6224 2 2 4 8 2121 4541 3694 +6225 2 2 4 8 2122 3695 4543 +6226 2 2 4 8 1444 4543 3695 +6227 2 2 4 8 1445 4544 3696 +6228 2 2 4 8 2125 3696 4544 +6229 2 2 4 8 2124 3697 4545 +6230 2 2 4 8 1446 4545 3697 +6231 2 2 4 8 1447 4546 3698 +6232 2 2 4 8 2126 3698 4546 +6233 2 2 4 8 1528 4945 2457 +6234 2 2 4 8 1007 2457 4945 +6235 2 2 4 8 1529 4946 2458 +6236 2 2 4 8 1008 2458 4946 +6237 2 2 4 8 820 3618 2555 +6238 2 2 4 8 818 2554 3619 +6239 2 2 4 8 1616 4742 2435 +6240 2 2 4 8 1135 4621 2427 +6241 2 2 4 8 40 41 3329 +6242 2 2 4 8 812 2429 4162 +6243 2 2 4 8 1253 4115 2580 +6244 2 2 4 8 1920 3001 4356 +6245 2 2 4 8 973 4356 3001 +6246 2 2 4 8 1268 2447 4220 +6247 2 2 4 8 1269 2448 4222 +6248 2 2 4 8 783 3742 3794 +6249 2 2 4 8 1776 3794 3742 +6250 2 2 4 8 750 2437 4726 +6251 2 2 4 8 1073 3374 2680 +6252 2 2 4 8 1525 4020 2958 +6253 2 2 4 8 1190 2958 4020 +6254 2 2 4 8 1148 5223 3375 +6255 2 2 4 8 2205 3375 5223 +6256 2 2 4 8 1629 3876 3285 +6257 2 2 4 8 1139 3285 3876 +6258 2 2 4 8 1718 4586 4157 +6259 2 2 4 8 751 3655 4789 +6260 2 2 4 8 2222 4789 3655 +6261 2 2 4 8 957 2472 5294 +6262 2 2 4 8 1337 5059 2476 +6263 2 2 4 8 954 4282 2603 +6264 2 2 4 8 1608 5195 2600 +6265 2 2 4 8 1558 4262 2424 +6266 2 2 4 8 942 4016 2628 +6267 2 2 4 8 1443 2713 4454 +6268 2 2 4 8 1442 2712 4455 +6269 2 2 4 8 1444 4456 2714 +6270 2 2 4 8 1445 4457 2715 +6271 2 2 4 8 1446 4458 2716 +6272 2 2 4 8 1447 4459 2717 +6273 2 2 4 8 1350 2536 3672 +6274 2 2 4 8 1349 2537 3673 +6275 2 2 4 8 1344 2489 4177 +6276 2 2 4 8 528 4177 2489 +6277 2 2 4 8 513 4287 2686 +6278 2 2 4 8 970 2610 5005 +6279 2 2 4 8 1101 2912 5201 +6280 2 2 4 8 2690 3283 5236 +6281 2 2 4 8 1288 4162 2429 +6282 2 2 4 8 980 2425 4326 +6283 2 2 4 8 1345 4326 2425 +6284 2 2 4 8 412 2711 4751 +6285 2 2 4 8 661 2677 4186 +6286 2 2 4 8 1051 3156 4941 +6287 2 2 4 8 528 4025 4177 +6288 2 2 4 8 1401 3056 3065 +6289 2 2 4 8 487 3763 2515 +6290 2 2 4 8 1264 3264 4393 +6291 2 2 4 8 393 394 3466 +6292 2 2 4 8 1492 3586 2585 +6293 2 2 4 8 82 83 3121 +6294 2 2 4 8 48 49 3122 +6295 2 2 4 8 269 270 3123 +6296 2 2 4 8 1492 2585 4615 +6297 2 2 4 8 722 4615 2585 +6298 2 2 4 8 668 5263 2843 +6299 2 2 4 8 1550 4421 2807 +6300 2 2 4 8 896 4497 2431 +6301 2 2 4 8 1346 4283 2429 +6302 2 2 4 8 491 4075 2436 +6303 2 2 4 8 1490 3192 3583 +6304 2 2 4 8 1217 3583 3192 +6305 2 2 4 8 1010 2529 5311 +6306 2 2 4 8 1628 5311 2529 +6307 2 2 4 8 317 318 3711 +6308 2 2 4 8 1782 5286 4578 +6309 2 2 4 8 1740 5107 2980 +6310 2 2 4 8 1423 2513 3774 +6311 2 2 4 8 1439 5170 3000 +6312 2 2 4 8 662 4319 2682 +6313 2 2 4 8 894 2500 3812 +6314 2 2 4 8 1536 3397 3935 +6315 2 2 4 8 2121 5256 3093 +6316 2 2 4 8 567 3093 5256 +6317 2 2 4 8 355 356 3298 +6318 2 2 4 8 168 169 3299 +6319 2 2 4 8 1069 2653 4665 +6320 2 2 4 8 1183 3065 3056 +6321 2 2 4 8 2267 5300 2762 +6322 2 2 4 8 980 2432 4330 +6323 2 2 4 8 1114 3043 4867 +6324 2 2 4 8 445 4102 2570 +6325 2 2 4 8 70 3131 69 +6326 2 2 4 8 2459 4324 2884 +6327 2 2 4 8 2460 2883 4325 +6328 2 2 4 8 195 196 3452 +6329 2 2 4 8 360 361 3449 +6330 2 2 4 8 140 3448 139 +6331 2 2 4 8 1001 4377 5152 +6332 2 2 4 8 1211 2720 4078 +6333 2 2 4 8 932 3183 3986 +6334 2 2 4 8 933 3182 3987 +6335 2 2 4 8 1501 4626 2597 +6336 2 2 4 8 727 2597 4626 +6337 2 2 4 8 1929 5096 3819 +6338 2 2 4 8 1228 4141 2550 +6339 2 2 4 8 774 2496 5084 +6340 2 2 4 8 1562 5063 4832 +6341 2 2 4 8 1291 5124 3979 +6342 2 2 4 8 1109 5285 3661 +6343 2 2 4 8 92 3620 91 +6344 2 2 4 8 1027 3662 2563 +6345 2 2 4 8 1813 3172 5090 +6346 2 2 4 8 1814 3173 5091 +6347 2 2 4 8 597 2664 3436 +6348 2 2 4 8 4198 2857 4769 +6349 2 2 4 8 4199 2859 4768 +6350 2 2 4 8 4206 3228 5382 +6351 2 2 4 8 2284 5043 5188 +6352 2 2 4 8 2285 5044 5187 +6353 2 2 4 8 2484 2870 4372 +6354 2 2 4 8 1548 2627 3597 +6355 2 2 4 8 900 4290 3920 +6356 2 2 4 8 238 2744 4940 +6357 2 2 4 8 1605 3013 4526 +6358 2 2 4 8 1543 4211 3323 +6359 2 2 4 8 1710 2443 4471 +6360 2 2 4 8 2334 2695 4977 +6361 2 2 4 8 1435 4691 3203 +6362 2 2 4 8 1266 3755 3982 +6363 2 2 4 8 464 4491 3915 +6364 2 2 4 8 2242 3915 4491 +6365 2 2 4 8 1452 4412 4250 +6366 2 2 4 8 648 4959 2482 +6367 2 2 4 8 650 4960 2483 +6368 2 2 4 8 2321 5307 4956 +6369 2 2 4 8 441 3025 5380 +6370 2 2 4 8 1131 4106 2892 +6371 2 2 4 8 999 4688 5303 +6372 2 2 4 8 1195 4986 4288 +6373 2 2 4 8 1323 4026 2907 +6374 2 2 4 8 1960 2915 4188 +6375 2 2 4 8 471 2781 3587 +6376 2 2 4 8 1280 3587 2781 +6377 2 2 4 8 233 234 3836 +6378 2 2 4 8 988 3094 3444 +6379 2 2 4 8 1495 3444 3094 +6380 2 2 4 8 960 2478 4905 +6381 2 2 4 8 541 3337 3498 +6382 2 2 4 8 1504 3498 3337 +6383 2 2 4 8 960 3928 2478 +6384 2 2 4 8 894 2446 4218 +6385 2 2 4 8 2526 2888 4439 +6386 2 2 4 8 1629 2869 3876 +6387 2 2 4 8 2740 4877 4972 +6388 2 2 4 8 2155 3041 5316 +6389 2 2 4 8 1501 2597 3601 +6390 2 2 4 8 1086 3113 5228 +6391 2 2 4 8 1084 3115 5342 +6392 2 2 4 8 1083 3116 5343 +6393 2 2 4 8 531 2447 4219 +6394 2 2 4 8 531 4220 2447 +6395 2 2 4 8 532 2448 4221 +6396 2 2 4 8 532 4222 2448 +6397 2 2 4 8 2356 5297 4409 +6398 2 2 4 8 1788 5080 2935 +6399 2 2 4 8 883 4943 5370 +6400 2 2 4 8 884 4944 5371 +6401 2 2 4 8 71 72 3312 +6402 2 2 4 8 170 171 3149 +6403 2 2 4 8 357 358 3150 +6404 2 2 4 8 682 2737 3385 +6405 2 2 4 8 1256 2677 3543 +6406 2 2 4 8 661 3543 2677 +6407 2 2 4 8 1701 3233 5165 +6408 2 2 4 8 1455 3228 4206 +6409 2 2 4 8 1085 3114 5322 +6410 2 2 4 8 643 2595 4300 +6411 2 2 4 8 1178 2570 3709 +6412 2 2 4 8 709 3278 4225 +6413 2 2 4 8 1087 5320 3112 +6414 2 2 4 8 1547 3937 4203 +6415 2 2 4 8 669 3159 3573 +6416 2 2 4 8 1458 3573 3159 +6417 2 2 4 8 1459 3574 3160 +6418 2 2 4 8 670 3160 3574 +6419 2 2 4 8 592 4750 2468 +6420 2 2 4 8 706 4197 2602 +6421 2 2 4 8 707 4196 2604 +6422 2 2 4 8 1327 3907 3844 +6423 2 2 4 8 441 5380 3205 +6424 2 2 4 8 2117 3205 5380 +6425 2 2 4 8 57 4591 3109 +6426 2 2 4 8 278 4593 3110 +6427 2 2 4 8 498 3616 2698 +6428 2 2 4 8 1275 4598 2674 +6429 2 2 4 8 1670 4699 3169 +6430 2 2 4 8 1631 4330 3504 +6431 2 2 4 8 1524 4514 4710 +6432 2 2 4 8 1523 4513 4709 +6433 2 2 4 8 1383 3742 3944 +6434 2 2 4 8 1449 3913 2785 +6435 2 2 4 8 1672 4012 2482 +6436 2 2 4 8 1671 4011 2483 +6437 2 2 4 8 1968 2929 4305 +6438 2 2 4 8 1494 3089 4015 +6439 2 2 4 8 732 2942 4575 +6440 2 2 4 8 1646 4575 2942 +6441 2 2 4 8 1803 4606 5081 +6442 2 2 4 8 835 2899 3203 +6443 2 2 4 8 896 4617 2462 +6444 2 2 4 8 2077 4582 3666 +6445 2 2 4 8 849 3666 4582 +6446 2 2 4 8 493 2461 4176 +6447 2 2 4 8 1470 4095 3409 +6448 2 2 4 8 1729 3409 4095 +6449 2 2 4 8 1466 4094 3410 +6450 2 2 4 8 1728 3410 4094 +6451 2 2 4 8 2027 3920 4290 +6452 2 2 4 8 1366 4002 4345 +6453 2 2 4 8 2202 4345 4002 +6454 2 2 4 8 1909 5399 3533 +6455 2 2 4 8 1910 5400 3534 +6456 2 2 4 8 1908 3535 5398 +6457 2 2 4 8 1907 3532 5397 +6458 2 2 4 8 1906 3531 5396 +6459 2 2 4 8 1420 2976 3773 +6460 2 2 4 8 758 3773 2976 +6461 2 2 4 8 1861 5288 2547 +6462 2 2 4 8 1022 2557 4614 +6463 2 2 4 8 3055 3265 5041 +6464 2 2 4 8 3050 4897 2731 +6465 2 2 4 8 1492 3233 3586 +6466 2 2 4 8 538 3586 3233 +6467 2 2 4 8 2514 5009 1684 +6468 2 2 4 8 577 4063 4862 +6469 2 2 4 8 1664 4470 2972 +6470 2 2 4 8 702 2972 4470 +6471 2 2 4 8 1232 4770 2619 +6472 2 2 4 8 813 3731 5073 +6473 2 2 4 8 1146 4869 2491 +6474 2 2 4 8 1757 3729 2944 +6475 2 2 4 8 866 2944 3729 +6476 2 2 4 8 1248 2873 3224 +6477 2 2 4 8 2620 3544 4644 +6478 2 2 4 8 1119 2984 4340 +6479 2 2 4 8 1120 2985 4339 +6480 2 2 4 8 1666 2743 3655 +6481 2 2 4 8 1565 4716 2720 +6482 2 2 4 8 733 2720 4716 +6483 2 2 4 8 568 4682 2471 +6484 2 2 4 8 2440 4862 4063 +6485 2 2 4 8 229 230 3215 +6486 2 2 4 8 718 3247 3476 +6487 2 2 4 8 1456 3476 3247 +6488 2 2 4 8 962 5237 2741 +6489 2 2 4 8 699 3622 4242 +6490 2 2 4 8 697 3621 4244 +6491 2 2 4 8 1079 2551 3825 +6492 2 2 4 8 344 345 3177 +6493 2 2 4 8 678 5344 3133 +6494 2 2 4 8 2049 3133 5344 +6495 2 2 4 8 676 2501 3984 +6496 2 2 4 8 1727 3905 2523 +6497 2 2 4 8 1076 4549 3551 +6498 2 2 4 8 1077 4548 3552 +6499 2 2 4 8 640 5051 2520 +6500 2 2 4 8 1835 2477 4104 +6501 2 2 4 8 1731 2854 5217 +6502 2 2 4 8 1732 2855 5218 +6503 2 2 4 8 1608 2600 4147 +6504 2 2 4 8 2441 5132 3342 +6505 2 2 4 8 13 3612 3019 +6506 2 2 4 8 1126 3641 2608 +6507 2 2 4 8 1352 2782 3967 +6508 2 2 4 8 1875 4173 2874 +6509 2 2 4 8 970 2874 4173 +6510 2 2 4 8 1046 2508 4936 +6511 2 2 4 8 1045 2507 4935 +6512 2 2 4 8 1120 4339 4062 +6513 2 2 4 8 1272 3584 2816 +6514 2 2 4 8 8 9 3460 +6515 2 2 4 8 390 4279 3047 +6516 2 2 4 8 1482 3825 2551 +6517 2 2 4 8 1338 4917 2472 +6518 2 2 4 8 571 4487 2470 +6519 2 2 4 8 25 3938 24 +6520 2 2 4 8 522 2805 4714 +6521 2 2 4 8 1770 2920 4959 +6522 2 2 4 8 1771 2919 4960 +6523 2 2 4 8 1452 2908 4412 +6524 2 2 4 8 564 2469 4557 +6525 2 2 4 8 1082 2474 5330 +6526 2 2 4 8 1191 3878 4785 +6527 2 2 4 8 1194 4784 3879 +6528 2 2 4 8 1666 5105 2743 +6529 2 2 4 8 494 2743 5105 +6530 2 2 4 8 555 2997 4728 +6531 2 2 4 8 628 5351 2475 +6532 2 2 4 8 98 99 3214 +6533 2 2 4 8 102 103 5290 +6534 2 2 4 8 1751 4673 2986 +6535 2 2 4 8 1368 2471 4682 +6536 2 2 4 8 686 2476 5059 +6537 2 2 4 8 1790 4876 3458 +6538 2 2 4 8 398 4367 2590 +6539 2 2 4 8 1244 3202 5324 +6540 2 2 4 8 1281 2969 3187 +6541 2 2 4 8 875 2488 4724 +6542 2 2 4 8 414 415 3202 +6543 2 2 4 8 982 3170 5043 +6544 2 2 4 8 983 3171 5044 +6545 2 2 4 8 1719 4086 3405 +6546 2 2 4 8 1460 3405 4086 +6547 2 2 4 8 543 4630 2580 +6548 2 2 4 8 461 5003 3137 +6549 2 2 4 8 1629 5185 5010 +6550 2 2 4 8 388 2853 5216 +6551 2 2 4 8 1190 4020 4732 +6552 2 2 4 8 642 2592 3716 +6553 2 2 4 8 842 3968 5133 +6554 2 2 4 8 68 3405 67 +6555 2 2 4 8 1194 2955 3531 +6556 2 2 4 8 1193 2956 3532 +6557 2 2 4 8 1192 2957 3535 +6558 2 2 4 8 1190 3533 2958 +6559 2 2 4 8 1191 3534 2959 +6560 2 2 4 8 493 4160 2491 +6561 2 2 4 8 2206 5357 4403 +6562 2 2 4 8 1007 4401 2477 +6563 2 2 4 8 2281 5286 3571 +6564 2 2 4 8 565 4997 2527 +6565 2 2 4 8 1124 4845 2511 +6566 2 2 4 8 1366 4048 3415 +6567 2 2 4 8 655 4553 2485 +6568 2 2 4 8 667 2488 4643 +6569 2 2 4 8 1517 4566 3457 +6570 2 2 4 8 106 3692 105 +6571 2 2 4 8 91 3620 2638 +6572 2 2 4 8 1020 2484 4501 +6573 2 2 4 8 320 321 3225 +6574 2 2 4 8 3025 1896 5380 +6575 2 2 4 8 1303 5404 2519 +6576 2 2 4 8 1400 2840 4848 +6577 2 2 4 8 875 4618 2489 +6578 2 2 4 8 1474 3387 3884 +6579 2 2 4 8 1539 3269 3011 +6580 2 2 4 8 1037 3011 3269 +6581 2 2 4 8 1540 3270 3012 +6582 2 2 4 8 1038 3012 3270 +6583 2 2 4 8 2912 4968 5201 +6584 2 2 4 8 156 3217 155 +6585 2 2 4 8 376 377 3216 +6586 2 2 4 8 110 111 3831 +6587 2 2 4 8 1585 4563 2838 +6588 2 2 4 8 1130 2838 4563 +6589 2 2 4 8 1601 2994 4501 +6590 2 2 4 8 72 5361 3312 +6591 2 2 4 8 551 5314 3331 +6592 2 2 4 8 1466 3410 3485 +6593 2 2 4 8 1344 4643 2488 +6594 2 2 4 8 2492 4632 1766 +6595 2 2 4 8 1119 4340 4108 +6596 2 2 4 8 1405 3725 4509 +6597 2 2 4 8 1406 3724 4508 +6598 2 2 4 8 652 2644 3617 +6599 2 2 4 8 1252 3617 2644 +6600 2 2 4 8 458 2517 5310 +6601 2 2 4 8 217 2647 3818 +6602 2 2 4 8 435 2648 3817 +6603 2 2 4 8 1453 3560 3200 +6604 2 2 4 8 540 3200 3560 +6605 2 2 4 8 539 3561 3201 +6606 2 2 4 8 1454 3201 3561 +6607 2 2 4 8 1200 5321 4893 +6608 2 2 4 8 313 314 4040 +6609 2 2 4 8 661 5074 2725 +6610 2 2 4 8 671 4339 2985 +6611 2 2 4 8 672 4340 2984 +6612 2 2 4 8 1708 3633 2835 +6613 2 2 4 8 1709 2836 3632 +6614 2 2 4 8 2415 5175 3910 +6615 2 2 4 8 1278 3281 3072 +6616 2 2 4 8 824 2824 4111 +6617 2 2 4 8 1470 4111 2824 +6618 2 2 4 8 816 2827 4110 +6619 2 2 4 8 1467 4110 2827 +6620 2 2 4 8 879 2600 5195 +6621 2 2 4 8 1253 3303 2865 +6622 2 2 4 8 584 2533 3976 +6623 2 2 4 8 514 4516 2990 +6624 2 2 4 8 509 4515 2989 +6625 2 2 4 8 271 272 3249 +6626 2 2 4 8 51 3248 50 +6627 2 2 4 8 1408 3953 2636 +6628 2 2 4 8 406 2636 3953 +6629 2 2 4 8 1199 4466 2493 +6630 2 2 4 8 1431 3471 3232 +6631 2 2 4 8 1304 3232 3471 +6632 2 2 4 8 1270 3767 3324 +6633 2 2 4 8 2533 4685 3976 +6634 2 2 4 8 1648 4209 2943 +6635 2 2 4 8 695 2865 3303 +6636 2 2 4 8 172 173 3410 +6637 2 2 4 8 359 360 3409 +6638 2 2 4 8 1383 3944 3388 +6639 2 2 4 8 755 3411 4332 +6640 2 2 4 8 1252 3564 2679 +6641 2 2 4 8 2497 4409 1927 +6642 2 2 4 8 1368 2626 4479 +6643 2 2 4 8 641 3394 2807 +6644 2 2 4 8 1682 5307 2944 +6645 2 2 4 8 1232 2619 4240 +6646 2 2 4 8 1098 2759 4668 +6647 2 2 4 8 1562 4668 2759 +6648 2 2 4 8 758 3357 4598 +6649 2 2 4 8 1245 4838 2872 +6650 2 2 4 8 378 379 3230 +6651 2 2 4 8 157 158 3231 +6652 2 2 4 8 1230 4849 3063 +6653 2 2 4 8 700 3614 3360 +6654 2 2 4 8 1534 3360 3614 +6655 2 2 4 8 1367 3396 3931 +6656 2 2 4 8 327 328 3947 +6657 2 2 4 8 1867 2571 5273 +6658 2 2 4 8 929 5018 2502 +6659 2 2 4 8 522 4821 2500 +6660 2 2 4 8 616 3910 5175 +6661 2 2 4 8 1640 2554 5151 +6662 2 2 4 8 446 3550 3564 +6663 2 2 4 8 492 2524 4127 +6664 2 2 4 8 1689 4043 4916 +6665 2 2 4 8 673 4027 2535 +6666 2 2 4 8 674 4029 2536 +6667 2 2 4 8 675 4028 2537 +6668 2 2 4 8 457 5384 2584 +6669 2 2 4 8 3030 4982 5127 +6670 2 2 4 8 232 233 4719 +6671 2 2 4 8 721 2873 3433 +6672 2 2 4 8 1667 2744 5297 +6673 2 2 4 8 1726 2522 4159 +6674 2 2 4 8 4177 2009 4675 +6675 2 2 4 8 611 4530 2503 +6676 2 2 4 8 1175 2891 4299 +6677 2 2 4 8 1423 4794 2513 +6678 2 2 4 8 2866 1716 5163 +6679 2 2 4 8 1715 5162 2868 +6680 2 2 4 8 1714 2867 5161 +6681 2 2 4 8 1978 4927 3839 +6682 2 2 4 8 184 4599 3243 +6683 2 2 4 8 547 4810 2526 +6684 2 2 4 8 1005 2801 3496 +6685 2 2 4 8 1539 3496 2801 +6686 2 2 4 8 1004 2800 3495 +6687 2 2 4 8 1540 3495 2800 +6688 2 2 4 8 2323 4566 3870 +6689 2 2 4 8 576 5097 2983 +6690 2 2 4 8 1997 3430 5330 +6691 2 2 4 8 1102 5284 3128 +6692 2 2 4 8 552 4505 2509 +6693 2 2 4 8 553 4506 2510 +6694 2 2 4 8 979 2763 3477 +6695 2 2 4 8 1512 3009 3666 +6696 2 2 4 8 4104 2263 5255 +6697 2 2 4 8 582 4441 2511 +6698 2 2 4 8 1096 2567 5205 +6699 2 2 4 8 1097 2568 5206 +6700 2 2 4 8 521 5130 4794 +6701 2 2 4 8 831 5009 3393 +6702 2 2 4 8 21 3518 20 +6703 2 2 4 8 335 336 3925 +6704 2 2 4 8 1654 3610 2932 +6705 2 2 4 8 225 226 4055 +6706 2 2 4 8 201 202 4054 +6707 2 2 4 8 1415 3580 3268 +6708 2 2 4 8 4133 2260 5090 +6709 2 2 4 8 4136 2261 5091 +6710 2 2 4 8 1434 2934 4119 +6711 2 2 4 8 1777 4616 5203 +6712 2 2 4 8 1794 4191 2733 +6713 2 2 4 8 2513 4794 5130 +6714 2 2 4 8 688 4268 2656 +6715 2 2 4 8 1153 4407 4688 +6716 2 2 4 8 1305 3450 3237 +6717 2 2 4 8 1419 3237 3450 +6718 2 2 4 8 144 5217 2854 +6719 2 2 4 8 365 5218 2855 +6720 2 2 4 8 1541 2721 4658 +6721 2 2 4 8 854 4658 2721 +6722 2 2 4 8 1792 5401 4040 +6723 2 2 4 8 1431 3232 4788 +6724 2 2 4 8 1127 4632 2973 +6725 2 2 4 8 563 4877 2740 +6726 2 2 4 8 236 237 4017 +6727 2 2 4 8 547 4645 2523 +6728 2 2 4 8 4191 1794 4312 +6729 2 2 4 8 994 2560 3990 +6730 2 2 4 8 995 2561 3991 +6731 2 2 4 8 2330 4747 5070 +6732 2 2 4 8 1019 3031 4915 +6733 2 2 4 8 1147 4403 3751 +6734 2 2 4 8 2033 3751 4403 +6735 2 2 4 8 690 3236 3541 +6736 2 2 4 8 1538 3541 3236 +6737 2 2 4 8 1153 4688 2527 +6738 2 2 4 8 1595 3047 4279 +6739 2 2 4 8 1503 4044 2983 +6740 2 2 4 8 576 2983 4044 +6741 2 2 4 8 882 4124 3263 +6742 2 2 4 8 1655 3263 4124 +6743 2 2 4 8 2463 4812 5014 +6744 2 2 4 8 2018 4954 3718 +6745 2 2 4 8 887 4409 5297 +6746 2 2 4 8 441 3875 2991 +6747 2 2 4 8 3337 5358 4438 +6748 2 2 4 8 1306 3917 2702 +6749 2 2 4 8 1121 3540 2734 +6750 2 2 4 8 543 2522 5122 +6751 2 2 4 8 621 4838 2546 +6752 2 2 4 8 711 2777 3475 +6753 2 2 4 8 1622 5171 2638 +6754 2 2 4 8 1696 4681 4989 +6755 2 2 4 8 1828 3826 4810 +6756 2 2 4 8 1385 2846 4005 +6757 2 2 4 8 1639 4499 4325 +6758 2 2 4 8 2460 4325 4499 +6759 2 2 4 8 1638 4324 4500 +6760 2 2 4 8 2459 4500 4324 +6761 2 2 4 8 1625 5392 4664 +6762 2 2 4 8 1070 2639 3710 +6763 2 2 4 8 92 93 4996 +6764 2 2 4 8 1577 2543 4145 +6765 2 2 4 8 1578 2542 4146 +6766 2 2 4 8 942 2628 3974 +6767 2 2 4 8 1150 2924 3883 +6768 2 2 4 8 1649 3093 5029 +6769 2 2 4 8 516 3892 2847 +6770 2 2 4 8 2847 3892 1387 +6771 2 2 4 8 505 4146 3166 +6772 2 2 4 8 504 4145 3162 +6773 2 2 4 8 1836 5345 3431 +6774 2 2 4 8 1309 4021 2564 +6775 2 2 4 8 760 3643 3958 +6776 2 2 4 8 1754 3958 3643 +6777 2 2 4 8 1043 5014 4812 +6778 2 2 4 8 625 2528 4653 +6779 2 2 4 8 891 2535 4428 +6780 2 2 4 8 892 2536 4430 +6781 2 2 4 8 893 2537 4429 +6782 2 2 4 8 1027 2638 5058 +6783 2 2 4 8 1256 3663 2677 +6784 2 2 4 8 1376 3286 3813 +6785 2 2 4 8 394 395 4208 +6786 2 2 4 8 1269 3778 3390 +6787 2 2 4 8 1305 2549 4186 +6788 2 2 4 8 2024 5374 2592 +6789 2 2 4 8 1228 2698 3616 +6790 2 2 4 8 22 4091 21 +6791 2 2 4 8 691 3255 3542 +6792 2 2 4 8 1537 3542 3255 +6793 2 2 4 8 702 4156 2972 +6794 2 2 4 8 1718 4157 2930 +6795 2 2 4 8 1481 3355 3495 +6796 2 2 4 8 1004 3495 3355 +6797 2 2 4 8 1005 3496 3356 +6798 2 2 4 8 1480 3356 3496 +6799 2 2 4 8 1050 3625 2698 +6800 2 2 4 8 940 2562 5042 +6801 2 2 4 8 351 352 4948 +6802 2 2 4 8 164 165 4947 +6803 2 2 4 8 1241 4596 3899 +6804 2 2 4 8 1243 2793 3467 +6805 2 2 4 8 1646 2942 3832 +6806 2 2 4 8 227 5270 2945 +6807 2 2 4 8 200 2946 5271 +6808 2 2 4 8 1057 5338 3575 +6809 2 2 4 8 1058 3577 5339 +6810 2 2 4 8 334 335 3302 +6811 2 2 4 8 1504 3337 4438 +6812 2 2 4 8 1287 3155 3374 +6813 2 2 4 8 1154 3417 2862 +6814 2 2 4 8 1787 5174 5073 +6815 2 2 4 8 1814 4486 2925 +6816 2 2 4 8 1813 4485 2926 +6817 2 2 4 8 237 238 4940 +6818 2 2 4 8 1070 4675 2898 +6819 2 2 4 8 1176 2581 5204 +6820 2 2 4 8 1484 2851 3408 +6821 2 2 4 8 1055 3408 2851 +6822 2 2 4 8 686 3926 2591 +6823 2 2 4 8 314 4854 4040 +6824 2 2 4 8 1295 3048 3752 +6825 2 2 4 8 1002 2677 3663 +6826 2 2 4 8 668 2601 3880 +6827 2 2 4 8 1263 3264 3002 +6828 2 2 4 8 1901 4509 3725 +6829 2 2 4 8 1900 4508 3724 +6830 2 2 4 8 661 4186 2549 +6831 2 2 4 8 1210 4620 2943 +6832 2 2 4 8 498 2961 4715 +6833 2 2 4 8 1842 5360 3757 +6834 2 2 4 8 1993 4515 3628 +6835 2 2 4 8 1992 4516 3629 +6836 2 2 4 8 770 4154 2564 +6837 2 2 4 8 1126 3087 3641 +6838 2 2 4 8 1486 3641 3087 +6839 2 2 4 8 1761 2703 3881 +6840 2 2 4 8 1808 4615 3674 +6841 2 2 4 8 1069 2983 4354 +6842 2 2 4 8 1346 4025 3229 +6843 2 2 4 8 242 5262 2928 +6844 2 2 4 8 1606 4527 3044 +6845 2 2 4 8 1607 4528 3045 +6846 2 2 4 8 929 3872 2611 +6847 2 2 4 8 1284 4797 2583 +6848 2 2 4 8 746 3457 3924 +6849 2 2 4 8 1652 3924 3457 +6850 2 2 4 8 2345 4980 3700 +6851 2 2 4 8 62 2866 5163 +6852 2 2 4 8 283 2868 5162 +6853 2 2 4 8 260 5161 2867 +6854 2 2 4 8 1067 4923 3350 +6855 2 2 4 8 1309 2564 4154 +6856 2 2 4 8 93 3004 4996 +6857 2 2 4 8 1200 2546 4309 +6858 2 2 4 8 2049 2927 4618 +6859 2 2 4 8 700 4364 2971 +6860 2 2 4 8 1510 4480 3888 +6861 2 2 4 8 1180 4963 2565 +6862 2 2 4 8 2039 3312 5361 +6863 2 2 4 8 1681 3982 3755 +6864 2 2 4 8 1368 3022 3639 +6865 2 2 4 8 714 3639 3022 +6866 2 2 4 8 722 2585 4018 +6867 2 2 4 8 655 2662 4553 +6868 2 2 4 8 1252 2679 4193 +6869 2 2 4 8 1536 2973 3310 +6870 2 2 4 8 76 4798 75 +6871 2 2 4 8 1022 2678 3690 +6872 2 2 4 8 956 2591 5354 +6873 2 2 4 8 1920 4992 3828 +6874 2 2 4 8 1803 2796 3497 +6875 2 2 4 8 490 5410 2666 +6876 2 2 4 8 1014 4150 2571 +6877 2 2 4 8 1323 2907 3370 +6878 2 2 4 8 109 2970 4690 +6879 2 2 4 8 728 4087 5189 +6880 2 2 4 8 242 243 5262 +6881 2 2 4 8 621 2546 4460 +6882 2 2 4 8 1022 4803 2557 +6883 2 2 4 8 1621 2787 3662 +6884 2 2 4 8 597 2581 5116 +6885 2 2 4 8 1882 2814 3554 +6886 2 2 4 8 1881 3553 2813 +6887 2 2 4 8 1883 3555 2815 +6888 2 2 4 8 1014 2571 4952 +6889 2 2 4 8 729 5202 3724 +6890 2 2 4 8 190 191 3338 +6891 2 2 4 8 85 4147 2600 +6892 2 2 4 8 1269 3783 3778 +6893 2 2 4 8 1724 3778 3783 +6894 2 2 4 8 1998 5313 4053 +6895 2 2 4 8 701 4611 2963 +6896 2 2 4 8 1812 3551 4549 +6897 2 2 4 8 1811 3552 4548 +6898 2 2 4 8 948 4212 2989 +6899 2 2 4 8 1978 2989 4212 +6900 2 2 4 8 947 4211 2990 +6901 2 2 4 8 1976 2990 4211 +6902 2 2 4 8 1027 2550 4636 +6903 2 2 4 8 963 2612 3907 +6904 2 2 4 8 317 3711 3293 +6905 2 2 4 8 1252 3034 3564 +6906 2 2 4 8 1397 3927 2860 +6907 2 2 4 8 502 2860 3927 +6908 2 2 4 8 1448 2553 5017 +6909 2 2 4 8 22 23 3343 +6910 2 2 4 8 1657 3368 5280 +6911 2 2 4 8 1656 3367 5281 +6912 2 2 4 8 478 3556 2778 +6913 2 2 4 8 1065 2661 4871 +6914 2 2 4 8 1268 3781 3777 +6915 2 2 4 8 1723 3777 3781 +6916 2 2 4 8 245 246 3346 +6917 2 2 4 8 252 253 3347 +6918 2 2 4 8 729 4363 5202 +6919 2 2 4 8 1590 5188 5043 +6920 2 2 4 8 1592 5187 5044 +6921 2 2 4 8 1012 2643 3813 +6922 2 2 4 8 1177 2569 4233 +6923 2 2 4 8 924 2580 4115 +6924 2 2 4 8 1050 4443 2729 +6925 2 2 4 8 646 2739 4039 +6926 2 2 4 8 1704 4271 3400 +6927 2 2 4 8 1706 3399 4270 +6928 2 2 4 8 1705 3398 4269 +6929 2 2 4 8 620 4982 3030 +6930 2 2 4 8 509 3581 2769 +6931 2 2 4 8 514 3582 2770 +6932 2 2 4 8 1217 2771 3583 +6933 2 2 4 8 231 232 4098 +6934 2 2 4 8 919 4466 2875 +6935 2 2 4 8 579 4232 2588 +6936 2 2 4 8 1388 3688 3339 +6937 2 2 4 8 1389 3340 3687 +6938 2 2 4 8 1588 3988 4084 +6939 2 2 4 8 1603 2974 3522 +6940 2 2 4 8 1600 2975 3521 +6941 2 2 4 8 1261 3856 2686 +6942 2 2 4 8 1154 2593 4019 +6943 2 2 4 8 1544 3769 2663 +6944 2 2 4 8 1625 3916 5392 +6945 2 2 4 8 1736 3980 3630 +6946 2 2 4 8 1375 3630 3980 +6947 2 2 4 8 1735 3981 3631 +6948 2 2 4 8 1374 3631 3981 +6949 2 2 4 8 662 2921 4319 +6950 2 2 4 8 667 2639 4045 +6951 2 2 4 8 499 2772 4059 +6952 2 2 4 8 501 2773 4060 +6953 2 2 4 8 1492 4323 3233 +6954 2 2 4 8 601 5312 2566 +6955 2 2 4 8 752 4987 2573 +6956 2 2 4 8 753 2574 4988 +6957 2 2 4 8 1564 4755 2757 +6958 2 2 4 8 1096 2757 4755 +6959 2 2 4 8 1563 4756 2758 +6960 2 2 4 8 1097 2758 4756 +6961 2 2 4 8 483 4650 2558 +6962 2 2 4 8 2109 4393 4976 +6963 2 2 4 8 374 375 3358 +6964 2 2 4 8 153 154 3359 +6965 2 2 4 8 681 3703 2699 +6966 2 2 4 8 1611 2749 5241 +6967 2 2 4 8 1331 3818 2647 +6968 2 2 4 8 1332 3817 2648 +6969 2 2 4 8 1134 4468 2558 +6970 2 2 4 8 1565 2720 3806 +6971 2 2 4 8 327 2765 5240 +6972 2 2 4 8 1694 3598 3909 +6973 2 2 4 8 1333 3909 3598 +6974 2 2 4 8 746 4550 3404 +6975 2 2 4 8 790 3164 5086 +6976 2 2 4 8 791 3167 5085 +6977 2 2 4 8 1841 3726 2967 +6978 2 2 4 8 1248 3433 2873 +6979 2 2 4 8 728 5189 3725 +6980 2 2 4 8 969 2566 4370 +6981 2 2 4 8 909 3962 2622 +6982 2 2 4 8 1290 2622 3962 +6983 2 2 4 8 1017 4913 2996 +6984 2 2 4 8 30 3592 29 +6985 2 2 4 8 640 2951 4216 +6986 2 2 4 8 727 4030 2597 +6987 2 2 4 8 345 346 5015 +6988 2 2 4 8 1812 2794 3551 +6989 2 2 4 8 2795 3552 1811 +6990 2 2 4 8 1515 3986 3183 +6991 2 2 4 8 1514 3987 3182 +6992 2 2 4 8 1682 4956 5307 +6993 2 2 4 8 1002 3761 2677 +6994 2 2 4 8 758 2976 3357 +6995 2 2 4 8 1013 2581 4202 +6996 2 2 4 8 1353 4061 2783 +6997 2 2 4 8 415 416 5324 +6998 2 2 4 8 1022 4614 2678 +6999 2 2 4 8 1698 5144 2592 +7000 2 2 4 8 253 254 4813 +7001 2 2 4 8 197 198 3602 +7002 2 2 4 8 475 4397 2572 +7003 2 2 4 8 1268 3777 3609 +7004 2 2 4 8 2668 3059 4741 +7005 2 2 4 8 2667 3058 4740 +7006 2 2 4 8 2342 5028 3500 +7007 2 2 4 8 2270 3683 5003 +7008 2 2 4 8 1174 3652 2852 +7009 2 2 4 8 852 4133 5090 +7010 2 2 4 8 853 4136 5091 +7011 2 2 4 8 1002 4792 2576 +7012 2 2 4 8 692 2964 4097 +7013 2 2 4 8 1548 4653 4692 +7014 2 2 4 8 1591 3169 4517 +7015 2 2 4 8 1427 4376 3671 +7016 2 2 4 8 1404 3705 4307 +7017 2 2 4 8 90 2638 5171 +7018 2 2 4 8 471 3978 2622 +7019 2 2 4 8 909 2622 3979 +7020 2 2 4 8 1332 2648 4249 +7021 2 2 4 8 1701 2844 4076 +7022 2 2 4 8 1646 3832 3576 +7023 2 2 4 8 569 3576 3832 +7024 2 2 4 8 28 29 4787 +7025 2 2 4 8 396 4921 3014 +7026 2 2 4 8 987 3665 3227 +7027 2 2 4 8 1498 3227 3665 +7028 2 2 4 8 315 2676 4854 +7029 2 2 4 8 1431 4788 3895 +7030 2 2 4 8 1094 4776 4584 +7031 2 2 4 8 4225 3278 4815 +7032 2 2 4 8 1946 5076 2965 +7033 2 2 4 8 1746 4114 4536 +7034 2 2 4 8 1747 4113 4535 +7035 2 2 4 8 2017 3899 4596 +7036 2 2 4 8 588 4247 2587 +7037 2 2 4 8 1569 3689 2736 +7038 2 2 4 8 703 4172 3259 +7039 2 2 4 8 1572 4895 2725 +7040 2 2 4 8 945 2725 4895 +7041 2 2 4 8 511 4005 2846 +7042 2 2 4 8 1806 3678 4601 +7043 2 2 4 8 878 3559 5224 +7044 2 2 4 8 2207 5224 3559 +7045 2 2 4 8 1485 5070 4747 +7046 2 2 4 8 2082 4363 3314 +7047 2 2 4 8 1900 3738 4951 +7048 2 2 4 8 1901 3737 4950 +7049 2 2 4 8 4173 4716 1565 +7050 2 2 4 8 315 4604 2676 +7051 2 2 4 8 1488 4970 3841 +7052 2 2 4 8 1491 4969 3839 +7053 2 2 4 8 992 2583 4797 +7054 2 2 4 8 1223 3472 3219 +7055 2 2 4 8 1674 2608 5252 +7056 2 2 4 8 1485 2947 3417 +7057 2 2 4 8 1033 2582 4685 +7058 2 2 4 8 1435 4685 2582 +7059 2 2 4 8 1460 4086 2909 +7060 2 2 4 8 732 2909 4086 +7061 2 2 4 8 1294 4292 3542 +7062 2 2 4 8 1258 3974 2628 +7063 2 2 4 8 1253 2580 4630 +7064 2 2 4 8 663 3719 2729 +7065 2 2 4 8 1227 3605 3604 +7066 2 2 4 8 1834 3604 3605 +7067 2 2 4 8 462 4833 3951 +7068 2 2 4 8 463 4834 3950 +7069 2 2 4 8 1781 3404 4550 +7070 2 2 4 8 1044 2586 5011 +7071 2 2 4 8 671 3250 4339 +7072 2 2 4 8 672 3251 4340 +7073 2 2 4 8 1861 3202 5288 +7074 2 2 4 8 569 5131 2630 +7075 2 2 4 8 1152 3117 5251 +7076 2 2 4 8 1911 5251 3117 +7077 2 2 4 8 869 4104 5255 +7078 2 2 4 8 1595 4279 4865 +7079 2 2 4 8 926 4847 3258 +7080 2 2 4 8 112 113 4459 +7081 2 2 4 8 124 4458 123 +7082 2 2 4 8 134 135 4457 +7083 2 2 4 8 179 180 4456 +7084 2 2 4 8 292 293 4455 +7085 2 2 4 8 303 304 4454 +7086 2 2 4 8 1761 4807 3103 +7087 2 2 4 8 1200 5001 4460 +7088 2 2 4 8 254 255 3446 +7089 2 2 4 8 1720 3569 5323 +7090 2 2 4 8 1686 5173 3548 +7091 2 2 4 8 521 4794 3001 +7092 2 2 4 8 507 5383 3274 +7093 2 2 4 8 1400 4848 2589 +7094 2 2 4 8 518 5110 3608 +7095 2 2 4 8 1806 4165 3678 +7096 2 2 4 8 1396 3678 4165 +7097 2 2 4 8 628 2609 5184 +7098 2 2 4 8 1080 4493 3147 +7099 2 2 4 8 1475 5302 4565 +7100 2 2 4 8 1786 3329 4006 +7101 2 2 4 8 1398 4006 3329 +7102 2 2 4 8 1808 3674 4171 +7103 2 2 4 8 1401 4171 3674 +7104 2 2 4 8 2831 4869 2024 +7105 2 2 4 8 1153 2911 4407 +7106 2 2 4 8 719 3489 2979 +7107 2 2 4 8 1286 2979 3489 +7108 2 2 4 8 2144 3608 5110 +7109 2 2 4 8 1299 3675 3943 +7110 2 2 4 8 1800 3830 2724 +7111 2 2 4 8 1620 5212 2670 +7112 2 2 4 8 926 2670 5212 +7113 2 2 4 8 1561 2981 4790 +7114 2 2 4 8 445 2589 4848 +7115 2 2 4 8 1861 5308 3202 +7116 2 2 4 8 738 4927 2663 +7117 2 2 4 8 1544 2663 4927 +7118 2 2 4 8 1266 2777 3755 +7119 2 2 4 8 2031 3015 4584 +7120 2 2 4 8 1847 4874 3227 +7121 2 2 4 8 987 3227 4874 +7122 2 2 4 8 513 2686 3856 +7123 2 2 4 8 1087 2732 5320 +7124 2 2 4 8 1555 4728 5064 +7125 2 2 4 8 1684 5009 3898 +7126 2 2 4 8 1655 3331 3263 +7127 2 2 4 8 1549 4152 3007 +7128 2 2 4 8 548 3007 4152 +7129 2 2 4 8 1815 3705 4626 +7130 2 2 4 8 666 3776 2730 +7131 2 2 4 8 4177 4675 1344 +7132 2 2 4 8 1304 3625 3719 +7133 2 2 4 8 38 39 3445 +7134 2 2 4 8 1553 3998 4236 +7135 2 2 4 8 1568 4157 4586 +7136 2 2 4 8 2130 3452 5276 +7137 2 2 4 8 1262 5276 3452 +7138 2 2 4 8 1815 4307 3705 +7139 2 2 4 8 262 4213 3252 +7140 2 2 4 8 281 3253 4214 +7141 2 2 4 8 60 3254 4215 +7142 2 2 4 8 2433 3402 4934 +7143 2 2 4 8 441 3205 3875 +7144 2 2 4 8 1829 4375 2964 +7145 2 2 4 8 243 244 3505 +7146 2 2 4 8 1833 3671 4376 +7147 2 2 4 8 1630 2697 5267 +7148 2 2 4 8 1112 5267 2697 +7149 2 2 4 8 1453 3200 4352 +7150 2 2 4 8 1454 4353 3201 +7151 2 2 4 8 1782 3571 5286 +7152 2 2 4 8 1253 2865 4284 +7153 2 2 4 8 3030 4537 2382 +7154 2 2 4 8 1432 2688 3945 +7155 2 2 4 8 55 3945 2688 +7156 2 2 4 8 1433 2689 3946 +7157 2 2 4 8 276 3946 2689 +7158 2 2 4 8 683 3514 2887 +7159 2 2 4 8 1136 2922 3843 +7160 2 2 4 8 1364 3843 2922 +7161 2 2 4 8 692 4097 2632 +7162 2 2 4 8 1506 4828 2598 +7163 2 2 4 8 1505 2599 4827 +7164 2 2 4 8 2385 2897 4088 +7165 2 2 4 8 2384 4087 2896 +7166 2 2 4 8 698 4109 3634 +7167 2 2 4 8 1763 3634 4109 +7168 2 2 4 8 1868 3692 4302 +7169 2 2 4 8 1517 4302 3692 +7170 2 2 4 8 1018 2995 5050 +7171 2 2 4 8 1545 4218 3333 +7172 2 2 4 8 386 3318 4295 +7173 2 2 4 8 146 4294 3317 +7174 2 2 4 8 367 4293 3316 +7175 2 2 4 8 686 2806 3926 +7176 2 2 4 8 1339 3926 2806 +7177 2 2 4 8 1079 2624 5174 +7178 2 2 4 8 471 4329 2781 +7179 2 2 4 8 2123 5257 3291 +7180 2 2 4 8 566 3291 5257 +7181 2 2 4 8 1069 4665 3020 +7182 2 2 4 8 1706 5291 5034 +7183 2 2 4 8 965 3996 2655 +7184 2 2 4 8 966 3997 2657 +7185 2 2 4 8 1568 4047 4714 +7186 2 2 4 8 748 3037 3972 +7187 2 2 4 8 1477 3972 3037 +7188 2 2 4 8 248 4749 2661 +7189 2 2 4 8 1516 4966 4314 +7190 2 2 4 8 53 3478 52 +7191 2 2 4 8 273 274 3479 +7192 2 2 4 8 458 4371 3228 +7193 2 2 4 8 1678 3228 4371 +7194 2 2 4 8 782 4568 3793 +7195 2 2 4 8 680 2764 4316 +7196 2 2 4 8 981 4699 2658 +7197 2 2 4 8 1634 5247 3152 +7198 2 2 4 8 1409 3901 2718 +7199 2 2 4 8 151 2718 3901 +7200 2 2 4 8 1410 3902 2719 +7201 2 2 4 8 372 2719 3902 +7202 2 2 4 8 1017 3632 2836 +7203 2 2 4 8 1018 2835 3633 +7204 2 2 4 8 298 299 3483 +7205 2 2 4 8 309 310 3484 +7206 2 2 4 8 173 174 3485 +7207 2 2 4 8 128 129 3486 +7208 2 2 4 8 118 3487 117 +7209 2 2 4 8 1189 3290 3963 +7210 2 2 4 8 1277 4510 2674 +7211 2 2 4 8 1596 4971 4511 +7212 2 2 4 8 1094 4584 2606 +7213 2 2 4 8 267 2810 3887 +7214 2 2 4 8 46 2809 3886 +7215 2 2 4 8 1335 3886 2809 +7216 2 2 4 8 1334 3887 2810 +7217 2 2 4 8 102 5290 2637 +7218 2 2 4 8 1127 2605 4659 +7219 2 2 4 8 1587 4982 2619 +7220 2 2 4 8 1309 3853 3238 +7221 2 2 4 8 732 4013 2909 +7222 2 2 4 8 1412 2909 4013 +7223 2 2 4 8 1331 4721 3818 +7224 2 2 4 8 1332 4722 3817 +7225 2 2 4 8 681 2699 3911 +7226 2 2 4 8 1896 3850 5381 +7227 2 2 4 8 1236 3864 5340 +7228 2 2 4 8 1237 3865 5341 +7229 2 2 4 8 926 5212 2629 +7230 2 2 4 8 945 4895 2617 +7231 2 2 4 8 712 4435 2611 +7232 2 2 4 8 711 3755 2777 +7233 2 2 4 8 523 2694 3932 +7234 2 2 4 8 2106 4230 2748 +7235 2 2 4 8 668 3880 3935 +7236 2 2 4 8 1423 2609 5375 +7237 2 2 4 8 702 3220 4156 +7238 2 2 4 8 1654 2932 4892 +7239 2 2 4 8 523 4892 2932 +7240 2 2 4 8 1072 4476 2636 +7241 2 2 4 8 1408 2636 4476 +7242 2 2 4 8 1474 3884 4359 +7243 2 2 4 8 1457 5005 2610 +7244 2 2 4 8 1231 3600 3062 +7245 2 2 4 8 1121 5295 3540 +7246 2 2 4 8 3200 5378 4352 +7247 2 2 4 8 697 2746 4521 +7248 2 2 4 8 699 2747 4522 +7249 2 2 4 8 2451 4314 4966 +7250 2 2 4 8 1432 3109 3746 +7251 2 2 4 8 1601 3746 3109 +7252 2 2 4 8 1433 3110 3747 +7253 2 2 4 8 1602 3747 3110 +7254 2 2 4 8 1397 3941 3927 +7255 2 2 4 8 3927 3941 1809 +7256 2 2 4 8 235 3090 5147 +7257 2 2 4 8 1551 2765 4816 +7258 2 2 4 8 1023 4816 2765 +7259 2 2 4 8 1811 4548 5099 +7260 2 2 4 8 2060 5278 3869 +7261 2 2 4 8 597 5116 3547 +7262 2 2 4 8 2094 3547 5116 +7263 2 2 4 8 727 2858 3980 +7264 2 2 4 8 1375 3980 2858 +7265 2 2 4 8 729 2859 3981 +7266 2 2 4 8 1374 3981 2859 +7267 2 2 4 8 866 3664 2944 +7268 2 2 4 8 1682 2944 3664 +7269 2 2 4 8 759 5276 3199 +7270 2 2 4 8 2521 5022 3709 +7271 2 2 4 8 1409 3637 3044 +7272 2 2 4 8 1606 3044 3637 +7273 2 2 4 8 1410 3638 3045 +7274 2 2 4 8 1607 3045 3638 +7275 2 2 4 8 1590 2684 5188 +7276 2 2 4 8 725 5188 2684 +7277 2 2 4 8 723 5187 2685 +7278 2 2 4 8 1592 2685 5187 +7279 2 2 4 8 1134 4410 2882 +7280 2 2 4 8 1059 3952 2889 +7281 2 2 4 8 1382 2889 3952 +7282 2 2 4 8 801 5406 4140 +7283 2 2 4 8 845 2619 4770 +7284 2 2 4 8 839 3084 3420 +7285 2 2 4 8 1303 3420 3084 +7286 2 2 4 8 1755 3310 5013 +7287 2 2 4 8 1288 3019 3612 +7288 2 2 4 8 1236 2817 3864 +7289 2 2 4 8 1237 2818 3865 +7290 2 2 4 8 400 401 3739 +7291 2 2 4 8 1537 4972 4877 +7292 2 2 4 8 1368 4682 2626 +7293 2 2 4 8 1057 3933 2883 +7294 2 2 4 8 1058 2884 3934 +7295 2 2 4 8 1371 2883 3933 +7296 2 2 4 8 1370 3934 2884 +7297 2 2 4 8 1360 2640 4215 +7298 2 2 4 8 1362 2642 4214 +7299 2 2 4 8 1361 4213 2641 +7300 2 2 4 8 1327 3922 2830 +7301 2 2 4 8 1328 2829 3923 +7302 2 2 4 8 1190 2937 3537 +7303 2 2 4 8 1191 2936 3536 +7304 2 2 4 8 1195 3539 2938 +7305 2 2 4 8 1194 3538 2939 +7306 2 2 4 8 1212 3562 2982 +7307 2 2 4 8 83 5190 3121 +7308 2 2 4 8 49 5191 3122 +7309 2 2 4 8 270 5192 3123 +7310 2 2 4 8 82 3121 5094 +7311 2 2 4 8 48 3122 5092 +7312 2 2 4 8 269 3123 5093 +7313 2 2 4 8 1214 3189 4835 +7314 2 2 4 8 1215 3190 4836 +7315 2 2 4 8 1217 3192 4837 +7316 2 2 4 8 1373 2767 3885 +7317 2 2 4 8 381 3885 2767 +7318 2 2 4 8 743 4992 2736 +7319 2 2 4 8 1569 2736 4992 +7320 2 2 4 8 69 3131 4713 +7321 2 2 4 8 1277 3595 3176 +7322 2 2 4 8 111 5395 3831 +7323 2 2 4 8 1258 5326 2882 +7324 2 2 4 8 1658 5047 2633 +7325 2 2 4 8 1373 3013 3524 +7326 2 2 4 8 1605 3524 3013 +7327 2 2 4 8 1628 2625 4745 +7328 2 2 4 8 568 2626 4682 +7329 2 2 4 8 1631 4746 3381 +7330 2 2 4 8 2338 5340 3864 +7331 2 2 4 8 2339 5341 3865 +7332 2 2 4 8 536 4398 3916 +7333 2 2 4 8 1028 5376 3016 +7334 2 2 4 8 1029 3018 5377 +7335 2 2 4 8 759 4453 5276 +7336 2 2 4 8 1383 3105 4235 +7337 2 2 4 8 1601 3109 4591 +7338 2 2 4 8 1602 3110 4593 +7339 2 2 4 8 584 3976 5069 +7340 2 2 4 8 1335 3521 2975 +7341 2 2 4 8 1334 3522 2974 +7342 2 2 4 8 652 3617 3402 +7343 2 2 4 8 1830 3402 3617 +7344 2 2 4 8 1521 4390 2901 +7345 2 2 4 8 1138 2901 4390 +7346 2 2 4 8 1520 4389 2902 +7347 2 2 4 8 1140 2902 4389 +7348 2 2 4 8 1229 3615 3061 +7349 2 2 4 8 1148 3375 3266 +7350 2 2 4 8 2004 3266 3375 +7351 2 2 4 8 2005 3267 3376 +7352 2 2 4 8 1149 3376 3267 +7353 2 2 4 8 2825 4333 814 +7354 2 2 4 8 2825 1469 4333 +7355 2 2 4 8 815 2826 4334 +7356 2 2 4 8 1468 4334 2826 +7357 2 2 4 8 1466 4337 2828 +7358 2 2 4 8 823 2828 4337 +7359 2 2 4 8 1255 5140 2856 +7360 2 2 4 8 1541 4658 4056 +7361 2 2 4 8 1377 2649 4295 +7362 2 2 4 8 1379 4294 2650 +7363 2 2 4 8 1378 4293 2651 +7364 2 2 4 8 1089 2713 4541 +7365 2 2 4 8 1443 4541 2713 +7366 2 2 4 8 1442 4542 2712 +7367 2 2 4 8 1087 2712 4542 +7368 2 2 4 8 1086 4543 2714 +7369 2 2 4 8 1444 2714 4543 +7370 2 2 4 8 1445 2715 4544 +7371 2 2 4 8 1085 4544 2715 +7372 2 2 4 8 1446 2716 4545 +7373 2 2 4 8 1084 4545 2716 +7374 2 2 4 8 1447 2717 4546 +7375 2 2 4 8 1083 4546 2717 +7376 2 2 4 8 1548 4692 2627 +7377 2 2 4 8 1286 3489 3501 +7378 2 2 4 8 1478 3501 3489 +7379 2 2 4 8 2005 5328 3267 +7380 2 2 4 8 785 3267 5328 +7381 2 2 4 8 786 3266 5329 +7382 2 2 4 8 2004 5329 3266 +7383 2 2 4 8 358 4729 3150 +7384 2 2 4 8 171 4730 3149 +7385 2 2 4 8 1048 4606 3497 +7386 2 2 4 8 961 4083 2740 +7387 2 2 4 8 2740 4083 1337 +7388 2 2 4 8 1119 4108 3194 +7389 2 2 4 8 1699 3194 4108 +7390 2 2 4 8 1371 3933 3492 +7391 2 2 4 8 524 2992 4753 +7392 2 2 4 8 496 2842 3708 +7393 2 2 4 8 1450 2775 5411 +7394 2 2 4 8 529 3866 5047 +7395 2 2 4 8 1482 2891 4285 +7396 2 2 4 8 1175 4285 2891 +7397 2 2 4 8 1294 3403 3849 +7398 2 2 4 8 2271 3717 3718 +7399 2 2 4 8 1240 3718 3717 +7400 2 2 4 8 112 4459 3100 +7401 2 2 4 8 123 4458 3099 +7402 2 2 4 8 134 4457 3098 +7403 2 2 4 8 179 4456 3097 +7404 2 2 4 8 293 3095 4455 +7405 2 2 4 8 304 3096 4454 +7406 2 2 4 8 1244 5288 3202 +7407 2 2 4 8 2102 4289 4811 +7408 2 2 4 8 1495 2643 4859 +7409 2 2 4 8 561 4859 2643 +7410 2 2 4 8 1708 3560 4725 +7411 2 2 4 8 1709 4726 3561 +7412 2 2 4 8 1114 2799 4143 +7413 2 2 4 8 1641 4047 3454 +7414 2 2 4 8 739 3454 4047 +7415 2 2 4 8 1256 2666 5410 +7416 2 2 4 8 326 327 5240 +7417 2 2 4 8 1932 3661 5285 +7418 2 2 4 8 1976 3841 4970 +7419 2 2 4 8 1978 3839 4969 +7420 2 2 4 8 962 3239 5237 +7421 2 2 4 8 738 2663 4239 +7422 2 2 4 8 1424 3995 4698 +7423 2 2 4 8 1572 5074 4861 +7424 2 2 4 8 271 3249 5192 +7425 2 2 4 8 50 3248 5191 +7426 2 2 4 8 3326 4633 2144 +7427 2 2 4 8 1566 4633 3326 +7428 2 2 4 8 1260 5018 3078 +7429 2 2 4 8 1744 4577 2963 +7430 2 2 4 8 701 2963 4577 +7431 2 2 4 8 1287 2738 4886 +7432 2 2 4 8 1212 4967 3562 +7433 2 2 4 8 1012 4480 2643 +7434 2 2 4 8 425 3588 424 +7435 2 2 4 8 207 208 3589 +7436 2 2 4 8 219 220 3590 +7437 2 2 4 8 437 438 3591 +7438 2 2 4 8 1333 2850 3909 +7439 2 2 4 8 722 3909 2850 +7440 2 2 4 8 517 2884 4324 +7441 2 2 4 8 520 4325 2883 +7442 2 2 4 8 740 3840 4740 +7443 2 2 4 8 742 3841 4741 +7444 2 2 4 8 1398 4402 2675 +7445 2 2 4 8 1408 4316 2764 +7446 2 2 4 8 1669 4811 3118 +7447 2 2 4 8 718 3476 4994 +7448 2 2 4 8 700 3360 4364 +7449 2 2 4 8 1015 5346 2754 +7450 2 2 4 8 988 5234 3094 +7451 2 2 4 8 1829 3094 5234 +7452 2 2 4 8 1337 2806 5059 +7453 2 2 4 8 1245 3462 4838 +7454 2 2 4 8 632 4085 2704 +7455 2 2 4 8 1382 3952 3488 +7456 2 2 4 8 1069 4354 2653 +7457 2 2 4 8 934 3720 3800 +7458 2 2 4 8 1645 3800 3720 +7459 2 2 4 8 935 3722 3799 +7460 2 2 4 8 1644 3799 3722 +7461 2 2 4 8 87 88 3659 +7462 2 2 4 8 2478 5243 4851 +7463 2 2 4 8 1021 5114 3089 +7464 2 2 4 8 1785 3089 5114 +7465 2 2 4 8 1156 2708 4529 +7466 2 2 4 8 1430 4529 2708 +7467 2 2 4 8 721 4193 2679 +7468 2 2 4 8 695 2775 4451 +7469 2 2 4 8 1450 4451 2775 +7470 2 2 4 8 216 217 3818 +7471 2 2 4 8 434 435 3817 +7472 2 2 4 8 1202 3263 3331 +7473 2 2 4 8 1296 3842 3824 +7474 2 2 4 8 1699 3824 3842 +7475 2 2 4 8 1894 5192 3249 +7476 2 2 4 8 1892 5191 3248 +7477 2 2 4 8 757 5277 4786 +7478 2 2 4 8 414 3202 5308 +7479 2 2 4 8 715 4585 3960 +7480 2 2 4 8 2096 3960 4585 +7481 2 2 4 8 1803 3497 4606 +7482 2 2 4 8 733 4078 2720 +7483 2 2 4 8 433 434 4722 +7484 2 2 4 8 215 216 4721 +7485 2 2 4 8 1500 4761 4052 +7486 2 2 4 8 2274 4052 4761 +7487 2 2 4 8 1513 4888 2654 +7488 2 2 4 8 1345 3814 4787 +7489 2 2 4 8 155 3217 5363 +7490 2 2 4 8 376 3216 5362 +7491 2 2 4 8 1285 3181 3739 +7492 2 2 4 8 717 2760 4564 +7493 2 2 4 8 1474 4564 2760 +7494 2 2 4 8 1475 4565 2761 +7495 2 2 4 8 716 2761 4565 +7496 2 2 4 8 1967 5363 3217 +7497 2 2 4 8 1966 5362 3216 +7498 2 2 4 8 1697 3186 4062 +7499 2 2 4 8 1120 4062 3186 +7500 2 2 4 8 827 3718 4954 +7501 2 2 4 8 1040 2706 4149 +7502 2 2 4 8 1041 2707 4148 +7503 2 2 4 8 716 4565 3954 +7504 2 2 4 8 2080 3954 4565 +7505 2 2 4 8 717 4564 3955 +7506 2 2 4 8 2079 3955 4564 +7507 2 2 4 8 714 2929 3639 +7508 2 2 4 8 1489 4607 3840 +7509 2 2 4 8 16 2935 5080 +7510 2 2 4 8 1986 3562 4967 +7511 2 2 4 8 12 3019 4254 +7512 2 2 4 8 1512 4254 3019 +7513 2 2 4 8 1280 2781 5282 +7514 2 2 4 8 1093 2664 5139 +7515 2 2 4 8 551 3762 5314 +7516 2 2 4 8 2315 5314 3762 +7517 2 2 4 8 1471 4207 2693 +7518 2 2 4 8 1417 4161 3353 +7519 2 2 4 8 993 4760 2652 +7520 2 2 4 8 1251 4039 2739 +7521 2 2 4 8 156 5266 3217 +7522 2 2 4 8 1914 3216 5265 +7523 2 2 4 8 377 5265 3216 +7524 2 2 4 8 1915 3217 5266 +7525 2 2 4 8 1265 2951 4394 +7526 2 2 4 8 1796 4469 3523 +7527 2 2 4 8 1581 3523 4469 +7528 2 2 4 8 1716 3805 3254 +7529 2 2 4 8 1360 3254 3805 +7530 2 2 4 8 1714 3252 3803 +7531 2 2 4 8 1362 3253 3804 +7532 2 2 4 8 1715 3804 3253 +7533 2 2 4 8 1361 3803 3252 +7534 2 2 4 8 1088 5241 2749 +7535 2 2 4 8 1143 2869 5010 +7536 2 2 4 8 1629 5010 2869 +7537 2 2 4 8 1214 4835 3412 +7538 2 2 4 8 1215 4836 3413 +7539 2 2 4 8 1217 4837 3414 +7540 2 2 4 8 820 3922 3618 +7541 2 2 4 8 818 3619 3923 +7542 2 2 4 8 661 2725 4153 +7543 2 2 4 8 492 3707 2893 +7544 2 2 4 8 680 2799 3889 +7545 2 2 4 8 2090 4708 3879 +7546 2 2 4 8 1522 3879 4708 +7547 2 2 4 8 1526 4711 3878 +7548 2 2 4 8 2093 3878 4711 +7549 2 2 4 8 1570 5168 4446 +7550 2 2 4 8 1303 2750 5404 +7551 2 2 4 8 829 5071 2665 +7552 2 2 4 8 378 3230 5265 +7553 2 2 4 8 157 3231 5266 +7554 2 2 4 8 1525 4672 4020 +7555 2 2 4 8 2178 4020 4672 +7556 2 2 4 8 2496 4587 5084 +7557 2 2 4 8 1571 4644 4401 +7558 2 2 4 8 1374 2766 4347 +7559 2 2 4 8 1030 3017 5365 +7560 2 2 4 8 669 3023 4134 +7561 2 2 4 8 670 3024 4135 +7562 2 2 4 8 32 3645 31 +7563 2 2 4 8 158 5087 3231 +7564 2 2 4 8 379 5088 3230 +7565 2 2 4 8 1558 3371 5084 +7566 2 2 4 8 964 2673 4412 +7567 2 2 4 8 1793 4764 4141 +7568 2 2 4 8 1245 2872 4313 +7569 2 2 4 8 1505 2832 4819 +7570 2 2 4 8 574 2667 5123 +7571 2 2 4 8 1542 5123 2667 +7572 2 2 4 8 715 2776 4585 +7573 2 2 4 8 1476 4585 2776 +7574 2 2 4 8 671 2706 4228 +7575 2 2 4 8 2347 3948 5149 +7576 2 2 4 8 1384 4051 2885 +7577 2 2 4 8 510 2885 4051 +7578 2 2 4 8 2575 4446 5168 +7579 2 2 4 8 1278 4503 2802 +7580 2 2 4 8 834 4782 3585 +7581 2 2 4 8 1958 3585 4782 +7582 2 2 4 8 850 4976 4393 +7583 2 2 4 8 683 2887 4712 +7584 2 2 4 8 87 3659 3005 +7585 2 2 4 8 1074 2895 4802 +7586 2 2 4 8 1876 5394 2696 +7587 2 2 4 8 1711 5418 3779 +7588 2 2 4 8 2363 3779 5418 +7589 2 2 4 8 701 3455 4611 +7590 2 2 4 8 2321 4956 3104 +7591 2 2 4 8 313 4040 2749 +7592 2 2 4 8 679 2674 4510 +7593 2 2 4 8 1571 4938 4644 +7594 2 2 4 8 1105 4341 2687 +7595 2 2 4 8 230 4520 3215 +7596 2 2 4 8 1506 2833 4828 +7597 2 2 4 8 1917 3994 2881 +7598 2 2 4 8 1000 5388 4479 +7599 2 2 4 8 2620 4644 4938 +7600 2 2 4 8 1977 3840 4607 +7601 2 2 4 8 1279 4377 5131 +7602 2 2 4 8 2630 5131 4377 +7603 2 2 4 8 926 4995 2670 +7604 2 2 4 8 1479 3071 3949 +7605 2 2 4 8 1297 3302 3925 +7606 2 2 4 8 1646 3576 4661 +7607 2 2 4 8 1607 2888 5365 +7608 2 2 4 8 2520 5051 3523 +7609 2 2 4 8 233 3836 4719 +7610 2 2 4 8 1024 4806 3037 +7611 2 2 4 8 1370 3525 3934 +7612 2 2 4 8 1860 5281 5415 +7613 2 2 4 8 1859 5280 5414 +7614 2 2 4 8 1163 4619 2722 +7615 2 2 4 8 1441 2722 4619 +7616 2 2 4 8 818 4494 4069 +7617 2 2 4 8 2111 4495 4068 +7618 2 2 4 8 820 4068 4495 +7619 2 2 4 8 2110 4069 4494 +7620 2 2 4 8 1503 4789 4044 +7621 2 2 4 8 1377 3318 3863 +7622 2 2 4 8 1730 3863 3318 +7623 2 2 4 8 3317 1379 3862 +7624 2 2 4 8 3317 3862 1731 +7625 2 2 4 8 1732 3316 3861 +7626 2 2 4 8 1378 3861 3316 +7627 2 2 4 8 1620 2670 4719 +7628 2 2 4 8 899 4191 4312 +7629 2 2 4 8 1347 3703 3055 +7630 2 2 4 8 681 3055 3703 +7631 2 2 4 8 1588 4084 3341 +7632 2 2 4 8 1885 3438 4489 +7633 2 2 4 8 766 4489 3438 +7634 2 2 4 8 767 4490 3437 +7635 2 2 4 8 1886 3437 4490 +7636 2 2 4 8 726 5219 2683 +7637 2 2 4 8 828 4590 3389 +7638 2 2 4 8 1755 3389 4590 +7639 2 2 4 8 677 4099 2748 +7640 2 2 4 8 876 3624 5066 +7641 2 2 4 8 2064 5066 3624 +7642 2 2 4 8 1679 2676 4604 +7643 2 2 4 8 1932 2690 5236 +7644 2 2 4 8 741 3829 4897 +7645 2 2 4 8 640 4216 5051 +7646 2 2 4 8 1434 3640 3608 +7647 2 2 4 8 1797 5296 4863 +7648 2 2 4 8 2045 3701 3700 +7649 2 2 4 8 1244 3700 3701 +7650 2 2 4 8 1259 2678 4614 +7651 2 2 4 8 1498 4851 5243 +7652 2 2 4 8 1414 3877 4260 +7653 2 2 4 8 1875 4260 3877 +7654 2 2 4 8 1157 4609 2709 +7655 2 2 4 8 1429 2709 4609 +7656 2 2 4 8 1158 2710 4610 +7657 2 2 4 8 1428 4610 2710 +7658 2 2 4 8 2222 4044 4789 +7659 2 2 4 8 1058 3934 2814 +7660 2 2 4 8 1057 2813 3933 +7661 2 2 4 8 819 3765 3515 +7662 2 2 4 8 1558 5084 4587 +7663 2 2 4 8 718 4994 3820 +7664 2 2 4 8 1409 3044 3901 +7665 2 2 4 8 150 3901 3044 +7666 2 2 4 8 371 3902 3045 +7667 2 2 4 8 1410 3045 3902 +7668 2 2 4 8 678 2705 5344 +7669 2 2 4 8 1484 3408 3680 +7670 2 2 4 8 1421 3680 3408 +7671 2 2 4 8 1792 4854 2676 +7672 2 2 4 8 1659 3078 4435 +7673 2 2 4 8 1516 3433 3349 +7674 2 2 4 8 1248 3349 3433 +7675 2 2 4 8 1059 2815 3952 +7676 2 2 4 8 1396 4165 2861 +7677 2 2 4 8 500 2861 4165 +7678 2 2 4 8 1692 4272 4864 +7679 2 2 4 8 2426 4864 4272 +7680 2 2 4 8 1432 4539 2688 +7681 2 2 4 8 1433 4540 2689 +7682 2 2 4 8 1238 3750 3168 +7683 2 2 4 8 455 2821 4348 +7684 2 2 4 8 1421 4348 2821 +7685 2 2 4 8 1604 4985 2845 +7686 2 2 4 8 751 2845 4985 +7687 2 2 4 8 1997 4698 3995 +7688 2 2 4 8 1340 4892 3764 +7689 2 2 4 8 513 3450 4287 +7690 2 2 4 8 1171 4411 2704 +7691 2 2 4 8 799 3379 4929 +7692 2 2 4 8 1853 4929 3379 +7693 2 2 4 8 798 3378 4928 +7694 2 2 4 8 1852 4928 3378 +7695 2 2 4 8 813 5200 3731 +7696 2 2 4 8 2193 3731 5200 +7697 2 2 4 8 1426 4625 3691 +7698 2 2 4 8 1929 3691 4625 +7699 2 2 4 8 9 10 5208 +7700 2 2 4 8 1409 2718 4360 +7701 2 2 4 8 1410 2719 4361 +7702 2 2 4 8 1346 2768 4283 +7703 2 2 4 8 1079 3825 2887 +7704 2 2 4 8 2931 3469 4681 +7705 2 2 4 8 1373 3885 3013 +7706 2 2 4 8 382 3013 3885 +7707 2 2 4 8 1487 4481 3829 +7708 2 2 4 8 725 2684 4914 +7709 2 2 4 8 1017 2683 4913 +7710 2 2 4 8 1019 4915 2685 +7711 2 2 4 8 1566 3279 4633 +7712 2 2 4 8 1107 3066 4537 +7713 2 2 4 8 1358 3178 4142 +7714 2 2 4 8 1018 5050 2684 +7715 2 2 4 8 723 2685 5049 +7716 2 2 4 8 1117 3022 3871 +7717 2 2 4 8 1368 3871 3022 +7718 2 2 4 8 521 2771 5130 +7719 2 2 4 8 2451 4966 3780 +7720 2 2 4 8 245 3346 4953 +7721 2 2 4 8 1106 3118 4811 +7722 2 2 4 8 1775 3793 4568 +7723 2 2 4 8 1275 3271 4598 +7724 2 2 4 8 2964 5239 4097 +7725 2 2 4 8 1315 3682 3740 +7726 2 2 4 8 1589 3740 3682 +7727 2 2 4 8 1679 2739 4276 +7728 2 2 4 8 1068 4891 2692 +7729 2 2 4 8 1911 5149 5251 +7730 2 2 4 8 1372 2998 4298 +7731 2 2 4 8 816 4110 4532 +7732 2 2 4 8 4110 2132 4532 +7733 2 2 4 8 824 4111 4533 +7734 2 2 4 8 4111 2131 4533 +7735 2 2 4 8 485 2856 5140 +7736 2 2 4 8 375 5362 3358 +7737 2 2 4 8 154 5363 3359 +7738 2 2 4 8 1223 3195 3472 +7739 2 2 4 8 1333 2808 4008 +7740 2 2 4 8 1335 2809 4010 +7741 2 2 4 8 1334 2810 4009 +7742 2 2 4 8 749 5039 4725 +7743 2 2 4 8 750 4726 5038 +7744 2 2 4 8 792 3936 4496 +7745 2 2 4 8 2020 4496 3936 +7746 2 2 4 8 2183 3772 4301 +7747 2 2 4 8 153 3359 5145 +7748 2 2 4 8 374 3358 5146 +7749 2 2 4 8 3324 3767 5268 +7750 2 2 4 8 1921 3829 4481 +7751 2 2 4 8 1034 2781 4142 +7752 2 2 4 8 1422 2915 3795 +7753 2 2 4 8 1604 2845 3910 +7754 2 2 4 8 1422 3428 3520 +7755 2 2 4 8 1375 2839 4434 +7756 2 2 4 8 1212 4665 4967 +7757 2 2 4 8 2653 4967 4665 +7758 2 2 4 8 743 2736 4343 +7759 2 2 4 8 1920 3828 4415 +7760 2 2 4 8 1490 4415 3828 +7761 2 2 4 8 1517 3870 4566 +7762 2 2 4 8 1500 4052 4241 +7763 2 2 4 8 748 3972 4818 +7764 2 2 4 8 466 5301 3391 +7765 2 2 4 8 1374 4199 2766 +7766 2 2 4 8 1373 4198 2767 +7767 2 2 4 8 3008 5244 3365 +7768 2 2 4 8 968 3377 4450 +7769 2 2 4 8 673 3212 4027 +7770 2 2 4 8 674 3213 4029 +7771 2 2 4 8 1746 3648 4244 +7772 2 2 4 8 697 4244 3648 +7773 2 2 4 8 1747 3649 4242 +7774 2 2 4 8 699 4242 3649 +7775 2 2 4 8 702 3650 4246 +7776 2 2 4 8 1745 4246 3650 +7777 2 2 4 8 1247 2729 4443 +7778 2 2 4 8 1220 3040 3716 +7779 2 2 4 8 314 315 4854 +7780 2 2 4 8 1125 4846 4440 +7781 2 2 4 8 2512 4440 4846 +7782 2 2 4 8 1251 3293 3711 +7783 2 2 4 8 716 4248 2761 +7784 2 2 4 8 80 4523 79 +7785 2 2 4 8 1546 3365 3963 +7786 2 2 4 8 1189 3963 3365 +7787 2 2 4 8 325 326 3921 +7788 2 2 4 8 94 4416 93 +7789 2 2 4 8 856 2998 3772 +7790 2 2 4 8 1913 4688 4407 +7791 2 2 4 8 526 4281 4603 +7792 2 2 4 8 1100 2728 4554 +7793 2 2 4 8 3131 5413 4713 +7794 2 2 4 8 1150 4257 2987 +7795 2 2 4 8 1734 5291 4046 +7796 2 2 4 8 1469 3789 3240 +7797 2 2 4 8 1615 3240 3789 +7798 2 2 4 8 1468 3790 3241 +7799 2 2 4 8 1614 3241 3790 +7800 2 2 4 8 1613 3242 3788 +7801 2 2 4 8 1467 3788 3242 +7802 2 2 4 8 1612 3243 3787 +7803 2 2 4 8 1465 3787 3243 +7804 2 2 4 8 1609 3784 3245 +7805 2 2 4 8 1463 3244 3785 +7806 2 2 4 8 1611 3785 3244 +7807 2 2 4 8 1610 3786 3246 +7808 2 2 4 8 1461 3245 3784 +7809 2 2 4 8 1462 3246 3786 +7810 2 2 4 8 874 4066 4120 +7811 2 2 4 8 1070 3710 4675 +7812 2 2 4 8 2085 4484 4106 +7813 2 2 4 8 949 4106 4484 +7814 2 2 4 8 1523 2956 4513 +7815 2 2 4 8 1193 4513 2956 +7816 2 2 4 8 1524 2957 4514 +7817 2 2 4 8 1192 4514 2957 +7818 2 2 4 8 4238 5247 1634 +7819 2 2 4 8 1720 3498 4786 +7820 2 2 4 8 1389 3687 4234 +7821 2 2 4 8 817 4335 2910 +7822 2 2 4 8 1462 2910 4335 +7823 2 2 4 8 1572 2725 5074 +7824 2 2 4 8 1616 3890 3596 +7825 2 2 4 8 770 3596 3890 +7826 2 2 4 8 754 4894 4015 +7827 2 2 4 8 1602 2996 4913 +7828 2 2 4 8 316 4604 315 +7829 2 2 4 8 120 2955 4384 +7830 2 2 4 8 1522 4384 2955 +7831 2 2 4 8 131 2956 4383 +7832 2 2 4 8 1523 4383 2956 +7833 2 2 4 8 176 2957 4382 +7834 2 2 4 8 1524 4382 2957 +7835 2 2 4 8 1525 2958 4381 +7836 2 2 4 8 1526 2959 4380 +7837 2 2 4 8 307 4380 2959 +7838 2 2 4 8 296 4381 2958 +7839 2 2 4 8 204 2 4882 +7840 2 2 4 8 2 205 4882 +7841 2 2 4 8 1 4885 440 +7842 2 2 4 8 5 422 4884 +7843 2 2 4 8 4 4883 222 +7844 2 2 4 8 4 223 4883 +7845 2 2 4 8 1 6 4885 +7846 2 2 4 8 5 4884 421 +7847 2 2 4 8 1049 3281 5210 +7848 2 2 4 8 572 2731 5235 +7849 2 2 4 8 1567 5235 2731 +7850 2 2 4 8 1035 2778 5006 +7851 2 2 4 8 2778 1545 5006 +7852 2 2 4 8 806 2803 4361 +7853 2 2 4 8 1410 4361 2803 +7854 2 2 4 8 1409 4360 2804 +7855 2 2 4 8 805 2804 4360 +7856 2 2 4 8 735 4612 2732 +7857 2 2 4 8 1503 2983 4387 +7858 2 2 4 8 1069 4387 2983 +7859 2 2 4 8 562 4413 4851 +7860 2 2 4 8 2478 4851 4413 +7861 2 2 4 8 1774 4398 3247 +7862 2 2 4 8 1456 3247 4398 +7863 2 2 4 8 2197 4603 4281 +7864 2 2 4 8 1659 3451 3519 +7865 2 2 4 8 653 3519 3451 +7866 2 2 4 8 654 2950 4488 +7867 2 2 4 8 1333 4523 2808 +7868 2 2 4 8 27 28 3814 +7869 2 2 4 8 1412 4013 4081 +7870 2 2 4 8 1837 4081 4013 +7871 2 2 4 8 1413 4014 4082 +7872 2 2 4 8 1838 4082 4014 +7873 2 2 4 8 1476 3568 3904 +7874 2 2 4 8 2988 5193 3369 +7875 2 2 4 8 19 3816 18 +7876 2 2 4 8 1157 3305 4433 +7877 2 2 4 8 1158 4432 3306 +7878 2 2 4 8 1774 3916 4398 +7879 2 2 4 8 1006 4922 4112 +7880 2 2 4 8 56 3109 3945 +7881 2 2 4 8 1432 3945 3109 +7882 2 2 4 8 1433 3946 3110 +7883 2 2 4 8 277 3110 3946 +7884 2 2 4 8 104 105 4395 +7885 2 2 4 8 478 5164 5275 +7886 2 2 4 8 567 5029 3093 +7887 2 2 4 8 1316 4521 3807 +7888 2 2 4 8 1317 4522 3808 +7889 2 2 4 8 1482 4178 2891 +7890 2 2 4 8 323 2891 4178 +7891 2 2 4 8 39 5103 3445 +7892 2 2 4 8 1789 3411 4764 +7893 2 2 4 8 755 4764 3411 +7894 2 2 4 8 1039 3392 3528 +7895 2 2 4 8 1557 3528 3392 +7896 2 2 4 8 1458 5387 3418 +7897 2 2 4 8 1341 3421 3422 +7898 2 2 4 8 1391 3422 3421 +7899 2 2 4 8 3423 3424 1392 +7900 2 2 4 8 3423 1342 3424 +7901 2 2 4 8 1343 3425 3426 +7902 2 2 4 8 1393 3426 3425 +7903 2 2 4 8 160 4347 2766 +7904 2 2 4 8 463 3950 4579 +7905 2 2 4 8 2030 4579 3950 +7906 2 2 4 8 997 2738 4669 +7907 2 2 4 8 4167 1573 4900 +7908 2 2 4 8 238 4605 2744 +7909 2 2 4 8 772 4349 3768 +7910 2 2 4 8 1826 3768 4349 +7911 2 2 4 8 1174 3402 4899 +7912 2 2 4 8 1830 4899 3402 +7913 2 2 4 8 430 431 3868 +7914 2 2 4 8 212 213 3867 +7915 2 2 4 8 1509 4596 3220 +7916 2 2 4 8 1436 4651 2832 +7917 2 2 4 8 567 2735 5029 +7918 2 2 4 8 1372 3772 2998 +7919 2 2 4 8 1600 4915 3031 +7920 2 2 4 8 1909 4573 3095 +7921 2 2 4 8 1910 4574 3096 +7922 2 2 4 8 1908 3097 4572 +7923 2 2 4 8 1907 3098 4571 +7924 2 2 4 8 1906 3099 4570 +7925 2 2 4 8 1905 3100 4569 +7926 2 2 4 8 961 4058 4083 +7927 2 2 4 8 1862 4083 4058 +7928 2 2 4 8 1411 3852 3133 +7929 2 2 4 8 678 3133 3852 +7930 2 2 4 8 2343 3744 4757 +7931 2 2 4 8 3745 2344 4758 +7932 2 2 4 8 805 5101 3211 +7933 2 2 4 8 806 5100 3210 +7934 2 2 4 8 3147 4493 1555 +7935 2 2 4 8 1770 4959 5231 +7936 2 2 4 8 1771 4960 5232 +7937 2 2 4 8 2092 4514 3383 +7938 2 2 4 8 2091 4513 3384 +7939 2 2 4 8 1163 3309 4392 +7940 2 2 4 8 2631 4876 4743 +7941 2 2 4 8 617 4743 4876 +7942 2 2 4 8 2226 4333 3487 +7943 2 2 4 8 2227 4334 3486 +7944 2 2 4 8 2228 4337 3485 +7945 2 2 4 8 2229 3483 4335 +7946 2 2 4 8 2230 3484 4336 +7947 2 2 4 8 495 3132 3982 +7948 2 2 4 8 784 4422 4008 +7949 2 2 4 8 1230 3063 3679 +7950 2 2 4 8 2080 4565 5302 +7951 2 2 4 8 45 3886 2975 +7952 2 2 4 8 1335 2975 3886 +7953 2 2 4 8 266 3887 2974 +7954 2 2 4 8 1334 2974 3887 +7955 2 2 4 8 1551 5240 2765 +7956 2 2 4 8 997 4886 2738 +7957 2 2 4 8 695 4451 2755 +7958 2 2 4 8 696 4452 2754 +7959 2 2 4 8 1432 2797 4539 +7960 2 2 4 8 843 4539 2797 +7961 2 2 4 8 1433 2798 4540 +7962 2 2 4 8 844 4540 2798 +7963 2 2 4 8 53 5253 3478 +7964 2 2 4 8 274 5254 3479 +7965 2 2 4 8 492 2893 3930 +7966 2 2 4 8 466 3584 5301 +7967 2 2 4 8 694 5170 2741 +7968 2 2 4 8 1549 3007 4597 +7969 2 2 4 8 1071 4597 3007 +7970 2 2 4 8 93 4416 3004 +7971 2 2 4 8 1340 5239 4892 +7972 2 2 4 8 1598 4273 2941 +7973 2 2 4 8 1599 2940 4274 +7974 2 2 4 8 1849 3752 3386 +7975 2 2 4 8 1925 2744 4605 +7976 2 2 4 8 676 5404 2750 +7977 2 2 4 8 1439 2741 5170 +7978 2 2 4 8 110 3831 2970 +7979 2 2 4 8 1118 4868 4448 +7980 2 2 4 8 2490 4448 4868 +7981 2 2 4 8 1239 3621 3136 +7982 2 2 4 8 1242 3622 3138 +7983 2 2 4 8 248 249 4749 +7984 2 2 4 8 711 4870 2742 +7985 2 2 4 8 106 107 3870 +7986 2 2 4 8 693 4909 2784 +7987 2 2 4 8 2009 2898 4675 +7988 2 2 4 8 1610 3111 4942 +7989 2 2 4 8 686 5059 2806 +7990 2 2 4 8 4172 5117 3259 +7991 2 2 4 8 1661 4450 3377 +7992 2 2 4 8 961 2740 4972 +7993 2 2 4 8 1023 2742 4816 +7994 2 2 4 8 2016 3750 4857 +7995 2 2 4 8 1238 4857 3750 +7996 2 2 4 8 496 3176 3595 +7997 2 2 4 8 4237 1289 5128 +7998 2 2 4 8 1860 4125 5281 +7999 2 2 4 8 1859 4126 5280 +8000 2 2 4 8 1071 2753 4597 +8001 2 2 4 8 1260 3563 5018 +8002 2 2 4 8 1659 4435 5196 +8003 2 2 4 8 1481 3495 3838 +8004 2 2 4 8 1540 3838 3495 +8005 2 2 4 8 1480 3496 3837 +8006 2 2 4 8 1539 3837 3496 +8007 2 2 4 8 713 3313 4057 +8008 2 2 4 8 823 4710 4837 +8009 2 2 4 8 814 4708 4835 +8010 2 2 4 8 815 4709 4836 +8011 2 2 4 8 1469 3487 4333 +8012 2 2 4 8 1468 3486 4334 +8013 2 2 4 8 1466 3485 4337 +8014 2 2 4 8 1463 4336 3484 +8015 2 2 4 8 1462 4335 3483 +8016 2 2 4 8 1107 4537 3030 +8017 2 2 4 8 382 3885 381 +8018 2 2 4 8 1060 5106 2999 +8019 2 2 4 8 2293 2999 5106 +8020 2 2 4 8 46 3886 45 +8021 2 2 4 8 266 267 3887 +8022 2 2 4 8 2314 3459 5010 +8023 2 2 4 8 757 4006 5277 +8024 2 2 4 8 525 3780 4966 +8025 2 2 4 8 714 4971 2914 +8026 2 2 4 8 1596 2914 4971 +8027 2 2 4 8 1283 4351 2863 +8028 2 2 4 8 2864 4350 1282 +8029 2 2 4 8 1026 4425 2812 +8030 2 2 4 8 1025 2811 4426 +8031 2 2 4 8 1224 3594 3593 +8032 2 2 4 8 2220 3593 3594 +8033 2 2 4 8 1667 4940 2744 +8034 2 2 4 8 237 4940 4017 +8035 2 2 4 8 954 3400 4282 +8036 2 2 4 8 336 337 4386 +8037 2 2 4 8 150 151 3901 +8038 2 2 4 8 372 3902 371 +8039 2 2 4 8 693 2792 4909 +8040 2 2 4 8 695 2755 4696 +8041 2 2 4 8 449 5249 4252 +8042 2 2 4 8 2547 5288 3701 +8043 2 2 4 8 511 3036 5227 +8044 2 2 4 8 446 3327 3956 +8045 2 2 4 8 1511 3956 3327 +8046 2 2 4 8 931 3971 2903 +8047 2 2 4 8 1449 2785 4462 +8048 2 2 4 8 1456 5037 2979 +8049 2 2 4 8 833 4195 3076 +8050 2 2 4 8 1749 5214 5206 +8051 2 2 4 8 1748 5213 5205 +8052 2 2 4 8 1184 2756 4697 +8053 2 2 4 8 478 5275 3556 +8054 2 2 4 8 1351 3139 4093 +8055 2 2 4 8 160 161 4347 +8056 2 2 4 8 1136 5319 2848 +8057 2 2 4 8 416 417 4556 +8058 2 2 4 8 2443 3447 4471 +8059 2 2 4 8 978 5411 2775 +8060 2 2 4 8 1434 3506 3640 +8061 2 2 4 8 590 5355 2757 +8062 2 2 4 8 591 5356 2758 +8063 2 2 4 8 589 5357 2759 +8064 2 2 4 8 960 2966 3928 +8065 2 2 4 8 1338 3928 2966 +8066 2 2 4 8 1026 2820 4425 +8067 2 2 4 8 1025 4426 2819 +8068 2 2 4 8 590 2757 5213 +8069 2 2 4 8 591 2758 5214 +8070 2 2 4 8 2677 3761 4186 +8071 2 2 4 8 618 4644 3544 +8072 2 2 4 8 1541 3466 4179 +8073 2 2 4 8 1739 4179 3466 +8074 2 2 4 8 1375 4185 2839 +8075 2 2 4 8 240 241 4092 +8076 2 2 4 8 1795 3364 4317 +8077 2 2 4 8 756 4317 3364 +8078 2 2 4 8 1904 2991 3875 +8079 2 2 4 8 1292 3107 5221 +8080 2 2 4 8 1293 5222 3108 +8081 2 2 4 8 474 5159 2820 +8082 2 2 4 8 472 2819 5160 +8083 2 2 4 8 350 351 4183 +8084 2 2 4 8 163 164 4182 +8085 2 2 4 8 1098 4989 2759 +8086 2 2 4 8 1343 3103 4807 +8087 2 2 4 8 1307 3268 3580 +8088 2 2 4 8 1604 3983 3734 +8089 2 2 4 8 1383 4235 3742 +8090 2 2 4 8 1642 5181 2937 +8091 2 2 4 8 1643 5180 2936 +8092 2 2 4 8 1644 2938 5179 +8093 2 2 4 8 1645 2939 5178 +8094 2 2 4 8 2139 4804 4825 +8095 2 2 4 8 2140 4805 4826 +8096 2 2 4 8 408 409 4032 +8097 2 2 4 8 1270 3768 3767 +8098 2 2 4 8 1826 3767 3768 +8099 2 2 4 8 43 44 4642 +8100 2 2 4 8 2340 4045 3702 +8101 2 2 4 8 4237 5128 2337 +8102 2 2 4 8 682 3385 5115 +8103 2 2 4 8 804 4536 4114 +8104 2 2 4 8 803 4535 4113 +8105 2 2 4 8 4164 4373 2034 +8106 2 2 4 8 4164 1417 4373 +8107 2 2 4 8 56 3945 55 +8108 2 2 4 8 276 277 3946 +8109 2 2 4 8 1590 3170 4444 +8110 2 2 4 8 539 3169 4445 +8111 2 2 4 8 1591 4445 3169 +8112 2 2 4 8 540 4444 3170 +8113 2 2 4 8 1321 5130 2771 +8114 2 2 4 8 3039 1246 3796 +8115 2 2 4 8 2424 4262 3223 +8116 2 2 4 8 527 3504 5013 +8117 2 2 4 8 1962 2879 4397 +8118 2 2 4 8 405 406 3953 +8119 2 2 4 8 1152 5251 2779 +8120 2 2 4 8 1829 5272 4375 +8121 2 2 4 8 1034 5282 2781 +8122 2 2 4 8 1661 5143 4450 +8123 2 2 4 8 193 194 4906 +8124 2 2 4 8 707 3273 4196 +8125 2 2 4 8 706 3272 4197 +8126 2 2 4 8 748 4818 3805 +8127 2 2 4 8 871 4896 5374 +8128 2 2 4 8 529 3193 4904 +8129 2 2 4 8 1072 2916 4476 +8130 2 2 4 8 1532 3197 4181 +8131 2 2 4 8 704 4181 3197 +8132 2 2 4 8 1116 2787 5386 +8133 2 2 4 8 1621 5386 2787 +8134 2 2 4 8 1663 5150 4354 +8135 2 2 4 8 1459 5057 3419 +8136 2 2 4 8 278 279 4593 +8137 2 2 4 8 58 4591 57 +8138 2 2 4 8 264 265 4592 +8139 2 2 4 8 518 3608 3640 +8140 2 2 4 8 1869 3505 4953 +8141 2 2 4 8 244 4953 3505 +8142 2 2 4 8 754 3861 4894 +8143 2 2 4 8 1266 3982 3132 +8144 2 2 4 8 980 4330 3381 +8145 2 2 4 8 1631 3381 4330 +8146 2 2 4 8 943 4022 3766 +8147 2 2 4 8 1673 3766 4022 +8148 2 2 4 8 1199 2780 4887 +8149 2 2 4 8 1051 2802 4503 +8150 2 2 4 8 1640 5151 3326 +8151 2 2 4 8 537 5046 3937 +8152 2 2 4 8 2189 3937 5046 +8153 2 2 4 8 1806 3993 3208 +8154 2 2 4 8 890 3208 3993 +8155 2 2 4 8 1533 3071 4374 +8156 2 2 4 8 705 4374 3071 +8157 2 2 4 8 1642 3067 3971 +8158 2 2 4 8 1603 5050 2995 +8159 2 2 4 8 693 2918 5002 +8160 2 2 4 8 464 3915 3757 +8161 2 2 4 8 1636 3757 3915 +8162 2 2 4 8 1369 2784 4909 +8163 2 2 4 8 1371 3492 4331 +8164 2 2 4 8 1458 3770 5387 +8165 2 2 4 8 1207 3275 3603 +8166 2 2 4 8 546 2833 4820 +8167 2 2 4 8 1506 4820 2833 +8168 2 2 4 8 728 2896 4087 +8169 2 2 4 8 731 4088 2897 +8170 2 2 4 8 1979 3396 5402 +8171 2 2 4 8 534 5402 3396 +8172 2 2 4 8 1336 3520 3428 +8173 2 2 4 8 1422 4188 2915 +8174 2 2 4 8 186 187 4038 +8175 2 2 4 8 77 4041 76 +8176 2 2 4 8 1312 3727 4282 +8177 2 2 4 8 1275 2962 5211 +8178 2 2 4 8 749 3803 5039 +8179 2 2 4 8 750 5038 3804 +8180 2 2 4 8 863 2832 4827 +8181 2 2 4 8 1505 4827 2832 +8182 2 2 4 8 1355 2819 4426 +8183 2 2 4 8 1356 4425 2820 +8184 2 2 4 8 80 2808 4523 +8185 2 2 4 8 1404 4767 2858 +8186 2 2 4 8 1405 4769 2857 +8187 2 2 4 8 1406 4768 2859 +8188 2 2 4 8 1401 2850 4422 +8189 2 2 4 8 1300 3077 5053 +8190 2 2 4 8 1301 3075 5052 +8191 2 2 4 8 1418 3085 4163 +8192 2 2 4 8 1844 4931 4140 +8193 2 2 4 8 1846 4139 4929 +8194 2 2 4 8 1845 4137 4928 +8195 2 2 4 8 1847 4138 4930 +8196 2 2 4 8 1377 3863 5137 +8197 2 2 4 8 753 3862 5136 +8198 2 2 4 8 782 3669 4359 +8199 2 2 4 8 2079 4359 3669 +8200 2 2 4 8 455 4348 2841 +8201 2 2 4 8 1319 3142 4428 +8202 2 2 4 8 1320 3141 4430 +8203 2 2 4 8 1321 3140 4429 +8204 2 2 4 8 1300 5053 3082 +8205 2 2 4 8 1301 5052 3083 +8206 2 2 4 8 1339 3964 4888 +8207 2 2 4 8 1420 3811 3297 +8208 2 2 4 8 533 3297 3811 +8209 2 2 4 8 1132 3762 5278 +8210 2 2 4 8 582 3083 5079 +8211 2 2 4 8 1688 5079 3083 +8212 2 2 4 8 1683 5078 3082 +8213 2 2 4 8 587 3082 5078 +8214 2 2 4 8 1738 5238 2792 +8215 2 2 4 8 285 286 4035 +8216 2 2 4 8 257 258 4036 +8217 2 2 4 8 65 4037 64 +8218 2 2 4 8 1658 3350 4923 +8219 2 2 4 8 1263 4800 3264 +8220 2 2 4 8 1141 5056 3713 +8221 2 2 4 8 1142 3712 5055 +8222 2 2 4 8 347 348 4434 +8223 2 2 4 8 58 2994 4591 +8224 2 2 4 8 279 2996 4593 +8225 2 2 4 8 264 4592 2995 +8226 2 2 4 8 1213 3188 5030 +8227 2 2 4 8 1216 3191 5031 +8228 2 2 4 8 201 4054 2946 +8229 2 2 4 8 226 2945 4055 +8230 2 2 4 8 710 2986 4673 +8231 2 2 4 8 855 5048 5166 +8232 2 2 4 8 1131 2865 4258 +8233 2 2 4 8 1586 3924 4551 +8234 2 2 4 8 693 5002 2965 +8235 2 2 4 8 1111 5379 3994 +8236 2 2 4 8 2359 3994 5379 +8237 2 2 4 8 1114 5292 2799 +8238 2 2 4 8 1579 2799 5292 +8239 2 2 4 8 1449 2990 4516 +8240 2 2 4 8 1448 2989 4515 +8241 2 2 4 8 1388 4631 3688 +8242 2 2 4 8 1451 4452 3280 +8243 2 2 4 8 1141 4758 3145 +8244 2 2 4 8 1142 3146 4757 +8245 2 2 4 8 845 4634 2880 +8246 2 2 4 8 1483 2880 4634 +8247 2 2 4 8 347 4434 2839 +8248 2 2 4 8 2042 4143 2916 +8249 2 2 4 8 1281 4034 2969 +8250 2 2 4 8 540 2835 4444 +8251 2 2 4 8 539 4445 2836 +8252 2 2 4 8 1518 4084 3988 +8253 2 2 4 8 92 4996 3620 +8254 2 2 4 8 392 393 4056 +8255 2 2 4 8 1676 3199 4085 +8256 2 2 4 8 359 3409 4729 +8257 2 2 4 8 1729 4729 3409 +8258 2 2 4 8 172 3410 4730 +8259 2 2 4 8 1728 4730 3410 +8260 2 2 4 8 1594 3550 3956 +8261 2 2 4 8 446 3956 3550 +8262 2 2 4 8 550 5109 2800 +8263 2 2 4 8 1540 2800 5109 +8264 2 2 4 8 549 5108 2801 +8265 2 2 4 8 1539 2801 5108 +8266 2 2 4 8 1131 4284 2865 +8267 2 2 4 8 619 4446 3545 +8268 2 2 4 8 2198 3736 5229 +8269 2 2 4 8 1129 5229 3736 +8270 2 2 4 8 1792 4040 4854 +8271 2 2 4 8 456 5394 4298 +8272 2 2 4 8 1677 2950 4067 +8273 2 2 4 8 1795 4317 3836 +8274 2 2 4 8 1620 3836 4317 +8275 2 2 4 8 1051 4941 2802 +8276 2 2 4 8 369 370 4528 +8277 2 2 4 8 148 149 4527 +8278 2 2 4 8 383 384 4526 +8279 2 2 4 8 630 5236 3283 +8280 2 2 4 8 142 4071 141 +8281 2 2 4 8 362 363 4072 +8282 2 2 4 8 400 3739 3181 +8283 2 2 4 8 445 4848 2840 +8284 2 2 4 8 475 3081 3849 +8285 2 2 4 8 1754 3643 3644 +8286 2 2 4 8 1265 3644 3643 +8287 2 2 4 8 43 4642 3031 +8288 2 2 4 8 568 4209 3577 +8289 2 2 4 8 1648 3577 4209 +8290 2 2 4 8 2394 5267 3900 +8291 2 2 4 8 2353 4649 3064 +8292 2 2 4 8 696 4263 2882 +8293 2 2 4 8 1136 2949 5319 +8294 2 2 4 8 2000 2913 4247 +8295 2 2 4 8 2350 3453 4777 +8296 2 2 4 8 972 2930 4157 +8297 2 2 4 8 2576 5306 4984 +8298 2 2 4 8 697 4521 3136 +8299 2 2 4 8 699 4522 3138 +8300 2 2 4 8 1416 2976 4057 +8301 2 2 4 8 68 4713 3405 +8302 2 2 4 8 1719 3405 4713 +8303 2 2 4 8 848 3734 3983 +8304 2 2 4 8 2372 4623 3756 +8305 2 2 4 8 1273 4821 3196 +8306 2 2 4 8 304 305 5400 +8307 2 2 4 8 293 294 5399 +8308 2 2 4 8 178 179 5398 +8309 2 2 4 8 133 134 5397 +8310 2 2 4 8 122 123 5396 +8311 2 2 4 8 112 5395 111 +8312 2 2 4 8 1626 3143 5042 +8313 2 2 4 8 798 4602 3378 +8314 2 2 4 8 1529 4079 4834 +8315 2 2 4 8 1528 4080 4833 +8316 2 2 4 8 1399 4184 2918 +8317 2 2 4 8 1438 2833 4666 +8318 2 2 4 8 700 3959 5289 +8319 2 2 4 8 1645 5178 3800 +8320 2 2 4 8 1643 3798 5180 +8321 2 2 4 8 1644 5179 3799 +8322 2 2 4 8 1642 3797 5181 +8323 2 2 4 8 462 5286 3965 +8324 2 2 4 8 2281 3965 5286 +8325 2 2 4 8 801 3482 5406 +8326 2 2 4 8 2003 5406 3482 +8327 2 2 4 8 546 4666 2833 +8328 2 2 4 8 86 4147 85 +8329 2 2 4 8 1663 4879 5150 +8330 2 2 4 8 1241 4156 3220 +8331 2 2 4 8 1518 3988 5037 +8332 2 2 4 8 418 419 4255 +8333 2 2 4 8 1371 4331 3687 +8334 2 2 4 8 542 4372 2870 +8335 2 2 4 8 1339 3642 5354 +8336 2 2 4 8 931 3797 3971 +8337 2 2 4 8 1642 3971 3797 +8338 2 2 4 8 2489 4618 2927 +8339 2 2 4 8 40 3329 5103 +8340 2 2 4 8 1786 5103 3329 +8341 2 2 4 8 1698 4091 5144 +8342 2 2 4 8 1673 4181 4000 +8343 2 2 4 8 1278 3072 4503 +8344 2 2 4 8 1651 5036 3068 +8345 2 2 4 8 1180 3068 5036 +8346 2 2 4 8 1181 3069 5035 +8347 2 2 4 8 3069 1650 5035 +8348 2 2 4 8 799 4766 3379 +8349 2 2 4 8 1355 5160 2819 +8350 2 2 4 8 1356 2820 5159 +8351 2 2 4 8 3086 2658 4699 +8352 2 2 4 8 445 3416 4102 +8353 2 2 4 8 1351 4093 3389 +8354 2 2 4 8 2104 3186 5220 +8355 2 2 4 8 1923 2972 4156 +8356 2 2 4 8 322 323 4178 +8357 2 2 4 8 1137 4623 2923 +8358 2 2 4 8 524 3605 4207 +8359 2 2 4 8 445 2840 4772 +8360 2 2 4 8 4237 2337 5060 +8361 2 2 4 8 912 4237 5060 +8362 2 2 4 8 464 3757 5360 +8363 2 2 4 8 1717 4839 2834 +8364 2 2 4 8 816 5031 3191 +8365 2 2 4 8 824 5030 3188 +8366 2 2 4 8 712 3051 4777 +8367 2 2 4 8 1849 3054 4248 +8368 2 2 4 8 739 3787 3454 +8369 2 2 4 8 1465 3454 3787 +8370 2 2 4 8 1071 5279 2840 +8371 2 2 4 8 1701 4924 3233 +8372 2 2 4 8 538 3233 4924 +8373 2 2 4 8 1371 3687 3340 +8374 2 2 4 8 1370 3339 3688 +8375 2 2 4 8 683 3127 4844 +8376 2 2 4 8 455 2895 5177 +8377 2 2 4 8 1588 5177 2895 +8378 2 2 4 8 73 74 4201 +8379 2 2 4 8 90 5171 89 +8380 2 2 4 8 1980 4802 2841 +8381 2 2 4 8 1265 4216 2951 +8382 2 2 4 8 1655 4901 3331 +8383 2 2 4 8 765 4627 5283 +8384 2 2 4 8 369 4528 3017 +8385 2 2 4 8 148 4527 3018 +8386 2 2 4 8 384 3016 4526 +8387 2 2 4 8 1258 2882 4410 +8388 2 2 4 8 1363 2952 4588 +8389 2 2 4 8 1476 4525 4585 +8390 2 2 4 8 2109 3513 4393 +8391 2 2 4 8 1006 3354 3949 +8392 2 2 4 8 1479 3949 3354 +8393 2 2 4 8 713 4057 4130 +8394 2 2 4 8 1790 3490 4876 +8395 2 2 4 8 617 4876 3490 +8396 2 2 4 8 2396 4701 3053 +8397 2 2 4 8 680 4316 2916 +8398 2 2 4 8 2443 3258 4984 +8399 2 2 4 8 1805 4234 4926 +8400 2 2 4 8 1930 4460 5001 +8401 2 2 4 8 12 4254 11 +8402 2 2 4 8 631 4984 5306 +8403 2 2 4 8 1660 4720 3380 +8404 2 2 4 8 497 4116 3053 +8405 2 2 4 8 1403 3053 4116 +8406 2 2 4 8 1767 5366 3052 +8407 2 2 4 8 403 3052 5366 +8408 2 2 4 8 2356 4656 5297 +8409 2 2 4 8 506 4163 3085 +8410 2 2 4 8 946 3322 4210 +8411 2 2 4 8 1542 4210 3322 +8412 2 2 4 8 1442 3095 4573 +8413 2 2 4 8 1443 3096 4574 +8414 2 2 4 8 1444 4572 3097 +8415 2 2 4 8 1445 4571 3098 +8416 2 2 4 8 1446 4570 3099 +8417 2 2 4 8 1447 4569 3100 +8418 2 2 4 8 1115 3144 4427 +8419 2 2 4 8 730 4439 2888 +8420 2 2 4 8 1549 3634 4965 +8421 2 2 4 8 1581 3882 3676 +8422 2 2 4 8 714 4305 2929 +8423 2 2 4 8 1609 4737 3112 +8424 2 2 4 8 301 3111 4739 +8425 2 2 4 8 1610 4739 3111 +8426 2 2 4 8 290 3112 4737 +8427 2 2 4 8 1612 3113 4736 +8428 2 2 4 8 182 4736 3113 +8429 2 2 4 8 1613 3114 4735 +8430 2 2 4 8 137 4735 3114 +8431 2 2 4 8 126 4734 3115 +8432 2 2 4 8 1614 3115 4734 +8433 2 2 4 8 115 4733 3116 +8434 2 2 4 8 1615 3116 4733 +8435 2 2 4 8 1055 2841 5157 +8436 2 2 4 8 1338 2966 4917 +8437 2 2 4 8 1240 4364 3360 +8438 2 2 4 8 876 4048 3624 +8439 2 2 4 8 1508 4242 3622 +8440 2 2 4 8 1507 4244 3621 +8441 2 2 4 8 96 4275 95 +8442 2 2 4 8 1696 2931 4681 +8443 2 2 4 8 214 2925 4486 +8444 2 2 4 8 432 2926 4485 +8445 2 2 4 8 1737 3297 4617 +8446 2 2 4 8 390 391 4279 +8447 2 2 4 8 451 2904 5337 +8448 2 2 4 8 442 5335 2906 +8449 2 2 4 8 450 5336 2905 +8450 2 2 4 8 1721 3918 3463 +8451 2 2 4 8 1722 3464 3919 +8452 2 2 4 8 1370 4388 3525 +8453 2 2 4 8 1484 4843 2851 +8454 2 2 4 8 1585 4686 3833 +8455 2 2 4 8 1848 5152 4377 +8456 2 2 4 8 2869 5389 3876 +8457 2 2 4 8 1168 2978 4230 +8458 2 2 4 8 1343 4807 3425 +8459 2 2 4 8 901 5381 3850 +8460 2 2 4 8 441 4652 3025 +8461 2 2 4 8 560 2851 4843 +8462 2 2 4 8 1678 3209 5382 +8463 2 2 4 8 1238 4611 3455 +8464 2 2 4 8 1264 4407 2911 +8465 2 2 4 8 1701 5165 2844 +8466 2 2 4 8 536 3748 3677 +8467 2 2 4 8 1518 3677 3748 +8468 2 2 4 8 1472 3647 3792 +8469 2 2 4 8 1390 3640 3506 +8470 2 2 4 8 1694 3909 4018 +8471 2 2 4 8 722 4018 3909 +8472 2 2 4 8 922 3499 5420 +8473 2 2 4 8 1347 4281 2968 +8474 2 2 4 8 1605 5376 2896 +8475 2 2 4 8 1606 2897 5377 +8476 2 2 4 8 1207 5227 3036 +8477 2 2 4 8 1313 4133 4134 +8478 2 2 4 8 4133 2407 4134 +8479 2 2 4 8 1314 4136 4135 +8480 2 2 4 8 4135 4136 2408 +8481 2 2 4 8 734 2943 4620 +8482 2 2 4 8 1905 3831 5395 +8483 2 2 4 8 694 4241 2987 +8484 2 2 4 8 1339 5354 3926 +8485 2 2 4 8 1402 3882 5019 +8486 2 2 4 8 1708 5039 3633 +8487 2 2 4 8 1709 3632 5038 +8488 2 2 4 8 1326 2848 5319 +8489 2 2 4 8 774 4184 4132 +8490 2 2 4 8 2092 4837 4710 +8491 2 2 4 8 2090 4835 4708 +8492 2 2 4 8 2091 4836 4709 +8493 2 2 4 8 2852 5077 1800 +8494 2 2 4 8 1267 3875 3205 +8495 2 2 4 8 495 3982 3607 +8496 2 2 4 8 213 214 4486 +8497 2 2 4 8 431 432 4485 +8498 2 2 4 8 771 4004 4101 +8499 2 2 4 8 1763 4101 4004 +8500 2 2 4 8 209 210 4830 +8501 2 2 4 8 427 428 4829 +8502 2 2 4 8 1279 2987 4257 +8503 2 2 4 8 1801 3972 4286 +8504 2 2 4 8 1477 4286 3972 +8505 2 2 4 8 1457 2874 5005 +8506 2 2 4 8 900 3038 4290 +8507 2 2 4 8 1270 3324 5166 +8508 2 2 4 8 702 4246 3220 +8509 2 2 4 8 1509 3220 4246 +8510 2 2 4 8 1510 4547 4765 +8511 2 2 4 8 767 3437 4079 +8512 2 2 4 8 1772 4079 3437 +8513 2 2 4 8 1773 4080 3438 +8514 2 2 4 8 766 3438 4080 +8515 2 2 4 8 1229 4974 2861 +8516 2 2 4 8 1231 4975 2860 +8517 2 2 4 8 2242 4790 5066 +8518 2 2 4 8 1307 4635 3268 +8519 2 2 4 8 1367 4132 3033 +8520 2 2 4 8 3513 1264 4393 +8521 2 2 4 8 398 399 4367 +8522 2 2 4 8 1995 5317 5293 +8523 2 2 4 8 1465 4599 2900 +8524 2 2 4 8 4152 4965 2219 +8525 2 2 4 8 1302 4814 3289 +8526 2 2 4 8 1213 5030 3473 +8527 2 2 4 8 1216 5031 3474 +8528 2 2 4 8 1292 5221 3527 +8529 2 2 4 8 1293 3526 5222 +8530 2 2 4 8 476 3386 3752 +8531 2 2 4 8 1483 2928 5262 +8532 2 2 4 8 656 4235 3105 +8533 2 2 4 8 77 3101 4041 +8534 2 2 4 8 2016 4823 3750 +8535 2 2 4 8 825 3750 4823 +8536 2 2 4 8 678 4100 3046 +8537 2 2 4 8 1963 3898 4762 +8538 2 2 4 8 831 4762 3898 +8539 2 2 4 8 621 2872 4838 +8540 2 2 4 8 1691 3613 5148 +8541 2 2 4 8 858 4206 5382 +8542 2 2 4 8 395 3014 4208 +8543 2 2 4 8 1541 4056 3466 +8544 2 2 4 8 393 3466 4056 +8545 2 2 4 8 1596 5008 3284 +8546 2 2 4 8 1156 4616 3304 +8547 2 2 4 8 1449 4462 2990 +8548 2 2 4 8 947 2990 4462 +8549 2 2 4 8 1590 5043 3170 +8550 2 2 4 8 1592 5044 3171 +8551 2 2 4 8 236 4017 3090 +8552 2 2 4 8 1271 3989 3124 +8553 2 2 4 8 1177 4394 2951 +8554 2 2 4 8 307 308 4380 +8555 2 2 4 8 296 297 4381 +8556 2 2 4 8 175 176 4382 +8557 2 2 4 8 130 131 4383 +8558 2 2 4 8 119 120 4384 +8559 2 2 4 8 1453 4352 4128 +8560 2 2 4 8 1899 4128 4352 +8561 2 2 4 8 1898 4353 4129 +8562 2 2 4 8 1454 4129 4353 +8563 2 2 4 8 1781 5325 3404 +8564 2 2 4 8 1993 3212 4779 +8565 2 2 4 8 1992 3213 4778 +8566 2 2 4 8 2116 4668 4832 +8567 2 2 4 8 2096 4585 4525 +8568 2 2 4 8 1401 3065 4171 +8569 2 2 4 8 431 4485 3868 +8570 2 2 4 8 1813 3868 4485 +8571 2 2 4 8 213 4486 3867 +8572 2 2 4 8 1814 3867 4486 +8573 2 2 4 8 1559 4825 4804 +8574 2 2 4 8 1560 4826 4805 +8575 2 2 4 8 1178 5022 3394 +8576 2 2 4 8 941 3380 4720 +8577 2 2 4 8 1654 2964 4375 +8578 2 2 4 8 1434 4467 2934 +8579 2 2 4 8 1500 3239 4761 +8580 2 2 4 8 569 3157 5131 +8581 2 2 4 8 1250 4150 3336 +8582 2 2 4 8 3086 4478 2314 +8583 2 2 4 8 1924 2971 4364 +8584 2 2 4 8 186 4038 4791 +8585 2 2 4 8 2046 4791 4038 +8586 2 2 4 8 2759 5357 3557 +8587 2 2 4 8 2758 5356 3559 +8588 2 2 4 8 2757 5355 3558 +8589 2 2 4 8 1459 4066 5057 +8590 2 2 4 8 1287 4886 3155 +8591 2 2 4 8 1075 3042 5064 +8592 2 2 4 8 1313 3434 4023 +8593 2 2 4 8 1314 3435 4024 +8594 2 2 4 8 471 3587 3978 +8595 2 2 4 8 579 5389 2869 +8596 2 2 4 8 2103 3194 5226 +8597 2 2 4 8 1741 4679 3091 +8598 2 2 4 8 1742 4680 3092 +8599 2 2 4 8 350 4183 3185 +8600 2 2 4 8 163 4182 3184 +8601 2 2 4 8 1531 4263 5346 +8602 2 2 4 8 1593 4483 4453 +8603 2 2 4 8 2130 4453 4483 +8604 2 2 4 8 803 4113 4472 +8605 2 2 4 8 1955 4472 4113 +8606 2 2 4 8 804 4114 4474 +8607 2 2 4 8 1956 4474 4114 +8608 2 2 4 8 613 4679 5172 +8609 2 2 4 8 1089 2877 4942 +8610 2 2 4 8 1746 4536 3648 +8611 2 2 4 8 1745 3650 4534 +8612 2 2 4 8 1747 4535 3649 +8613 2 2 4 8 1587 5127 4982 +8614 2 2 4 8 970 5005 2874 +8615 2 2 4 8 41 4402 3329 +8616 2 2 4 8 497 4171 3065 +8617 2 2 4 8 1285 4488 2950 +8618 2 2 4 8 1370 3688 4388 +8619 2 2 4 8 1996 4743 3706 +8620 2 2 4 8 617 3706 4743 +8621 2 2 4 8 238 239 4605 +8622 2 2 4 8 1365 2923 4623 +8623 2 2 4 8 2093 4530 4785 +8624 2 2 4 8 73 4201 5361 +8625 2 2 4 8 1303 3084 4200 +8626 2 2 4 8 842 5133 3350 +8627 2 2 4 8 1767 3350 5133 +8628 2 2 4 8 1186 5132 3005 +8629 2 2 4 8 1608 3005 5132 +8630 2 2 4 8 2342 5166 5048 +8631 2 2 4 8 2232 4765 4547 +8632 2 2 4 8 1476 3904 4525 +8633 2 2 4 8 1494 4015 4342 +8634 2 2 4 8 1828 4342 4015 +8635 2 2 4 8 1330 4099 3611 +8636 2 2 4 8 1653 3657 4278 +8637 2 2 4 8 530 4278 3657 +8638 2 2 4 8 11 4254 3041 +8639 2 2 4 8 1512 3041 4254 +8640 2 2 4 8 2638 3620 5058 +8641 2 2 4 8 230 231 4520 +8642 2 2 4 8 1402 5019 5289 +8643 2 2 4 8 1284 3126 4400 +8644 2 2 4 8 1263 3685 4800 +8645 2 2 4 8 330 331 4531 +8646 2 2 4 8 185 4791 2900 +8647 2 2 4 8 2410 3599 3943 +8648 2 2 4 8 2046 2900 4791 +8649 2 2 4 8 1483 4634 2928 +8650 2 2 4 8 1382 3488 4568 +8651 2 2 4 8 1479 5337 2904 +8652 2 2 4 8 1481 2905 5336 +8653 2 2 4 8 1480 2906 5335 +8654 2 2 4 8 1131 2892 5296 +8655 2 2 4 8 1357 3397 4628 +8656 2 2 4 8 781 3658 4525 +8657 2 2 4 8 2096 4525 3658 +8658 2 2 4 8 1228 3616 4141 +8659 2 2 4 8 1875 3877 4716 +8660 2 2 4 8 1913 5303 4688 +8661 2 2 4 8 974 3348 4355 +8662 2 2 4 8 1567 4355 3348 +8663 2 2 4 8 1509 4064 4596 +8664 2 2 4 8 830 4809 3873 +8665 2 2 4 8 1942 3873 4809 +8666 2 2 4 8 1527 2986 4831 +8667 2 2 4 8 710 4831 2986 +8668 2 2 4 8 645 4588 2952 +8669 2 2 4 8 1324 3723 3722 +8670 2 2 4 8 1644 3722 3723 +8671 2 2 4 8 1325 3721 3720 +8672 2 2 4 8 1645 3720 3721 +8673 2 2 4 8 2998 5391 4298 +8674 2 2 4 8 242 2928 4998 +8675 2 2 4 8 2076 4998 2928 +8676 2 2 4 8 1393 3650 4470 +8677 2 2 4 8 696 2882 5326 +8678 2 2 4 8 1557 5197 3461 +8679 2 2 4 8 783 3944 3742 +8680 2 2 4 8 1202 3278 4144 +8681 2 2 4 8 943 3766 4578 +8682 2 2 4 8 1782 4578 3766 +8683 2 2 4 8 1844 4140 3857 +8684 2 2 4 8 1846 3858 4139 +8685 2 2 4 8 1845 3859 4137 +8686 2 2 4 8 1847 3860 4138 +8687 2 2 4 8 1874 3064 4649 +8688 2 2 4 8 1399 4368 3033 +8689 2 2 4 8 510 3406 3903 +8690 2 2 4 8 1703 3903 3406 +8691 2 2 4 8 304 5400 3096 +8692 2 2 4 8 293 5399 3095 +8693 2 2 4 8 179 3097 5398 +8694 2 2 4 8 134 3098 5397 +8695 2 2 4 8 123 3099 5396 +8696 2 2 4 8 112 3100 5395 +8697 2 2 4 8 1126 3223 4262 +8698 2 2 4 8 773 3651 4731 +8699 2 2 4 8 1984 4731 3651 +8700 2 2 4 8 411 412 4751 +8701 2 2 4 8 1028 2896 5376 +8702 2 2 4 8 1029 5377 2897 +8703 2 2 4 8 1535 3741 4723 +8704 2 2 4 8 1030 5365 2888 +8705 2 2 4 8 2014 4379 4332 +8706 2 2 4 8 1622 4332 4379 +8707 2 2 4 8 521 4415 3583 +8708 2 2 4 8 1367 3325 4132 +8709 2 2 4 8 1922 2963 4611 +8710 2 2 4 8 1065 4871 2914 +8711 2 2 4 8 936 3896 3301 +8712 2 2 4 8 937 3300 3897 +8713 2 2 4 8 1612 5228 3113 +8714 2 2 4 8 1474 4359 4564 +8715 2 2 4 8 2079 4564 4359 +8716 2 2 4 8 2276 5222 3526 +8717 2 2 4 8 2277 3527 5221 +8718 2 2 4 8 1687 5069 2899 +8719 2 2 4 8 940 5042 3143 +8720 2 2 4 8 612 2937 4732 +8721 2 2 4 8 341 342 5107 +8722 2 2 4 8 704 4000 4181 +8723 2 2 4 8 1634 3152 4973 +8724 2 2 4 8 1179 4973 3152 +8725 2 2 4 8 1364 4174 3221 +8726 2 2 4 8 1365 3222 4175 +8727 2 2 4 8 1805 3801 4234 +8728 2 2 4 8 1359 4290 3038 +8729 2 2 4 8 1667 5297 4656 +8730 2 2 4 8 100 101 4689 +8731 2 2 4 8 1497 3903 4168 +8732 2 2 4 8 1703 4168 3903 +8733 2 2 4 8 108 109 4690 +8734 2 2 4 8 602 4968 2912 +8735 2 2 4 8 1496 4427 3144 +8736 2 2 4 8 2222 3158 4044 +8737 2 2 4 8 576 4044 3158 +8738 2 2 4 8 2272 5283 4627 +8739 2 2 4 8 732 4824 2942 +8740 2 2 4 8 1553 4062 4339 +8741 2 2 4 8 1138 5231 2901 +8742 2 2 4 8 1140 5232 2902 +8743 2 2 4 8 1329 3515 3765 +8744 2 2 4 8 1302 3076 4195 +8745 2 2 4 8 69 4713 68 +8746 2 2 4 8 704 3197 4671 +8747 2 2 4 8 2837 5158 5323 +8748 2 2 4 8 541 5323 5158 +8749 2 2 4 8 811 4170 3774 +8750 2 2 4 8 551 3331 4901 +8751 2 2 4 8 1403 4101 4109 +8752 2 2 4 8 1763 4109 4101 +8753 2 2 4 8 605 4784 2939 +8754 2 2 4 8 611 2936 4785 +8755 2 2 4 8 495 3501 3891 +8756 2 2 4 8 1478 3891 3501 +8757 2 2 4 8 358 359 4729 +8758 2 2 4 8 171 172 4730 +8759 2 2 4 8 2139 3172 4804 +8760 2 2 4 8 2140 3173 4805 +8761 2 2 4 8 116 4733 115 +8762 2 2 4 8 126 127 4734 +8763 2 2 4 8 138 4735 137 +8764 2 2 4 8 182 183 4736 +8765 2 2 4 8 300 301 4739 +8766 2 2 4 8 311 312 4738 +8767 2 2 4 8 290 4737 289 +8768 2 2 4 8 471 3106 4329 +8769 2 2 4 8 2284 5188 4303 +8770 2 2 4 8 2285 5187 4304 +8771 2 2 4 8 335 3925 3302 +8772 2 2 4 8 1401 4422 3056 +8773 2 2 4 8 261 3252 5161 +8774 2 2 4 8 1714 5161 3252 +8775 2 2 4 8 282 5162 3253 +8776 2 2 4 8 1715 3253 5162 +8777 2 2 4 8 1716 3254 5163 +8778 2 2 4 8 61 5163 3254 +8779 2 2 4 8 1318 5002 2918 +8780 2 2 4 8 1635 3455 3869 +8781 2 2 4 8 701 3869 3455 +8782 2 2 4 8 1230 4715 2961 +8783 2 2 4 8 1552 4589 4108 +8784 2 2 4 8 331 3120 4531 +8785 2 2 4 8 1574 4531 3120 +8786 2 2 4 8 1654 4375 3610 +8787 2 2 4 8 793 3610 4375 +8788 2 2 4 8 1303 4200 3151 +8789 2 2 4 8 2625 3706 4745 +8790 2 2 4 8 1390 3506 4365 +8791 2 2 4 8 1738 2965 5076 +8792 2 2 4 8 689 3546 3888 +8793 2 2 4 8 1510 3888 3546 +8794 2 2 4 8 523 2932 4893 +8795 2 2 4 8 1594 3985 3771 +8796 2 2 4 8 763 3771 3985 +8797 2 2 4 8 1537 4877 4436 +8798 2 2 4 8 2279 4436 4877 +8799 2 2 4 8 529 5047 3193 +8800 2 2 4 8 1658 3193 5047 +8801 2 2 4 8 4180 1832 4492 +8802 2 2 4 8 1068 2986 4891 +8803 2 2 4 8 1527 4891 2986 +8804 2 2 4 8 185 186 4791 +8805 2 2 4 8 1423 5375 3001 +8806 2 2 4 8 1601 4591 2994 +8807 2 2 4 8 1603 2995 4592 +8808 2 2 4 8 1602 4593 2996 +8809 2 2 4 8 1593 2948 4906 +8810 2 2 4 8 193 4906 2948 +8811 2 2 4 8 772 3430 3995 +8812 2 2 4 8 1997 3995 3430 +8813 2 2 4 8 1531 3704 4748 +8814 2 2 4 8 1367 4461 3325 +8815 2 2 4 8 823 4837 3192 +8816 2 2 4 8 814 4835 3189 +8817 2 2 4 8 815 4836 3190 +8818 2 2 4 8 789 4185 4767 +8819 2 2 4 8 1382 3884 3387 +8820 2 2 4 8 534 3033 4368 +8821 2 2 4 8 1448 5017 2989 +8822 2 2 4 8 1796 3523 5051 +8823 2 2 4 8 1471 3207 4207 +8824 2 2 4 8 524 4207 3207 +8825 2 2 4 8 1110 2917 5353 +8826 2 2 4 8 757 5141 3458 +8827 2 2 4 8 1790 3458 5141 +8828 2 2 4 8 79 4523 3598 +8829 2 2 4 8 1200 2932 5001 +8830 2 2 4 8 503 3353 4161 +8831 2 2 4 8 1225 3210 5100 +8832 2 2 4 8 1226 3211 5101 +8833 2 2 4 8 1431 3895 4577 +8834 2 2 4 8 710 4673 2988 +8835 2 2 4 8 1605 4526 3016 +8836 2 2 4 8 1606 3018 4527 +8837 2 2 4 8 1607 3017 4528 +8838 2 2 4 8 604 4986 2938 +8839 2 2 4 8 441 2991 4652 +8840 2 2 4 8 1041 4804 3172 +8841 2 2 4 8 1040 4805 3173 +8842 2 2 4 8 921 2924 5304 +8843 2 2 4 8 1554 3543 4153 +8844 2 2 4 8 661 4153 3543 +8845 2 2 4 8 1380 4121 3159 +8846 2 2 4 8 1381 4120 3160 +8847 2 2 4 8 1742 3987 4259 +8848 2 2 4 8 1423 3001 4794 +8849 2 2 4 8 918 3548 5173 +8850 2 2 4 8 1422 3520 4188 +8851 2 2 4 8 1331 3627 4228 +8852 2 2 4 8 1368 4479 3871 +8853 2 2 4 8 396 397 4921 +8854 2 2 4 8 792 4496 4315 +8855 2 2 4 8 2021 4315 4496 +8856 2 2 4 8 338 339 4933 +8857 2 2 4 8 579 5194 4232 +8858 2 2 4 8 328 329 4939 +8859 2 2 4 8 244 245 4953 +8860 2 2 4 8 1552 4108 4340 +8861 2 2 4 8 1630 5313 3782 +8862 2 2 4 8 1174 4899 3652 +8863 2 2 4 8 1685 2947 5072 +8864 2 2 4 8 4241 5237 1500 +8865 2 2 4 8 1538 3236 4905 +8866 2 2 4 8 614 2941 5176 +8867 2 2 4 8 1615 4733 3240 +8868 2 2 4 8 116 3240 4733 +8869 2 2 4 8 127 3241 4734 +8870 2 2 4 8 1614 4734 3241 +8871 2 2 4 8 1613 4735 3242 +8872 2 2 4 8 138 3242 4735 +8873 2 2 4 8 1612 4736 3243 +8874 2 2 4 8 183 3243 4736 +8875 2 2 4 8 1609 3245 4737 +8876 2 2 4 8 289 4737 3245 +8877 2 2 4 8 311 4738 3244 +8878 2 2 4 8 300 4739 3246 +8879 2 2 4 8 1611 3244 4738 +8880 2 2 4 8 1610 3246 4739 +8881 2 2 4 8 241 242 4998 +8882 2 2 4 8 630 3661 5236 +8883 2 2 4 8 1932 5236 3661 +8884 2 2 4 8 409 3366 4032 +8885 2 2 4 8 1514 4259 3987 +8886 2 2 4 8 611 4785 4530 +8887 2 2 4 8 2463 5014 3085 +8888 2 2 4 8 790 4198 4769 +8889 2 2 4 8 791 4199 4768 +8890 2 2 4 8 1510 4765 4480 +8891 2 2 4 8 1366 4345 3624 +8892 2 2 4 8 1880 3427 4327 +8893 2 2 4 8 764 4327 3427 +8894 2 2 4 8 1366 3415 4603 +8895 2 2 4 8 1034 4142 3178 +8896 2 2 4 8 1404 4307 3163 +8897 2 2 4 8 694 3000 5170 +8898 2 2 4 8 1152 3055 5041 +8899 2 2 4 8 240 4092 3401 +8900 2 2 4 8 830 3077 4754 +8901 2 2 4 8 787 4980 3835 +8902 2 2 4 8 1953 3835 4980 +8903 2 2 4 8 1155 5327 2942 +8904 2 2 4 8 16 5080 15 +8905 2 2 4 8 854 4865 4658 +8906 2 2 4 8 2357 4658 4865 +8907 2 2 4 8 1472 3025 4652 +8908 2 2 4 8 158 159 5087 +8909 2 2 4 8 379 380 5088 +8910 2 2 4 8 1473 2997 5125 +8911 2 2 4 8 48 5092 47 +8912 2 2 4 8 268 269 5093 +8913 2 2 4 8 81 82 5094 +8914 2 2 4 8 40 5103 39 +8915 2 2 4 8 880 5280 3368 +8916 2 2 4 8 881 5281 3367 +8917 2 2 4 8 851 4033 3268 +8918 2 2 4 8 1415 3268 4033 +8919 2 2 4 8 402 403 5366 +8920 2 2 4 8 203 204 5112 +8921 2 2 4 8 223 224 5113 +8922 2 2 4 8 616 3894 3910 +8923 2 2 4 8 1604 3910 3894 +8924 2 2 4 8 1512 5316 3041 +8925 2 2 4 8 106 3870 3692 +8926 2 2 4 8 1517 3692 3870 +8927 2 2 4 8 1664 2954 5102 +8928 2 2 4 8 893 4429 3140 +8929 2 2 4 8 892 4430 3141 +8930 2 2 4 8 891 4428 3142 +8931 2 2 4 8 152 153 5145 +8932 2 2 4 8 373 374 5146 +8933 2 2 4 8 234 235 5147 +8934 2 2 4 8 282 283 5162 +8935 2 2 4 8 260 261 5161 +8936 2 2 4 8 61 62 5163 +8937 2 2 4 8 1259 4753 2992 +8938 2 2 4 8 83 84 5190 +8939 2 2 4 8 49 50 5191 +8940 2 2 4 8 270 271 5192 +8941 2 2 4 8 1475 3388 3944 +8942 2 2 4 8 3422 1391 4536 +8943 2 2 4 8 3423 1392 4535 +8944 2 2 4 8 1393 3425 4534 +8945 2 2 4 8 1880 4327 4231 +8946 2 2 4 8 4231 4327 1637 +8947 2 2 4 8 1068 4898 4512 +8948 2 2 4 8 2300 4512 4898 +8949 2 2 4 8 1357 3935 3397 +8950 2 2 4 8 387 388 5216 +8951 2 2 4 8 144 145 5217 +8952 2 2 4 8 365 366 5218 +8953 2 2 4 8 1675 2960 5209 +8954 2 2 4 8 474 3107 5159 +8955 2 2 4 8 472 5160 3108 +8956 2 2 4 8 53 54 5253 +8957 2 2 4 8 275 5254 274 +8958 2 2 4 8 377 378 5265 +8959 2 2 4 8 156 157 5266 +8960 2 2 4 8 200 5271 199 +8961 2 2 4 8 227 228 5270 +8962 2 2 4 8 2887 3825 4712 +8963 2 2 4 8 1745 4112 4922 +8964 2 2 4 8 876 5066 4790 +8965 2 2 4 8 187 3332 4038 +8966 2 2 4 8 413 414 5308 +8967 2 2 4 8 1562 4832 4668 +8968 2 2 4 8 1953 4980 4556 +8969 2 2 4 8 2345 4556 4980 +8970 2 2 4 8 73 5361 72 +8971 2 2 4 8 375 376 5362 +8972 2 2 4 8 154 155 5363 +8973 2 2 4 8 784 3056 4422 +8974 2 2 4 8 1230 3679 4822 +8975 2 2 4 8 1789 4822 3679 +8976 2 2 4 8 511 4551 3036 +8977 2 2 4 8 427 4829 3287 +8978 2 2 4 8 1632 3287 4829 +8979 2 2 4 8 1633 3288 4830 +8980 2 2 4 8 209 4830 3288 +8981 2 2 4 8 1405 4509 3162 +8982 2 2 4 8 1406 4508 3166 +8983 2 2 4 8 1434 3608 4467 +8984 2 2 4 8 711 3475 4870 +8985 2 2 4 8 1732 5218 3316 +8986 2 2 4 8 366 3316 5218 +8987 2 2 4 8 145 3317 5217 +8988 2 2 4 8 3317 1731 5217 +8989 2 2 4 8 1730 3318 5216 +8990 2 2 4 8 387 5216 3318 +8991 2 2 4 8 1654 5239 2964 +8992 2 2 4 8 1473 3792 3647 +8993 2 2 4 8 4134 3023 4999 +8994 2 2 4 8 3024 5000 4135 +8995 2 2 4 8 1534 4385 3360 +8996 2 2 4 8 4238 5307 2321 +8997 2 2 4 8 535 5307 4238 +8998 2 2 4 8 1700 4202 3436 +8999 2 2 4 8 1273 3812 4821 +9000 2 2 4 8 1359 3038 4562 +9001 2 2 4 8 2132 4110 3448 +9002 2 2 4 8 1467 3448 4110 +9003 2 2 4 8 1470 3449 4111 +9004 2 2 4 8 2131 4111 3449 +9005 2 2 4 8 1175 3127 4285 +9006 2 2 4 8 241 4998 4092 +9007 2 2 4 8 2076 4092 4998 +9008 2 2 4 8 1809 4408 4517 +9009 2 2 4 8 812 4162 5269 +9010 2 2 4 8 1270 5166 3754 +9011 2 2 4 8 835 3203 4860 +9012 2 2 4 8 1600 3031 4642 +9013 2 2 4 8 480 4676 3028 +9014 2 2 4 8 479 4677 3027 +9015 2 2 4 8 1340 4097 5239 +9016 2 2 4 8 1404 3165 4767 +9017 2 2 4 8 1405 3164 4769 +9018 2 2 4 8 1406 3167 4768 +9019 2 2 4 8 727 3980 4030 +9020 2 2 4 8 1736 4030 3980 +9021 2 2 4 8 1158 3073 4432 +9022 2 2 4 8 1157 4433 3074 +9023 2 2 4 8 1681 3755 4151 +9024 2 2 4 8 711 4151 3755 +9025 2 2 4 8 2188 5353 3289 +9026 2 2 4 8 948 2989 5017 +9027 2 2 4 8 1114 4867 3003 +9028 2 2 4 8 1974 4860 3006 +9029 2 2 4 8 1773 4833 4080 +9030 2 2 4 8 1772 4834 4079 +9031 2 2 4 8 1607 5365 3017 +9032 2 2 4 8 1965 4763 4043 +9033 2 2 4 8 836 4043 4763 +9034 2 2 4 8 1220 3716 5144 +9035 2 2 4 8 1581 4469 3882 +9036 2 2 4 8 1496 3456 4964 +9037 2 2 4 8 1673 4000 4001 +9038 2 2 4 8 1418 4001 4000 +9039 2 2 4 8 1280 4537 3066 +9040 2 2 4 8 1573 3811 3773 +9041 2 2 4 8 712 4777 3453 +9042 2 2 4 8 801 4140 4931 +9043 2 2 4 8 799 4929 4139 +9044 2 2 4 8 798 4928 4137 +9045 2 2 4 8 800 4930 4138 +9046 2 2 4 8 1460 4070 3439 +9047 2 2 4 8 2112 3439 4070 +9048 2 2 4 8 2111 4068 3441 +9049 2 2 4 8 1464 3441 4068 +9050 2 2 4 8 2110 3440 4069 +9051 2 2 4 8 1461 4069 3440 +9052 2 2 4 8 2398 5193 2988 +9053 2 2 4 8 810 3520 4937 +9054 2 2 4 8 763 4624 3771 +9055 2 2 4 8 1244 3701 5288 +9056 2 2 4 8 836 4916 4043 +9057 2 2 4 8 1570 3431 4978 +9058 2 2 4 8 664 3853 3660 +9059 2 2 4 8 2081 3660 3853 +9060 2 2 4 8 1163 4392 3102 +9061 2 2 4 8 953 3398 5033 +9062 2 2 4 8 1705 5033 3398 +9063 2 2 4 8 1706 5034 3399 +9064 2 2 4 8 955 3399 5034 +9065 2 2 4 8 1704 3400 5032 +9066 2 2 4 8 954 5032 3400 +9067 2 2 4 8 1555 5064 3042 +9068 2 2 4 8 1075 5064 2997 +9069 2 2 4 8 4232 5194 2136 +9070 2 2 4 8 1382 4568 3884 +9071 2 2 4 8 1537 3255 4972 +9072 2 2 4 8 2208 3518 4896 +9073 2 2 4 8 1531 4477 4263 +9074 2 2 4 8 861 4352 5378 +9075 2 2 4 8 1760 3759 3954 +9076 2 2 4 8 716 3954 3759 +9077 2 2 4 8 717 3955 3758 +9078 2 2 4 8 1759 3758 3955 +9079 2 2 4 8 1109 3325 4461 +9080 2 2 4 8 4180 4492 1582 +9081 2 2 4 8 1357 4628 3753 +9082 2 2 4 8 1621 4996 3004 +9083 2 2 4 8 715 3960 3760 +9084 2 2 4 8 1758 3760 3960 +9085 2 2 4 8 555 5125 2997 +9086 2 2 4 8 593 4174 4117 +9087 2 2 4 8 2099 4117 4174 +9088 2 2 4 8 2100 4175 4118 +9089 2 2 4 8 594 4118 4175 +9090 2 2 4 8 1670 4478 3086 +9091 2 2 4 8 1561 4144 3278 +9092 2 2 4 8 1183 3056 4817 +9093 2 2 4 8 1456 3677 5037 +9094 2 2 4 8 337 3117 4386 +9095 2 2 4 8 1394 3508 5329 +9096 2 2 4 8 1395 3509 5328 +9097 2 2 4 8 1701 4076 5242 +9098 2 2 4 8 2937 5181 3537 +9099 2 2 4 8 2936 5180 3536 +9100 2 2 4 8 2939 3538 5178 +9101 2 2 4 8 2938 3539 5179 +9102 2 2 4 8 1627 4100 3852 +9103 2 2 4 8 678 3852 4100 +9104 2 2 4 8 735 3326 5151 +9105 2 2 4 8 710 3026 4831 +9106 2 2 4 8 858 5382 3209 +9107 2 2 4 8 1203 5086 3164 +9108 2 2 4 8 1205 5085 3167 +9109 2 2 4 8 860 4438 5358 +9110 2 2 4 8 3832 2942 5327 +9111 2 2 4 8 1411 3851 3852 +9112 2 2 4 8 1627 3852 3851 +9113 2 2 4 8 503 3163 4307 +9114 2 2 4 8 511 5227 4005 +9115 2 2 4 8 1457 3904 3568 +9116 2 2 4 8 898 3341 4084 +9117 2 2 4 8 4162 2158 5269 +9118 2 2 4 8 1443 4454 3096 +9119 2 2 4 8 1442 4455 3095 +9120 2 2 4 8 1444 3097 4456 +9121 2 2 4 8 1445 3098 4457 +9122 2 2 4 8 1446 3099 4458 +9123 2 2 4 8 1447 3100 4459 +9124 2 2 4 8 1493 4372 3234 +9125 2 2 4 8 542 3234 4372 +9126 2 2 4 8 1465 3243 4599 +9127 2 2 4 8 1390 4365 3802 +9128 2 2 4 8 1597 3128 5284 +9129 2 2 4 8 1477 3037 4806 +9130 2 2 4 8 795 3506 4119 +9131 2 2 4 8 2162 4983 4288 +9132 2 2 4 8 1623 4288 4983 +9133 2 2 4 8 22 3343 4091 +9134 2 2 4 8 553 4902 4064 +9135 2 2 4 8 2017 4064 4902 +9136 2 2 4 8 1116 5386 3004 +9137 2 2 4 8 1621 3004 5386 +9138 2 2 4 8 1158 4610 3073 +9139 2 2 4 8 1157 3074 4609 +9140 2 2 4 8 418 4255 3311 +9141 2 2 4 8 548 5153 3007 +9142 2 2 4 8 714 3022 4971 +9143 2 2 4 8 1360 4215 3254 +9144 2 2 4 8 1362 4214 3253 +9145 2 2 4 8 1361 3252 4213 +9146 2 2 4 8 1289 4237 3391 +9147 2 2 4 8 1436 3737 5189 +9148 2 2 4 8 1901 5189 3737 +9149 2 2 4 8 1931 3053 4701 +9150 2 2 4 8 1693 5391 2998 +9151 2 2 4 8 973 3001 5375 +9152 2 2 4 8 1609 3112 5320 +9153 2 2 4 8 1420 3773 3811 +9154 2 2 4 8 1632 3023 4943 +9155 2 2 4 8 1633 3024 4944 +9156 2 2 4 8 2117 4887 3205 +9157 2 2 4 8 1114 3003 5292 +9158 2 2 4 8 1579 5292 3003 +9159 2 2 4 8 1801 3775 4818 +9160 2 2 4 8 1360 4818 3775 +9161 2 2 4 8 1519 3415 4048 +9162 2 2 4 8 1613 5322 3114 +9163 2 2 4 8 1832 4180 3481 +9164 2 2 4 8 577 3562 4063 +9165 2 2 4 8 1808 3942 4323 +9166 2 2 4 8 901 3850 5385 +9167 2 2 4 8 2055 5385 3850 +9168 2 2 4 8 2217 5244 3008 +9169 2 2 4 8 1015 3704 5346 +9170 2 2 4 8 1570 4446 3431 +9171 2 2 4 8 619 3431 4446 +9172 2 2 4 8 4216 1796 5051 +9173 2 2 4 8 1086 5228 3010 +9174 2 2 4 8 1577 4145 3714 +9175 2 2 4 8 504 3714 4145 +9176 2 2 4 8 1578 4146 3715 +9177 2 2 4 8 505 3715 4146 +9178 2 2 4 8 1632 4999 3023 +9179 2 2 4 8 1633 5000 3024 +9180 2 2 4 8 740 4740 3058 +9181 2 2 4 8 742 4741 3059 +9182 2 2 4 8 1310 4197 3272 +9183 2 2 4 8 1311 4196 3273 +9184 2 2 4 8 161 3631 4347 +9185 2 2 4 8 1437 3738 5202 +9186 2 2 4 8 1900 5202 3738 +9187 2 2 4 8 720 5264 3060 +9188 2 2 4 8 489 5057 4670 +9189 2 2 4 8 1274 4357 3565 +9190 2 2 4 8 1326 4777 3051 +9191 2 2 4 8 2136 3257 4232 +9192 2 2 4 8 828 3389 4093 +9193 2 2 4 8 787 3700 4980 +9194 2 2 4 8 1427 3277 4376 +9195 2 2 4 8 1531 4748 4477 +9196 2 2 4 8 2134 4477 4748 +9197 2 2 4 8 1402 3676 3882 +9198 2 2 4 8 1424 4698 3218 +9199 2 2 4 8 1627 3699 4100 +9200 2 2 4 8 1327 3618 3922 +9201 2 2 4 8 1328 3923 3619 +9202 2 2 4 8 834 3075 4695 +9203 2 2 4 8 833 3076 4694 +9204 2 2 4 8 4142 2781 4329 +9205 2 2 4 8 2438 5120 4725 +9206 2 2 4 8 749 4725 5120 +9207 2 2 4 8 1742 3566 3987 +9208 2 2 4 8 1741 3567 3986 +9209 2 2 4 8 1605 3016 5376 +9210 2 2 4 8 1606 5377 3018 +9211 2 2 4 8 2370 3512 4563 +9212 2 2 4 8 1130 4563 3512 +9213 2 2 4 8 2009 4025 3906 +9214 2 2 4 8 1088 3021 5241 +9215 2 2 4 8 831 3898 5009 +9216 2 2 4 8 2592 5144 3716 +9217 2 2 4 8 1299 3943 3599 +9218 2 2 4 8 2474 3313 5330 +9219 2 2 4 8 2356 3361 4656 +9220 2 2 4 8 1258 4410 3974 +9221 2 2 4 8 1822 3974 4410 +9222 2 2 4 8 1391 3648 4536 +9223 2 2 4 8 1392 3649 4535 +9224 2 2 4 8 1393 4534 3650 +9225 2 2 4 8 1307 3866 4635 +9226 2 2 4 8 1959 4073 4783 +9227 2 2 4 8 835 4783 4073 +9228 2 2 4 8 1991 4256 4683 +9229 2 2 4 8 838 4683 4256 +9230 2 2 4 8 1163 3102 4619 +9231 2 2 4 8 2932 3610 5001 +9232 2 2 4 8 1353 4102 3416 +9233 2 2 4 8 1398 3329 4402 +9234 2 2 4 8 1614 5342 3115 +9235 2 2 4 8 1615 5343 3116 +9236 2 2 4 8 1851 4866 3179 +9237 2 2 4 8 1316 3136 4521 +9238 2 2 4 8 1317 3138 4522 +9239 2 2 4 8 4227 4752 2236 +9240 2 2 4 8 1271 3690 3989 +9241 2 2 4 8 2546 4838 3462 +9242 2 2 4 8 889 3942 4957 +9243 2 2 4 8 1931 4957 3942 +9244 2 2 4 8 1107 3030 5127 +9245 2 2 4 8 932 3986 3567 +9246 2 2 4 8 933 3987 3566 +9247 2 2 4 8 1682 3664 4624 +9248 2 2 4 8 1425 4624 3664 +9249 2 2 4 8 1375 4434 3630 +9250 2 2 4 8 720 5150 3029 +9251 2 2 4 8 1670 3086 4699 +9252 2 2 4 8 1243 5028 3120 +9253 2 2 4 8 1574 3120 5028 +9254 2 2 4 8 906 3063 4849 +9255 2 2 4 8 850 3264 4800 +9256 2 2 4 8 741 4897 3050 +9257 2 2 4 8 507 4625 3276 +9258 2 2 4 8 1361 3633 5039 +9259 2 2 4 8 1362 5038 3632 +9260 2 2 4 8 1473 5125 3088 +9261 2 2 4 8 2607 5345 4841 +9262 2 2 4 8 1836 4841 5345 +9263 2 2 4 8 1949 4479 5388 +9264 2 2 4 8 2296 4670 5057 +9265 2 2 4 8 1442 4573 3693 +9266 2 2 4 8 1443 4574 3694 +9267 2 2 4 8 1444 3695 4572 +9268 2 2 4 8 1445 3696 4571 +9269 2 2 4 8 1447 3698 4569 +9270 2 2 4 8 1446 3697 4570 +9271 2 2 4 8 2732 4612 5320 +9272 2 2 4 8 1854 3180 4646 +9273 2 2 4 8 1504 4438 4280 +9274 2 2 4 8 1889 4280 4438 +9275 2 2 4 8 1496 4558 4427 +9276 2 2 4 8 2011 4427 4558 +9277 2 2 4 8 720 3029 5264 +9278 2 2 4 8 1378 3316 4293 +9279 2 2 4 8 3317 4294 1379 +9280 2 2 4 8 1377 4295 3318 +9281 2 2 4 8 855 5166 3324 +9282 2 2 4 8 1681 3607 3982 +9283 2 2 4 8 712 4993 3051 +9284 2 2 4 8 2193 4039 3731 +9285 2 2 4 8 1251 3731 4039 +9286 2 2 4 8 826 3899 4955 +9287 2 2 4 8 2017 4955 3899 +9288 2 2 4 8 1603 3522 4914 +9289 2 2 4 8 752 3307 4273 +9290 2 2 4 8 753 4274 3308 +9291 2 2 4 8 2084 3652 4899 +9292 2 2 4 8 505 3166 4508 +9293 2 2 4 8 504 3162 4509 +9294 2 2 4 8 721 3433 4555 +9295 2 2 4 8 1225 5100 3544 +9296 2 2 4 8 1226 5101 3545 +9297 2 2 4 8 1553 4339 3250 +9298 2 2 4 8 1552 4340 3251 +9299 2 2 4 8 831 4310 4762 +9300 2 2 4 8 522 3196 4821 +9301 2 2 4 8 536 3677 4398 +9302 2 2 4 8 1242 5003 3683 +9303 2 2 4 8 1159 5065 3049 +9304 2 2 4 8 1174 4934 3402 +9305 2 2 4 8 851 3268 4635 +9306 2 2 4 8 1378 3826 4894 +9307 2 2 4 8 1828 4894 3826 +9308 2 2 4 8 443 3235 4562 +9309 2 2 4 8 828 4093 3975 +9310 2 2 4 8 1374 4347 3631 +9311 2 2 4 8 613 5172 4227 +9312 2 2 4 8 763 3985 3699 +9313 2 2 4 8 1511 3699 3985 +9314 2 2 4 8 1599 4988 3897 +9315 2 2 4 8 1598 3896 4987 +9316 2 2 4 8 1604 3894 3983 +9317 2 2 4 8 1668 4731 4251 +9318 2 2 4 8 1984 4251 4731 +9319 2 2 4 8 493 4176 4839 +9320 2 2 4 8 542 5419 3234 +9321 2 2 4 8 1702 3234 5419 +9322 2 2 4 8 1478 3489 4362 +9323 2 2 4 8 2093 3515 4530 +9324 2 2 4 8 1995 5293 4371 +9325 2 2 4 8 837 4990 3068 +9326 2 2 4 8 836 4991 3069 +9327 2 2 4 8 854 3198 4979 +9328 2 2 4 8 1580 3060 5264 +9329 2 2 4 8 1475 3944 5302 +9330 2 2 4 8 1576 3822 4059 +9331 2 2 4 8 499 4059 3822 +9332 2 2 4 8 1575 3823 4060 +9333 2 2 4 8 501 4060 3823 +9334 2 2 4 8 1379 3464 5136 +9335 2 2 4 8 1722 5136 3464 +9336 2 2 4 8 2238 5008 4511 +9337 2 2 4 8 1596 4511 5008 +9338 2 2 4 8 831 3393 4310 +9339 2 2 4 8 1421 3408 5157 +9340 2 2 4 8 1241 3220 4596 +9341 2 2 4 8 1594 3956 3985 +9342 2 2 4 8 1511 3985 3956 +9343 2 2 4 8 523 3932 3764 +9344 2 2 4 8 1156 4529 3204 +9345 2 2 4 8 746 4302 3457 +9346 2 2 4 8 1517 3457 4302 +9347 2 2 4 8 1434 4119 3506 +9348 2 2 4 8 1986 4063 3562 +9349 2 2 4 8 1665 3764 3932 +9350 2 2 4 8 929 3078 5018 +9351 2 2 4 8 850 4393 3264 +9352 2 2 4 8 834 5052 3075 +9353 2 2 4 8 830 5053 3077 +9354 2 2 4 8 1781 4862 5325 +9355 2 2 4 8 1085 5322 3050 +9356 2 2 4 8 2272 3757 5283 +9357 2 2 4 8 1636 5283 3757 +9358 2 2 4 8 537 3767 5046 +9359 2 2 4 8 1826 5046 3767 +9360 2 2 4 8 506 4376 3277 +9361 2 2 4 8 1988 4762 4310 +9362 2 2 4 8 1618 4554 4981 +9363 2 2 4 8 1620 4719 3836 +9364 2 2 4 8 1699 4108 4589 +9365 2 2 4 8 809 5149 3948 +9366 2 2 4 8 348 3630 4434 +9367 2 2 4 8 2002 3085 5014 +9368 2 2 4 8 729 3314 4363 +9369 2 2 4 8 4195 4814 1302 +9370 2 2 4 8 1083 5343 3058 +9371 2 2 4 8 1084 5342 3059 +9372 2 2 4 8 1616 3891 3890 +9373 2 2 4 8 1478 3890 3891 +9374 2 2 4 8 1204 5135 3165 +9375 2 2 4 8 797 4926 4234 +9376 2 2 4 8 1628 3490 5311 +9377 2 2 4 8 1312 4282 3400 +9378 2 2 4 8 1156 3204 4616 +9379 2 2 4 8 617 3490 4745 +9380 2 2 4 8 1628 4745 3490 +9381 2 2 4 8 457 3223 5384 +9382 2 2 4 8 1674 5384 3223 +9383 2 2 4 8 1706 4270 4046 +9384 2 2 4 8 864 4046 4270 +9385 2 2 4 8 1170 4471 3447 +9386 2 2 4 8 763 3104 4956 +9387 2 2 4 8 762 3481 4180 +9388 2 2 4 8 1631 5305 4746 +9389 2 2 4 8 2492 4746 5305 +9390 2 2 4 8 1503 3161 4789 +9391 2 2 4 8 1291 3979 3978 +9392 2 2 4 8 2622 3978 3979 +9393 2 2 4 8 1333 3598 4523 +9394 2 2 4 8 1359 4671 3197 +9395 2 2 4 8 1591 4517 4408 +9396 2 2 4 8 1186 5352 3342 +9397 2 2 4 8 1600 3521 5049 +9398 2 2 4 8 1185 3203 4691 +9399 2 2 4 8 1583 4310 3393 +9400 2 2 4 8 4793 3461 5197 +9401 2 2 4 8 1680 3294 5306 +9402 2 2 4 8 631 5306 3294 +9403 2 2 4 8 770 5250 4154 +9404 2 2 4 8 1938 3578 4974 +9405 2 2 4 8 3579 4975 1939 +9406 2 2 4 8 1218 3257 4538 +9407 2 2 4 8 1638 3844 4324 +9408 2 2 4 8 517 4324 3844 +9409 2 2 4 8 1639 4325 3845 +9410 2 2 4 8 520 3845 4325 +9411 2 2 4 8 789 4767 3165 +9412 2 2 4 8 791 4768 3167 +9413 2 2 4 8 790 4769 3164 +9414 2 2 4 8 766 4080 4423 +9415 2 2 4 8 767 4079 4424 +9416 2 2 4 8 1946 3753 4628 +9417 2 2 4 8 2117 5381 4074 +9418 2 2 4 8 901 4074 5381 +9419 2 2 4 8 751 4789 3161 +9420 2 2 4 8 522 4714 3196 +9421 2 2 4 8 583 3289 4814 +9422 2 2 4 8 1487 3335 4481 +9423 2 2 4 8 1144 4581 5369 +9424 2 2 4 8 2403 5369 4581 +9425 2 2 4 8 2081 4154 5250 +9426 2 2 4 8 1635 4857 3455 +9427 2 2 4 8 1238 3455 4857 +9428 2 2 4 8 249 4169 4749 +9429 2 2 4 8 1240 3360 4385 +9430 2 2 4 8 203 5112 3129 +9431 2 2 4 8 2066 3129 5112 +9432 2 2 4 8 224 3130 5113 +9433 2 2 4 8 2067 5113 3130 +9434 2 2 4 8 4307 1815 4346 +9435 2 2 4 8 503 4307 4346 +9436 2 2 4 8 1697 4062 4236 +9437 2 2 4 8 1553 4236 4062 +9438 2 2 4 8 810 4188 3520 +9439 2 2 4 8 913 5148 3613 +9440 2 2 4 8 1006 4065 4922 +9441 2 2 4 8 1308 3702 4045 +9442 2 2 4 8 617 4745 3706 +9443 2 2 4 8 1498 3665 4851 +9444 2 2 4 8 541 5158 3171 +9445 2 2 4 8 1592 3171 5158 +9446 2 2 4 8 1305 3761 4287 +9447 2 2 4 8 879 5195 5063 +9448 2 2 4 8 1793 4141 3616 +9449 2 2 4 8 1366 4603 4002 +9450 2 2 4 8 1305 4287 3450 +9451 2 2 4 8 1367 3931 4461 +9452 2 2 4 8 1489 3334 4607 +9453 2 2 4 8 1838 4576 4662 +9454 2 2 4 8 1837 4575 4661 +9455 2 2 4 8 713 3218 4698 +9456 2 2 4 8 1485 4747 3743 +9457 2 2 4 8 758 4598 3271 +9458 2 2 4 8 757 4786 5141 +9459 2 2 4 8 2397 5141 4786 +9460 2 2 4 8 1393 4470 5102 +9461 2 2 4 8 2330 5070 4019 +9462 2 2 4 8 1242 3137 5003 +9463 2 2 4 8 2216 5233 4358 +9464 2 2 4 8 1173 4358 5233 +9465 2 2 4 8 966 4700 3219 +9466 2 2 4 8 2273 5285 3549 +9467 2 2 4 8 516 4481 3335 +9468 2 2 4 8 1647 3575 5338 +9469 2 2 4 8 1648 5339 3577 +9470 2 2 4 8 1852 3378 4677 +9471 2 2 4 8 1853 3379 4676 +9472 2 2 4 8 1545 3667 4218 +9473 2 2 4 8 894 4218 3667 +9474 2 2 4 8 1186 3411 5352 +9475 2 2 4 8 474 5221 3107 +9476 2 2 4 8 472 3108 5222 +9477 2 2 4 8 210 3435 4830 +9478 2 2 4 8 428 3434 4829 +9479 2 2 4 8 452 5169 4917 +9480 2 2 4 8 2472 4917 5169 +9481 2 2 4 8 758 3271 4900 +9482 2 2 4 8 1673 4022 4181 +9483 2 2 4 8 763 4956 4624 +9484 2 2 4 8 2113 4250 3856 +9485 2 2 4 8 1758 4448 5412 +9486 2 2 4 8 1484 3206 4843 +9487 2 2 4 8 1426 3276 4625 +9488 2 2 4 8 1499 3983 3894 +9489 2 2 4 8 2337 5417 5078 +9490 2 2 4 8 1909 3095 5399 +9491 2 2 4 8 1908 5398 3097 +9492 2 2 4 8 1910 3096 5400 +9493 2 2 4 8 1907 5397 3098 +9494 2 2 4 8 1906 5396 3099 +9495 2 2 4 8 1905 5395 3100 +9496 2 2 4 8 718 4702 3247 +9497 2 2 4 8 538 4924 4761 +9498 2 2 4 8 2274 4761 4924 +9499 2 2 4 8 1636 3915 5139 +9500 2 2 4 8 1799 4779 3212 +9501 2 2 4 8 1798 4778 3213 +9502 2 2 4 8 1702 5420 3499 +9503 2 2 4 8 2335 5412 5062 +9504 2 2 4 8 2018 4277 4903 +9505 2 2 4 8 552 4903 4277 +9506 2 2 4 8 1154 5070 3417 +9507 2 2 4 8 2502 5018 3563 +9508 2 2 4 8 2036 4728 4493 +9509 2 2 4 8 1555 4493 4728 +9510 2 2 4 8 1203 3510 5086 +9511 2 2 4 8 1205 3511 5085 +9512 2 2 4 8 1542 3322 5123 +9513 2 2 4 8 3492 1878 4331 +9514 2 2 4 8 2441 5063 5195 +9515 2 2 4 8 1298 4904 3193 +9516 2 2 4 8 1389 4234 3801 +9517 2 2 4 8 1629 3285 5185 +9518 2 2 4 8 649 5185 3285 +9519 2 2 4 8 456 4298 5391 +9520 2 2 4 8 1250 3780 5273 +9521 2 2 4 8 1867 5273 3780 +9522 2 2 4 8 1802 3802 4365 +9523 2 2 4 8 1759 4440 5417 +9524 2 2 4 8 1305 4186 3761 +9525 2 2 4 8 2496 3661 4587 +9526 2 2 4 8 512 4607 3334 +9527 2 2 4 8 846 4788 3232 +9528 2 2 4 8 1193 3384 4513 +9529 2 2 4 8 1192 3383 4514 +9530 2 2 4 8 691 3542 4292 +9531 2 2 4 8 796 3688 4631 +9532 2 2 4 8 345 5015 3177 +9533 2 2 4 8 1584 4538 4256 +9534 2 2 4 8 782 3884 4568 +9535 2 2 4 8 1147 5225 4403 +9536 2 2 4 8 2206 4403 5225 +9537 2 2 4 8 1516 4555 3433 +9538 2 2 4 8 104 4395 3443 +9539 2 2 4 8 1547 4203 4151 +9540 2 2 4 8 1681 4151 4203 +9541 2 2 4 8 526 4603 3415 +9542 2 2 4 8 1699 4589 3824 +9543 2 2 4 8 491 3824 4589 +9544 2 2 4 8 1346 3906 4025 +9545 2 2 4 8 1155 5413 3131 +9546 2 2 4 8 719 4362 3489 +9547 2 2 4 8 1746 4244 4245 +9548 2 2 4 8 1507 4245 4244 +9549 2 2 4 8 4242 4243 1747 +9550 2 2 4 8 1508 4243 4242 +9551 2 2 4 8 449 4771 5249 +9552 2 2 4 8 1619 5201 4968 +9553 2 2 4 8 2401 5249 4771 +9554 2 2 4 8 905 3152 5247 +9555 2 2 4 8 2475 5351 3380 +9556 2 2 4 8 2164 4973 5263 +9557 2 2 4 8 2088 4322 4861 +9558 2 2 4 8 1332 4249 3626 +9559 2 2 4 8 718 3395 4702 +9560 2 2 4 8 1535 4258 4696 +9561 2 2 4 8 1632 3434 4999 +9562 2 2 4 8 1313 4999 3434 +9563 2 2 4 8 1314 5000 3435 +9564 2 2 4 8 1633 3435 5000 +9565 2 2 4 8 1324 3378 4602 +9566 2 2 4 8 904 4103 4442 +9567 2 2 4 8 795 4365 3506 +9568 2 2 4 8 1488 3582 4970 +9569 2 2 4 8 1491 3581 4969 +9570 2 2 4 8 864 3738 5393 +9571 2 2 4 8 1261 3258 4847 +9572 2 2 4 8 1972 4707 4694 +9573 2 2 4 8 1809 3941 4408 +9574 2 2 4 8 804 3422 4536 +9575 2 2 4 8 802 4534 3425 +9576 2 2 4 8 3423 4535 803 +9577 2 2 4 8 745 5220 3186 +9578 2 2 4 8 1667 4017 4940 +9579 2 2 4 8 2478 4413 4905 +9580 2 2 4 8 793 4375 5272 +9581 2 2 4 8 1151 4656 3361 +9582 2 2 4 8 1516 3349 4966 +9583 2 2 4 8 1202 4815 3278 +9584 2 2 4 8 1800 5077 3830 +9585 2 2 4 8 840 3830 5077 +9586 2 2 4 8 1537 4436 3542 +9587 2 2 4 8 1294 3542 4436 +9588 2 2 4 8 1293 3541 4437 +9589 2 2 4 8 1538 4437 3541 +9590 2 2 4 8 1510 3546 4547 +9591 2 2 4 8 774 5084 3371 +9592 2 2 4 8 1621 3620 4996 +9593 2 2 4 8 531 4825 3351 +9594 2 2 4 8 1559 3351 4825 +9595 2 2 4 8 532 4826 3352 +9596 2 2 4 8 1560 3352 4826 +9597 2 2 4 8 1388 4268 4631 +9598 2 2 4 8 2063 4631 4268 +9599 2 2 4 8 2566 5407 4962 +9600 2 2 4 8 1181 4962 5407 +9601 2 2 4 8 797 4234 3687 +9602 2 2 4 8 1711 3779 4801 +9603 2 2 4 8 793 4801 3779 +9604 2 2 4 8 841 4628 3397 +9605 2 2 4 8 1567 3348 5235 +9606 2 2 4 8 1536 3310 5287 +9607 2 2 4 8 1533 4374 4399 +9608 2 2 4 8 1832 4399 4374 +9609 2 2 4 8 1912 3525 4388 +9610 2 2 4 8 1483 5262 3505 +9611 2 2 4 8 744 5226 3194 +9612 2 2 4 8 1372 4298 3636 +9613 2 2 4 8 1423 3774 4170 +9614 2 2 4 8 1490 3583 4415 +9615 2 2 4 8 1184 4697 3468 +9616 2 2 4 8 1891 3468 4697 +9617 2 2 4 8 1384 3857 4140 +9618 2 2 4 8 1385 4137 3859 +9619 2 2 4 8 1387 4138 3860 +9620 2 2 4 8 1386 4139 3858 +9621 2 2 4 8 613 3383 4679 +9622 2 2 4 8 606 3384 4680 +9623 2 2 4 8 1802 4365 4855 +9624 2 2 4 8 1465 4552 3454 +9625 2 2 4 8 1973 4695 3516 +9626 2 2 4 8 1972 4694 3517 +9627 2 2 4 8 592 4686 4750 +9628 2 2 4 8 2075 4750 4686 +9629 2 2 4 8 796 4388 3688 +9630 2 2 4 8 1262 3199 5276 +9631 2 2 4 8 1336 4937 3520 +9632 2 2 4 8 1513 5312 3606 +9633 2 2 4 8 1776 3742 4235 +9634 2 2 4 8 760 3882 4469 +9635 2 2 4 8 1528 4833 3965 +9636 2 2 4 8 1529 4834 3966 +9637 2 2 4 8 1345 3681 4326 +9638 2 2 4 8 445 4772 3416 +9639 2 2 4 8 1556 3416 4772 +9640 2 2 4 8 1344 3710 4643 +9641 2 2 4 8 1720 5323 3498 +9642 2 2 4 8 541 3498 5323 +9643 2 2 4 8 1189 3365 5244 +9644 2 2 4 8 1479 3354 5337 +9645 2 2 4 8 1481 5336 3355 +9646 2 2 4 8 1480 5335 3356 +9647 2 2 4 8 2586 3353 5011 +9648 2 2 4 8 2259 4488 3968 +9649 2 2 4 8 1285 3968 4488 +9650 2 2 4 8 1713 4693 3938 +9651 2 2 4 8 1918 3938 4693 +9652 2 2 4 8 253 4813 3347 +9653 2 2 4 8 1185 4691 3429 +9654 2 2 4 8 415 5324 3202 +9655 2 2 4 8 2008 5041 3265 +9656 2 2 4 8 1757 5117 3729 +9657 2 2 4 8 1354 3729 5117 +9658 2 2 4 8 1137 3756 4623 +9659 2 2 4 8 1671 5378 3200 +9660 2 2 4 8 1338 3623 5243 +9661 2 2 4 8 1775 4568 3488 +9662 2 2 4 8 1552 4075 4589 +9663 2 2 4 8 1659 5196 3451 +9664 2 2 4 8 1233 3451 5196 +9665 2 2 4 8 2379 5301 3584 +9666 2 2 4 8 1325 3379 4766 +9667 2 2 4 8 1557 5153 3528 +9668 2 2 4 8 782 4359 3884 +9669 2 2 4 8 194 4483 4906 +9670 2 2 4 8 1757 3259 5117 +9671 2 2 4 8 543 5122 3601 +9672 2 2 4 8 738 4239 4095 +9673 2 2 4 8 1729 4095 4239 +9674 2 2 4 8 2665 5071 3407 +9675 2 2 4 8 1941 3407 5071 +9676 2 2 4 8 725 4914 3522 +9677 2 2 4 8 1552 3251 5154 +9678 2 2 4 8 1528 3965 4945 +9679 2 2 4 8 1529 3966 4946 +9680 2 2 4 8 1973 4782 4695 +9681 2 2 4 8 1183 4817 3469 +9682 2 2 4 8 1513 3642 4888 +9683 2 2 4 8 1539 5108 3269 +9684 2 2 4 8 1540 5109 3270 +9685 2 2 4 8 575 3769 4306 +9686 2 2 4 8 1398 3569 5277 +9687 2 2 4 8 1720 5277 3569 +9688 2 2 4 8 481 3713 4447 +9689 2 2 4 8 1584 4447 3713 +9690 2 2 4 8 2087 5387 3770 +9691 2 2 4 8 2035 4949 4396 +9692 2 2 4 8 811 4396 4949 +9693 2 2 4 8 1534 4277 4385 +9694 2 2 4 8 1500 5237 3239 +9695 2 2 4 8 797 3687 4331 +9696 2 2 4 8 1458 3418 4932 +9697 2 2 4 8 1459 3419 4925 +9698 2 2 4 8 1536 5287 3397 +9699 2 2 4 8 578 5062 5412 +9700 2 2 4 8 587 5078 5417 +9701 2 2 4 8 4240 2619 4982 +9702 2 2 4 8 620 4240 4982 +9703 2 2 4 8 1795 3836 5147 +9704 2 2 4 8 234 5147 3836 +9705 2 2 4 8 847 3275 5121 +9706 2 2 4 8 1616 3596 4742 +9707 2 2 4 8 1254 4742 3596 +9708 2 2 4 8 1290 4547 3546 +9709 2 2 4 8 2286 4979 3328 +9710 2 2 4 8 1869 4078 4194 +9711 2 2 4 8 566 3279 5367 +9712 2 2 4 8 1877 4502 5318 +9713 2 2 4 8 801 4646 3482 +9714 2 2 4 8 1289 3758 5128 +9715 2 2 4 8 1759 5128 3758 +9716 2 2 4 8 1760 5129 3759 +9717 2 2 4 8 1295 3759 5129 +9718 2 2 4 8 1291 3760 5124 +9719 2 2 4 8 1758 5124 3760 +9720 2 2 4 8 1319 4428 4027 +9721 2 2 4 8 1321 4429 4028 +9722 2 2 4 8 1320 4430 4029 +9723 2 2 4 8 589 4681 3469 +9724 2 2 4 8 833 4694 4707 +9725 2 2 4 8 1250 5273 4150 +9726 2 2 4 8 1583 3712 4482 +9727 2 2 4 8 470 4482 3712 +9728 2 2 4 8 1860 4908 4125 +9729 2 2 4 8 826 4125 4908 +9730 2 2 4 8 1859 4907 4126 +9731 2 2 4 8 827 4126 4907 +9732 2 2 4 8 1372 4301 3772 +9733 2 2 4 8 1780 4893 5321 +9734 2 2 4 8 566 5367 3291 +9735 2 2 4 8 1678 5382 3228 +9736 2 2 4 8 2274 5242 5304 +9737 2 2 4 8 1545 3333 5006 +9738 2 2 4 8 1544 4306 3769 +9739 2 2 4 8 1649 4662 4576 +9740 2 2 4 8 1646 4661 4575 +9741 2 2 4 8 525 4966 3349 +9742 2 2 4 8 513 3856 4250 +9743 2 2 4 8 612 4732 4981 +9744 2 2 4 8 2178 4981 4732 +9745 2 2 4 8 2090 3412 4835 +9746 2 2 4 8 2091 3413 4836 +9747 2 2 4 8 2092 3414 4837 +9748 2 2 4 8 1041 4148 4804 +9749 2 2 4 8 1040 4149 4805 +9750 2 2 4 8 2916 4316 4476 +9751 2 2 4 8 802 3425 4807 +9752 2 2 4 8 1278 5210 3281 +9753 2 2 4 8 1582 4492 3727 +9754 2 2 4 8 705 3727 4492 +9755 2 2 4 8 1512 3666 5316 +9756 2 2 4 8 1719 4713 5413 +9757 2 2 4 8 1569 4487 3689 +9758 2 2 4 8 571 3689 4487 +9759 2 2 4 8 1456 4398 3677 +9760 2 2 4 8 2001 5011 3353 +9761 2 2 4 8 1708 4725 5039 +9762 2 2 4 8 1709 5038 4726 +9763 2 2 4 8 1784 3947 4939 +9764 2 2 4 8 328 4939 3947 +9765 2 2 4 8 1520 4472 4473 +9766 2 2 4 8 1955 4473 4472 +9767 2 2 4 8 1521 4474 4475 +9768 2 2 4 8 1956 4475 4474 +9769 2 2 4 8 702 4470 3650 +9770 2 2 4 8 509 3628 4515 +9771 2 2 4 8 514 3629 4516 +9772 2 2 4 8 489 3419 5057 +9773 2 2 4 8 1838 4014 4576 +9774 2 2 4 8 1837 4013 4575 +9775 2 2 4 8 1632 4829 3434 +9776 2 2 4 8 1633 4830 3435 +9777 2 2 4 8 1944 4754 3470 +9778 2 2 4 8 877 4704 3558 +9779 2 2 4 8 1564 3558 4704 +9780 2 2 4 8 878 4703 3559 +9781 2 2 4 8 1563 3559 4703 +9782 2 2 4 8 1186 3342 5132 +9783 2 2 4 8 1556 3461 4793 +9784 2 2 4 8 1219 5054 3393 +9785 2 2 4 8 1583 3393 5054 +9786 2 2 4 8 2232 4547 3962 +9787 2 2 4 8 1290 3962 4547 +9788 2 2 4 8 1568 4586 4047 +9789 2 2 4 8 1710 4520 4098 +9790 2 2 4 8 231 4098 4520 +9791 2 2 4 8 507 3276 5383 +9792 2 2 4 8 1532 4181 4022 +9793 2 2 4 8 1566 5367 3279 +9794 2 2 4 8 1495 4859 3444 +9795 2 2 4 8 1588 3341 5177 +9796 2 2 4 8 1755 5013 3389 +9797 2 2 4 8 1204 3547 5135 +9798 2 2 4 8 341 5107 3565 +9799 2 2 4 8 1720 4786 5277 +9800 2 2 4 8 2261 3867 5091 +9801 2 2 4 8 1814 5091 3867 +9802 2 2 4 8 2260 3868 5090 +9803 2 2 4 8 1813 5090 3868 +9804 2 2 4 8 4170 2143 5184 +9805 2 2 4 8 1621 3662 5058 +9806 2 2 4 8 2033 3469 4817 +9807 2 2 4 8 507 5096 4625 +9808 2 2 4 8 783 3670 5302 +9809 2 2 4 8 2080 5302 3670 +9810 2 2 4 8 2050 3324 5268 +9811 2 2 4 8 1184 3369 5193 +9812 2 2 4 8 1477 4806 3507 +9813 2 2 4 8 1801 4818 3972 +9814 2 2 4 8 1471 5115 3385 +9815 2 2 4 8 2478 3928 5243 +9816 2 2 4 8 1997 5330 3313 +9817 2 2 4 8 2115 4320 4756 +9818 2 2 4 8 2114 4321 4755 +9819 2 2 4 8 723 5049 3521 +9820 2 2 4 8 834 4695 4782 +9821 2 2 4 8 630 4587 3661 +9822 2 2 4 8 1556 5279 3461 +9823 2 2 4 8 743 4343 4094 +9824 2 2 4 8 1728 4094 4343 +9825 2 2 4 8 765 4096 5111 +9826 2 2 4 8 1871 5111 4096 +9827 2 2 4 8 733 4194 4078 +9828 2 2 4 8 1832 4374 4492 +9829 2 2 4 8 705 4492 4374 +9830 2 2 4 8 1485 3417 5070 +9831 2 2 4 8 1958 4910 3585 +9832 2 2 4 8 2295 3585 4910 +9833 2 2 4 8 1179 5263 4973 +9834 2 2 4 8 796 5004 4388 +9835 2 2 4 8 1292 4964 3456 +9836 2 2 4 8 780 4569 3698 +9837 2 2 4 8 778 4571 3696 +9838 2 2 4 8 779 4570 3697 +9839 2 2 4 8 777 4572 3695 +9840 2 2 4 8 776 3694 4574 +9841 2 2 4 8 775 3693 4573 +9842 2 2 4 8 1458 4932 3573 +9843 2 2 4 8 1459 4925 3574 +9844 2 2 4 8 896 5293 5317 +9845 2 2 4 8 724 4601 3678 +9846 2 2 4 8 1672 5358 3337 +9847 2 2 4 8 4192 2381 5295 +9848 2 2 4 8 564 4557 3806 +9849 2 2 4 8 1719 5413 4824 +9850 2 2 4 8 1557 3392 5197 +9851 2 2 4 8 1055 5157 3408 +9852 2 2 4 8 2258 5327 4667 +9853 2 2 4 8 1155 4667 5327 +9854 2 2 4 8 722 3674 4615 +9855 2 2 4 8 1313 4134 4999 +9856 2 2 4 8 1314 4135 5000 +9857 2 2 4 8 889 4323 3942 +9858 2 2 4 8 1115 4427 4561 +9859 2 2 4 8 2011 4561 4427 +9860 2 2 4 8 2320 5055 5054 +9861 2 2 4 8 1583 5054 5055 +9862 2 2 4 8 2215 3683 4908 +9863 2 2 4 8 2214 3684 4907 +9864 2 2 4 8 1143 5010 3459 +9865 2 2 4 8 4223 1450 4647 +9866 2 2 4 8 4224 1451 4648 +9867 2 2 4 8 4205 4668 2116 +9868 2 2 4 8 1618 4981 4852 +9869 2 2 4 8 2178 4852 4981 +9870 2 2 4 8 1286 4994 3476 +9871 2 2 4 8 1571 3571 4938 +9872 2 2 4 8 879 5063 3557 +9873 2 2 4 8 2093 4785 3878 +9874 2 2 4 8 2090 3879 4784 +9875 2 2 4 8 1698 4896 3518 +9876 2 2 4 8 1609 4612 3784 +9877 2 2 4 8 735 3784 4612 +9878 2 2 4 8 1338 5243 3928 +9879 2 2 4 8 727 4626 3705 +9880 2 2 4 8 1551 3921 5240 +9881 2 2 4 8 243 3505 5262 +9882 2 2 4 8 841 3397 5287 +9883 2 2 4 8 1289 3391 5301 +9884 2 2 4 8 2147 3473 5030 +9885 2 2 4 8 2146 3474 5031 +9886 2 2 4 8 1011 3914 4744 +9887 2 2 4 8 1912 4744 3914 +9888 2 2 4 8 795 4855 4365 +9889 2 2 4 8 2143 3380 5351 +9890 2 2 4 8 746 3924 4550 +9891 2 2 4 8 1583 5055 3712 +9892 2 2 4 8 1584 3713 5056 +9893 2 2 4 8 2274 5304 4052 +9894 2 2 4 8 1807 5275 5164 +9895 2 2 4 8 752 4273 4987 +9896 2 2 4 8 753 4988 4274 +9897 2 2 4 8 2130 5276 4453 +9898 2 2 4 8 3572 5168 1570 +9899 2 2 4 8 800 3570 4866 +9900 2 2 4 8 1565 3806 4557 +9901 2 2 4 8 1222 3404 5325 +9902 2 2 4 8 1949 3871 4479 +9903 2 2 4 8 478 4799 4105 +9904 2 2 4 8 2043 4105 4799 +9905 2 2 4 8 1828 4015 4894 +9906 2 2 4 8 881 5415 5281 +9907 2 2 4 8 880 5414 5280 +9908 2 2 4 8 1243 3500 5028 +9909 2 2 4 8 1344 4675 3710 +9910 2 2 4 8 1741 5172 4679 +9911 2 2 4 8 817 3653 4852 +9912 2 2 4 8 1618 4852 3653 +9913 2 2 4 8 89 5171 4379 +9914 2 2 4 8 1635 5278 3762 +9915 2 2 4 8 1233 5196 3453 +9916 2 2 4 8 4233 4394 1177 +9917 2 2 4 8 4233 1950 4394 +9918 2 2 4 8 1789 5352 3411 +9919 2 2 4 8 726 4408 3941 +9920 2 2 4 8 1421 5157 4348 +9921 2 2 4 8 758 4900 3773 +9922 2 2 4 8 1425 3771 4624 +9923 2 2 4 8 9 5208 3460 +9924 2 2 4 8 761 4938 3571 +9925 2 2 4 8 488 3418 5387 +9926 2 2 4 8 2071 5085 3511 +9927 2 2 4 8 2070 5086 3510 +9928 2 2 4 8 1912 4388 5004 +9929 2 2 4 8 1002 3663 4792 +9930 2 2 4 8 1661 4795 5143 +9931 2 2 4 8 2190 5143 4795 +9932 2 2 4 8 921 5304 5242 +9933 2 2 4 8 1969 4461 3931 +9934 2 2 4 8 509 4969 3581 +9935 2 2 4 8 514 4970 3582 +9936 2 2 4 8 1895 4600 4705 +9937 2 2 4 8 1626 4705 4600 +9938 2 2 4 8 1680 4792 3663 +9939 2 2 4 8 821 3654 4889 +9940 2 2 4 8 1619 4889 3654 +9941 2 2 4 8 1279 4257 4377 +9942 2 2 4 8 1848 4377 4257 +9943 2 2 4 8 596 5390 4253 +9944 2 2 4 8 2317 4253 5390 +9945 2 2 4 8 1635 3762 4858 +9946 2 2 4 8 551 4858 3762 +9947 2 2 4 8 1071 3461 5279 +9948 2 2 4 8 1711 4801 4799 +9949 2 2 4 8 2043 4799 4801 +9950 2 2 4 8 1358 4142 4329 +9951 2 2 4 8 781 4525 3904 +9952 2 2 4 8 1336 3992 4937 +9953 2 2 4 8 734 4620 4131 +9954 2 2 4 8 1562 3557 5063 +9955 2 2 4 8 2380 3898 5309 +9956 2 2 4 8 1963 5309 3898 +9957 2 2 4 8 2254 4800 3685 +9958 2 2 4 8 1339 4888 3642 +9959 2 2 4 8 2128 3544 5100 +9960 2 2 4 8 2127 3545 5101 +9961 2 2 4 8 1674 5252 3646 +9962 2 2 4 8 1306 3646 5252 +9963 2 2 4 8 2242 4491 4790 +9964 2 2 4 8 701 4577 3895 +9965 2 2 4 8 1586 4550 3924 +9966 2 2 4 8 2054 3820 4994 +9967 2 2 4 8 2535 4027 4428 +9968 2 2 4 8 2537 4028 4429 +9969 2 2 4 8 2536 4029 4430 +9970 2 2 4 8 1930 5001 3610 +9971 2 2 4 8 2237 4635 3866 +9972 2 2 4 8 2094 5135 3547 +9973 2 2 4 8 1142 4757 3744 +9974 2 2 4 8 1141 3745 4758 +9975 2 2 4 8 1740 3565 5107 +9976 2 2 4 8 2060 3895 4788 +9977 2 2 4 8 2374 5246 3874 +9978 2 2 4 8 1943 3874 5246 +9979 2 2 4 8 2373 3873 5245 +9980 2 2 4 8 1942 5245 3873 +9981 2 2 4 8 776 3536 5180 +9982 2 2 4 8 775 3537 5181 +9983 2 2 4 8 779 5178 3538 +9984 2 2 4 8 780 5179 3539 +9985 2 2 4 8 2402 3613 5194 +9986 2 2 4 8 993 3810 4760 +9987 2 2 4 8 1624 4760 3810 +9988 2 2 4 8 1528 4423 4080 +9989 2 2 4 8 1529 4424 4079 +9990 2 2 4 8 1154 4019 5070 +9991 2 2 4 8 858 4664 5392 +9992 2 2 4 8 1043 4812 3967 +9993 2 2 4 8 547 4342 4810 +9994 2 2 4 8 1828 4810 4342 +9995 2 2 4 8 2507 3793 4935 +9996 2 2 4 8 1775 4935 3793 +9997 2 2 4 8 1776 4936 3794 +9998 2 2 4 8 2508 3794 4936 +9999 2 2 4 8 2322 4465 4889 +10000 2 2 4 8 821 4889 4465 +10001 2 2 4 8 216 3818 4721 +10002 2 2 4 8 434 3817 4722 +10003 2 2 4 8 527 5305 3504 +10004 2 2 4 8 1631 3504 5305 +10005 2 2 4 8 1482 4712 3825 +10006 2 2 4 8 762 5168 3572 +10007 2 2 4 8 1621 5058 3620 +10008 2 2 4 8 827 4907 3684 +10009 2 2 4 8 826 4908 3683 +10010 2 2 4 8 1027 5058 3662 +10011 2 2 4 8 2852 3652 5077 +10012 2 2 4 8 1501 3601 5122 +10013 2 2 4 8 2162 4288 4986 +10014 2 2 4 8 1742 4259 4680 +10015 2 2 4 8 606 4680 4259 +10016 2 2 4 8 785 5328 3509 +10017 2 2 4 8 786 5329 3508 +10018 2 2 4 8 1666 3734 5134 +10019 2 2 4 8 848 5134 3734 +10020 2 2 4 8 2084 5299 4555 +10021 2 2 4 8 721 4555 5299 +10022 2 2 4 8 1833 4442 4103 +10023 2 2 4 8 765 4164 4627 +10024 2 2 4 8 1929 4625 5096 +10025 2 2 4 8 921 5242 4076 +10026 2 2 4 8 732 4575 4013 +10027 2 2 4 8 737 4576 4014 +10028 2 2 4 8 1109 3549 5285 +10029 2 2 4 8 1322 3556 5275 +10030 2 2 4 8 1870 4058 4727 +10031 2 2 4 8 961 4727 4058 +10032 2 2 4 8 1602 5219 3747 +10033 2 2 4 8 2197 4002 4603 +10034 2 2 4 8 1656 4955 4902 +10035 2 2 4 8 1657 4954 4903 +10036 2 2 4 8 1990 4123 4991 +10037 2 2 4 8 1989 4122 4990 +10038 2 2 4 8 733 4716 3877 +10039 2 2 4 8 1669 5067 4811 +10040 2 2 4 8 2102 4811 5067 +10041 2 2 4 8 28 4787 3814 +10042 2 2 4 8 1482 4285 4712 +10043 2 2 4 8 840 5077 3652 +10044 2 2 4 8 1256 5408 3663 +10045 2 2 4 8 1360 3805 4818 +10046 2 2 4 8 1513 4370 5312 +10047 2 2 4 8 817 4852 4672 +10048 2 2 4 8 2178 4672 4852 +10049 2 2 4 8 2035 4759 4949 +10050 2 2 4 8 1660 4949 4759 +10051 2 2 4 8 2500 4821 3812 +10052 2 2 4 8 2136 5194 3613 +10053 2 2 4 8 523 3764 4892 +10054 2 2 4 8 1518 5037 3677 +10055 2 2 4 8 2018 4385 4277 +10056 2 2 4 8 739 4047 4586 +10057 2 2 4 8 2178 4732 4020 +10058 2 2 4 8 1991 4447 4256 +10059 2 2 4 8 1584 4256 4447 +10060 2 2 4 8 2206 3557 5357 +10061 2 2 4 8 2205 3558 5355 +10062 2 2 4 8 2207 3559 5356 +10063 2 2 4 8 1060 4678 5106 +10064 2 2 4 8 2044 5106 4678 +10065 2 2 4 8 2017 4596 4064 +10066 2 2 4 8 1604 3734 4985 +10067 2 2 4 8 491 4589 4075 +10068 2 2 4 8 1573 3773 4900 +10069 2 2 4 8 1178 3709 5022 +10070 2 2 4 8 1498 5243 3623 +10071 2 2 4 8 1435 3976 4685 +10072 2 2 4 8 1436 5189 4087 +10073 2 2 4 8 1741 3986 5172 +10074 2 2 4 8 1552 5154 4075 +10075 2 2 4 8 1680 3663 5408 +10076 2 2 4 8 601 3606 5312 +10077 2 2 4 8 4150 5273 2571 +10078 2 2 4 8 504 4509 4950 +10079 2 2 4 8 1901 4950 4509 +10080 2 2 4 8 505 4508 4951 +10081 2 2 4 8 1900 4951 4508 +10082 2 2 4 8 537 5268 3767 +10083 2 2 4 8 1988 4310 4482 +10084 2 2 4 8 2158 4583 5269 +10085 2 2 4 8 1788 5269 4583 +10086 2 2 4 8 2032 4421 4498 +10087 2 2 4 8 956 5354 3642 +10088 2 2 4 8 1985 4608 5073 +10089 2 2 4 8 1787 5073 4608 +10090 2 2 4 8 1515 5172 3986 +10091 2 2 4 8 837 4684 4990 +10092 2 2 4 8 1989 4990 4684 +10093 2 2 4 8 1843 4131 4620 +10094 2 2 4 8 1378 4894 3861 +10095 2 2 4 8 2017 4902 4955 +10096 2 2 4 8 2018 4903 4954 +10097 2 2 4 8 4172 1354 5117 +10098 2 2 4 8 1583 4482 4310 +10099 2 2 4 8 2016 4901 4823 +10100 2 2 4 8 1655 4823 4901 +10101 2 2 4 8 1408 4476 4316 +10102 2 2 4 8 738 3839 4927 +10103 2 2 4 8 2200 3876 5389 +10104 2 2 4 8 1437 5393 3738 +10105 2 2 4 8 2016 4857 4858 +10106 2 2 4 8 1635 4858 4857 +10107 2 2 4 8 1502 5298 4103 +10108 2 2 4 8 1833 4103 5298 +10109 2 2 4 8 950 3782 5313 +10110 2 2 4 8 1900 3724 5202 +10111 2 2 4 8 1756 5019 3958 +10112 2 2 4 8 760 3958 5019 +10113 2 2 4 8 882 4622 5416 +10114 2 2 4 8 2171 5416 4622 +10115 2 2 4 8 1901 3725 5189 +10116 2 2 4 8 4164 2034 4627 +10117 2 2 4 8 1362 3804 5038 +10118 2 2 4 8 1361 5039 3803 +10119 2 2 4 8 830 4754 4809 +10120 2 2 4 8 1944 4809 4754 +10121 2 2 4 8 743 3828 4992 +10122 2 2 4 8 4225 4815 1695 +10123 2 2 4 8 1879 3967 4812 +10124 2 2 4 8 2342 3754 5166 +10125 2 2 4 8 493 4839 4160 +10126 2 2 4 8 1717 4160 4839 +10127 2 2 4 8 1833 5298 3671 +10128 2 2 4 8 2016 4858 4901 +10129 2 2 4 8 551 4901 4858 +10130 2 2 4 8 1134 4477 4468 +10131 2 2 4 8 2134 4468 4477 +10132 2 2 4 8 849 5316 3666 +10133 2 2 4 8 4105 2280 5164 +10134 2 2 4 8 835 4860 4783 +10135 2 2 4 8 1974 4783 4860 +10136 2 2 4 8 2286 5176 3957 +10137 2 2 4 8 462 3965 4833 +10138 2 2 4 8 463 3966 4834 +10139 2 2 4 8 1858 4124 5416 +10140 2 2 4 8 882 5416 4124 +10141 2 2 4 8 726 3747 5219 +10142 2 2 4 8 518 3846 5110 +10143 2 2 4 8 411 4751 4251 +10144 2 2 4 8 2043 5272 5234 +10145 2 2 4 8 1550 4498 4421 +10146 2 2 4 8 4225 4878 2283 +10147 2 2 4 8 4225 1695 4878 +10148 2 2 4 8 1080 4504 4493 +10149 2 2 4 8 2036 4493 4504 +10150 2 2 4 8 732 4086 4824 +10151 2 2 4 8 1098 4668 4205 +10152 2 2 4 8 765 5283 4096 +10153 2 2 4 8 2164 4687 4973 +10154 2 2 4 8 1690 4958 4856 +10155 2 2 4 8 1531 5346 3704 +10156 2 2 4 8 760 5019 3882 +10157 2 2 4 8 223 5113 4883 +10158 2 2 4 8 2067 4883 5113 +10159 2 2 4 8 2066 5112 4882 +10160 2 2 4 8 204 4882 5112 +10161 2 2 4 8 2198 5229 5045 +10162 2 2 4 8 1725 5045 5229 +10163 2 2 4 8 1640 5110 3846 +10164 2 2 4 8 2006 4856 4958 +10165 2 2 4 8 1990 4991 4763 +10166 2 2 4 8 836 4763 4991 +10167 2 2 4 8 2417 5321 4309 +10168 2 2 4 8 744 3781 5226 +10169 2 2 4 8 1034 5349 5282 +10170 2 2 4 8 2382 5282 5349 +10171 2 2 4 8 745 3783 5220 +10172 2 2 4 8 1656 4125 4955 +10173 2 2 4 8 1657 4126 4954 +10174 2 2 4 8 1975 4663 4664 +10175 2 2 4 8 1625 4664 4663 +10176 2 2 4 8 1275 5211 3809 +10177 2 2 4 8 1379 5136 3862 +10178 2 2 4 8 752 5137 3863 +10179 2 2 4 8 1666 5134 5105 +10180 2 2 4 8 2167 5105 5134 +10181 2 2 4 8 2065 4937 3992 +10182 2 2 4 8 4169 1530 4749 +10183 2 2 4 8 1719 4824 4086 +10184 2 2 4 8 985 4873 4418 +10185 2 2 4 8 1852 4418 4873 +10186 2 2 4 8 987 4874 4419 +10187 2 2 4 8 1853 4420 4875 +10188 2 2 4 8 984 4417 4872 +10189 2 2 4 8 1854 4872 4417 +10190 2 2 4 8 986 4875 4420 +10191 2 2 4 8 1851 4419 4874 +10192 2 2 4 8 1755 4590 4660 +10193 2 2 4 8 1559 4804 4148 +10194 2 2 4 8 1560 4805 4149 +10195 2 2 4 8 1502 4439 5298 +10196 2 2 4 8 1977 4607 5198 +10197 2 2 4 8 512 5198 4607 +10198 2 2 4 8 4227 1515 4752 +10199 2 2 4 8 2007 4683 4850 +10200 2 2 4 8 838 4850 4683 +10201 2 2 4 8 1668 4251 4751 +10202 2 2 4 8 837 4856 4684 +10203 2 2 4 8 2006 4684 4856 +10204 2 2 4 8 4193 5299 1830 +10205 2 2 4 8 721 5299 4193 +10206 2 2 4 8 456 5391 3809 +10207 2 2 4 8 1693 3809 5391 +10208 2 2 4 8 4166 1690 4856 +10209 2 2 4 8 1509 4922 4065 +10210 2 2 4 8 1767 5133 4567 +10211 2 2 4 8 2173 4567 5133 +10212 2 2 4 8 4707 1998 4840 +10213 2 2 4 8 833 4707 4840 +10214 2 2 4 8 4195 2137 4814 +10215 2 2 4 8 837 4166 4856 +10216 2 2 4 8 458 5310 4204 +10217 2 2 4 8 1635 3869 5278 +10218 2 2 4 8 469 4524 5248 +10219 2 2 4 8 1948 5248 4524 +10220 2 2 4 8 3832 5327 2258 +10221 2 2 4 8 1682 4624 4956 +10222 2 2 4 8 1895 4853 4855 +10223 2 2 4 8 1745 4922 4246 +10224 2 2 4 8 1509 4246 4922 +10225 2 2 4 8 1097 4756 4320 +10226 2 2 4 8 1096 4755 4321 +10227 2 2 4 8 826 4955 4125 +10228 2 2 4 8 827 4954 4126 +10229 2 2 4 8 1112 3900 5267 +10230 2 2 4 8 1675 5209 3959 +10231 2 2 4 8 1878 5364 4331 +10232 2 2 4 8 1793 4822 4764 +10233 2 2 4 8 4098 2670 4995 +10234 2 2 4 8 1710 4098 4995 +10235 2 2 4 8 326 5240 3921 +10236 2 2 4 8 2566 5312 4370 +10237 2 2 4 8 1549 4965 4152 +10238 2 2 4 8 1854 4646 4931 +10239 2 2 4 8 801 4931 4646 +10240 2 2 4 8 1127 4659 4632 +10241 2 2 4 8 1766 4632 4659 +10242 2 2 4 8 1738 4660 4590 +10243 2 2 4 8 1035 5315 5418 +10244 2 2 4 8 2363 5418 5315 +10245 2 2 4 8 1402 3959 5209 +10246 2 2 4 8 1802 4855 4853 +10247 2 2 4 8 4238 2321 5247 +10248 2 2 4 8 797 4331 5364 +10249 2 2 4 8 2296 5057 4066 +10250 2 2 4 8 1756 5289 5019 +10251 2 2 4 8 1256 5410 5408 +10252 2 2 4 8 2454 5408 5410 +10253 2 2 4 8 2064 5068 4780 +10254 2 2 4 8 2083 5230 4312 +10255 2 2 4 8 871 5374 4674 +10256 2 2 4 8 2024 4674 5374 +10257 2 2 4 8 1870 4727 4926 +10258 2 2 4 8 1805 4926 4727 +10259 2 2 4 8 2292 4005 5227 +10260 2 2 4 8 1572 4861 4322 +10261 2 2 4 8 783 5302 3944 +10262 2 2 4 8 1402 5289 3959 +10263 2 2 4 8 1827 4744 5004 +10264 2 2 4 8 1912 5004 4744 +10265 2 2 4 8 1131 5296 4284 +10266 2 2 4 8 1830 5299 4899 +10267 2 2 4 8 2084 4899 5299 +10268 2 2 4 8 2591 3926 5354 +10269 2 2 4 8 1774 5392 3916 +10270 2 2 4 8 1793 4715 4822 +10271 2 2 4 8 1597 5284 3999 +10272 2 2 4 8 2074 5401 4920 +10273 2 2 4 8 1398 5277 4006 +10274 2 2 4 8 1738 5076 4660 +10275 2 2 4 8 2339 4718 4703 +10276 2 2 4 8 2338 4717 4704 +10277 2 2 4 8 1561 4790 4491 +10278 2 2 4 8 928 5021 4808 +10279 2 2 4 8 1945 4808 5021 +10280 2 2 4 8 2576 4792 5306 +10281 2 2 4 8 478 4105 5164 +10282 2 2 4 8 1664 5102 4470 +10283 2 2 4 8 1598 4987 4273 +10284 2 2 4 8 1599 4274 4988 +10285 2 2 4 8 1564 4704 4717 +10286 2 2 4 8 1563 4703 4718 +10287 2 2 4 8 2256 4881 5182 +10288 2 2 4 8 1789 4764 4822 +10289 2 2 4 8 1943 5246 4654 +10290 2 2 4 8 556 4654 5246 +10291 2 2 4 8 554 5245 4655 +10292 2 2 4 8 1942 4655 5245 +10293 2 2 4 8 1829 5234 5272 +10294 2 2 4 8 1895 4855 4600 +10295 2 2 4 8 2262 5173 4890 +10296 2 2 4 8 1706 4046 5291 +10297 2 2 4 8 860 5350 4438 +10298 2 2 4 8 1889 4438 5350 +10299 2 2 4 8 1538 4905 4413 +10300 2 2 4 8 1636 4096 5283 +10301 2 2 4 8 1630 4053 5313 +10302 2 2 4 8 1726 4559 5333 +10303 2 2 4 8 1727 5334 4560 +10304 2 2 4 8 2300 4879 5097 +10305 2 2 4 8 1738 4590 5238 +10306 2 2 4 8 2274 4924 5242 +10307 2 2 4 8 795 4600 4855 +10308 2 2 4 8 1593 4906 4483 +10309 2 2 4 8 1737 4617 5317 +10310 2 2 4 8 1656 5281 4125 +10311 2 2 4 8 1657 5280 4126 +10312 2 2 4 8 449 4759 4771 +10313 2 2 4 8 2742 4870 4816 +10314 2 2 4 8 2035 4771 4759 +10315 2 2 4 8 4227 5172 1515 +10316 2 2 4 8 2043 4801 5272 +10317 2 2 4 8 2840 5279 4772 +10318 2 2 4 8 1471 4315 5115 +10319 2 2 4 8 2001 5082 5011 +10320 2 2 4 8 1044 5011 5082 +10321 2 2 4 8 1230 4822 4715 +10322 2 2 4 8 1043 5083 5014 +10323 2 2 4 8 2002 5014 5083 +10324 2 2 4 8 1654 4892 5239 +10325 2 2 4 8 2021 5115 4315 +10326 2 2 4 8 2841 4348 5157 +10327 2 2 4 8 2278 4918 5148 +10328 2 2 4 8 725 4303 5188 +10329 2 2 4 8 723 4304 5187 +10330 2 2 4 8 2418 5331 5032 +10331 2 2 4 8 2419 5033 5332 +10332 2 2 4 8 2684 5050 4914 +10333 2 2 4 8 2685 4915 5049 +10334 2 2 4 8 4192 5295 1121 +10335 2 2 4 8 4206 5392 1774 +10336 2 2 4 8 858 5392 4206 +10337 2 2 4 8 4204 5310 2040 +10338 2 2 4 8 1437 4391 5393 +10339 2 2 4 8 899 4312 5230 +10340 2 2 4 8 800 4866 4930 +10341 2 2 4 8 1851 4930 4866 +10342 2 2 4 8 1551 4816 4870 +10343 2 2 4 8 1556 4772 5279 +10344 2 2 4 8 2143 5351 5184 +10345 2 2 4 8 628 5184 5351 +10346 2 2 4 8 1622 4379 5171 +10347 2 2 4 8 1634 4973 4687 +10348 2 2 4 8 1844 4872 4931 +10349 2 2 4 8 1854 4931 4872 +10350 2 2 4 8 1846 4929 4875 +10351 2 2 4 8 1845 4928 4873 +10352 2 2 4 8 1852 4873 4928 +10353 2 2 4 8 1847 4930 4874 +10354 2 2 4 8 1853 4875 4929 +10355 2 2 4 8 1851 4874 4930 +10356 2 2 4 8 1437 5202 4363 +10357 2 2 4 8 15 5080 4583 +10358 2 2 4 8 1788 4583 5080 +10359 2 2 4 8 2390 4962 5035 +10360 2 2 4 8 1181 5035 4962 +10361 2 2 4 8 2391 4963 5036 +10362 2 2 4 8 1180 5036 4963 +10363 2 2 4 8 1797 4284 5296 +10364 2 2 4 8 1726 5333 4911 +10365 2 2 4 8 1727 4912 5334 +10366 2 2 4 8 402 5366 4567 +10367 2 2 4 8 1602 4913 5219 +10368 2 2 4 8 2518 5420 5419 +10369 2 2 4 8 1702 5419 5420 +10370 2 2 4 8 1200 4309 5321 +10371 2 2 4 8 841 4660 5076 +10372 2 2 4 8 2335 5124 5412 +10373 2 2 4 8 1678 4371 5293 +10374 2 2 4 8 2337 5128 5417 +10375 2 2 4 8 2394 5274 5075 +10376 2 2 4 8 1700 4780 5068 +10377 2 2 4 8 828 5238 4590 +10378 2 2 4 8 708 4793 5197 +10379 2 2 4 8 2387 5393 4391 +10380 2 2 4 8 1762 5318 4502 +10381 2 2 4 8 1600 5049 4915 +10382 2 2 4 8 1603 4914 5050 +10383 2 2 4 8 1663 5097 4879 +10384 2 2 4 8 638 5333 4559 +10385 2 2 4 8 637 4560 5334 +10386 2 2 4 8 2337 5078 5060 +10387 2 2 4 8 2336 5079 5061 +10388 2 2 4 8 882 5359 4622 +10389 2 2 4 8 1842 4622 5359 +10390 2 2 4 8 896 5317 4617 +10391 2 2 4 8 1767 4567 5366 +10392 2 2 4 8 1609 5320 4612 +10393 2 2 4 8 2472 5169 5294 +10394 2 2 4 8 1683 5060 5078 +10395 2 2 4 8 1688 5061 5079 +10396 2 2 4 8 1689 5182 4881 +10397 2 2 4 8 1686 4890 5173 +10398 2 2 4 8 1691 5148 4918 +10399 2 2 4 8 1979 5385 5167 +10400 2 2 4 8 2055 5167 5385 +10401 2 2 4 8 2440 5325 4862 +10402 2 2 4 8 644 5186 5405 +10403 2 2 4 8 2061 5405 5186 +10404 2 2 4 8 2683 5219 4913 +10405 2 2 4 8 793 5272 4801 +10406 2 2 4 8 2176 5334 4912 +10407 2 2 4 8 2177 4911 5333 +10408 2 2 4 8 2135 5360 5359 +10409 2 2 4 8 1842 5359 5360 +10410 2 2 4 8 1680 5306 4792 +10411 2 2 4 8 1701 5242 4924 +10412 2 2 4 8 1707 5075 5274 +10413 2 2 4 8 1792 4920 5401 +10414 2 2 4 8 1704 5032 5331 +10415 2 2 4 8 1705 5332 5033 +10416 2 2 4 8 1712 5294 5169 +10417 2 2 4 8 2117 5380 5381 +10418 2 2 4 8 1896 5381 5380 +10419 2 2 4 8 1758 5412 5124 +10420 2 2 4 8 1759 5417 5128 +$EndElements diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh_prestress_reinforcement.msh b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh_prestress_reinforcement.msh new file mode 100644 index 000000000..5dd1487ce --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/embedded_mesh_prestress_reinforcement.msh @@ -0,0 +1,414 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +1 +1 1 "reinforcement" +$EndPhysicalNames +$Nodes +201 +1 10 0.25 0 +2 0 0.25 0 +3 0.04999999999996232 0.25 0 +4 0.09999999999992584 0.25 0 +5 0.1499999999998909 0.25 0 +6 0.199999999999856 0.25 0 +7 0.249999999999819 0.25 0 +8 0.2999999999997771 0.25 0 +9 0.3499999999997248 0.25 0 +10 0.3999999999996677 0.25 0 +11 0.4499999999996051 0.25 0 +12 0.4999999999995511 0.25 0 +13 0.5499999999995031 0.25 0 +14 0.5999999999994683 0.25 0 +15 0.6499999999994334 0.25 0 +16 0.6999999999993983 0.25 0 +17 0.7499999999993634 0.25 0 +18 0.7999999999993286 0.25 0 +19 0.8499999999992935 0.25 0 +20 0.8999999999992587 0.25 0 +21 0.9499999999992237 0.25 0 +22 0.9999999999991888 0.25 0 +23 1.049999999999154 0.25 0 +24 1.099999999999119 0.25 0 +25 1.149999999999084 0.25 0 +26 1.199999999999033 0.25 0 +27 1.24999999999897 0.25 0 +28 1.299999999998852 0.25 0 +29 1.349999999998722 0.25 0 +30 1.399999999998576 0.25 0 +31 1.44999999999843 0.25 0 +32 1.499999999998284 0.25 0 +33 1.549999999998138 0.25 0 +34 1.599999999997992 0.25 0 +35 1.649999999997846 0.25 0 +36 1.6999999999977 0.25 0 +37 1.749999999997554 0.25 0 +38 1.799999999997408 0.25 0 +39 1.849999999997263 0.25 0 +40 1.899999999997116 0.25 0 +41 1.949999999996971 0.25 0 +42 1.999999999996825 0.25 0 +43 2.049999999996679 0.25 0 +44 2.099999999996533 0.25 0 +45 2.149999999996387 0.25 0 +46 2.199999999996241 0.25 0 +47 2.249999999996095 0.25 0 +48 2.299999999995949 0.25 0 +49 2.349999999995803 0.25 0 +50 2.399999999995657 0.25 0 +51 2.449999999995511 0.25 0 +52 2.499999999995365 0.25 0 +53 2.54999999999522 0.25 0 +54 2.599999999995073 0.25 0 +55 2.649999999994928 0.25 0 +56 2.699999999994782 0.25 0 +57 2.749999999994635 0.25 0 +58 2.79999999999449 0.25 0 +59 2.849999999994344 0.25 0 +60 2.899999999994198 0.25 0 +61 2.949999999994052 0.25 0 +62 2.999999999993906 0.25 0 +63 3.04999999999376 0.25 0 +64 3.099999999993614 0.25 0 +65 3.149999999993468 0.25 0 +66 3.199999999993322 0.25 0 +67 3.249999999993176 0.25 0 +68 3.299999999993029 0.25 0 +69 3.349999999992884 0.25 0 +70 3.399999999992738 0.25 0 +71 3.449999999992592 0.25 0 +72 3.499999999992446 0.25 0 +73 3.5499999999923 0.25 0 +74 3.599999999992154 0.25 0 +75 3.649999999992009 0.25 0 +76 3.699999999991863 0.25 0 +77 3.749999999991717 0.25 0 +78 3.799999999991571 0.25 0 +79 3.849999999991425 0.25 0 +80 3.899999999991278 0.25 0 +81 3.949999999991132 0.25 0 +82 3.999999999991022 0.25 0 +83 4.049999999990987 0.25 0 +84 4.099999999991035 0.25 0 +85 4.149999999991111 0.25 0 +86 4.199999999991187 0.25 0 +87 4.249999999991263 0.25 0 +88 4.299999999991338 0.25 0 +89 4.349999999991415 0.25 0 +90 4.399999999991491 0.25 0 +91 4.449999999991566 0.25 0 +92 4.499999999991642 0.25 0 +93 4.549999999991719 0.25 0 +94 4.599999999991795 0.25 0 +95 4.649999999991871 0.25 0 +96 4.699999999991947 0.25 0 +97 4.749999999992022 0.25 0 +98 4.799999999992099 0.25 0 +99 4.849999999992175 0.25 0 +100 4.89999999999225 0.25 0 +101 4.949999999992326 0.25 0 +102 4.999999999992403 0.25 0 +103 5.049999999992478 0.25 0 +104 5.099999999992555 0.25 0 +105 5.14999999999263 0.25 0 +106 5.199999999992706 0.25 0 +107 5.249999999992783 0.25 0 +108 5.299999999992858 0.25 0 +109 5.349999999992933 0.25 0 +110 5.39999999999301 0.25 0 +111 5.449999999993086 0.25 0 +112 5.499999999993161 0.25 0 +113 5.549999999993238 0.25 0 +114 5.599999999993313 0.25 0 +115 5.649999999993391 0.25 0 +116 5.699999999993466 0.25 0 +117 5.749999999993543 0.25 0 +118 5.799999999993618 0.25 0 +119 5.849999999993694 0.25 0 +120 5.899999999993771 0.25 0 +121 5.949999999993846 0.25 0 +122 5.999999999993922 0.25 0 +123 6.049999999993998 0.25 0 +124 6.099999999994074 0.25 0 +125 6.14999999999415 0.25 0 +126 6.199999999994227 0.25 0 +127 6.249999999994302 0.25 0 +128 6.299999999994378 0.25 0 +129 6.349999999994455 0.25 0 +130 6.39999999999453 0.25 0 +131 6.449999999994606 0.25 0 +132 6.499999999994682 0.25 0 +133 6.549999999994759 0.25 0 +134 6.599999999994833 0.25 0 +135 6.64999999999491 0.25 0 +136 6.699999999994986 0.25 0 +137 6.749999999995062 0.25 0 +138 6.799999999995138 0.25 0 +139 6.849999999995214 0.25 0 +140 6.899999999995289 0.25 0 +141 6.949999999995366 0.25 0 +142 6.999999999995442 0.25 0 +143 7.049999999995517 0.25 0 +144 7.099999999995594 0.25 0 +145 7.14999999999567 0.25 0 +146 7.199999999995747 0.25 0 +147 7.249999999995821 0.25 0 +148 7.299999999995897 0.25 0 +149 7.349999999995973 0.25 0 +150 7.39999999999605 0.25 0 +151 7.449999999996125 0.25 0 +152 7.499999999996202 0.25 0 +153 7.549999999996278 0.25 0 +154 7.599999999996353 0.25 0 +155 7.64999999999643 0.25 0 +156 7.699999999996505 0.25 0 +157 7.749999999996582 0.25 0 +158 7.799999999996658 0.25 0 +159 7.849999999996734 0.25 0 +160 7.899999999996808 0.25 0 +161 7.949999999996885 0.25 0 +162 7.999999999996962 0.25 0 +163 8.049999999997038 0.25 0 +164 8.099999999997113 0.25 0 +165 8.14999999999719 0.25 0 +166 8.199999999997265 0.25 0 +167 8.249999999997341 0.25 0 +168 8.299999999997418 0.25 0 +169 8.349999999997493 0.25 0 +170 8.399999999997569 0.25 0 +171 8.449999999997646 0.25 0 +172 8.499999999997721 0.25 0 +173 8.549999999997798 0.25 0 +174 8.599999999997873 0.25 0 +175 8.649999999997949 0.25 0 +176 8.699999999998024 0.25 0 +177 8.749999999998101 0.25 0 +178 8.799999999998176 0.25 0 +179 8.849999999998253 0.25 0 +180 8.899999999998329 0.25 0 +181 8.949999999998404 0.25 0 +182 8.999999999998479 0.25 0 +183 9.049999999998557 0.25 0 +184 9.099999999998634 0.25 0 +185 9.149999999998709 0.25 0 +186 9.199999999998786 0.25 0 +187 9.24999999999886 0.25 0 +188 9.299999999998937 0.25 0 +189 9.349999999999012 0.25 0 +190 9.399999999999089 0.25 0 +191 9.449999999999164 0.25 0 +192 9.499999999999241 0.25 0 +193 9.549999999999315 0.25 0 +194 9.599999999999392 0.25 0 +195 9.649999999999469 0.25 0 +196 9.699999999999545 0.25 0 +197 9.749999999999622 0.25 0 +198 9.799999999999697 0.25 0 +199 9.849999999999774 0.25 0 +200 9.899999999999848 0.25 0 +201 9.949999999999925 0.25 0 +$EndNodes +$Elements +200 +1 1 2 1 6 2 3 +2 1 2 1 6 3 4 +3 1 2 1 6 4 5 +4 1 2 1 6 5 6 +5 1 2 1 6 6 7 +6 1 2 1 6 7 8 +7 1 2 1 6 8 9 +8 1 2 1 6 9 10 +9 1 2 1 6 10 11 +10 1 2 1 6 11 12 +11 1 2 1 6 12 13 +12 1 2 1 6 13 14 +13 1 2 1 6 14 15 +14 1 2 1 6 15 16 +15 1 2 1 6 16 17 +16 1 2 1 6 17 18 +17 1 2 1 6 18 19 +18 1 2 1 6 19 20 +19 1 2 1 6 20 21 +20 1 2 1 6 21 22 +21 1 2 1 6 22 23 +22 1 2 1 6 23 24 +23 1 2 1 6 24 25 +24 1 2 1 6 25 26 +25 1 2 1 6 26 27 +26 1 2 1 6 27 28 +27 1 2 1 6 28 29 +28 1 2 1 6 29 30 +29 1 2 1 6 30 31 +30 1 2 1 6 31 32 +31 1 2 1 6 32 33 +32 1 2 1 6 33 34 +33 1 2 1 6 34 35 +34 1 2 1 6 35 36 +35 1 2 1 6 36 37 +36 1 2 1 6 37 38 +37 1 2 1 6 38 39 +38 1 2 1 6 39 40 +39 1 2 1 6 40 41 +40 1 2 1 6 41 42 +41 1 2 1 6 42 43 +42 1 2 1 6 43 44 +43 1 2 1 6 44 45 +44 1 2 1 6 45 46 +45 1 2 1 6 46 47 +46 1 2 1 6 47 48 +47 1 2 1 6 48 49 +48 1 2 1 6 49 50 +49 1 2 1 6 50 51 +50 1 2 1 6 51 52 +51 1 2 1 6 52 53 +52 1 2 1 6 53 54 +53 1 2 1 6 54 55 +54 1 2 1 6 55 56 +55 1 2 1 6 56 57 +56 1 2 1 6 57 58 +57 1 2 1 6 58 59 +58 1 2 1 6 59 60 +59 1 2 1 6 60 61 +60 1 2 1 6 61 62 +61 1 2 1 6 62 63 +62 1 2 1 6 63 64 +63 1 2 1 6 64 65 +64 1 2 1 6 65 66 +65 1 2 1 6 66 67 +66 1 2 1 6 67 68 +67 1 2 1 6 68 69 +68 1 2 1 6 69 70 +69 1 2 1 6 70 71 +70 1 2 1 6 71 72 +71 1 2 1 6 72 73 +72 1 2 1 6 73 74 +73 1 2 1 6 74 75 +74 1 2 1 6 75 76 +75 1 2 1 6 76 77 +76 1 2 1 6 77 78 +77 1 2 1 6 78 79 +78 1 2 1 6 79 80 +79 1 2 1 6 80 81 +80 1 2 1 6 81 82 +81 1 2 1 6 82 83 +82 1 2 1 6 83 84 +83 1 2 1 6 84 85 +84 1 2 1 6 85 86 +85 1 2 1 6 86 87 +86 1 2 1 6 87 88 +87 1 2 1 6 88 89 +88 1 2 1 6 89 90 +89 1 2 1 6 90 91 +90 1 2 1 6 91 92 +91 1 2 1 6 92 93 +92 1 2 1 6 93 94 +93 1 2 1 6 94 95 +94 1 2 1 6 95 96 +95 1 2 1 6 96 97 +96 1 2 1 6 97 98 +97 1 2 1 6 98 99 +98 1 2 1 6 99 100 +99 1 2 1 6 100 101 +100 1 2 1 6 101 102 +101 1 2 1 6 102 103 +102 1 2 1 6 103 104 +103 1 2 1 6 104 105 +104 1 2 1 6 105 106 +105 1 2 1 6 106 107 +106 1 2 1 6 107 108 +107 1 2 1 6 108 109 +108 1 2 1 6 109 110 +109 1 2 1 6 110 111 +110 1 2 1 6 111 112 +111 1 2 1 6 112 113 +112 1 2 1 6 113 114 +113 1 2 1 6 114 115 +114 1 2 1 6 115 116 +115 1 2 1 6 116 117 +116 1 2 1 6 117 118 +117 1 2 1 6 118 119 +118 1 2 1 6 119 120 +119 1 2 1 6 120 121 +120 1 2 1 6 121 122 +121 1 2 1 6 122 123 +122 1 2 1 6 123 124 +123 1 2 1 6 124 125 +124 1 2 1 6 125 126 +125 1 2 1 6 126 127 +126 1 2 1 6 127 128 +127 1 2 1 6 128 129 +128 1 2 1 6 129 130 +129 1 2 1 6 130 131 +130 1 2 1 6 131 132 +131 1 2 1 6 132 133 +132 1 2 1 6 133 134 +133 1 2 1 6 134 135 +134 1 2 1 6 135 136 +135 1 2 1 6 136 137 +136 1 2 1 6 137 138 +137 1 2 1 6 138 139 +138 1 2 1 6 139 140 +139 1 2 1 6 140 141 +140 1 2 1 6 141 142 +141 1 2 1 6 142 143 +142 1 2 1 6 143 144 +143 1 2 1 6 144 145 +144 1 2 1 6 145 146 +145 1 2 1 6 146 147 +146 1 2 1 6 147 148 +147 1 2 1 6 148 149 +148 1 2 1 6 149 150 +149 1 2 1 6 150 151 +150 1 2 1 6 151 152 +151 1 2 1 6 152 153 +152 1 2 1 6 153 154 +153 1 2 1 6 154 155 +154 1 2 1 6 155 156 +155 1 2 1 6 156 157 +156 1 2 1 6 157 158 +157 1 2 1 6 158 159 +158 1 2 1 6 159 160 +159 1 2 1 6 160 161 +160 1 2 1 6 161 162 +161 1 2 1 6 162 163 +162 1 2 1 6 163 164 +163 1 2 1 6 164 165 +164 1 2 1 6 165 166 +165 1 2 1 6 166 167 +166 1 2 1 6 167 168 +167 1 2 1 6 168 169 +168 1 2 1 6 169 170 +169 1 2 1 6 170 171 +170 1 2 1 6 171 172 +171 1 2 1 6 172 173 +172 1 2 1 6 173 174 +173 1 2 1 6 174 175 +174 1 2 1 6 175 176 +175 1 2 1 6 176 177 +176 1 2 1 6 177 178 +177 1 2 1 6 178 179 +178 1 2 1 6 179 180 +179 1 2 1 6 180 181 +180 1 2 1 6 181 182 +181 1 2 1 6 182 183 +182 1 2 1 6 183 184 +183 1 2 1 6 184 185 +184 1 2 1 6 185 186 +185 1 2 1 6 186 187 +186 1 2 1 6 187 188 +187 1 2 1 6 188 189 +188 1 2 1 6 189 190 +189 1 2 1 6 190 191 +190 1 2 1 6 191 192 +191 1 2 1 6 192 193 +192 1 2 1 6 193 194 +193 1 2 1 6 194 195 +194 1 2 1 6 195 196 +195 1 2 1 6 196 197 +196 1 2 1 6 197 198 +197 1 2 1 6 198 199 +198 1 2 1 6 199 200 +199 1 2 1 6 200 201 +200 1 2 1 6 201 1 +$EndElements diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/material.dat b/test/test_model/test_solid_mechanics_model/test_embedded_interface/material.dat index 3baedcc01..23e677b42 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/material.dat +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/material.dat @@ -1,19 +1,13 @@ -embedded_interface truc [ - name = reinforcement - material = elastic_r - points = [[0, 0.5], [1, 0.5]] -] - material reinforcement elastic [ - name = elastic_r + name = reinforcement E = 210e9 area = 0.1 ] material elastic [ name = concrete rho = 2500 # density E = 30e9 # young's modulus nu = 0.0 # poisson's ratio Plane_Stress = true ] diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/material.dat b/test/test_model/test_solid_mechanics_model/test_embedded_interface/prestress.dat similarity index 65% copy from test/test_model/test_solid_mechanics_model/test_embedded_interface/material.dat copy to test/test_model/test_solid_mechanics_model/test_embedded_interface/prestress.dat index 3baedcc01..55f8b64d2 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/material.dat +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/prestress.dat @@ -1,19 +1,14 @@ -embedded_interface truc [ - name = reinforcement - material = elastic_r - points = [[0, 0.5], [1, 0.5]] -] - material reinforcement elastic [ - name = elastic_r + name = reinforcement E = 210e9 - area = 0.1 + area = 1e-2 + pre_stress = 1e6 ] material elastic [ name = concrete rho = 2500 # density E = 30e9 # young's modulus nu = 0.0 # poisson's ratio Plane_Stress = true ] diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc index efb93663b..a597947f5 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc @@ -1,74 +1,89 @@ /** * @file test_embedded_interface_model.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date Thu 19 Mar 2015 * * @brief test of the class EmbeddedInterfaceModel * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "embedded_interface_model.hh" using namespace akantu; int main(int argc, char * argv[]) { debug::setDebugLevel(dblWarning); initialize("embedded_element.dat", argc, argv); const UInt dim = 2; + const Real height = 0.5; Mesh mesh(dim); mesh.read("triangle.msh"); - EmbeddedInterfaceModel model(mesh, dim); + Array<Real> nodes_vec(2, dim, "reinforcement_nodes"); + nodes_vec.storage()[0] = 0; nodes_vec.storage()[1] = height; + nodes_vec.storage()[2] = 1; nodes_vec.storage()[3] = height; - const Real height = 0.5; + Array<UInt> conn_vec(1, 2, "reinforcement_connectivity"); + conn_vec.storage()[0] = 0; conn_vec.storage()[1] = 1; + + Array<std::string> names_vec(1, 1, "reinforcement", "reinforcement_names"); + + Mesh reinforcement_mesh(dim, "reinforcement_mesh"); + reinforcement_mesh.getNodes().copy(nodes_vec); + reinforcement_mesh.addConnectivityType(_segment_2); + reinforcement_mesh.getConnectivity(_segment_2).copy(conn_vec); + reinforcement_mesh.registerData<std::string>("physical_names").alloc(1, 1, _segment_2); + reinforcement_mesh.getData<std::string>("physical_names")(_segment_2).copy(names_vec); + + EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim); model.initFull(SolidMechanicsModelOptions(_static)); if (model.getInterfaceMesh().getNbElement(_segment_2) != 1) return EXIT_FAILURE; if (model.getInterfaceMesh().getSpatialDimension() != 2) return EXIT_FAILURE; model.assembleStiffnessMatrix(); SparseMatrix & K = model.getStiffnessMatrix(); Math::setTolerance(1e-8); // Testing the assembled stiffness matrix if (!Math::are_float_equal(K(0, 0), 1. - height) || !Math::are_float_equal(K(0, 2), height - 1.) || !Math::are_float_equal(K(2, 0), height - 1.) || !Math::are_float_equal(K(2, 2), 1. - height)) return EXIT_FAILURE; model.updateResidual(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model.cc index 0a5beef3b..7ed6dde50 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model.cc +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model.cc @@ -1,82 +1,98 @@ /** - * @file reinforced_concrete + * @file test_embedded_interface_model.cc * - * @author Lucas Frerot + * @author Lucas Frerot <lucas.frerot@epfl.ch> * * @date lun. 09 29 16:03:10 2014 * - * @brief Reinforced concrete simulation + * @brief Embedded model test based on potential energy * * @section LICENSE * * Copyright (©) 2010-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 <iostream> #include "aka_common.hh" #include "embedded_interface_model.hh" using namespace akantu; int main (int argc, char * argv[]) { debug::setDebugLevel(dblWarning); initialize("material.dat", argc, argv); UInt dim = 2; Math::setTolerance(1e-7); // Mesh here is a 1x1 patch Mesh mesh(dim); mesh.read("embedded_mesh.msh"); - EmbeddedInterfaceModel model(mesh, dim); + Array<Real> nodes_vec(2, dim, "reinforcement_nodes"); + nodes_vec.storage()[0] = 0; nodes_vec.storage()[1] = 0.5; + nodes_vec.storage()[2] = 1; nodes_vec.storage()[3] = 0.5; + + Array<UInt> conn_vec(1, 2, "reinforcement_connectivity"); + conn_vec.storage()[0] = 0; conn_vec.storage()[1] = 1; + + Array<std::string> names_vec(1, 1, "reinforcement", "reinforcement_names"); + + Mesh reinforcement_mesh(dim, "reinforcement_mesh"); + reinforcement_mesh.getNodes().copy(nodes_vec); + reinforcement_mesh.addConnectivityType(_segment_2); + reinforcement_mesh.getConnectivity(_segment_2).copy(conn_vec); + reinforcement_mesh.registerData<std::string>("physical_names").alloc(1, 1, _segment_2); + reinforcement_mesh.getData<std::string>("physical_names")(_segment_2).copy(names_vec); + + EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim); model.initFull(SolidMechanicsModelOptions(_static)); Array<Real> & nodes = mesh.getNodes(); Array<Real> & forces = model.getForce(); Array<bool> & bound = model.getBlockedDOFs(); forces(2, 0) = -250; forces(5, 0) = -500; forces(8, 0) = -250; for (UInt i = 0 ; i < mesh.getNbNodes() ; i++) { if (Math::are_float_equal(nodes(i, 0), 0.)) bound(i, 0) = true; if (Math::are_float_equal(nodes(i, 1), 0.)) bound(i, 1) = true; } // Assemble the global stiffness matrix model.assembleStiffnessMatrix(); model.updateResidual(); model.getStiffnessMatrix().saveMatrix("matrix_test"); model.solveStatic<_scm_newton_raphson_tangent_not_computed, _scc_residual>(1e-7, 1); model.updateResidual(); Real pot_energy = model.getEnergy("potential"); if (std::abs(pot_energy - 7.37343e-06) > 1e-5) return EXIT_FAILURE; finalize(); return 0; } diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc new file mode 100644 index 000000000..57f9b33ff --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc @@ -0,0 +1,225 @@ +/** + * @file test_embedded_interface_model_prestress.cc + * + * @author Lucas Frerot <lucas.frerot@epfl.ch> + * + * @date creation: mar. avril 28 2015 + * @date last modification: mar. avril 28 2015 + * + * @brief Embedded model test for prestressing (bases on stress norm) + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "aka_common.hh" +#include "embedded_interface_model.hh" + +/* -------------------------------------------------------------------------- */ + +using namespace akantu; + +#define YG 0.483644859 +#define I_eq 0.012488874 +#define A_eq (1e-2 + 1. / 7. * 1.) + +/* -------------------------------------------------------------------------- */ + +struct StressSolution : public BC::Neumann::FromHigherDim { + Real M; + Real I; + Real yg; + Real pre_stress; + + StressSolution(UInt dim, Real M, Real I, Real yg = 0, Real pre_stress = 0) : + BC::Neumann::FromHigherDim(Matrix<Real>(dim, dim)), + M(M), I(I), yg(yg), pre_stress(pre_stress) + {} + + virtual ~StressSolution() {} + + void operator()(const QuadraturePoint & quad_point, + Vector<Real> & dual, + const Vector<Real> & coord, + const Vector<Real> & normals) const { + UInt dim = coord.size(); + + if (dim < 2) AKANTU_DEBUG_ERROR("Solution not valid for 1D"); + + Matrix<Real> stress(dim, dim); stress.clear(); + stress(0, 0) = this->stress(coord(1)); + dual.mul<false>(stress, normals); + } + + inline Real stress(Real height) const { + return -M / I * (height - yg) + pre_stress; + } + + inline Real neutral_axis() const { + return -I * pre_stress / M + yg; + } +}; + +/* -------------------------------------------------------------------------- */ + +int main (int argc, char * argv[]) { + initialize("prestress.dat", argc, argv); + debug::setDebugLevel(dblError); + + Math::setTolerance(1e-6); + + const UInt dim = 2; + +/* -------------------------------------------------------------------------- */ + + Mesh mesh(dim); + mesh.read("embedded_mesh_prestress.msh"); + mesh.createGroupsFromMeshData<std::string>("physical_names"); + + Mesh reinforcement_mesh(dim, "reinforcement_mesh"); + try { + reinforcement_mesh.read("embedded_mesh_prestress_reinforcement.msh"); + } catch(debug::Exception & e) {} + + reinforcement_mesh.createGroupsFromMeshData<std::string>("physical_names"); + + EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim); + model.initFull(SolidMechanicsModelOptions(_static)); + +/* -------------------------------------------------------------------------- */ +/* Computation of analytical residual */ +/* -------------------------------------------------------------------------- */ + + /* + * q = 1000 N/m + * L = 20 m + * a = 1 m + */ + + Real steel_area = model.getMaterial("reinforcement").getParam<Real>("area"); + Real pre_stress = 1e6; + Real stress_norm = 0.; + + StressSolution * concrete_stress = NULL, * steel_stress = NULL; + + Real pre_force = pre_stress * steel_area; + Real pre_moment = -pre_force * (YG - 0.25); + Real neutral_axis = YG - I_eq / A_eq * pre_force / pre_moment; + + concrete_stress = new StressSolution(dim, pre_moment, 7. * I_eq, YG, -pre_force / (7. * A_eq)); + steel_stress = new StressSolution(dim, pre_moment, I_eq, YG, pre_stress - pre_force / A_eq); + + stress_norm = std::abs(concrete_stress->stress(1)) * (1 - neutral_axis) * 0.5 + + std::abs(concrete_stress->stress(0)) * neutral_axis * 0.5 + + std::abs(steel_stress->stress(0.25)) * steel_area; + + model.applyBC(*concrete_stress, "XBlocked"); + ElementGroup & end_node = mesh.getElementGroup("EndNode"); + NodeGroup & end_node_group = end_node.getNodeGroup(); + NodeGroup::const_node_iterator end_node_it = end_node_group.begin(); + + Vector<Real> end_node_force = model.getForce().begin(dim)[*end_node_it]; + end_node_force(0) += steel_stress->stress(0.25) * steel_area; + + Array<Real> analytical_residual(mesh.getNbNodes(), dim, "analytical_residual"); + analytical_residual.copy(model.getForce()); + model.getForce().clear(); + + delete concrete_stress; + delete steel_stress; + +/* -------------------------------------------------------------------------- */ + + model.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "XBlocked"); + model.applyBC(BC::Dirichlet::FixedValue(0.0, _y), "YBlocked"); + + // Assemble the global stiffness matrix + model.assembleStiffnessMatrix(); + + model.updateResidual(); + + if (!model.solveStatic<_scm_newton_raphson_tangent_not_computed, _scc_residual>(1e-6, 1)) + return EXIT_FAILURE; + + model.updateResidual(); + +/* -------------------------------------------------------------------------- */ +/* Computation of FEM residual norm */ +/* -------------------------------------------------------------------------- */ + + ElementGroup & xblocked = mesh.getElementGroup("XBlocked"); + NodeGroup & boundary_nodes = xblocked.getNodeGroup(); + NodeGroup::const_node_iterator + nodes_it = boundary_nodes.begin(), + nodes_end = boundary_nodes.end(); + Array<Real>::vector_iterator com_res = model.getResidual().begin(dim); + Array<Real>::vector_iterator ana_res = analytical_residual.begin(dim); + Array<Real>::vector_iterator position = mesh.getNodes().begin(dim); + + Real res_sum = 0.; + UInt lower_node = -1; + UInt upper_node = -1; + Real lower_dist = 1; + Real upper_dist = 1; + + for (; nodes_it != nodes_end ; ++nodes_it) { + UInt node_number = *nodes_it; + const Vector<Real> res = com_res[node_number]; + const Vector<Real> ana = ana_res[node_number]; + const Vector<Real> pos = position[node_number]; + + if (!Math::are_float_equal(pos(1), 0.25)) { + if ((std::abs(pos(1) - 0.25) < lower_dist) && (pos(1) < 0.25)) { + lower_dist = std::abs(pos(1) - 0.25); + lower_node = node_number; + } + + if ((std::abs(pos(1) - 0.25) < upper_dist) && (pos(1) > 0.25)) { + upper_dist = std::abs(pos(1) - 0.25); + upper_node = node_number; + } + } + + for (UInt i = 0 ; i < dim ; i++) { + if (!Math::are_float_equal(pos(1), 0.25)) { + res_sum += std::abs(res(i)); + } + } + } + + const Vector<Real> upper_res = com_res[upper_node], lower_res = com_res[lower_node]; + const Vector<Real> end_node_res = com_res[*end_node_it]; + Vector<Real> delta = upper_res - lower_res; + delta *= lower_dist / (upper_dist + lower_dist); + Vector<Real> concrete_residual = lower_res + delta; + Vector<Real> steel_residual = end_node_res - concrete_residual; + + for (UInt i = 0 ; i < dim ; i++) { + res_sum += std::abs(concrete_residual(i)); + res_sum += std::abs(steel_residual(i)); + } + + Real relative_error = std::abs(res_sum - stress_norm) / stress_norm; + + if (relative_error > 1e-3) + return EXIT_FAILURE; + + finalize(); + return 0; +} diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/triangle.msh b/test/test_model/test_solid_mechanics_model/test_embedded_interface/triangle.msh index 924ed76e5..94ac34b28 100644 --- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/triangle.msh +++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/triangle.msh @@ -1,13 +1,17 @@ $MeshFormat 2.2 0 8 $EndMeshFormat +$PhysicalNames +1 +2 1 "null" +$EndPhysicalNames $Nodes 3 1 0 0 0 2 1 0 0 3 0 1 0 $EndNodes $Elements 1 -1 2 2 0 5 1 2 3 +2 2 2 1 6 1 2 3 $EndElements diff --git a/test/test_model/test_solid_mechanics_model/test_material_selector.cc b/test/test_model/test_solid_mechanics_model/test_material_selector.cc new file mode 100644 index 000000000..c082e2ef7 --- /dev/null +++ b/test/test_model/test_solid_mechanics_model/test_material_selector.cc @@ -0,0 +1,64 @@ +/** + * @file test_material_selector.cc + * + * @author Lucas Frerot <lucas.frerot@epfl.ch> + * + * @date creation: Fri May 01 2015 + * @date last modification: Fri May 01 2015 + * + * @brief Test for material selector + * + * @section LICENSE + * + * Copyright (©) 2010-2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "aka_common.hh" +#include "solid_mechanics_model.hh" + +using namespace akantu; + +int main(int argc, char * argv[]) { + initialize("material_selector.dat", argc, argv); + + Math::setTolerance(1e-8); + + Mesh mesh(1); + mesh.read("material_selector.msh"); + + SolidMechanicsModel model(mesh); + MeshDataMaterialSelector<std::string> selector("physical_names", model); + model.setMaterialSelector(selector); + + model.initFull(); + + Material & chocolate = model.getMaterial("chocolate"); + Material & chewing_gum = model.getMaterial("chewing-gum"); + Material & candy = model.getMaterial("candy"); + + UInt chocolate_element = chocolate.getElementFilter(_segment_2)(0, 0); + UInt chewing_gum_element = chewing_gum.getElementFilter(_segment_2)(0, 0); + UInt candy_element = candy.getElementFilter(_segment_2)(0, 0); + + if (chocolate_element != 0 || + chewing_gum_element != 1 || + candy_element != 2) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} diff --git a/test/test_model/test_structural_mechanics_model/CMakeLists.txt b/test/test_model/test_structural_mechanics_model/CMakeLists.txt index 7ba2bce7e..61e318ca2 100644 --- a/test/test_model/test_structural_mechanics_model/CMakeLists.txt +++ b/test/test_model/test_structural_mechanics_model/CMakeLists.txt @@ -1,72 +1,72 @@ #=============================================================================== # @file CMakeLists.txt # # @author Fabian Barras <fabian.barras@epfl.ch> # # @date creation: Fri Jul 15 2011 # @date last modification: Mon Jul 07 2014 # # @brief Structural Mechanics Model 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/>. # #=============================================================================== register_test(test_structural_mechanics_model_bernoulli_beam_2_exemple_1_1 test_structural_mechanics_model_bernoulli_beam_2_exemple_1_1.cc - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) register_test(test_structural_mechanics_model_bernoulli_beam_2_exemple_1_1_y test_structural_mechanics_model_bernoulli_beam_2_exemple_1_1_y.cc - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) register_test(test_structural_mechanics_model_bernoulli_beam_3_exemple_1_1_xy test_structural_mechanics_model_bernoulli_beam_3_exemple_1_1_xy.cc - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) register_test(test_structural_mechanics_model_bernoulli_beam_3_exemple_1_1_zy test_structural_mechanics_model_bernoulli_beam_3_exemple_1_1_zy.cc - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) register_test(test_structural_mechanics_model_bernoulli_beam_3_exercice_12_10_13 test_structural_mechanics_model_bernoulli_beam_3_exercice_12_10_13.cc - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) register_test(test_structural_mechanics_model_bernoulli_beam_dynamics test_structural_mechanics_model_bernoulli_beam_dynamics.cc - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) register_test(test_structural_mechanics_model_kirchhoff_shell_patch_test_4_5_5 test_structural_mechanics_model_kirchhoff_shell_patch_test_4_5_5.cc - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) add_mesh(complicated_mesh complicated.geo 1 1) register_test(test_structural_mechanics_model_bernoulli_beam_2_complicated test_structural_mechanics_model_bernoulli_beam_2_complicated.cc DEPENDENCIES complicated_mesh - PACKAGE structural_mechanics_model + PACKAGE structural_mechanics ) diff --git a/test/test_solver/1D_bar.geo b/test/test_solver/1D_bar.geo new file mode 100644 index 000000000..235f16da2 --- /dev/null +++ b/test/test_solver/1D_bar.geo @@ -0,0 +1,4 @@ +Point(1) = {0, 0, 0, 1}; +Point(2) = {10, 0, 0, 1}; +Line(1) = {1, 2}; +Physical Line(2) = {1}; diff --git a/test/test_solver/CMakeLists.txt b/test/test_solver/CMakeLists.txt index fd1de042c..61ee1e556 100644 --- a/test/test_solver/CMakeLists.txt +++ b/test/test_solver/CMakeLists.txt @@ -1,70 +1,84 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Dec 13 2010 # @date last modification: Tue Nov 06 2012 # # @brief configuration for solver 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_solver_mesh triangle.geo 2 1) +add_mesh(test_matrix_mesh square.geo 2 1) +add_mesh(test_solver_petsc_mesh 1D_bar.geo 1 1) register_test(test_sparse_matrix_profile SOURCES test_sparse_matrix_profile.cc DEPENDENCIES test_solver_mesh PACKAGE implicit ) register_test(test_sparse_matrix_assemble SOURCES test_sparse_matrix_assemble.cc DEPENDENCIES test_solver_mesh PACKAGE implicit ) register_test(test_sparse_matrix_product SOURCES test_sparse_matrix_product.cc FILES_TO_COPY bar.msh PACKAGE implicit ) register_test(test_petsc_matrix_profile SOURCES test_petsc_matrix_profile.cc + DEPENDENCIES test_matrix_mesh + PACKAGE petsc + ) + +register_test(test_petsc_matrix_profile_parallel + SOURCES test_petsc_matrix_profile_parallel.cc + DEPENDENCIES test_matrix_mesh + PACKAGE petsc + ) + +register_test(test_petsc_matrix_diagonal + SOURCES test_petsc_matrix_diagonal.cc DEPENDENCIES test_solver_mesh PACKAGE petsc ) register_test(test_petsc_matrix_apply_boundary SOURCES test_petsc_matrix_apply_boundary.cc DEPENDENCIES test_solver_mesh PACKAGE petsc ) register_test(test_solver_petsc SOURCES test_solver_petsc.cc - DEPENDENCIES profile.mtx + DEPENDENCIES test_solver_petsc_mesh PACKAGE petsc ) \ No newline at end of file diff --git a/test/test_solver/square.geo b/test/test_solver/square.geo new file mode 100644 index 000000000..67df205f8 --- /dev/null +++ b/test/test_solver/square.geo @@ -0,0 +1,28 @@ +// Mesh size +h = 1.0; // 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, 0.0, 0.0, h}; // Bottom Face +Point(103) = { Lx, Ly, 0.0, h}; // Bottom Face +Point(104) = { 0.0, Ly, 0.0, h}; // Bottom Face + +// Base Cube +Line(101) = {101,102}; // Bottom Face +Line(102) = {102,103}; // Bottom Face +Line(103) = {103,104}; // Bottom Face +Line(104) = {104,101}; // Bottom Face + +// Base Cube +Line Loop(101) = {101:104}; + +// Base Cube +Plane Surface(101) = {101}; diff --git a/test/test_solver/test_petsc_matrix_apply_boundary.cc b/test/test_solver/test_petsc_matrix_apply_boundary.cc index 068750a25..92e598bab 100644 --- a/test/test_solver/test_petsc_matrix_apply_boundary.cc +++ b/test/test_solver/test_petsc_matrix_apply_boundary.cc @@ -1,151 +1,140 @@ /** * @file test_petsc_matrix_profile.cc * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Wed Jul 30 12:34:08 2014 * * @brief test the applyBoundary method of the PETScMatrix class * * @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 <cstdlib> /* -------------------------------------------------------------------------- */ #include "static_communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "distributed_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ DistributedSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("triangle.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); // fill the matrix with UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; SparseMatrix K(nb_global_nodes * spatial_dimension, _symmetric); K.buildProfile(mesh, dof_synchronizer, spatial_dimension); Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type); // create petsc matrix PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _symmetric); petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); // add stiffness matrix to petsc matrix petsc_matrix.add(K, 1); // create boundary array: block all dofs UInt nb_nodes = mesh.getNbNodes(); Array<bool> boundary = Array<bool>(nb_nodes, spatial_dimension, true); - //boundary(2,1) = true; - - - std::cout << dof_synchronizer.getDOFGlobalID(2*2+1) <<std::endl; - - - // apply boundary petsc_matrix.applyBoundary(boundary); // test if all entries except the diagonal ones have been zeroed Real test_passed = 0; for (UInt i = 0; i < nb_nodes * spatial_dimension; ++i) { if (dof_synchronizer.isLocalOrMasterDOF(i)) { for (UInt j = 0; j < nb_nodes * spatial_dimension; ++j) { if (dof_synchronizer.isLocalOrMasterDOF(j)) { if (i == j) test_passed += petsc_matrix(i, j) - 1; else test_passed += petsc_matrix(i, j) - 0; - UInt global_i = dof_synchronizer.getDOFGlobalID(i); - UInt global_j = dof_synchronizer.getDOFGlobalID(j); - std::cout << "K(" << global_i << "," << global_j << ")=" << petsc_matrix(i, j) << std::endl; } } } } - petsc_matrix.saveMatrix("profile_after_boundary.mtx"); + + if (std::abs(test_passed) > Math::getTolerance()) + return EXIT_FAILURE; + delete communicator; finalize(); - // if (std::abs(test_passed) > Math::getTolerance()) - // return EXIT_FAILURE; - - std::cout << " Test passed!!!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_solver/test_petsc_matrix_apply_boundary.sh b/test/test_solver/test_petsc_matrix_apply_boundary.sh new file mode 100755 index 000000000..f053c4da0 --- /dev/null +++ b/test/test_solver/test_petsc_matrix_apply_boundary.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +mpirun -np 4 ./test_petsc_matrix_apply_boundary diff --git a/test/test_solver/test_petsc_matrix_profile.cc b/test/test_solver/test_petsc_matrix_diagonal.cc similarity index 61% copy from test/test_solver/test_petsc_matrix_profile.cc copy to test/test_solver/test_petsc_matrix_diagonal.cc index 1a8f2f4e7..eef514153 100644 --- a/test/test_solver/test_petsc_matrix_profile.cc +++ b/test/test_solver/test_petsc_matrix_diagonal.cc @@ -1,137 +1,146 @@ /** - * @file test_petsc_matrix_profile.cc - * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> - * @date Wed Jul 30 12:34:08 2014 + * @file test_petsc_matrix_diagonal.cc + * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> + * @date Wed Apr 22 09:41:14 2015 * - * @brief test the profile generation of the PETScMatrix class + * @brief test the connectivity is correctly represented in the PETScMatrix * * @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 <cstdlib> /* -------------------------------------------------------------------------- */ #include "static_communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "distributed_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" - +#include "dumper_paraview.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ DistributedSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("triangle.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } + DumperParaview mesh_dumper("mesh_dumper"); + mesh_dumper.registerMesh(mesh, spatial_dimension, _not_ghost); + mesh_dumper.dump(); + /// initialize the FEEngine and the dof_synchronizer FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); - // fill the matrix with + // construct an Akantu sparse matrix, build the profile and fill the matrix for the given mesh UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; - SparseMatrix K(nb_global_nodes * spatial_dimension, _unsymmetric); - K.buildProfile(mesh, dof_synchronizer, spatial_dimension); - Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1); + SparseMatrix K_akantu(nb_global_nodes * spatial_dimension, _unsymmetric); + K_akantu.buildProfile(mesh, dof_synchronizer, spatial_dimension); + /// use as elemental matrices a matrix with values equal to 1 every where + Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1.); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix - fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type); - + fem->assembleMatrix(K_e, K_akantu, spatial_dimension, element_type, ghost_type); + + /// construct a PETSc matrix + PETScMatrix K_petsc(nb_global_nodes * spatial_dimension, _unsymmetric); + /// build the profile of the PETSc matrix for the mesh of this example + K_petsc.buildProfile(mesh, dof_synchronizer, spatial_dimension); + /// add an Akantu sparse matrix to a PETSc sparse matrix + K_petsc.add(K_akantu, 1); + + /// check to how many elements each node is connected CSR<Element> node_to_elem; MeshUtils::buildNode2Elements(mesh, node_to_elem, spatial_dimension); - for (UInt i = 0; i < mesh.getNbNodes(); ++i) { - std::cout << node_to_elem.getNbCols(i) << std::endl; + /// test the diagonal of the PETSc matrix: the diagonal entries + /// of the PETSc matrix correspond to the number of elements + /// connected to the node of the dof. Note: for an Akantu matrix this is only true for the serial case + Real error = 0.; + /// loop over all diagonal values of the matrix + for (UInt i = 0; i < mesh.getNbNodes(); ++i) { + for (UInt j = 0; j < spatial_dimension; ++j) { + UInt dof = i * spatial_dimension + j; + /// for PETSc matrix only DOFs on the processor and be accessed + if (dof_synchronizer.isLocalOrMasterDOF(dof)) { + UInt global_dof = dof_synchronizer.getDOFGlobalID(dof); + std::cout << "Number of elements connected: " << node_to_elem.getNbCols(i) << std::endl; + std::cout << "K_petsc(" << global_dof << "," << global_dof << ")=" << K_petsc(dof,dof) << std::endl; + error += std::abs(K_petsc(dof, dof) - node_to_elem.getNbCols(i)); + } + } } - PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _unsymmetric); - - petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); - - - petsc_matrix.add(K, 1); - - // for (UInt i = 0; i < mesh.getNbNodes(); ++i) { - // for (UInt j = 0; j < spatial_dimension; ++j) { - // UInt dof = i * spatial_dimension + j; - // if (dof_synchronizer.isLocalOrMasterDOF(dof)) { - // UInt global_dof = dof_synchronizer.getDOFGlobalID(dof); - // std::cout << "K(" << global_dof << "," << global_dof << ")=" << petsc_matrix(dof,dof) << std::endl; - // std::cout << node_to_elem.getNbCols(i) << std::endl; - // } - // } - // } - - - - - petsc_matrix.saveMatrix("profile.dat"); + if(error > Math::getTolerance() ) { + std::cout << "error in the stiffness matrix!!!" << std::cout; + return EXIT_FAILURE; + } delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_petsc_matrix_diagonal.sh b/test/test_solver/test_petsc_matrix_diagonal.sh new file mode 100755 index 000000000..5f592e4b2 --- /dev/null +++ b/test/test_solver/test_petsc_matrix_diagonal.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +mpirun -np 4 ./test_petsc_matrix_diagonal diff --git a/test/test_solver/test_petsc_matrix_profile.cc b/test/test_solver/test_petsc_matrix_profile.cc index 1a8f2f4e7..bff41dcfd 100644 --- a/test/test_solver/test_petsc_matrix_profile.cc +++ b/test/test_solver/test_petsc_matrix_profile.cc @@ -1,137 +1,131 @@ /** * @file test_petsc_matrix_profile.cc * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Wed Jul 30 12:34:08 2014 * * @brief test the profile generation of the PETScMatrix class * * @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 <cstdlib> +#include <fstream> /* -------------------------------------------------------------------------- */ #include "static_communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "distributed_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" - +/// #include "dumper_paraview.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ DistributedSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh - mesh.read("triangle.msh"); + mesh.read("square.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } - + // dump mesh in paraview + // DumperParaview mesh_dumper("mesh_dumper"); + // mesh_dumper.registerMesh(mesh, spatial_dimension, _not_ghost); + // mesh_dumper.dump(); + + /// initialize the FEEngine and the dof_synchronizer FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); - // fill the matrix with + // construct an Akantu sparse matrix, build the profile and fill the matrix for the given mesh UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; - SparseMatrix K(nb_global_nodes * spatial_dimension, _unsymmetric); - K.buildProfile(mesh, dof_synchronizer, spatial_dimension); - Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1); + SparseMatrix K_akantu(nb_global_nodes * spatial_dimension, _unsymmetric); + K_akantu.buildProfile(mesh, dof_synchronizer, spatial_dimension); + /// use as elemental matrices a matrix with values equal to 1 every where + Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1.); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix - fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type); - - CSR<Element> node_to_elem; - - MeshUtils::buildNode2Elements(mesh, node_to_elem, spatial_dimension); - - for (UInt i = 0; i < mesh.getNbNodes(); ++i) { - std::cout << node_to_elem.getNbCols(i) << std::endl; - } - - PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _unsymmetric); - - petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); - - - petsc_matrix.add(K, 1); + fem->assembleMatrix(K_e, K_akantu, spatial_dimension, element_type, ghost_type); - // for (UInt i = 0; i < mesh.getNbNodes(); ++i) { - // for (UInt j = 0; j < spatial_dimension; ++j) { - // UInt dof = i * spatial_dimension + j; - // if (dof_synchronizer.isLocalOrMasterDOF(dof)) { - // UInt global_dof = dof_synchronizer.getDOFGlobalID(dof); - // std::cout << "K(" << global_dof << "," << global_dof << ")=" << petsc_matrix(dof,dof) << std::endl; - // std::cout << node_to_elem.getNbCols(i) << std::endl; - // } - // } - // } - - - - - petsc_matrix.saveMatrix("profile.dat"); + /// construct a PETSc matrix + PETScMatrix K_petsc(nb_global_nodes * spatial_dimension, _unsymmetric); + /// build the profile of the PETSc matrix for the mesh of this example + K_petsc.buildProfile(mesh, dof_synchronizer, spatial_dimension); + /// add an Akantu sparse matrix to a PETSc sparse matrix + K_petsc.add(K_akantu, 1); + + /// save the profile + K_petsc.saveMatrix("profile.txt"); + + /// print the matrix to screen + std::ifstream profile; + profile.open("profile.txt"); + std::string current_line; + while(getline(profile, current_line)) + std::cout << current_line << std::endl; + profile.close(); delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_petsc_matrix_profile.verified b/test/test_solver/test_petsc_matrix_profile.verified new file mode 100644 index 000000000..4213dba00 --- /dev/null +++ b/test/test_solver/test_petsc_matrix_profile.verified @@ -0,0 +1,12 @@ +Matrix Object: 1 MPI processes + type: seqaij +row 0: (0, 2) (1, 2) (2, 1) (3, 1) (6, 1) (7, 1) (8, 2) (9, 2) +row 1: (0, 2) (1, 2) (2, 1) (3, 1) (6, 1) (7, 1) (8, 2) (9, 2) +row 2: (0, 1) (1, 1) (2, 2) (3, 2) (4, 1) (5, 1) (8, 2) (9, 2) +row 3: (0, 1) (1, 1) (2, 2) (3, 2) (4, 1) (5, 1) (8, 2) (9, 2) +row 4: (2, 1) (3, 1) (4, 2) (5, 2) (6, 1) (7, 1) (8, 2) (9, 2) +row 5: (2, 1) (3, 1) (4, 2) (5, 2) (6, 1) (7, 1) (8, 2) (9, 2) +row 6: (0, 1) (1, 1) (4, 1) (5, 1) (6, 2) (7, 2) (8, 2) (9, 2) +row 7: (0, 1) (1, 1) (4, 1) (5, 1) (6, 2) (7, 2) (8, 2) (9, 2) +row 8: (0, 2) (1, 2) (2, 2) (3, 2) (4, 2) (5, 2) (6, 2) (7, 2) (8, 4) (9, 4) +row 9: (0, 2) (1, 2) (2, 2) (3, 2) (4, 2) (5, 2) (6, 2) (7, 2) (8, 4) (9, 4) diff --git a/test/test_solver/test_petsc_matrix_profile.cc b/test/test_solver/test_petsc_matrix_profile_parallel.cc similarity index 71% copy from test/test_solver/test_petsc_matrix_profile.cc copy to test/test_solver/test_petsc_matrix_profile_parallel.cc index 1a8f2f4e7..2ec40523c 100644 --- a/test/test_solver/test_petsc_matrix_profile.cc +++ b/test/test_solver/test_petsc_matrix_profile_parallel.cc @@ -1,137 +1,130 @@ /** * @file test_petsc_matrix_profile.cc * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Wed Jul 30 12:34:08 2014 * - * @brief test the profile generation of the PETScMatrix class + * @brief test the profile generation of the PETScMatrix class in parallel * * @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 <cstdlib> +#include <fstream> /* -------------------------------------------------------------------------- */ #include "static_communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "distributed_synchronizer.hh" #include "petsc_matrix.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" - +/// #include "dumper_paraview.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _triangle_3; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 2; StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ DistributedSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh - mesh.read("triangle.msh"); + mesh.read("square.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } - + // dump mesh in paraview + // DumperParaview mesh_dumper("mesh_dumper"); + // mesh_dumper.registerMesh(mesh, spatial_dimension, _not_ghost); + // mesh_dumper.dump(); + + /// initialize the FEEngine and the dof_synchronizer FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); - // fill the matrix with + // construct an Akantu sparse matrix, build the profile and fill the matrix for the given mesh UInt nb_element = mesh.getNbElement(element_type); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; - SparseMatrix K(nb_global_nodes * spatial_dimension, _unsymmetric); - K.buildProfile(mesh, dof_synchronizer, spatial_dimension); - Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1); + SparseMatrix K_akantu(nb_global_nodes * spatial_dimension, _unsymmetric); + K_akantu.buildProfile(mesh, dof_synchronizer, spatial_dimension); + /// use as elemental matrices a matrix with values equal to 1 every where + Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1.); Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix - fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type); - - CSR<Element> node_to_elem; - - MeshUtils::buildNode2Elements(mesh, node_to_elem, spatial_dimension); - - for (UInt i = 0; i < mesh.getNbNodes(); ++i) { - std::cout << node_to_elem.getNbCols(i) << std::endl; - } - - PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _unsymmetric); - - petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); - - - petsc_matrix.add(K, 1); + fem->assembleMatrix(K_e, K_akantu, spatial_dimension, element_type, ghost_type); - // for (UInt i = 0; i < mesh.getNbNodes(); ++i) { - // for (UInt j = 0; j < spatial_dimension; ++j) { - // UInt dof = i * spatial_dimension + j; - // if (dof_synchronizer.isLocalOrMasterDOF(dof)) { - // UInt global_dof = dof_synchronizer.getDOFGlobalID(dof); - // std::cout << "K(" << global_dof << "," << global_dof << ")=" << petsc_matrix(dof,dof) << std::endl; - // std::cout << node_to_elem.getNbCols(i) << std::endl; - // } - // } - // } - - - - - petsc_matrix.saveMatrix("profile.dat"); + /// construct a PETSc matrix + PETScMatrix K_petsc(nb_global_nodes * spatial_dimension, _unsymmetric); + /// build the profile of the PETSc matrix for the mesh of this example + K_petsc.buildProfile(mesh, dof_synchronizer, spatial_dimension); + /// add an Akantu sparse matrix to a PETSc sparse matrix + K_petsc.add(K_akantu, 1); + + /// save the profile + K_petsc.saveMatrix("profile_parallel.txt"); + /// print the matrix to screen + std::ifstream profile; + profile.open("profile_parallel.txt"); + std::string current_line; + while(getline(profile, current_line)) + std::cout << current_line << std::endl; + profile.close(); delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_petsc_matrix_profile_parallel.sh b/test/test_solver/test_petsc_matrix_profile_parallel.sh new file mode 100755 index 000000000..2dd775687 --- /dev/null +++ b/test/test_solver/test_petsc_matrix_profile_parallel.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +mpirun -np 2 ./test_petsc_matrix_profile_parallel diff --git a/test/test_solver/test_petsc_matrix_profile_parallel.verified b/test/test_solver/test_petsc_matrix_profile_parallel.verified new file mode 100644 index 000000000..662687ada --- /dev/null +++ b/test/test_solver/test_petsc_matrix_profile_parallel.verified @@ -0,0 +1,12 @@ +Matrix Object: 1 MPI processes + type: mpiaij +row 0: (0, 2) (1, 2) (2, 1) (3, 1) (4, 1) (5, 1) (6, 2) (7, 2) +row 1: (0, 2) (1, 2) (2, 1) (3, 1) (4, 1) (5, 1) (6, 2) (7, 2) +row 2: (0, 1) (1, 1) (2, 2) (3, 2) (6, 2) (7, 2) (8, 1) (9, 1) +row 3: (0, 1) (1, 1) (2, 2) (3, 2) (6, 2) (7, 2) (8, 1) (9, 1) +row 4: (0, 1) (1, 1) (4, 2) (5, 2) (6, 2) (7, 2) (8, 1) (9, 1) +row 5: (0, 1) (1, 1) (4, 2) (5, 2) (6, 2) (7, 2) (8, 1) (9, 1) +row 6: (0, 2) (1, 2) (2, 2) (3, 2) (4, 2) (5, 2) (6, 4) (7, 4) (8, 2) (9, 2) +row 7: (0, 2) (1, 2) (2, 2) (3, 2) (4, 2) (5, 2) (6, 4) (7, 4) (8, 2) (9, 2) +row 8: (2, 1) (3, 1) (4, 1) (5, 1) (6, 2) (7, 2) (8, 2) (9, 2) +row 9: (2, 1) (3, 1) (4, 1) (5, 1) (6, 2) (7, 2) (8, 2) (9, 2) diff --git a/test/test_solver/test_solver_petsc.cc b/test/test_solver/test_solver_petsc.cc index 41aaea640..2eb172f50 100644 --- a/test/test_solver/test_solver_petsc.cc +++ b/test/test_solver/test_solver_petsc.cc @@ -1,154 +1,161 @@ /** * @file test_solver_petsc.cc * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Tue Dec 2 17:17:34 2014 * * @brief test the PETSc solver interface * * @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 <cstdlib> /* -------------------------------------------------------------------------- */ #include "static_communicator.hh" #include "aka_common.hh" #include "aka_csr.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_utils.hh" #include "distributed_synchronizer.hh" #include "petsc_matrix.hh" #include "solver_petsc.hh" #include "fe_engine.hh" #include "dof_synchronizer.hh" #include "mesh_partition_scotch.hh" using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); const ElementType element_type = _segment_2; const GhostType ghost_type = _not_ghost; UInt spatial_dimension = 1; StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); /// read the mesh and partition it Mesh mesh(spatial_dimension); /* ------------------------------------------------------------------------ */ /* Parallel initialization */ /* ------------------------------------------------------------------------ */ DistributedSynchronizer * communicator = NULL; if(prank == 0) { /// creation mesh mesh.read("1D_bar.msh"); MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition); delete partition; } else { communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL); } FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem"); DOFSynchronizer dof_synchronizer(mesh, spatial_dimension); UInt nb_global_nodes = mesh.getNbGlobalNodes(); dof_synchronizer.initGlobalDOFEquationNumbers(); // fill the matrix with UInt nb_element = mesh.getNbElement(element_type); - std::cout << mesh.getNbElement(element_type, _ghost) <<std::endl; - UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type); UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element; SparseMatrix K(nb_global_nodes * spatial_dimension, _symmetric); K.buildProfile(mesh, dof_synchronizer, spatial_dimension); Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 0); for (UInt i = 0; i < nb_dofs_per_element; ++i) { for (UInt j = 0; j < nb_dofs_per_element; ++j) { element_input(i, j) = ((i == j) ? 1 : -1); } } Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e"); Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element); Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element); for(; K_e_it != K_e_end; ++K_e_it) *K_e_it = element_input; // assemble the test matrix fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type); // apply boundary: block first node const Array<Real> & position = mesh.getNodes(); UInt nb_nodes = mesh.getNbNodes(); Array<bool> boundary = Array<bool>(nb_nodes, spatial_dimension, false); for (UInt i = 0; i < nb_nodes; ++i) { if (std::abs(position(i, 0)) < Math::getTolerance() ) boundary(i, 0) = true; } K.applyBoundary(boundary); /// create the PETSc matrix for the solve step PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _symmetric); petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); /// copy the stiffness matrix into the petsc matrix petsc_matrix.add(K, 1); // initialize internal forces: they are zero because imposed displacement is zero Array<Real> internal_forces(nb_nodes, spatial_dimension, 0.); // compute residual: apply nodal force on last node Array<Real> residual(nb_nodes, spatial_dimension, 0.); - residual -= internal_forces; + for (UInt i = 0; i < nb_nodes; ++i) { if (std::abs(position(i, 0) - 10) < Math::getTolerance() ) residual(i, 0) += 2; } - /// solve the matrix before the solve step - petsc_matrix.saveMatrix("1D_bar.mtx"); + residual -= internal_forces; /// initialize solver and solution Array<Real> solution(nb_nodes, spatial_dimension, 0.); SolverPETSc solver(petsc_matrix); solver.initialize(); + solver.setOperators(); solver.setRHS(residual); solver.solve(solution); + /// verify solution + Math::setTolerance(1e-11); + for (UInt i = 0; i < nb_nodes; ++i) { + if (!dof_synchronizer.isPureGhostDOF(i) && !Math::are_float_equal(2 * position(i, 0), solution(i, 0))) { + std::cout << "The solution is not correct!!!!" << std::endl; + return EXIT_FAILURE; + } + } + delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_solver/test_solver_petsc.sh b/test/test_solver/test_solver_petsc.sh new file mode 100755 index 000000000..edcc7916c --- /dev/null +++ b/test/test_solver/test_solver_petsc.sh @@ -0,0 +1,5 @@ +#! /bin/bash + +# choose solver Mumps through the PETSc interface +./test_solver_petsc -ksp_type preonly -pc_type lu -pc_factor_mat_solver_package mumps -mat_mumps_icntl_7 2 +mpirun -np 4 ./test_solver_petsc -ksp_type preonly -pc_type lu -pc_factor_mat_solver_package mumps -mat_mumps_icntl_7 2