diff --git a/packages/00_core.cmake b/packages/00_core.cmake index b8e823857..8dc96d9a1 100644 --- a/packages/00_core.cmake +++ b/packages/00_core.cmake @@ -1,434 +1,435 @@ #=============================================================================== # @file 00_core.cmake # # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Mon Nov 21 2011 # @date last modification: Fri Sep 19 2014 # # @brief package description for core # # @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/>. # #=============================================================================== set(AKANTU_CORE ON CACHE INTERNAL "core package for Akantu" FORCE) set(AKANTU_CORE_FILES common/aka_array.cc common/aka_array.hh common/aka_array_tmpl.hh common/aka_blas_lapack.hh common/aka_circular_array.hh common/aka_circular_array_inline_impl.cc common/aka_common.cc common/aka_common.hh common/aka_common_inline_impl.cc common/aka_csr.hh common/aka_error.cc common/aka_error.hh common/aka_event_handler_manager.hh common/aka_extern.cc common/aka_fwd.hh common/aka_grid_dynamic.hh common/aka_math.cc common/aka_math.hh common/aka_math_tmpl.hh common/aka_memory.cc common/aka_memory.hh common/aka_memory_inline_impl.cc common/aka_random_generator.hh common/aka_safe_enum.hh common/aka_static_memory.cc common/aka_static_memory.hh common/aka_static_memory_inline_impl.cc common/aka_static_memory_tmpl.hh common/aka_typelist.hh common/aka_types.hh common/aka_visitor.hh common/aka_voigthelper.hh common/aka_voigthelper.cc fe_engine/element_class.cc fe_engine/element_class.hh fe_engine/element_class_tmpl.hh fe_engine/element_classes/element_class_hexahedron_8_inline_impl.cc fe_engine/element_classes/element_class_pentahedron_6_inline_impl.cc fe_engine/element_classes/element_class_point_1_inline_impl.cc fe_engine/element_classes/element_class_quadrangle_4_inline_impl.cc fe_engine/element_classes/element_class_quadrangle_8_inline_impl.cc fe_engine/element_classes/element_class_segment_2_inline_impl.cc fe_engine/element_classes/element_class_segment_3_inline_impl.cc fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.cc fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.cc fe_engine/element_classes/element_class_triangle_3_inline_impl.cc fe_engine/element_classes/element_class_triangle_6_inline_impl.cc fe_engine/fe_engine.cc fe_engine/fe_engine.hh fe_engine/fe_engine_inline_impl.cc fe_engine/fe_engine_template.hh fe_engine/fe_engine_template_tmpl.hh fe_engine/geometrical_data_tmpl.hh fe_engine/geometrical_element.cc fe_engine/integration_element.cc fe_engine/integrator.hh fe_engine/integrator_gauss.hh fe_engine/integrator_gauss_inline_impl.cc fe_engine/interpolation_element.cc fe_engine/interpolation_element_tmpl.hh fe_engine/shape_functions.hh fe_engine/shape_functions_inline_impl.cc fe_engine/shape_lagrange.cc fe_engine/shape_lagrange.hh fe_engine/shape_lagrange_inline_impl.cc fe_engine/shape_linked.cc fe_engine/shape_linked.hh fe_engine/shape_linked_inline_impl.cc fe_engine/element.hh io/dumper/dumpable.hh io/dumper/dumpable.cc io/dumper/dumpable_inline_impl.hh io/dumper/dumper_field.hh io/dumper/dumper_material_padders.hh io/dumper/dumper_filtered_connectivity.hh io/dumper/dumper_element_type.hh io/dumper/dumper_element_partition.hh io/mesh_io.cc io/mesh_io.hh io/mesh_io/mesh_io_abaqus.cc io/mesh_io/mesh_io_abaqus.hh io/mesh_io/mesh_io_diana.cc io/mesh_io/mesh_io_diana.hh io/mesh_io/mesh_io_msh.cc io/mesh_io/mesh_io_msh.hh io/model_io.cc io/model_io.hh io/parser/algebraic_parser.hh io/parser/input_file_parser.hh io/parser/parsable.cc io/parser/parsable.hh io/parser/parsable_tmpl.hh io/parser/parser.cc io/parser/parser.hh io/parser/parser_tmpl.hh io/parser/cppargparse/cppargparse.hh io/parser/cppargparse/cppargparse.cc io/parser/cppargparse/cppargparse_tmpl.hh mesh/element_group.cc mesh/element_group.hh mesh/element_group_inline_impl.cc mesh/element_type_map.hh mesh/element_type_map_tmpl.hh mesh/element_type_map_filter.hh mesh/group_manager.cc mesh/group_manager.hh mesh/group_manager_inline_impl.cc mesh/mesh.cc mesh/mesh.hh mesh/mesh_filter.hh mesh/mesh_data.cc mesh/mesh_data.hh mesh/mesh_data_tmpl.hh mesh/mesh_inline_impl.cc mesh/node_group.cc mesh/node_group.hh mesh/node_group_inline_impl.cc mesh_utils/mesh_partition.cc mesh_utils/mesh_partition.hh mesh_utils/mesh_partition/mesh_partition_mesh_data.cc mesh_utils/mesh_partition/mesh_partition_mesh_data.hh mesh_utils/mesh_partition/mesh_partition_scotch.hh mesh_utils/mesh_pbc.cc mesh_utils/mesh_utils.cc mesh_utils/mesh_utils.hh mesh_utils/mesh_utils_inline_impl.cc model/boundary_condition.hh model/boundary_condition_functor.hh model/boundary_condition_functor_inline_impl.cc model/boundary_condition_tmpl.hh model/integration_scheme/generalized_trapezoidal.hh model/integration_scheme/generalized_trapezoidal_inline_impl.cc model/integration_scheme/integration_scheme_1st_order.hh model/integration_scheme/integration_scheme_2nd_order.hh model/integration_scheme/newmark-beta.hh model/integration_scheme/newmark-beta_inline_impl.cc model/model.cc model/model.hh model/model_inline_impl.cc model/solid_mechanics/material.cc model/solid_mechanics/material.hh model/solid_mechanics/material_inline_impl.cc model/solid_mechanics/material_list.hh model/solid_mechanics/material_random_internal.hh model/solid_mechanics/material_selector.hh model/solid_mechanics/material_selector_tmpl.hh model/solid_mechanics/materials/internal_field.hh model/solid_mechanics/materials/internal_field_tmpl.hh model/solid_mechanics/materials/random_internal_field.hh model/solid_mechanics/materials/random_internal_field_tmpl.hh model/solid_mechanics/solid_mechanics_model.cc model/solid_mechanics/solid_mechanics_model.hh model/solid_mechanics/solid_mechanics_model_inline_impl.cc model/solid_mechanics/solid_mechanics_model_mass.cc model/solid_mechanics/solid_mechanics_model_material.cc model/solid_mechanics/solid_mechanics_model_tmpl.hh model/solid_mechanics/solid_mechanics_model_event_handler.hh model/solid_mechanics/materials/plane_stress_toolbox.hh model/solid_mechanics/materials/plane_stress_toolbox_tmpl.hh model/solid_mechanics/materials/material_elastic.cc model/solid_mechanics/materials/material_elastic.hh model/solid_mechanics/materials/material_elastic_inline_impl.cc model/solid_mechanics/materials/material_thermal.cc model/solid_mechanics/materials/material_thermal.hh model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh model/solid_mechanics/materials/material_elastic_orthotropic.cc model/solid_mechanics/materials/material_elastic_orthotropic.hh model/solid_mechanics/materials/material_damage/material_damage.hh model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh model/solid_mechanics/materials/material_damage/material_marigo.cc model/solid_mechanics/materials/material_damage/material_marigo.hh model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc model/solid_mechanics/materials/material_damage/material_mazars.cc model/solid_mechanics/materials/material_damage/material_mazars.hh model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc model/solid_mechanics/materials/material_plastic/material_plastic.cc model/solid_mechanics/materials/material_plastic/material_plastic.hh model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh solver/solver.cc solver/solver.hh + solver/solver_inline_impl.cc solver/sparse_matrix.cc solver/sparse_matrix.hh solver/sparse_matrix_inline_impl.cc solver/static_solver.hh solver/static_solver.cc synchronizer/communication_buffer.hh synchronizer/communication_buffer_inline_impl.cc synchronizer/data_accessor.cc synchronizer/data_accessor.hh synchronizer/data_accessor_inline_impl.cc synchronizer/distributed_synchronizer.cc synchronizer/distributed_synchronizer.hh synchronizer/distributed_synchronizer_tmpl.hh synchronizer/dof_synchronizer.cc synchronizer/dof_synchronizer.hh synchronizer/dof_synchronizer_inline_impl.cc synchronizer/filtered_synchronizer.cc synchronizer/filtered_synchronizer.hh synchronizer/mpi_type_wrapper.hh synchronizer/pbc_synchronizer.cc synchronizer/pbc_synchronizer.hh synchronizer/real_static_communicator.hh synchronizer/static_communicator.cc synchronizer/static_communicator.hh synchronizer/static_communicator_dummy.hh synchronizer/static_communicator_inline_impl.hh synchronizer/synchronizer.cc synchronizer/synchronizer.hh synchronizer/synchronizer_registry.cc synchronizer/synchronizer_registry.hh ) set(AKANTU_CORE_DEB_DEPEND libboost-dev ) set(AKANTU_CORE_TESTS test_csr test_facet_element_mapping test_facet_extraction_tetrahedron_4 test_facet_extraction_triangle_3 test_grid test_interpolate_stress test_local_material test_material_damage_non_local test_material_thermal test_matrix test_mesh_boundary test_mesh_data test_mesh_io_msh test_mesh_io_msh_physical_names test_mesh_partitionate_mesh_data test_parser test_dumper test_pbc_tweak test_purify_mesh test_solid_mechanics_model_bar_traction2d test_solid_mechanics_model_bar_traction2d_structured test_solid_mechanics_model_bar_traction2d_structured_pbc test_solid_mechanics_model_boundary_condition test_solid_mechanics_model_circle_2 test_solid_mechanics_model_cube3d test_solid_mechanics_model_cube3d_pbc test_solid_mechanics_model_cube3d_tetra10 test_solid_mechanics_model_square test_solid_mechanics_model_material_eigenstrain test_static_memory test_surface_extraction_tetrahedron_4 test_surface_extraction_triangle_3 test_vector test_vector_iterator test_weight test_math test_material_standard_linear_solid_deviatoric_relaxation test_material_standard_linear_solid_deviatoric_relaxation_tension test_material_plasticity ) set(AKANTU_CORE_MANUAL_FILES manual.sty manual.cls manual.tex manual-macros.sty manual-titlepages.tex manual-introduction.tex manual-gettingstarted.tex manual-io.tex manual-solidmechanicsmodel.tex manual-constitutive-laws.tex manual-lumping.tex manual-elements.tex manual-appendix-elements.tex manual-appendix-materials.tex manual-appendix-packages.tex manual-backmatter.tex manual-bibliography.bib manual-bibliographystyle.bst figures/bc_and_ic_example.pdf figures/boundary.pdf figures/boundary.svg figures/dirichlet.pdf figures/dirichlet.svg figures/doc_wheel.pdf figures/doc_wheel.svg figures/dynamic_analysis.png figures/explicit_dynamic.pdf figures/explicit_dynamic.svg figures/static.pdf figures/static.svg figures/hooke_law.pdf figures/hot-point-1.png figures/hot-point-2.png figures/implicit_dynamic.pdf figures/implicit_dynamic.svg figures/insertion.pdf figures/interpolate.pdf figures/interpolate.svg figures/problemDomain.pdf_tex figures/problemDomain.pdf figures/static_analysis.png figures/stress_strain_el.pdf figures/tangent.pdf figures/tangent.svg figures/vectors.pdf figures/vectors.svg figures/stress_strain_neo.pdf figures/visco_elastic_law.pdf figures/isotropic_hardening_plasticity.pdf figures/stress_strain_visco.pdf figures/elements/hexahedron_8.pdf figures/elements/hexahedron_8.svg figures/elements/quadrangle_4.pdf figures/elements/quadrangle_4.svg figures/elements/quadrangle_8.pdf figures/elements/quadrangle_8.svg figures/elements/segment_2.pdf figures/elements/segment_2.svg figures/elements/segment_3.pdf figures/elements/segment_3.svg figures/elements/tetrahedron_10.pdf figures/elements/tetrahedron_10.svg figures/elements/tetrahedron_4.pdf figures/elements/tetrahedron_4.svg figures/elements/triangle_3.pdf figures/elements/triangle_3.svg figures/elements/triangle_6.pdf figures/elements/triangle_6.svg figures/elements/xtemp.pdf ) find_program(READLINK_COMMAND readlink) find_program(ADDR2LINE_COMMAND addr2line) mark_as_advanced(READLINK_COMMAND) mark_as_advanced(ADDR2LINE_COMMAND) include(CheckFunctionExists) check_function_exists(clock_gettime _clock_gettime) if(NOT _clock_gettime) set(AKANTU_USE_OBSOLETE_GETTIMEOFDAY ON) else() set(AKANTU_USE_OBSOLETE_GETTIMEOFDAY OFF) endif() set(AKANTU_CORE_DOCUMENTATION " This package is the core engine of \\akantu. It depends on: \\begin{itemize} \\item A C++ compiler (\\href{http://gcc.gnu.org/}{GCC} >= 4, or \\href{https://software.intel.com/en-us/intel-compilers}{Intel}). \\item The cross-platform, open-source \\href{http://www.cmake.org/}{CMake} build system. \\item The \\href{http://www.boost.org/}{Boost} C++ portable libraries. \\item The \\href{http://www.zlib.net/}{zlib} compression library. \\end{itemize} Under Ubuntu (14.04 LTS) the installation can be performed using the commands: \\begin{command} > sudo apt-get install build-essential cmake-curses-gui libboost-dev zlib1g-dev \\end{command} Under Mac OS X the installation requires the following steps: \\begin{itemize} \\item Install Xcode \\item Install the command line tools. \\item Install the MacPorts project which allows to automatically download and install opensource packages. \\end{itemize} Then the following commands should be typed in a terminal: \\begin{command} > sudo port install cmake gcc48 boost \\end{command} ") \ No newline at end of file diff --git a/packages/50_parallel.cmake b/packages/50_parallel.cmake index 2a91df104..173a943d8 100644 --- a/packages/50_parallel.cmake +++ b/packages/50_parallel.cmake @@ -1,48 +1,49 @@ #=============================================================================== # @file 50_parallel.cmake # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Tue Oct 16 2012 # @date last modification: Wed Jun 11 2014 # # @brief meta package description for parallelization # # @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/>. # #=============================================================================== add_meta_package(PARALLEL "Add parallel support in Akantu" OFF MPI SCOTCH) set(AKANTU_PARALLEL_TESTS test_solid_mechanics_model_bar_traction2d_parallel test_solid_mechanics_model_segment_parallel test_solid_mechanics_model_pbc_parallel test_synchronizer_communication test_dof_synchronizer + test_dof_synchronizer_communication test_solid_mechanics_model_reassign_material ) set(AKANTU_PARALLEL_MANUAL_FILES manual-parallel.tex ) set(AKANTU_PARALLEL_DOCUMENTATION " This option activates the parallel features of AKANTU. " ) diff --git a/packages/84_petsc.cmake b/packages/84_petsc.cmake index dceacb9ba..ddbec6201 100644 --- a/packages/84_petsc.cmake +++ b/packages/84_petsc.cmake @@ -1,45 +1,48 @@ #=============================================================================== # @file petsc.cmake # # @author Nicolas Richart <nicolas.richart@epfl.ch> # @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> # @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> # # @date Mon Nov 21 18:19:15 2011 # # @brief package description for PETSc support # # @section LICENSE # # Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see <http://www.gnu.org/licenses/>. # #=============================================================================== add_optional_external_package(PETSc "Add PETSc support in akantu" OFF ARGS COMPONENT ARGS CXX) add_internal_package_dependencies(petsc parallel) set(AKANTU_PETSC_FILES solver/petsc_matrix.hh solver/petsc_matrix.cc solver/petsc_matrix_inline_impl.cc solver/solver_petsc.hh solver/solver_petsc.cc + solver/petsc_wrapper.hh ) set(AKANTU_PETSC_TESTS test_petsc_matrix_profile + test_petsc_matrix_apply_boundary + test_solver_petsc ) diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh index 0f5da70bc..bb4076853 100644 --- a/src/common/aka_common.hh +++ b/src/common/aka_common.hh @@ -1,697 +1,699 @@ /** * @file aka_common.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Jun 14 2010 * @date last modification: Mon Sep 15 2014 * * @brief common type descriptions for akantu * * @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 * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMON_HH__ #define __AKANTU_COMMON_HH__ /* -------------------------------------------------------------------------- */ #include <list> #include <limits> #include <boost/preprocessor.hpp> /* -------------------------------------------------------------------------- */ #define __BEGIN_AKANTU__ namespace akantu { #define __END_AKANTU__ }; /* -------------------------------------------------------------------------- */ #define __BEGIN_AKANTU_DUMPER__ namespace dumper { #define __END_AKANTU_DUMPER__ } /* -------------------------------------------------------------------------- */ #if defined(WIN32) # define __attribute__(x) #endif /* -------------------------------------------------------------------------- */ #include "aka_config.hh" #include "aka_error.hh" #include "aka_safe_enum.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Common types */ /* -------------------------------------------------------------------------- */ typedef double Real; typedef unsigned int UInt; typedef unsigned long long UInt64; typedef signed int Int; typedef std::string ID; static const Real UINT_INIT_VALUE = 0; #ifdef AKANTU_NDEBUG static const Real REAL_INIT_VALUE = 0; #else static const Real REAL_INIT_VALUE = std::numeric_limits<Real>::quiet_NaN(); #endif /* -------------------------------------------------------------------------- */ /* Memory types */ /* -------------------------------------------------------------------------- */ typedef UInt MemoryID; /* -------------------------------------------------------------------------- */ /* Mesh/FEM/Model types */ /* -------------------------------------------------------------------------- */ typedef std::string Surface; typedef std::pair<Surface, Surface> SurfacePair; typedef std::list< SurfacePair > SurfacePairList; /* -------------------------------------------------------------------------- */ extern const UInt _all_dimensions; /// @boost sequence of element to loop on in global tasks #define AKANTU_ek_regular_ELEMENT_TYPE \ (_point_1) \ (_segment_2) \ (_segment_3) \ (_triangle_3) \ (_triangle_6) \ (_quadrangle_4) \ (_quadrangle_8) \ (_tetrahedron_4) \ (_tetrahedron_10) \ (_pentahedron_6) \ (_hexahedron_8) #if defined(AKANTU_STRUCTURAL_MECHANICS) #define AKANTU_ek_structural_ELEMENT_TYPE \ (_bernoulli_beam_2) \ (_bernoulli_beam_3) \ (_kirchhoff_shell) #else #define AKANTU_ek_structural_ELEMENT_TYPE #endif #if defined(AKANTU_COHESIVE_ELEMENT) # define AKANTU_ek_cohesive_ELEMENT_TYPE \ (_cohesive_2d_4) \ (_cohesive_2d_6) \ (_cohesive_1d_2) \ (_cohesive_3d_6) \ (_cohesive_3d_12) #else # define AKANTU_ek_cohesive_ELEMENT_TYPE #endif #if defined(AKANTU_IGFEM) #define AKANTU_ek_igfem_ELEMENT_TYPE \ (_igfem_triangle_3) #else #define AKANTU_ek_igfem_ELEMENT_TYPE #endif #define AKANTU_ALL_ELEMENT_TYPE \ AKANTU_ek_regular_ELEMENT_TYPE \ AKANTU_ek_cohesive_ELEMENT_TYPE \ AKANTU_ek_structural_ELEMENT_TYPE \ AKANTU_ek_igfem_ELEMENT_TYPE #define AKANTU_NOT_STRUCTURAL_ELEMENT_TYPE \ AKANTU_ek_regular_ELEMENT_TYPE \ AKANTU_ek_cohesive_ELEMENT_TYPE \ AKANTU_ek_igfem_ELEMENT_TYPE /// @enum ElementType type of elements enum ElementType { _not_defined, _point_1, _segment_2, ///< first order segment _segment_3, ///< second order segment _triangle_3, ///< first order triangle _triangle_6, ///< second order triangle _tetrahedron_4, ///< first order tetrahedron _tetrahedron_10, ///< second order tetrahedron _quadrangle_4, ///< first order quadrangle _quadrangle_8, ///< second order quadrangle _hexahedron_8, ///< first order hexahedron _pentahedron_6, ///< first order pentahedron #if defined (AKANTU_STRUCTURAL_MECHANICS) _bernoulli_beam_2, ///< Bernoulli beam 2D _bernoulli_beam_3, ///< Bernoulli beam 3D _kirchhoff_shell, ///< Kirchhoff shell #endif #if defined(AKANTU_COHESIVE_ELEMENT) _cohesive_2d_4, ///< first order 2D cohesive _cohesive_2d_6, ///< second order 2D cohesive _cohesive_1d_2, ///< first order 1D cohesive _cohesive_3d_6, ///< first order 3D cohesive _cohesive_3d_12, ///< second order 3D cohesive #endif #if defined(AKANTU_IGFEM) _igfem_triangle_3, ///< first order triangle for IGFEM #endif _max_element_type }; /// @enum GeometricalType type of element potentially contained in a Mesh enum GeometricalType { _gt_point, ///< point @remark only for some algorithm to be generic like mesh partitioning */ _gt_segment_2, ///< 2 nodes segment _gt_segment_3, ///< 3 nodes segment _gt_triangle_3, ///< 3 nodes triangle _gt_triangle_6, ///< 6 nodes triangle _gt_quadrangle_4, ///< 4 nodes quadrangle _gt_quadrangle_8, ///< 8 nodes quadrangle _gt_tetrahedron_4, ///< 4 nodes tetrahedron _gt_tetrahedron_10, ///< 10 nodes tetrahedron _gt_hexahedron_8, ///< 8 nodes hexahedron _gt_pentahedron_6, ///< 6 nodes pentahedron #if defined(AKANTU_COHESIVE_ELEMENT) _gt_cohesive_2d_4, ///< 4 nodes 2D cohesive _gt_cohesive_2d_6, ///< 6 nodes 2D cohesive _gt_cohesive_1d_2, ///< 2 nodes 1D cohesive _gt_cohesive_3d_6, ///< 6 nodes 3D cohesive _gt_cohesive_3d_12, ///< 12 nodes 3D cohesive #endif _gt_not_defined }; /// @enum InterpolationType type of elements enum InterpolationType { _itp_lagrange_point_1, ///< zeroth (!) order lagrangian point (for compatibility purposes) _itp_lagrange_segment_2, ///< first order lagrangian segment _itp_lagrange_segment_3, ///< second order lagrangian segment _itp_lagrange_triangle_3, ///< first order lagrangian triangle _itp_lagrange_triangle_6, ///< second order lagrangian triangle _itp_lagrange_quadrangle_4, ///< first order lagrangian quadrangle _itp_serendip_quadrangle_8, /**< second order serendipian quadrangle @remark used insted of the 9 node lagrangian element */ _itp_lagrange_tetrahedron_4, ///< first order lagrangian tetrahedron _itp_lagrange_tetrahedron_10, ///< second order lagrangian tetrahedron _itp_lagrange_hexahedron_8, ///< first order lagrangian hexahedron _itp_lagrange_pentahedron_6, ///< first order lagrangian pentahedron #if defined(AKANTU_STRUCTURAL_MECHANICS) _itp_bernoulli_beam, ///< Bernoulli beam _itp_kirchhoff_shell, ///< Kirchhoff shell #endif _itp_not_defined }; //! standard output stream operator for ElementType inline std::ostream & operator <<(std::ostream & stream, ElementType type); #define AKANTU_REGULAR_KIND (_ek_regular) #ifdef AKANTU_COHESIVE_ELEMENT # define AKANTU_COHESIVE_KIND (_ek_cohesive) #else # define AKANTU_COHESIVE_KIND #endif #ifdef AKANTU_STRUCTURAL_MECHANICS # define AKANTU_STRUCTURAL_KIND (_ek_structural) #else # define AKANTU_STRUCTURAL_KIND #endif #ifdef AKANTU_IGFEM # define AKANTU_IGFEM_KIND (_ek_igfem) #else # define AKANTU_IGFEM_KIND #endif #define AKANTU_ELEMENT_KIND \ AKANTU_REGULAR_KIND \ AKANTU_COHESIVE_KIND \ AKANTU_STRUCTURAL_KIND \ AKANTU_IGFEM_KIND enum ElementKind { BOOST_PP_SEQ_ENUM(AKANTU_ELEMENT_KIND), _ek_not_defined }; /// small help to use names for directions enum SpacialDirection { _x = 0, _y = 1, _z = 2 }; /// enum MeshIOType type of mesh reader/writer enum MeshIOType { _miot_auto, ///< Auto guess of the reader to use based on the extension _miot_gmsh, ///< Gmsh files _miot_gmsh_struct, ///< Gsmh reader with reintpretation of elements has structures elements _miot_diana, ///< TNO Diana mesh format _miot_abaqus ///< Abaqus mesh format }; /// enum AnalysisMethod type of solving method used to solve the equation of motion enum AnalysisMethod { _static, _implicit_dynamic, _explicit_lumped_mass, _explicit_lumped_capacity, _explicit_consistent_mass }; //! enum ContactResolutionMethod types of solving for the contact enum ContactResolutionMethod { _penalty, _lagrangian, _augmented_lagrangian, _nitsche, _mortar }; //! enum ContactImplementationMethod types for different contact implementations enum ContactImplementationMethod { _none, _uzawa, _generalized_newton }; /// enum SolveConvergenceMethod different resolution algorithms enum SolveConvergenceMethod { _scm_newton_raphson_tangent, ///< Newton-Raphson with tangent matrix _scm_newton_raphson_tangent_modified, ///< Newton-Raphson with constant tangent matrix _scm_newton_raphson_tangent_not_computed ///< Newton-Raphson with constant tangent matrix (user has to assemble it) }; /// enum SolveConvergenceCriteria different convergence criteria enum SolveConvergenceCriteria { _scc_residual, ///< Use residual to test the convergence _scc_increment, ///< Use increment to test the convergence _scc_residual_mass_wgh ///< Use residual weighted by inv. nodal mass to testb }; /// enum CohesiveMethod type of insertion of cohesive elements enum CohesiveMethod { _intrinsic, _extrinsic }; /// myfunction(double * position, double * stress/force, double * normal, unsigned int material_id) typedef void (*BoundaryFunction)(double *,double *, double*, unsigned int); /// @enum BoundaryFunctionType type of function passed for boundary conditions enum BoundaryFunctionType { _bft_stress, _bft_traction, _bft_traction_local }; /// @enum SparseMatrixType type of sparse matrix used enum SparseMatrixType { _unsymmetric, _symmetric }; /* -------------------------------------------------------------------------- */ /* Contact */ /* -------------------------------------------------------------------------- */ typedef ID ContactID; typedef ID ContactSearchID; typedef ID ContactNeighborStructureID; enum ContactType { _ct_not_defined = 0, _ct_2d_expli = 1, _ct_3d_expli = 2, _ct_rigid = 3 }; enum ContactSearchType { _cst_not_defined = 0, _cst_2d_expli = 1, _cst_expli = 2 }; enum ContactNeighborStructureType { _cnst_not_defined = 0, _cnst_regular_grid = 1, _cnst_2d_grid = 2 }; /* -------------------------------------------------------------------------- */ /* Friction */ /* -------------------------------------------------------------------------- */ typedef ID FrictionID; /* -------------------------------------------------------------------------- */ /* Ghosts handling */ /* -------------------------------------------------------------------------- */ typedef ID SynchronizerID; /// @enum CommunicatorType type of communication method to use enum CommunicatorType { _communicator_mpi, _communicator_dummy }; /// @enum SynchronizationTag type of synchronizations enum SynchronizationTag { //--- SolidMechanicsModel tags --- _gst_smm_mass, //< synchronization of the SolidMechanicsModel.mass _gst_smm_for_gradu, //< synchronization of the SolidMechanicsModel.displacement _gst_smm_boundary, //< synchronization of the boundary, forces, velocities and displacement _gst_smm_uv, //< synchronization of the nodal velocities and displacement _gst_smm_res, //< synchronization of the nodal residual _gst_smm_init_mat, //< synchronization of the data to initialize materials _gst_smm_stress, //< synchronization of the stresses to compute the internal forces _gst_smmc_facets, //< synchronization of facet data to setup facet synch _gst_smmc_facets_conn, //< synchronization of facet global connectivity _gst_smmc_facets_stress, //< synchronization of facets' stress to setup facet synch _gst_smmc_damage, //< synchronization of damage //--- CohesiveElementInserter tags --- _gst_ce_inserter, //< synchronization of global nodes id of newly inserted cohesive elements //--- GroupManager tags --- _gst_gm_clusters, //< synchronization of clusters //--- HeatTransfer tags --- _gst_htm_capacity, //< synchronization of the nodal heat capacity _gst_htm_temperature, //< synchronization of the nodal temperature _gst_htm_gradient_temperature, //< synchronization of the element gradient temperature //--- LevelSet tags --- /// synchronization of the nodal level set value phi _gst_htm_phi, /// synchronization of the element gradient phi _gst_htm_gradient_phi, //--- Material non local --- _gst_mnl_for_average, //< synchronization of data to average in non local material _gst_mnl_weight, //< synchronization of data for the weight computations //--- General tags --- _gst_test, //< Test tag _gst_material_id, //< synchronization of the material ids _gst_for_dump, //< everything that needs to be synch before dump //--- Contact & Friction --- _gst_cf_nodal, //< synchronization of disp, velo, and current position - _gst_cf_incr //< synchronization of increment + _gst_cf_incr, //< synchronization of increment + ///--- Solver tags --- + _gst_solver_solution //< synchronization of the solution obained with the PETSc solver }; /// standard output stream operator for SynchronizationTag inline std::ostream & operator <<(std::ostream & stream, SynchronizationTag type); /// @enum GhostType type of ghost enum GhostType { _not_ghost, _ghost, _casper // not used but a real cute ghost }; /* -------------------------------------------------------------------------- */ struct GhostType_def { typedef GhostType type; static const type _begin_ = _not_ghost; static const type _end_ = _casper; }; typedef safe_enum<GhostType_def> ghost_type_t; /// standard output stream operator for GhostType inline std::ostream & operator <<(std::ostream & stream, GhostType type); /// @enum SynchronizerOperation reduce operation that the synchronizer can perform enum SynchronizerOperation { _so_sum, _so_min, _so_max, _so_null }; /* -------------------------------------------------------------------------- */ /* Global defines */ /* -------------------------------------------------------------------------- */ #define AKANTU_MIN_ALLOCATION 2000 #define AKANTU_INDENT " " #define AKANTU_INCLUDE_INLINE_IMPL /* -------------------------------------------------------------------------- */ // int 2 type construct template <int d> struct Int2Type { enum { result = d }; }; // type 2 type construct template <class T> class Type2Type { typedef T OriginalType; }; /* -------------------------------------------------------------------------- */ template<class T> struct is_scalar { enum{ value = false }; }; #define AKANTU_SPECIFY_IS_SCALAR(type) \ template<> \ struct is_scalar<type> { \ enum { value = true }; \ } AKANTU_SPECIFY_IS_SCALAR(Real); AKANTU_SPECIFY_IS_SCALAR(UInt); AKANTU_SPECIFY_IS_SCALAR(Int); AKANTU_SPECIFY_IS_SCALAR(bool); template < typename T1, typename T2 > struct is_same { enum { value = false }; // is_same represents a bool. }; template < typename T > struct is_same<T, T> { enum { value = true }; }; /* -------------------------------------------------------------------------- */ #define AKANTU_SET_MACRO(name, variable, type) \ inline void set##name (type variable) { \ this->variable = variable; \ } #define AKANTU_GET_MACRO(name, variable, type) \ inline type get##name () const { \ return variable; \ } #define AKANTU_GET_MACRO_NOT_CONST(name, variable, type) \ inline type get##name () { \ return variable; \ } #define AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, \ support, con) \ inline con Array<type> & \ get##name (const support & el_type, \ const GhostType & ghost_type = _not_ghost) con { \ return variable(el_type, ghost_type); \ } #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType,) #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType, const) #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType,) #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE_CONST(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType, const) /* -------------------------------------------------------------------------- */ /// initialize the static part of akantu void initialize(int & argc, char ** & argv); /// initialize the static part of akantu and read the global input_file void initialize(const std::string & input_file, int & argc, char ** & argv); /* -------------------------------------------------------------------------- */ /// finilize correctly akantu and clean the memory void finalize (); /* -------------------------------------------------------------------------- */ /* * For intel compiler annoying remark */ #if defined(__INTEL_COMPILER) /// remark #981: operands are evaluated in unspecified order #pragma warning ( disable : 981 ) /// remark #383: value copied to temporary, reference to temporary used #pragma warning ( disable : 383 ) #endif //defined(__INTEL_COMPILER) /* -------------------------------------------------------------------------- */ /* string manipulation */ /* -------------------------------------------------------------------------- */ inline std::string to_lower(const std::string & str); /* -------------------------------------------------------------------------- */ inline std::string trim(const std::string & to_trim); /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /// give a string representation of the a human readable size in bit template<typename T> std::string printMemorySize(UInt size); /* -------------------------------------------------------------------------- */ __END_AKANTU__ #include "aka_fwd.hh" __BEGIN_AKANTU__ /// get access to the internal argument parser cppargparse::ArgumentParser & getStaticArgumentParser(); /// get access to the internal input file parser Parser & getStaticParser(); /// get access to the user part of the internal input file parser const ParserSection & getUserParser(); __END_AKANTU__ /* -------------------------------------------------------------------------- */ // BOOST PART: TOUCH ONLY IF YOU KNOW WHAT YOU ARE DOING #define AKANTU_BOOST_CASE_MACRO(r,macro,type) \ case type : { macro(type); break; } #define AKANTU_BOOST_LIST_SWITCH(macro1, list1, var) \ do { \ switch(var) { \ BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, macro1, list1) \ default: { \ AKANTU_DEBUG_ERROR("Type (" << var << ") not handled by this function"); \ } \ } \ } while(0) #define AKANTU_BOOST_ELEMENT_SWITCH(macro1, list1) \ AKANTU_BOOST_LIST_SWITCH(macro1, list1, type) #define AKANTU_BOOST_ALL_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_ALL_ELEMENT_TYPE) #define AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_ek_regular_ELEMENT_TYPE) #define AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_ek_cohesive_ELEMENT_TYPE) #define AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_ek_structural_ELEMENT_TYPE) #define AKANTU_BOOST_IGFEM_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_ek_igfem_ELEMENT_TYPE) #define AKANTU_BOOST_LIST_MACRO(r, macro, type) \ macro(type) #define AKANTU_BOOST_APPLY_ON_LIST(macro, list) \ BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_LIST_MACRO, macro, list) #define AKANTU_BOOST_ALL_ELEMENT_LIST(macro) \ AKANTU_BOOST_APPLY_ON_LIST(macro, \ AKANTU_ALL_ELEMENT_TYPE) #define AKANTU_BOOST_REGULAR_ELEMENT_LIST(macro) \ AKANTU_BOOST_APPLY_ON_LIST(macro, \ AKANTU_ek_regular_ELEMENT_TYPE) #define AKANTU_BOOST_STRUCTURAL_ELEMENT_LIST(macro) \ AKANTU_BOOST_APPLY_ON_LIST(macro, \ AKANTU_ek_structural_ELEMENT_TYPE) #define AKANTU_BOOST_COHESIVE_ELEMENT_LIST(macro) \ AKANTU_BOOST_APPLY_ON_LIST(macro, \ AKANTU_ek_cohesive_ELEMENT_TYPE) #define AKANTU_BOOST_IGFEM_ELEMENT_LIST(macro) \ AKANTU_BOOST_APPLY_ON_LIST(macro, \ AKANTU_ek_igfem_ELEMENT_TYPE) #define AKANTU_GET_ELEMENT_LIST(kind) \ AKANTU##kind##_ELEMENT_TYPE #define AKANTU_BOOST_KIND_ELEMENT_SWITCH(macro, kind) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_GET_ELEMENT_LIST(kind)) // BOOST_PP_SEQ_TO_LIST does not exists in Boost < 1.49 #define AKANTU_GENERATE_KIND_LIST(seq) \ BOOST_PP_TUPLE_TO_LIST(BOOST_PP_SEQ_SIZE(seq), \ BOOST_PP_SEQ_TO_TUPLE(seq)) #define AKANTU_ELEMENT_KIND_BOOST_LIST AKANTU_GENERATE_KIND_LIST(AKANTU_ELEMENT_KIND) #define AKANTU_BOOST_ALL_KIND_LIST(macro, list) \ BOOST_PP_LIST_FOR_EACH(AKANTU_BOOST_LIST_MACRO, macro, list) #define AKANTU_BOOST_ALL_KIND(macro) \ AKANTU_BOOST_ALL_KIND_LIST(macro, AKANTU_ELEMENT_KIND_BOOST_LIST) #define AKANTU_BOOST_ALL_KIND_SWITCH(macro) \ AKANTU_BOOST_LIST_SWITCH(macro, \ AKANTU_ELEMENT_KIND, \ kind) /// define kept for compatibility reasons (they are most probably not needed /// anymore) \todo check if they can be removed #define AKANTU_REGULAR_ELEMENT_TYPE AKANTU_ek_regular_ELEMENT_TYPE #define AKANTU_COHESIVE_ELEMENT_TYPE AKANTU_ek_cohesive_ELEMENT_TYPE #define AKANTU_STRUCTURAL_ELEMENT_TYPE AKANTU_ek_structural_ELEMENT_TYPE #define AKANTU_IGFEM_ELEMENT_TYPE AKANTU_ek_igfem_ELEMENT_TYPE #include "aka_common_inline_impl.cc" #endif /* __AKANTU_COMMON_HH__ */ diff --git a/src/common/aka_common_inline_impl.cc b/src/common/aka_common_inline_impl.cc index 98f333536..f7da7198f 100644 --- a/src/common/aka_common_inline_impl.cc +++ b/src/common/aka_common_inline_impl.cc @@ -1,233 +1,234 @@ /** * @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; #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_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/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index ce40bc72f..f25f0280f 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1830 +1,1840 @@ /** * @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_IOHELPER # include "dumper_field.hh" # include "dumper_paraview.hh" # include "dumper_homogenizing_field.hh" # include "dumper_material_internal_field.hh" # include "dumper_elemental_field.hh" # include "dumper_material_padders.hh" # include "dumper_element_partition.hh" # include "dumper_iohelper.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const SolidMechanicsModelOptions default_solid_mechanics_model_options(_explicit_lumped_mass, false); /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), BoundaryCondition<SolidMechanicsModel>(), time_step(NAN), f_m2a(1.0), mass_matrix(NULL), velocity_damping_matrix(NULL), stiffness_matrix(NULL), jacobian_matrix(NULL), element_index_by_material("element index by material", id), material_selector(new DefaultMaterialSelector(element_index_by_material)), is_default_material_selector(true), integrator(NULL), increment_flag(false), solver(NULL), synch_parallel(NULL), are_materials_instantiated(false) { AKANTU_DEBUG_IN(); createSynchronizerRegistry(this); registerFEEngineObject<MyFEEngineType>("SolidMechanicsFEEngine", mesh, spatial_dimension); this->displacement = NULL; this->mass = NULL; this->velocity = NULL; this->acceleration = NULL; this->force = NULL; this->residual = NULL; this->blocked_dofs = NULL; this->increment = NULL; this->increment_acceleration = NULL; this->dof_synchronizer = NULL; this->previous_displacement = NULL; materials.clear(); mesh.registerEventHandler(*this); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { delete *mat_it; } materials.clear(); delete integrator; delete solver; delete mass_matrix; delete velocity_damping_matrix; if(stiffness_matrix && stiffness_matrix != jacobian_matrix) delete stiffness_matrix; delete jacobian_matrix; delete synch_parallel; if(is_default_material_selector) { delete material_selector; material_selector = NULL; } AKANTU_DEBUG_OUT(); } void SolidMechanicsModel::setTimeStep(Real time_step) { this->time_step = time_step; #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilities */ void SolidMechanicsModel::initFull(const ModelOptions & options) { Model::initFull(options); const SolidMechanicsModelOptions & smm_options = dynamic_cast<const SolidMechanicsModelOptions &>(options); method = smm_options.analysis_method; // initialize the vectors initArrays(); // set the initial condition to 0 force->clear(); velocity->clear(); acceleration->clear(); displacement->clear(); // initialize pcb if(pbc_pair.size()!=0) initPBC(); // initialize the time integration schemes switch(method) { case _explicit_lumped_mass: initExplicit(); break; case _explicit_consistent_mass: initSolver(); initExplicit(); break; case _implicit_dynamic: initImplicit(true); break; case _static: initImplicit(false); break; default: AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel"); break; } // initialize the materials if(this->parser->getLastParsedFile() != "") { instantiateMaterials(); } if(!smm_options.no_init_materials) { initMaterials(); } if(increment_flag) initBC(*this, *displacement, *increment, *force); else initBC(*this, *displacement, *force); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initParallel(MeshPartition * partition, DataAccessor * data_accessor) { AKANTU_DEBUG_IN(); if (data_accessor == NULL) data_accessor = this; synch_parallel = &createParallelSynch(partition,data_accessor); synch_registry->registerSynchronizer(*synch_parallel, _gst_material_id); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_mass); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_stress); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnControlPoints(_not_ghost); fem_boundary.computeNormalsOnControlPoints(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initExplicit(AnalysisMethod analysis_method) { AKANTU_DEBUG_IN(); //in case of switch from implicit to explicit if(!this->isExplicit()) method = analysis_method; if (integrator) delete integrator; integrator = new CentralDifference(); UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); std::stringstream sstr; sstr << id << ":increment_acceleration"; increment_acceleration = &(alloc<Real>(sstr.str(), nb_nodes, nb_degree_of_freedom, Real())); AKANTU_DEBUG_OUT(); } void SolidMechanicsModel::initArraysPreviousDisplacment() { AKANTU_DEBUG_IN(); SolidMechanicsModel::setIncrementFlagOn(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp_t; sstr_disp_t << id << ":previous_displacement"; previous_displacement = &(alloc<Real > (sstr_disp_t.str(), nb_nodes, spatial_dimension, 0.)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Allocate all the needed vectors. By default their are not necessarily set to * 0 * */ void SolidMechanicsModel::initArrays() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":displacement"; // std::stringstream sstr_mass; sstr_mass << id << ":mass"; std::stringstream sstr_velo; sstr_velo << id << ":velocity"; std::stringstream sstr_acce; sstr_acce << id << ":acceleration"; std::stringstream sstr_forc; sstr_forc << id << ":force"; std::stringstream sstr_resi; sstr_resi << id << ":residual"; std::stringstream sstr_boun; sstr_boun << id << ":blocked_dofs"; displacement = &(alloc<Real>(sstr_disp.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); // mass = &(alloc<Real>(sstr_mass.str(), nb_nodes, spatial_dimension, 0)); velocity = &(alloc<Real>(sstr_velo.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); acceleration = &(alloc<Real>(sstr_acce.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); force = &(alloc<Real>(sstr_forc.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); residual = &(alloc<Real>(sstr_resi.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); blocked_dofs = &(alloc<bool>(sstr_boun.str(), nb_nodes, spatial_dimension, false)); std::stringstream sstr_curp; sstr_curp << id << ":current_position"; current_position = &(alloc<Real>(sstr_curp.str(), 0, spatial_dimension, REAL_INIT_VALUE)); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, gt); element_index_by_material.alloc(nb_element, 2, *it, gt); } } dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian * */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initPBC() { Model::initPBC(); registerPBCSynchronizer(); // as long as there are ones on the diagonal of the matrix, we can put boudandary true for slaves std::map<UInt, UInt>::iterator it = pbc_pair.begin(); std::map<UInt, UInt>::iterator end = pbc_pair.end(); UInt dim = mesh.getSpatialDimension(); while(it != end) { for (UInt i=0; i<dim; ++i) (*blocked_dofs)((*it).first,i) = true; ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::registerPBCSynchronizer(){ PBCSynchronizer * synch = new PBCSynchronizer(pbc_pair); synch_registry->registerSynchronizer(*synch, _gst_smm_uv); synch_registry->registerSynchronizer(*synch, _gst_smm_mass); synch_registry->registerSynchronizer(*synch, _gst_smm_res); synch_registry->registerSynchronizer(*synch, _gst_for_dump); changeLocalEquationNumberForPBC(pbc_pair, mesh.getSpatialDimension()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); current_position->resize(nb_nodes); Real * current_position_val = current_position->storage(); Real * position_val = mesh.getNodes().storage(); Real * displacement_val = displacement->storage(); /// compute current_position = initial_position + displacement memcpy(current_position_val, position_val, nb_nodes*spatial_dimension*sizeof(Real)); for (UInt n = 0; n < nb_nodes*spatial_dimension; ++n) { *current_position_val++ += *displacement_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeUpdateResidualData() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); residual->resize(nb_nodes); /// copy the forces in residual for boundary conditions memcpy(residual->storage(), force->storage(), nb_nodes*spatial_dimension*sizeof(Real)); // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); updateCurrentPosition(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Explicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * This function compute the second member of the motion equation. That is to * say the sum of forces @f$ r = F_{ext} - F_{int} @f$. @f$ F_{ext} @f$ is given * by the user in the force vector, and @f$ F_{int} @f$ is computed as @f$ * F_{int} = \int_{\Omega} N \sigma d\Omega@f$ * */ void SolidMechanicsModel::updateResidual(bool need_initialize) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); // f = f_ext - f_int // f = f_ext if(need_initialize) initializeUpdateResidualData(); AKANTU_DEBUG_INFO("Compute local stresses"); std::vector<Material *>::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } #ifdef AKANTU_DAMAGE_NON_LOCAL /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ synch_registry->asynchronousSynchronize(_gst_mnl_for_average); AKANTU_DEBUG_INFO("Compute non local stresses for local elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_not_ghost); } AKANTU_DEBUG_INFO("Wait distant non local stresses"); synch_registry->waitEndSynchronize(_gst_mnl_for_average); AKANTU_DEBUG_INFO("Compute non local stresses for ghosts elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_ghost); } #endif /* ------------------------------------------------------------------------ */ /* assembling the forces internal */ // communicate the stress AKANTU_DEBUG_INFO("Send data for residual assembly"); synch_registry->asynchronousSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for local elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_not_ghost); } AKANTU_DEBUG_INFO("Wait distant stresses"); // finalize communications synch_registry->waitEndSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeStresses() { if (isExplicit()) { // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); // compute stresses on all local elements for each materials std::vector<Material *>::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ #ifdef AKANTU_DAMAGE_NON_LOCAL /* Computation of the non local part */ synch_registry->asynchronousSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_not_ghost); } synch_registry->waitEndSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_ghost); } #endif } else { std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStressesFromTangentModuli(_not_ghost); } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateResidualInternal() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Update the residual"); // f = f_ext - f_int - Ma - Cv = r - Ma - Cv; if(method != _static) { // f -= Ma if(mass_matrix) { // if full mass_matrix Array<Real> * Ma = new Array<Real>(*acceleration, true, "Ma"); *Ma *= *mass_matrix; /// \todo check unit conversion for implicit dynamics // *Ma /= f_m2a *residual -= *Ma; delete Ma; } else if (mass) { // else lumped mass UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); Real * mass_val = mass->storage(); Real * accel_val = acceleration->storage(); Real * res_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *res_val -= *accel_val * *mass_val /f_m2a; } blocked_dofs_val++; res_val++; mass_val++; accel_val++; } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } // f -= Cv if(velocity_damping_matrix) { Array<Real> * Cv = new Array<Real>(*velocity); *Cv *= *velocity_damping_matrix; *residual -= *Cv; delete Cv; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateAcceleration() { AKANTU_DEBUG_IN(); updateResidualInternal(); if(method == _explicit_lumped_mass) { /* residual = residual_{n+1} - M * acceleration_n therefore solution = increment acceleration not acceleration */ solveLumped(*increment_acceleration, *mass, *residual, *blocked_dofs, f_m2a); } else if (method == _explicit_consistent_mass) { solve<NewmarkBeta::_acceleration_corrector>(*increment_acceleration); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveLumped(Array<Real> & x, const Array<Real> & A, const Array<Real> & b, const Array<bool> & blocked_dofs, Real alpha) { Real * A_val = A.storage(); Real * b_val = b.storage(); Real * x_val = x.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); UInt nb_degrees_of_freedom = x.getSize() * x.getNbComponent(); for (UInt n = 0; n < nb_degrees_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *x_val = alpha * (*b_val / *A_val); } x_val++; A_val++; b_val++; blocked_dofs_val++; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitPred() { AKANTU_DEBUG_IN(); if(increment_flag) { if(previous_displacement) increment->copy(*previous_displacement); else increment->copy(*displacement); } AKANTU_DEBUG_ASSERT(integrator,"itegrator should have been allocated: " << "have called initExplicit ? " << "or initImplicit ?"); integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); if(increment_flag) { Real * inc_val = increment->storage(); Real * dis_val = displacement->storage(); UInt nb_degree_of_freedom = displacement->getSize() * displacement->getNbComponent(); for (UInt n = 0; n < nb_degree_of_freedom; ++n) { *inc_val = *dis_val - *inc_val; inc_val++; dis_val++; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitCorr() { AKANTU_DEBUG_IN(); integrator->integrationSchemeCorrAccel(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment_acceleration); if(previous_displacement) previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveStep() { AKANTU_DEBUG_IN(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); this->explicitPred(); this->updateResidual(); this->updateAcceleration(); this->explicitCorr(); EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Implicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * Initialize the solver and create the sparse matrices needed. * */ void SolidMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) { -#if !defined(AKANTU_USE_MUMPS) // or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake +#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"; - jacobian_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); +#ifdef AKANTU_USE_PETSC + jacobian_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); +#else + jacobian_matrix = new PETScMatrix(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(*jacobian_matrix, sstr_sti.str(), memory_id); +#else + stiffness_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); + stiffness_matrix->buildProfile(); +#endif //AKANTU_USE_PETSC } -#ifdef AKANTU_USE_MUMPS std::stringstream sstr_solv; sstr_solv << id << ":solver"; +#ifdef AKANTU_USE_MUMPS solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); - dof_synchronizer->initScatterGatherCommunicationScheme(); +#elif defined(AKANTU_USE_PETSC) + solver = new SolverPETSc(*jacobian_matrix, sstr_solv.str()); #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() { #ifdef AKANTU_USE_MUMPS // @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 should at least activate one solver."); + AKANTU_DEBUG_ERROR("You need to activate the solver mumps."); #endif } /* -------------------------------------------------------------------------- */ /** * Initialize the implicit solver, either for dynamic or static cases, * * @param dynamic */ void SolidMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); method = dynamic ? _implicit_dynamic : _static; if (!increment) setIncrementFlagOn(); initSolver(solver_options); if(method == _implicit_dynamic) { if(integrator) delete integrator; integrator = new TrapezoidalRule2(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initialAcceleration() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving Ma = f"); Solver * acc_solver = NULL; std::stringstream sstr; sstr << id << ":tmp_mass_matrix"; SparseMatrix * tmp_mass = new SparseMatrix(*mass_matrix, sstr.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solver; sstr << id << ":solver_mass_matrix"; acc_solver = new SolverMumps(*mass_matrix, sstr_solver.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS acc_solver->initialize(); tmp_mass->applyBoundary(*blocked_dofs); acc_solver->setRHS(*residual); acc_solver->solve(*acceleration); delete acc_solver; delete tmp_mass; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); stiffness_matrix->clear(); // call compute stiffness matrix on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->assembleStiffnessMatrix(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix & SolidMechanicsModel::initVelocityDampingMatrix() { if(!velocity_damping_matrix) velocity_damping_matrix = new SparseMatrix(*jacobian_matrix, id + ":velocity_damping_matrix", memory_id); return *velocity_damping_matrix; } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_increment>(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); Real * displacement_val = displacement->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val) && is_local_node) { norm[0] += *increment_val * *increment_val; norm[1] += *displacement_val * *displacement_val; } blocked_dofs_val++; increment_val++; displacement_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum); norm[0] = sqrt(norm[0]); norm[1] = sqrt(norm[1]); AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something goes wrong in the solve phase"); if (norm[1] < Math::getTolerance()) { error = norm[0]; AKANTU_DEBUG_OUT(); // cout<<"Error 1: "<<error<<endl; return error < tolerance; } AKANTU_DEBUG_OUT(); if(norm[1] > Math::getTolerance()) error = norm[0] / norm[1]; else error = norm[0]; //In case the total displacement is zero! // cout<<"Error 2: "<<error<<endl; return (error < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_residual>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < spatial_dimension; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val; } blocked_dofs_val++; residual_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_residual_mass_wgh>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->storage(); Real * mass_val = this->mass->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < spatial_dimension; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val/(*mass_val * *mass_val); } blocked_dofs_val++; residual_val++; mass_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; mass_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitPred() { AKANTU_DEBUG_IN(); if(previous_displacement) previous_displacement->copy(*displacement); if(method == _implicit_dynamic) integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitCorr() { AKANTU_DEBUG_IN(); if(method == _implicit_dynamic) { integrator->integrationSchemeCorrDispl(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment); } else { UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); bool * boun_val = blocked_dofs->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++boun_val){ *incr_val *= (1. - *boun_val); *disp_val += *incr_val; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateIncrement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); Real * prev_disp_val = previous_displacement->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++prev_disp_val) *incr_val = (*disp_val - *prev_disp_val); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updatePreviousDisplacement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeBoundaries() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initParallel?"); synch_registry->synchronize(_gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeResidual() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initPBC?"); synch_registry->synchronize(_gst_smm_res); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setIncrementFlagOn() { AKANTU_DEBUG_IN(); if(!increment) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_inc; sstr_inc << id << ":increment"; increment = &(alloc<Real>(sstr_inc.str(), nb_nodes, spatial_dimension, 0.)); } increment_flag = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors StaticCommunicator::getStaticCommunicator().allReduce(&min_dt, 1, _so_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Material ** mat_val = &(materials.at(0)); Real min_dt = std::numeric_limits<Real>::max(); updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; elem.kind = _ek_regular; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { elem.type = *it; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); UInt nb_element = mesh.getNbElement(*it); Array<UInt>::iterator< Vector<UInt> > eibm = element_index_by_material(*it, ghost_type).begin(2); Array<Real> X(0, nb_nodes_per_element*spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, *it, _not_ghost); Array<Real>::matrix_iterator X_el = X.begin(spatial_dimension, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++X_el, ++eibm) { elem.element = (*eibm)(1); Real el_h = getFEEngine().getElementInradius(*X_el, *it); Real el_c = mat_val[(*eibm)(0)]->getCelerity(elem); Real el_dt = el_h / el_c; min_dt = std::min(min_dt, el_dt); } } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real energy = 0.; /// call update residual on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getPotentialEnergy(); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy() { AKANTU_DEBUG_IN(); if (!mass && !mass_matrix) AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); Real * vel_val = velocity->storage(); Real * mass_val = mass->storage(); for (UInt n = 0; n < nb_nodes; ++n) { Real mv2 = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { if (count_node) mv2 += *vel_val * *vel_val * *mass_val; vel_val++; mass_val++; } ekin += mv2; } StaticCommunicator::getStaticCommunicator().allReduce(&ekin, 1, _so_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(type); Array<Real> vel_on_quad(nb_quadrature_points, spatial_dimension); Array<UInt> filter_element(1, 1, index); getFEEngine().interpolateOnQuadraturePoints(*velocity, vel_on_quad, spatial_dimension, type, _not_ghost, filter_element); Array<Real>::vector_iterator vit = vel_on_quad.begin(spatial_dimension); Array<Real>::vector_iterator vend = vel_on_quad.end(spatial_dimension); Vector<Real> rho_v2(nb_quadrature_points); Real rho = materials[element_index_by_material(type)(index, 0)]->getRho(); for (UInt q = 0; vit != vend; ++vit, ++q) { rho_v2(q) = rho * vit->dot(*vit); } AKANTU_DEBUG_OUT(); return .5*getFEEngine().integrate(rho_v2, type, index); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); Real * velo = velocity->storage(); Real * forc = force->storage(); Real * resi = residual->storage(); bool * boun = blocked_dofs->storage(); Real work = 0.; UInt nb_nodes = mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { if (count_node) { if(*boun) work -= *resi * *velo * time_step; else work += *forc * *velo * time_step; } ++velo; ++forc; ++resi; ++boun; } } StaticCommunicator::getStaticCommunicator().allReduce(&work, 1, _so_sum); AKANTU_DEBUG_OUT(); return work; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(); } else if (energy_id == "external work"){ return getExternalWork(); } Real energy = 0.; std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getEnergy(energy_id); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id, const ElementType & type, UInt index){ AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(type, index); } std::vector<Material *>::iterator mat_it; Vector<UInt> mat = element_index_by_material(type, _not_ghost).begin(2)[index]; Real energy = materials[mat(0)]->getEnergy(energy_id, type, mat(1)); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array<UInt> & nodes_list, __attribute__((unused)) const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if(displacement) displacement->resize(nb_nodes); if(mass ) mass ->resize(nb_nodes); if(velocity ) velocity ->resize(nb_nodes); if(acceleration) acceleration->resize(nb_nodes); if(force ) force ->resize(nb_nodes); if(residual ) residual ->resize(nb_nodes); if(blocked_dofs) blocked_dofs->resize(nb_nodes); if(previous_displacement) previous_displacement->resize(nb_nodes); if(increment_acceleration) increment_acceleration->resize(nb_nodes); if(increment) increment->resize(nb_nodes); if(current_position) current_position->resize(nb_nodes); delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onNodesAdded(nodes_list, event); } if (method != _explicit_lumped_mass) { delete stiffness_matrix; delete jacobian_matrix; delete solver; SolverOptions solver_options; initImplicit((method == _implicit_dynamic), solver_options); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); Array<Element>::const_iterator<Element> it = element_list.begin(); Array<Element>::const_iterator<Element> end = element_list.end(); /// \todo have rules to choose the correct material UInt mat_id = 0; UInt * mat_id_vect = NULL; try { const NewMaterialElementsEvent & event_mat = dynamic_cast<const NewMaterialElementsEvent &>(event); mat_id_vect = event_mat.getMaterialList().storage(); } catch(...) { } for (UInt el = 0; it != end; ++it, ++el) { const Element & elem = *it; if(mat_id_vect) mat_id = mat_id_vect[el]; else mat_id = (*material_selector)(elem); Material & mat = *materials[mat_id]; UInt mat_index = mat.addElement(elem.type, elem.element, elem.ghost_type); Vector<UInt> id(2); id[0] = mat_id; id[1] = mat_index; if(!element_index_by_material.exists(elem.type, elem.ghost_type)) element_index_by_material.alloc(0, 2, elem.type, elem.ghost_type); element_index_by_material(elem.type, elem.ghost_type).push_back(id); } 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) AKANTU_DEBUG_TO_IMPLEMENT(); assembleMassLumped(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved(__attribute__((unused)) const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) { // MeshUtils::purifyMesh(mesh); getFEEngine().initShapeFunctions(_not_ghost); 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::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(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::reassignMaterial() { AKANTU_DEBUG_IN(); std::vector< Array<Element> > element_to_add (materials.size()); std::vector< Array<Element> > element_to_remove(materials.size()); Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; element.ghost_type = ghost_type; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_regular); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type, _ek_regular); for(; it != end; ++it) { ElementType type = *it; element.type = type; element.kind = Mesh::getKind(type); UInt nb_element = mesh.getNbElement(type, ghost_type); Array<UInt> & el_index_by_mat = element_index_by_material(type, ghost_type); for (UInt el = 0; el < nb_element; ++el) { element.element = el; UInt old_material = el_index_by_mat(el, 0); UInt new_material = (*material_selector)(element); if(old_material != new_material) { element_to_add [new_material].push_back(element); element_to_remove[old_material].push_back(element); } } } } std::vector<Material *>::iterator mat_it; UInt mat_index = 0; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it, ++mat_index) { (*mat_it)->removeElements(element_to_remove[mat_index]); (*mat_it)->addElements (element_to_add[mat_index]); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::isInternal(const std::string & field_name, const ElementKind & element_kind){ bool is_internal = false; /// check if at least one material contains field_id as an internal for (UInt m = 0; m < materials.size() && !is_internal; ++m) { is_internal |= materials[m]->isInternal(field_name, element_kind); } return is_internal; } /* -------------------------------------------------------------------------- */ ElementTypeMap<UInt> SolidMechanicsModel::getInternalDataPerElem(const std::string & field_name, const ElementKind & element_kind){ if (!(this->isInternal(field_name,element_kind))) AKANTU_EXCEPTION("unknown internal " << field_name); for (UInt m = 0; m < materials.size() ; ++m) { if (materials[m]->isInternal(field_name, element_kind)) return materials[m]->getInternalDataPerElem(field_name,element_kind); } return ElementTypeMap<UInt>(); } /* -------------------------------------------------------------------------- */ ElementTypeMapArray<Real> & SolidMechanicsModel::flattenInternal(const std::string & field_name, const ElementKind & kind){ std::pair<std::string,ElementKind> key(field_name,kind); if (this->registered_internals.count(key) == 0){ this->registered_internals[key] = new ElementTypeMapArray<Real>(field_name,this->id); } ElementTypeMapArray<Real> * internal_flat = this->registered_internals[key]; for (UInt m = 0; m < materials.size(); ++m) materials[m]->flattenInternal(field_name,*internal_flat,_not_ghost,kind); return *internal_flat; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::flattenAllRegisteredInternals(const ElementKind & kind){ std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *> ::iterator it = this->registered_internals.begin(); std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *>::iterator end = this->registered_internals.end(); while (it != end){ if (kind == it->first.second) this->flattenInternal(it->first.first,kind); ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onDump(){ this->flattenAllRegisteredInternals(_ek_regular); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind){ dumper::Field * field = NULL; if(field_name == "partitions") field = mesh.createElementalField<UInt, dumper::ElementPartitionField>(mesh.getConnectivities(),group_name,this->spatial_dimension,kind); else if(field_name == "element_index_by_material") field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(element_index_by_material,group_name,this->spatial_dimension,kind); else { bool is_internal = this->isInternal(field_name,kind); if (is_internal) { ElementTypeMap<UInt> nb_data_per_elem = this->getInternalDataPerElem(field_name,kind); ElementTypeMapArray<Real> & internal_flat = this->flattenInternal(field_name,kind); field = mesh.createElementalField<Real, dumper::InternalMaterialField>(internal_flat, group_name, this->spatial_dimension,kind,nb_data_per_elem); //treat the paddings if (padding_flag){ if (field_name == "stress"){ if (this->spatial_dimension == 2) { dumper::StressPadder<2> * foo = new dumper::StressPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } // else if (field_name == "strain"){ // if (this->spatial_dimension == 2) { // dumper::StrainPadder<2> * foo = new dumper::StrainPadder<2>(*this); // field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); // } // } } // homogenize the field dumper::ComputeFunctorInterface * foo = dumper::HomogenizerProxy::createHomogenizer(*field); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string,Array<Real>* > real_nodal_fields; real_nodal_fields["displacement" ] = displacement; real_nodal_fields["mass" ] = mass; real_nodal_fields["velocity" ] = velocity; real_nodal_fields["acceleration" ] = acceleration; real_nodal_fields["force" ] = force; real_nodal_fields["residual" ] = residual; real_nodal_fields["increment" ] = increment; dumper::Field * field = NULL; if (padding_flag) field = mesh.createNodalField(real_nodal_fields[field_name],group_name, 3); else field = mesh.createNodalField(real_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string,Array<bool>* > uint_nodal_fields; uint_nodal_fields["blocked_dofs" ] = blocked_dofs; dumper::Field * field = NULL; field = mesh.createNodalField(uint_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ #else /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind){ return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump() { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeCauchyStresses() { AKANTU_DEBUG_IN(); // call compute stiffness matrix on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; if(mat.isFiniteDeformation()) mat.computeAllCauchyStresses(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::saveStressAndStrainBeforeDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::BeginningOfDamageIterationEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateEnergiesAfterDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::AfterDamageEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); mass ->printself(stream, indent + 2); velocity ->printself(stream, indent + 2); acceleration->printself(stream, indent + 2); force ->printself(stream, indent + 2); residual ->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + connectivity type information [" << std::endl; element_index_by_material.printself(stream, indent + 2); stream << space << 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 5209ed661..9a6b33463 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,737 +1,736 @@ /** * @file solid_mechanics_model.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Sep 16 2014 * * @brief Model of Solid Mechanics * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include <fstream> /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_types.hh" #include "model.hh" #include "data_accessor.hh" #include "mesh.hh" #include "dumpable.hh" #include "boundary_condition.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "integration_scheme_2nd_order.hh" #include "solver.hh" #include "material_selector.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Material; class IntegrationScheme2ndOrder; class SparseMatrix; class DumperIOHelper; } /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ struct SolidMechanicsModelOptions : public ModelOptions { SolidMechanicsModelOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool no_init_materials = false) : analysis_method(analysis_method), no_init_materials(no_init_materials) { } AnalysisMethod analysis_method; bool no_init_materials; }; extern const SolidMechanicsModelOptions default_solid_mechanics_model_options; class SolidMechanicsModel : public Model, public DataAccessor, public MeshEventHandler, public BoundaryCondition<SolidMechanicsModel>, public EventHandlerManager<SolidMechanicsModelEventHandler> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewMaterialElementsEvent : public NewElementsEvent { public: AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array <UInt> &); AKANTU_GET_MACRO(MaterialList, material, const Array <UInt> &); protected: Array <UInt> material; }; typedef FEEngineTemplate <IntegratorGauss, ShapeLagrange> MyFEEngineType; protected: typedef EventHandlerManager <SolidMechanicsModelEventHandler> EventManager; public: SolidMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize completely the model virtual void initFull(const ModelOptions & options = default_solid_mechanics_model_options); /// initialize the fem object needed for boundary conditions void initFEEngineBoundary(); /// register the tags associated with the parallel synchronizer void initParallel(MeshPartition *partition, DataAccessor *data_accessor = NULL); /// allocate all vectors void initArrays(); /// allocate all vectors void initArraysPreviousDisplacment(); /// initialize all internal arrays for materials virtual void initMaterials(); /// initialize the model virtual void initModel(); /// init PBC synchronizer void initPBC(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* PBC */ /* ------------------------------------------------------------------------ */ public: /// change the equation number for proper assembly when using PBC void changeEquationNumberforPBC(std::map <UInt, UInt> & pbc_pair); /// synchronize Residual for output void synchronizeResidual(); protected: /// register PBC synchronizer void registerPBCSynchronizer(); /* ------------------------------------------------------------------------ */ /* Explicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the stuff for the explicit scheme void initExplicit(AnalysisMethod analysis_method = _explicit_lumped_mass); bool isExplicit() { return method == _explicit_lumped_mass || method == _explicit_consistent_mass; } /// initialize the array needed by updateResidual (residual, current_position) void initializeUpdateResidualData(); /// update the current position vector void updateCurrentPosition(); /// assemble the residual for the explicit scheme virtual void updateResidual(bool need_initialize = true); /** * \brief compute the acceleration from the residual * this function is the explicit equivalent to solveDynamic in implicit * In the case of lumped mass just divide the residual by the mass * In the case of not lumped mass call solveDynamic<_acceleration_corrector> */ void updateAcceleration(); void updateIncrement(); void updatePreviousDisplacement(); void saveStressAndStrainBeforeDamage(); void updateEnergiesAfterDamage(); /// Solve the system @f[ A x = \alpha b @f] with A a lumped matrix void solveLumped(Array <Real> & x, const Array <Real> & A, const Array <Real> & b, const Array <bool> & blocked_dofs, Real alpha); /// explicit integration predictor void explicitPred(); /// explicit integration corrector void explicitCorr(); public: void solveStep(); /* ------------------------------------------------------------------------ */ /* Implicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver and the jacobian_matrix (called by initImplicit) void initSolver(SolverOptions & options = _solver_no_options); /// initialize the stuff for the implicit solver void initImplicit(bool dynamic = false, SolverOptions & solver_options = _solver_no_options); /// solve Ma = f to get the initial acceleration void initialAcceleration(); /// assemble the stiffness matrix void assembleStiffnessMatrix(); public: /** * solve a step (predictor + convergence loop + corrector) using the * the given convergence method (see akantu::SolveConvergenceMethod) * and the given convergence criteria (see * akantu::SolveConvergenceCriteria) **/ template <SolveConvergenceMethod method, SolveConvergenceCriteria criteria> bool solveStep(Real tolerance, UInt max_iteration = 100); template <SolveConvergenceMethod method, SolveConvergenceCriteria criteria> bool solveStep(Real tolerance, Real & error, UInt max_iteration = 100, bool do_not_factorize = false); public: /** * solve Ku = f using the the given convergence method (see * akantu::SolveConvergenceMethod) and the given convergence * criteria (see akantu::SolveConvergenceCriteria) **/ template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria> bool solveStatic(Real tolerance, UInt max_iteration, bool do_not_factorize = false); /// test if the system is converged template <SolveConvergenceCriteria criteria> bool testConvergence(Real tolerance, Real & error); /// test the convergence (norm of increment) bool testConvergenceIncrement(Real tolerance) __attribute__((deprecated)); bool testConvergenceIncrement(Real tolerance, Real & error) __attribute__((deprecated)); /// test the convergence (norm of residual) bool testConvergenceResidual(Real tolerance) __attribute__((deprecated)); bool testConvergenceResidual(Real tolerance, Real & error) __attribute__((deprecated)); /// create and return the velocity damping matrix SparseMatrix & initVelocityDampingMatrix(); /// implicit time integration predictor void implicitPred(); /// implicit time integration corrector void implicitCorr(); /// compute the Cauchy stress on user demand. void computeCauchyStresses(); protected: /// finish the computation of residual to solve in increment void updateResidualInternal(); /// compute the support reaction and store it in force void updateSupportReaction(); public: //protected: Daniel changed it just for a test /// compute A and solve @f[ A\delta u = f_ext - f_int @f] template <NewmarkBeta::IntegrationSchemeCorrectorType type> void solve(Array<Real> &increment, Real block_val = 1., - bool need_factorize = true, bool has_profile_changed = false, - const Array<Real> &rhs = Array<Real>()); + 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(); /* ------------------------------------------------------------------------ */ /* 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; + 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); //! give the amount of data per element ElementTypeMap<UInt> getInternalDataPerElem(const std::string & field_name, const ElementKind & kind); //! flatten a given material internal field ElementTypeMapArray<Real> & flattenInternal(const std::string & field_name, const ElementKind & kind); //! flatten all the registered material internals void flattenAllRegisteredInternals(const ElementKind & kind); virtual dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag); virtual dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind); virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); virtual void dump(); virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the current value of the time step AKANTU_GET_MACRO(TimeStep, time_step, Real); /// set the value of the time step void setTimeStep(Real time_step); /// get the value of the conversion from forces/ mass to acceleration AKANTU_GET_MACRO(F_M2A, f_m2a, Real); /// set the value of the conversion from forces/ mass to acceleration AKANTU_SET_MACRO(F_M2A, f_m2a, Real); /// get the SolidMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array <Real> &); /// get the SolidMechanicsModel::previous_displacement vector AKANTU_GET_MACRO(PreviousDisplacement, *previous_displacement, Array <Real> &); /// get the SolidMechanicsModel::current_position vector \warn only consistent /// after a call to SolidMechanicsModel::updateCurrentPosition AKANTU_GET_MACRO(CurrentPosition, *current_position, const Array <Real> &); /// get the SolidMechanicsModel::increment vector \warn only consistent if /// SolidMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *increment, Array <Real> &); /// get the lumped SolidMechanicsModel::mass vector AKANTU_GET_MACRO(Mass, *mass, Array <Real> &); /// get the SolidMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array <Real> &); /// get the SolidMechanicsModel::acceleration vector, updated by /// SolidMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array <Real> &); /// get the SolidMechanicsModel::force vector (boundary forces) AKANTU_GET_MACRO(Force, *force, Array <Real> &); /// get the SolidMechanicsModel::residual vector, computed by /// SolidMechanicsModel::updateResidual AKANTU_GET_MACRO(Residual, *residual, Array <Real> &); /// get the SolidMechanicsModel::blocked_dofs vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array <bool> &); /// get the SolidMechnicsModel::incrementAcceleration vector AKANTU_GET_MACRO(IncrementAcceleration, *increment_acceleration, Array <Real> &); /// get the value of the SolidMechanicsModel::increment_flag AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool); /// get a particular material (by material index) inline Material & getMaterial(UInt mat_index); /// get a particular material (by material index) inline const Material & getMaterial(UInt mat_index) const; /// get a particular material (by material name) inline Material & getMaterial(const std::string & name); /// get a particular material (by material name) inline const Material & getMaterial(const std::string & name) const; /// get a particular material id from is name inline UInt getMaterialIndex(const std::string & name) const; /// give the number of materials inline UInt getNbMaterials() const { return materials.size(); } inline void setMaterialSelector(MaterialSelector & selector); /// give the material internal index from its id Int getInternalIndexFromID(const ID & id) const; /// compute the stable time step Real getStableTimeStep(); /// compute the potential energy Real getPotentialEnergy(); /// compute the kinetic energy Real getKineticEnergy(); Real getKineticEnergy(const ElementType & type, UInt index); /// compute the external work (for impose displacement, the velocity should be given too) Real getExternalWork(); /// get the energies Real getEnergy(const std::string & energy_id); /// compute the energy for energy Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index); /** * @brief set the SolidMechanicsModel::increment_flag to on, the activate the * update of the SolidMechanicsModel::increment vector */ void setIncrementFlagOn(); /// get the stiffness matrix AKANTU_GET_MACRO(StiffnessMatrix, *stiffness_matrix, SparseMatrix &); /// get the global jacobian matrix of the system AKANTU_GET_MACRO(GlobalJacobianMatrix, *jacobian_matrix, const SparseMatrix &); /// get the mass matrix AKANTU_GET_MACRO(MassMatrix, *mass_matrix, SparseMatrix &); /// get the velocity damping matrix AKANTU_GET_MACRO(VelocityDampingMatrix, *velocity_damping_matrix, SparseMatrix &); /// get the FEEngine object to integrate or interpolate on the boundary inline FEEngine & getFEEngineBoundary(const ID & name = ""); /// get integrator AKANTU_GET_MACRO(Integrator, *integrator, const IntegrationScheme2ndOrder &); /// get access to the internal solver AKANTU_GET_MACRO(Solver, *solver, Solver &); /// get synchronizer AKANTU_GET_MACRO(Synchronizer, *synch_parallel, const DistributedSynchronizer &); AKANTU_GET_MACRO(ElementIndexByMaterial, element_index_by_material, const ElementTypeMapArray <UInt> &); /// vectors containing local material element index for each global element index AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementIndexByMaterial, element_index_by_material, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementIndexByMaterial, element_index_by_material, UInt); /// 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; template <UInt DIM, template <UInt> class WeightFunction> friend class MaterialNonLocal; protected: /// compute the stable time step Real getStableTimeStep(const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array <Real> *displacement; /// displacements array at the previous time step (used in finite deformation) Array <Real> *previous_displacement; /// lumped mass array Array <Real> *mass; /// velocities array Array <Real> *velocity; /// accelerations array Array <Real> *acceleration; /// accelerations array Array <Real> *increment_acceleration; /// forces array Array <Real> *force; /// residuals array Array <Real> *residual; /// array specifing if a degree of freedom is blocked or not Array <bool> *blocked_dofs; /// array of current position used during update residual Array <Real> *current_position; /// mass matrix SparseMatrix *mass_matrix; /// velocity damping matrix SparseMatrix *velocity_damping_matrix; /// stiffness matrix SparseMatrix *stiffness_matrix; /// jacobian matrix @f[A = cM + dD + K@f] with @f[c = \frac{1}{\beta \Delta /// t^2}, d = \frac{\gamma}{\beta \Delta t} @f] SparseMatrix *jacobian_matrix; /// vectors containing local material element index for each global element index ElementTypeMapArray<UInt> element_index_by_material; /// 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_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc index d4aece91b..48d6b26f6 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc @@ -1,609 +1,608 @@ /** * @file solid_mechanics_model_inline_impl.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Aug 04 2010 * @date last modification: Mon Sep 15 2014 * * @brief Implementation of the inline functions of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(UInt mat_index) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(UInt mat_index) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(const std::string & name) { AKANTU_DEBUG_IN(); std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getMaterialIndex(const std::string & name) const { AKANTU_DEBUG_IN(); std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return it->second; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(const std::string & name) const { AKANTU_DEBUG_IN(); std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::setMaterialSelector(MaterialSelector & selector) { if(is_default_material_selector) delete material_selector; material_selector = &selector; is_default_material_selector = false; } /* -------------------------------------------------------------------------- */ inline FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) { return dynamic_cast<FEEngine &>(getFEEngineClassBoundary<MyFEEngineType>(name)); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::splitElementByMaterial(const Array<Element> & elements, Array<Element> * elements_per_mat) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; const Array<UInt> * elem_mat = NULL; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> end = elements.end(); for (; it != end; ++it) { Element el = *it; if(el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; elem_mat = &element_index_by_material(el.type, el.ghost_type); } UInt old_id = el.element; el.element = (*elem_mat)(old_id, 1); elements_per_mat[(*elem_mat)(old_id, 0)].push_back(el); } } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataForElements(const Array<Element> & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes_per_element = 0; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> end = elements.end(); for (; it != end; ++it) { const Element & el = *it; nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch(tag) { case _gst_material_id: { size += elements.getSize() * 2 * sizeof(UInt); break; } case _gst_smm_mass: { size += nb_nodes_per_element * sizeof(Real) * spatial_dimension; // mass vector break; } case _gst_smm_for_gradu: { size += nb_nodes_per_element * spatial_dimension * sizeof(Real); // displacement break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } default: { } } if(tag != _gst_material_id) { Array<Element> * elements_per_mat = new Array<Element>[materials.size()]; this->splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { size += materials[i]->getNbDataForElements(elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::packElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); switch(tag) { case _gst_material_id: { packElementalDataHelper(element_index_by_material, buffer, elements, false, getFEEngine()); break; } case _gst_smm_mass: { packNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { packNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_smm_boundary: { packNodalDataHelper(*force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id) { Array<Element> * elements_per_mat = new Array<Element>[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->packElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::unpackElementData(CommunicationBuffer & buffer, const Array<Element> & elements, SynchronizationTag tag) { AKANTU_DEBUG_IN(); switch(tag) { case _gst_material_id: { unpackElementalDataHelper(element_index_by_material, buffer, elements, false, getFEEngine()); break; } case _gst_smm_mass: { unpackNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id) { Array<Element> * elements_per_mat = new Array<Element>[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->unpackElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToPack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } case _gst_for_dump: { size += sizeof(Real) * spatial_dimension * 5; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToUnpack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } case _gst_for_dump: { size += sizeof(Real) * spatial_dimension * 5; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Array<Real>::const_vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::const_vector_iterator it_velo = velocity->begin(spatial_dimension); buffer << it_disp[index]; buffer << it_velo[index]; break; } case _gst_smm_res: { Array<Real>::const_vector_iterator it_res = residual->begin(spatial_dimension); buffer << it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("pack mass of node " << index << " which is " << (*mass)(index,0)); Array<Real>::const_vector_iterator it_mass = mass->begin(spatial_dimension); buffer << it_mass[index]; break; } case _gst_for_dump: { Array<Real>::const_vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::const_vector_iterator it_velo = velocity->begin(spatial_dimension); Array<Real>::const_vector_iterator it_acce = acceleration->begin(spatial_dimension); Array<Real>::const_vector_iterator it_resi = residual->begin(spatial_dimension); Array<Real>::const_vector_iterator it_forc = force->begin(spatial_dimension); buffer << it_disp[index]; buffer << it_velo[index]; buffer << it_acce[index]; buffer << it_resi[index]; buffer << it_forc[index]; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Array<Real>::vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::vector_iterator it_velo = velocity->begin(spatial_dimension); buffer >> it_disp[index]; buffer >> it_velo[index]; break; } case _gst_smm_res: { Array<Real>::vector_iterator it_res = residual->begin(spatial_dimension); buffer >> it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("mass of node " << index << " was " << (*mass)(index,0)); Array<Real>::vector_iterator it_mass = mass->begin(spatial_dimension); buffer >> it_mass[index]; AKANTU_DEBUG_INFO("mass of node " << index << " is now " << (*mass)(index,0)); break; } case _gst_for_dump: { Array<Real>::vector_iterator it_disp = displacement->begin(spatial_dimension); Array<Real>::vector_iterator it_velo = velocity->begin(spatial_dimension); Array<Real>::vector_iterator it_acce = acceleration->begin(spatial_dimension); Array<Real>::vector_iterator it_resi = residual->begin(spatial_dimension); Array<Real>::vector_iterator it_forc = force->begin(spatial_dimension); buffer >> it_disp[index]; buffer >> it_velo[index]; buffer >> it_acce[index]; buffer >> it_resi[index]; buffer >> it_forc[index]; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ #include "sparse_matrix.hh" #include "solver.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template <NewmarkBeta::IntegrationSchemeCorrectorType type> void SolidMechanicsModel::solve(Array<Real> &increment, Real block_val, - bool need_factorize, bool has_profile_changed, - const Array<Real> &rhs) { + 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 + // if (rhs.getSize() != 0) + // solver->setRHS(rhs); + // else 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/solver/petsc_matrix.cc b/src/solver/petsc_matrix.cc index 793f8a196..e64367c3f 100644 --- a/src/solver/petsc_matrix.cc +++ b/src/solver/petsc_matrix.cc @@ -1,534 +1,625 @@ /** * @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 <mpi.h> -#include <petscmat.h> -#include <petscao.h> -#include <petscis.h> #include <petscsys.h> - __BEGIN_AKANTU__ -struct PETScWrapper { - Mat mat; - AO ao; - ISLocalToGlobalMapping mapping; - /// pointer to the MPI communicator for PETSc commands - MPI_Comm communicator; -}; +// 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_wrapper(new PETScWrapper), - d_nnz(0,1,"dnnz"), - o_nnz(0,1,"onnz"), + petsc_matrix_wrapper(new PETScMatrixWrapper), + d_nnz(0,1,"dnnz"), + o_nnz(0,1,"onnz"), first_global_index(0), - is_petsc_matrix_initialized(false) { + 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_wrapper(new PETScWrapper), + 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_IN(); + // StaticSolver::getStaticSolver().registerEventHandler(*this); + // this->offset = 0; + // this->init(); - AKANTU_DEBUG_OUT(); + // AKANTU_DEBUG_OUT(); + AKANTU_DEBUG_TO_IMPLEMENT(); } /* -------------------------------------------------------------------------- */ PETScMatrix::~PETScMatrix() { AKANTU_DEBUG_IN(); + /// destroy all the PETSc data structures used for this matrix this->destroyInternalData(); 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_wrapper->communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator(); + this->petsc_matrix_wrapper->communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator(); #else - this->petsc_wrapper->communicator = PETSC_COMM_SELF; + this->petsc_matrix_wrapper->communicator = PETSC_COMM_SELF; #endif PetscErrorCode ierr; - - ierr = MatCreate(this->petsc_wrapper->communicator, &(this->petsc_wrapper->mat)); CHKERRXX(ierr); - /// set matrix type - ierr = MatSetType(this->petsc_wrapper->mat, MATAIJ); CHKERRXX(ierr); + + /// create the PETSc matrix object + ierr = MatCreate(this->petsc_matrix_wrapper->communicator, &(this->petsc_matrix_wrapper->mat)); CHKERRXX(ierr); - //if (this->sparse_matrix_type==_symmetric) - /// set flag for symmetry to enable ICC/Cholesky preconditioner - // ierr = MatSetOption(this->petsc_wrapper->mat, MAT_SYMMETRIC, PETSC_TRUE); 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(); } /* -------------------------------------------------------------------------- */ -void PETScMatrix::resize(const DOFSynchronizer & dof_synchronizer) { +/** + * 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; - this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer); - /// find the number of dofs corresponding to master or local nodes - UInt nb_dofs = dof_synchronizer.getNbDOFs(); + 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 gloabl equation number array - Int * eq_nb_val = dof_synchronizer.getGlobalDOFEquationNumbers().storage(); + /// 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 (dof_synchronizer.isLocalOrMasterDOF(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_wrapper->mat, this->local_size, this->local_size, this->size, this->size); CHKERRXX(ierr); + ierr = MatSetSizes(this->petsc_matrix_wrapper->mat, this->local_size, this->local_size, this->size, this->size); CHKERRXX(ierr); #else - ierr = MatSetSizes(this->petsc_wrapper->mat, this->local_size, this->local_size); CHKERRXX(ierr); + 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_wrapper->communicator, this->local_size, local_master_eq_nbs_ptr, petsc_dofs.storage(), &(this->petsc_wrapper->ao)); CHKERRXX(ierr); + 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_wrapper->ao != NULL, +// 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 -// AOApplicationToPETSc(this->petsc_wrapper->ao, nb_dofs, -// global_dof_equation_numbers.storage()); +// 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 -// ISLocalToGlobalMappingCreate(this->petsc_wrapper->communicator, +// ierr = ISLocalToGlobalMappingCreate(this->petsc_matrix_wrapper->communicator, // 1, nb_dofs, global_dof_equation_numbers.storage(), -// PETSC_COPY_VALUES, mapping); +// 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); - this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer); // 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(); /// 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); + 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); } - // 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) { Int c_irn = local_eq_nb_val[i]; - UInt j_start = (sparse_matrix_type == _symmetric) ? i : 0; + 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_wrapper->ao, 2, index_pair.storage()); - if(sparse_matrix_type == _symmetric && (index_pair(0) > index_pair(1))) - std::swap(index_pair(0), index_pair(1)); + 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 = key(c_irn, c_jcn); + 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_wrapper->mat, &type); - - // PetscTypeCompare((PetscObject)(this->petsc_wrapper->mat),MATSEQAIJ,&sametype); - //ierr = PetscTypeCompare(pet, MATSEQAIJ, &sametype); CHKERRXX(ierr); - + MatGetType(this->petsc_matrix_wrapper->mat, &type); + 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_wrapper->mat, - 0, d_nnz.storage()); CHKERRXX(ierr); + ierr = MatSeqAIJSetPreallocation(this->petsc_matrix_wrapper->mat, + 0, d_nnz.storage()); CHKERRXX(ierr); } else if ((strcmp(type, MATMPIAIJ) == 0)) { - ierr = MatMPIAIJSetPreallocation(this->petsc_wrapper->mat, - 0, d_nnz.storage(), 0, - o_nnz.storage()); CHKERRXX(ierr); + 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"); + << " 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); + } + /// 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(); } /* -------------------------------------------------------------------------- */ -void PETScMatrix::saveMatrix(const std::string & filename) const { +/** + * 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_wrapper->communicator, filename.c_str(), &viewer); CHKERRXX(ierr); + 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 - ierr = MatView(this->petsc_wrapper->mat, viewer); CHKERRXX(ierr); + ierr = MatView(this->petsc_matrix_wrapper->mat, viewer); CHKERRXX(ierr); /// destroy the viewer ierr = PetscViewerDestroy(&viewer); CHKERRXX(ierr); AKANTU_DEBUG_OUT(); } -// /* -------------------------------------------------------------------------- */ -// Array<Real> & operator*=(Array<Real> & vect, const PETScMatrix & mat) { -// AKANTU_DEBUG_IN(); - -// Array<Real> result -// MatMult(this->mat, vect, ) - -// // AKANTU_DEBUG_ASSERT((vect.getSize()*vect.getNbComponent() == mat.getSize()) && -// // (vect.getNbComponent() == mat.getNbDegreOfFreedom()), -// // "The size of the matrix and the vector do not match"); - -// const PETScMatrixType & sparse_matrix_type = mat.getPETScMatrixType(); -// DOFSynchronizer * dof_synchronizer = mat.getDOFSynchronizerPointer(); - -// UInt nb_non_zero = mat.getNbNonZero(); -// Real * tmp = new Real [vect.getNbComponent() * vect.getSize()]; -// std::fill_n(tmp, vect.getNbComponent() * vect.getSize(), 0); - -// Int * i_val = mat.getIRN().storage(); -// Int * j_val = mat.getJCN().storage(); -// Real * a_val = mat.getA().storage(); - -// Real * vect_val = vect.storage(); - -// for (UInt k = 0; k < nb_non_zero; ++k) { -// UInt i = *(i_val++); -// UInt j = *(j_val++); -// Real a = *(a_val++); - -// UInt local_i = i - 1; -// UInt local_j = j - 1; -// if(dof_synchronizer) { -// local_i = dof_synchronizer->getDOFLocalID(local_i); -// local_j = dof_synchronizer->getDOFLocalID(local_j); -// } - -// tmp[local_i] += a * vect_val[local_j]; -// if((sparse_matrix_type == _symmetric) && (local_i != local_j)) -// tmp[local_j] += a * vect_val[local_i]; -// } - -// memcpy(vect_val, tmp, vect.getNbComponent() * vect.getSize() * sizeof(Real)); -// delete [] tmp; - -// if(dof_synchronizer) -// dof_synchronizer->reduceSynchronize<AddOperation>(vect); - -// AKANTU_DEBUG_OUT(); - -// return vect; -// } - -// /* -------------------------------------------------------------------------- */ -// void PETScMatrix::copyContent(const PETScMatrix & matrix) { -// AKANTU_DEBUG_IN(); -// AKANTU_DEBUG_ASSERT(nb_non_zero == matrix.getNbNonZero(), -// "The two matrices don't have the same profiles"); - -// MatCopy(this->mat, matrix->mat, SAME_NONZERO_PATTERN); - -// AKANTU_DEBUG_OUT(); -// } - -// ///* -------------------------------------------------------------------------- */ -// //void PETScMatrix::copyProfile(const PETScMatrix & matrix) { -// // AKANTU_DEBUG_IN(); -// // irn = matrix.irn; -// // jcn = matrix.jcn; -// // nb_non_zero = matrix.nb_non_zero; -// // irn_jcn_k = matrix.irn_jcn_k; -// // a.resize(nb_non_zero); -// // 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"); 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(); - AOApplicationToPetsc(this->petsc_wrapper->ao, 2, index.storage()); - if (_symmetric && index(0) > index(1)) + 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)); - ierr = MatSetValue(this->petsc_wrapper->mat, index(0), index(1), matrix.getA()(n) * alpha, ADD_VALUES); CHKERRXX(ierr); + /// 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); + /// 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); } + 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_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr); - ierr = MatAssemblyEnd(this->petsc_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(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_wrapper->mat)); CHKERRXX(ierr); - delete petsc_wrapper; + 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(); + for (UInt i = 0; i < boundary.getSize(); ++i) { + for (UInt j = 0; j < boundary.getNbComponent(); ++j) { + UInt local_dof = i * boundary.getNbComponent() + 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()); + + + 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/petsc_matrix.hh b/src/solver/petsc_matrix.hh index ea1369539..d09eae806 100644 --- a/src/solver/petsc_matrix.hh +++ b/src/solver/petsc_matrix.hh @@ -1,158 +1,146 @@ /** * @file petsc_matrix.hh * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Mon Jul 21 14:49:49 2014 * * @brief Interface for PETSc matrices * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PETSC_MATRIX_HH__ #define __AKANTU_PETSC_MATRIX_HH__ /* -------------------------------------------------------------------------- */ #include "sparse_matrix.hh" #include "static_communicator.hh" #include "static_solver.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ -class PETScWrapper; +class PETScMatrixWrapper; class PETScMatrix : public SparseMatrix, StaticSolverEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: PETScMatrix(UInt size, const SparseMatrixType & sparse_matrix_type, const ID & id = "petsc_matrix", const MemoryID & memory_id = 0); PETScMatrix(const SparseMatrix & matrix, const ID & id = "petsc_matrix", const MemoryID & memory_id = 0); virtual ~PETScMatrix(); private: /// init internal PETSc matrix void init(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - /// resize PETSc matrix - void resize(const DOFSynchronizer & dof_synchronizer); - void createGlobalAkantuToPETScMap(Int* local_master_eq_nbs_ptr); - - // /// remove the existing profile - // inline void clearProfile(); - - // /// add a non-zero element - // virtual UInt addToProfile(UInt i, UInt j); - - // /// set the matrix to 0 - // inline void clear(); - - // /// assemble a local matrix in the sparse one - // inline void addToMatrix(UInt i, UInt j, Real value); + /// set the matrix to 0 + virtual void clear(); /// fill the profil of the matrix virtual void buildProfile(const Mesh & mesh, const DOFSynchronizer & dof_synchronizer, UInt nb_degree_of_freedom); - // /// modify the matrix to "remove" the blocked dof - // virtual void applyBoundary(const Array<bool> & boundary, Real block_val = 1.); - - /// perform assembly so that matrix is ready for use - void performAssembly(); - - // /// restore the profile that was before removing the boundaries - // virtual void restoreProfile(); + /// modify the matrix to "remove" the blocked dof + virtual void applyBoundary(const Array<bool> & boundary, Real block_val = 1.); - // /// save the profil in a file using the MatrixMarket file format - // virtual void saveProfile(const std::string & filename) const; - - /// save the matrix in a file using the MatrixMarket file format + /// save the matrix in a ASCII file format virtual void saveMatrix(const std::string & filename) const; - // /// copy assuming the profile are the same - // virtual void copyContent(const SparseMatrix & matrix); - - // /// copy profile - // // void copyProfile(const SparseMatrix & matrix); - - /// add matrix assuming the profile are the same + /// add a sparse matrix assuming the profile are the same virtual void add(const SparseMatrix & matrix, Real alpha); + /// add a petsc matrix assuming the profile are the same + virtual void add(const PETScMatrix & matrix, Real alpha); - // /// diagonal lumping - // virtual void lump(Array<Real> & lumped); - - // /// function to print the contain of the class - // //virtual void printself(std::ostream & stream, int indent = 0) const; virtual void beforeStaticSolverDestroy(); + Real operator()(UInt i, UInt j) const; + +protected: + inline KeyCOO keyPETSc(UInt i, UInt j) const { + return std::make_pair(i, j); + } + private: virtual void destroyInternalData(); + /// set the size of the PETSc matrix + void setSize(); + void createGlobalAkantuToPETScMap(Int* local_master_eq_nbs_ptr); + void createLocalAkantuToPETScMap(const DOFSynchronizer & dof_synchronizer); + /// perform assembly so that matrix is ready for use + void performAssembly(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ +public: + + AKANTU_GET_MACRO(PETScMatrixWrapper, petsc_matrix_wrapper, PETScMatrixWrapper*); + AKANTU_GET_MACRO(LocalSize, local_size, Int); + /// AKANTU_GET_MACRO(LocalSize, local_size, Int); + + public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// store the PETSc structures - PETScWrapper * petsc_wrapper; + PETScMatrixWrapper * petsc_matrix_wrapper; /// size of the diagonal part of the matrix partition Int local_size; /// number of nonzeros in every row of the diagonal part Array<Int> d_nnz; /// number of nonzeros in every row of the off-diagonal part Array<Int> o_nnz; /// the global index of the first local row Int first_global_index; /// bool to indicate if the matrix data has been initialized by calling MatCreate bool is_petsc_matrix_initialized; - }; __END_AKANTU__ -#endif /* __AKANTU_PETSCI_MATRIX_HH__ */ +#endif /* __AKANTU_PETSC_MATRIX_HH__ */ diff --git a/src/solver/petsc_wrapper.hh b/src/solver/petsc_wrapper.hh index af1704e44..14bd59b4e 100644 --- a/src/solver/petsc_wrapper.hh +++ b/src/solver/petsc_wrapper.hh @@ -1,61 +1,62 @@ /** * @file petsc_wrapper.hh * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * @date Mon Jul 21 17:40:41 2014 * * @brief Wrapper of PETSc structures * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_PETSC_WRAPPER_HH__ #define __AKANTU_PETSC_WRAPPER_HH__ /* -------------------------------------------------------------------------- */ #include <mpi.h> #include <petscmat.h> +#include <petscvec.h> #include <petscao.h> #include <petscis.h> #include <petscksp.h> __BEGIN_AKANTU__ struct PETScMatrixWrapper { Mat mat; AO ao; ISLocalToGlobalMapping mapping; /// pointer to the MPI communicator for PETSc commands MPI_Comm communicator; }; struct PETScSolverWrapper { KSP ksp; Vec solution; Vec rhs; /// pointer to the MPI communicator for PETSc commands MPI_Comm communicator; }; __END_AKANTU__ #endif /* __AKANTU_PETSC_WRAPPER_HH__ */ diff --git a/src/solver/solver.cc b/src/solver/solver.cc index ee6706eb4..7d9d4746e 100644 --- a/src/solver/solver.cc +++ b/src/solver/solver.cc @@ -1,76 +1,87 @@ /** * @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()){ + 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; 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.hh b/src/solver/solver.hh index 99bb1bd4a..9377bd932 100644 --- a/src/solver/solver.hh +++ b/src/solver/solver.hh @@ -1,134 +1,165 @@ /** * @file solver.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> + * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Mon Dec 13 2010 * @date last modification: Mon Sep 15 2014 * * @brief interface for solvers * * @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_SOLVER_HH__ #define __AKANTU_SOLVER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "aka_array.hh" #include "sparse_matrix.hh" #include "mesh.hh" #include "static_communicator.hh" #include "static_solver.hh" +#include "data_accessor.hh" +#include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class SolverOptions { public: SolverOptions(bool no_option = false) : no_option(no_option) { } virtual ~SolverOptions() {} private: bool no_option; }; extern SolverOptions _solver_no_options; class Solver : protected Memory, - public StaticSolverEventHandler { + public StaticSolverEventHandler, + public DataAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Solver(SparseMatrix & matrix, const ID & id = "solver", const MemoryID & memory_id = 0); virtual ~Solver(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver virtual void initialize(SolverOptions & options = _solver_no_options) = 0; virtual void analysis() {}; virtual void factorize() {}; /// solve virtual void solve(Array<Real> & solution) = 0; virtual void solve() = 0; - virtual void setRHS(const Array<Real> & rhs) = 0; + virtual void setRHS(Array<Real> & rhs) = 0; /// function to print the contain of the class // virtual void printself(std::ostream & stream, int indent = 0) const; protected: virtual void destroyInternalData() {}; public: virtual void beforeStaticSolverDestroy(); + void createSynchronizerRegistry(); + /* ------------------------------------------------------------------------ */ + /* Data Accessor inherited members */ + /* ------------------------------------------------------------------------ */ +public: + inline virtual UInt getNbDataForDOFs(const Array <UInt> & dofs, + SynchronizationTag tag) const; + + inline virtual void packDOFData(CommunicationBuffer & buffer, + const Array<UInt> & dofs, + SynchronizationTag tag) const; + + inline virtual void unpackDOFData(CommunicationBuffer & buffer, + const Array<UInt> & dofs, + SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(RHS, *rhs, Array<Real> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the matrix SparseMatrix * matrix; /// is sparse matrix allocated bool is_matrix_allocated; /// the right hand side Array<Real> * rhs; /// mesh const Mesh * mesh; /// pointer to the communicator StaticCommunicator & communicator; + + /// the solution obtained from the solve step + Array<Real> * solution; + + /// synchronizer registry + SynchronizerRegistry * synch_registry; + }; +/* -------------------------------------------------------------------------- */ +/* inline functions */ +/* -------------------------------------------------------------------------- */ + +#include "solver_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_SOLVER_HH__ */ diff --git a/src/solver/solver_mumps.cc b/src/solver/solver_mumps.cc index 526f034e3..68ba81c0d 100644 --- a/src/solver/solver_mumps.cc +++ b/src/solver/solver_mumps.cc @@ -1,374 +1,374 @@ /** * @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(const Array<Real> & rhs) { +void SolverMumps::setRHS(Array<Real> & rhs) { if(prank == 0) { - std::copy(rhs.storage(), rhs.storage() + this->rhs->getSize(), this->rhs->storage()); + //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); + 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()); + 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() { if(info(1) != 0) { communicator.allReduce(&info(1), 1, _so_min); switch(info(1)) { 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; 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(1)); } } } __END_AKANTU__ diff --git a/src/solver/solver_mumps.hh b/src/solver/solver_mumps.hh index 5bff7da6d..c843439d1 100644 --- a/src/solver/solver_mumps.hh +++ b/src/solver/solver_mumps.hh @@ -1,154 +1,154 @@ /** * @file solver_mumps.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 * @date last modification: Mon Sep 15 2014 * * @brief Solver class implementation for the mumps solver * * @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_SOLVER_MUMPS_HH__ #define __AKANTU_SOLVER_MUMPS_HH__ #include <dmumps_c.h> #include "solver.hh" #include "static_communicator.hh" __BEGIN_AKANTU__ class SolverMumpsOptions : public SolverOptions { public: enum ParallelMethod { _not_parallel, _fully_distributed, _master_slave_distributed }; SolverMumpsOptions(ParallelMethod parallel_method = _fully_distributed) : SolverOptions(), parallel_method(parallel_method) { } private: friend class SolverMumps; ParallelMethod parallel_method; }; class SolverMumps : public Solver { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SolverMumps(SparseMatrix & sparse_matrix, const ID & id = "solver_mumps", const MemoryID & memory_id = 0); virtual ~SolverMumps(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// build the profile and do the analysis part - void initialize(SolverOptions & options = _solver_no_options); + virtual void initialize(SolverOptions & options = _solver_no_options); void initializeSlave(SolverOptions & options = _solver_no_options); /// analysis (symbolic facto + permutations) - void analysis(); + virtual void analysis(); /// factorize the matrix - void factorize(); + virtual void factorize(); /// solve the system - void solve(Array<Real> & solution); - void solve(); + virtual void solve(Array<Real> & solution); + virtual void solve(); void solveSlave(); - virtual void setRHS(const Array<Real> & rhs); + virtual void setRHS(Array<Real> & rhs); private: /// print the error if any happened in mumps void printError(); /// clean the mumps info - void destroyInternalData(); + virtual void destroyInternalData(); /// set internal values; void initMumpsData(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ private: /// access the control variable inline Int & icntl(UInt i) { return mumps_data.icntl[i - 1]; } /// access the results info inline Int & info(UInt i) { return mumps_data.info[i - 1]; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// mumps data DMUMPS_STRUC_C mumps_data; /// specify if the mumps_data are initialized or not bool is_mumps_data_initialized; UInt prank; /* ------------------------------------------------------------------------ */ /* Local types */ /* ------------------------------------------------------------------------ */ private: SolverMumpsOptions::ParallelMethod parallel_method; bool rhs_is_local; enum SolverMumpsJob { _smj_initialize = -1, _smj_analyze = 1, _smj_factorize = 2, _smj_solve = 3, _smj_analyze_factorize = 4, _smj_factorize_solve = 5, _smj_complete = 6, // analyze, factorize, solve _smj_destroy = -2 }; }; __END_AKANTU__ #endif /* __AKANTU_SOLVER_MUMPS_HH__ */ diff --git a/src/solver/solver_petsc.cc b/src/solver/solver_petsc.cc index ce058bc87..09b3c0c74 100644 --- a/src/solver/solver_petsc.cc +++ b/src/solver/solver_petsc.cc @@ -1,954 +1,1082 @@ -// /** -// * @file solver_petsc.cc -// * -// * @author Nicolas Richart <nicolas.richart@epfl.ch> -// # @author Alejandro M. Aragón <alejandro.aragon@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/>. -// * -// */ - -// /* -------------------------------------------------------------------------- */ -// #ifdef AKANTU_USE_MPI -// #include "static_communicator_mpi.hh" -// #endif - -// #include "solver_petsc.hh" -// #include "dof_synchronizer.hh" - -// __BEGIN_AKANTU__ +/** + * @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; + + /// create a solver context + ierr = KSPCreate(this->petsc_solver_wrapper->communicator, &(this->petsc_solver_wrapper->ksp)); CHKERRXX(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 + + ierr = VecCreate(this->petsc_solver_wrapper->communicator, &(this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr); + + 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); + ierr = VecSetSizes((this->petsc_solver_wrapper->rhs), petsc_matrix->getLocalSize(), petsc_matrix->getSize()); CHKERRXX(ierr); + ierr = VecSetFromOptions((this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr); + + for (UInt i = 0; i < rhs.getSize(); ++i) { + if (matrix->getDOFSynchronizer().isLocalOrMasterDOF(i)) { + Int i_global = matrix->getDOFSynchronizer().getDOFGlobalID(i); + AOApplicationToPetsc(petsc_matrix->getPETScMatrixWrapper()->ao, 1, &(i_global) ); + ierr = VecSetValue((this->petsc_solver_wrapper->rhs), i_global, rhs(i), INSERT_VALUES); CHKERRXX(ierr); + } + } + ierr = VecAssemblyBegin(this->petsc_solver_wrapper->rhs); CHKERRXX(ierr); + ierr = VecAssemblyEnd(this->petsc_solver_wrapper->rhs); CHKERRXX(ierr); + ierr = VecDuplicate((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); + + for (UInt i = 0; i < solution.getSize(); ++i) { + if (this->matrix->getDOFSynchronizer().isLocalOrMasterDOF(i)) { + Int i_global = this->matrix->getDOFSynchronizer().getDOFGlobalID(i); + ierr = AOApplicationToPetsc(petsc_matrix->getPETScMatrixWrapper()->ao, 1, &(i_global) ); CHKERRXX(ierr); + ierr = VecGetValues(this->petsc_solver_wrapper->solution, 1, &i_global, &solution(i)); CHKERRXX(ierr); + + } + } + + synch_registry->synchronize(_gst_solver_solution); + + 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__ -// __END_AKANTU__ diff --git a/src/solver/solver_petsc.hh b/src/solver/solver_petsc.hh index 352a2db88..40c27c7d5 100644 --- a/src/solver/solver_petsc.hh +++ b/src/solver/solver_petsc.hh @@ -1,271 +1,165 @@ /** * @file solver_petsc.hh * # @author Alejandro M. Aragón <alejandro.aragon@epfl.ch> * @author Nicolas Richart <nicolas.richart@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 + * @brief Solver class interface 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/>. * */ /* -------------------------------------------------------------------------- */ -// #ifndef __AKANTU_SOLVER_PETSC_HH__ -// #define __AKANTU_SOLVER_PETSC_HH__ +#ifndef __AKANTU_SOLVER_PETSC_HH__ +#define __AKANTU_SOLVER_PETSC_HH__ +/* -------------------------------------------------------------------------- */ +#include "solver.hh" -// #include <petscksp.h> +/* -------------------------------------------------------------------------- */ +__BEGIN_AKANTU__ -// #include "solver.hh" -// #include "static_communicator.hh" -// #include "sparse_matrix.hh" +class PETScSolverWrapper; -// __BEGIN_AKANTU__ +class SolverPETSc : public Solver { + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + SolverPETSc(SparseMatrix & sparse_matrix, + const ID & id = "solver_petsc", + const MemoryID & memory_id = 0); -// struct SolverPETSc : public Solver, public CommunicatorEventHandler { - -// typedef double value_type; -// typedef sparse_vector<value_type> sparse_vector_type; -// typedef SparseMatrix sparse_matrix_type; - -// Mat A_; //!< linear system matrix -// Vec x_; //!< Solution vector -// KSP ksp_; //!< linear solver context - -// bool allocated_; + virtual ~SolverPETSc(); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ +public: + /// create the solver context and set the matrices + virtual void initialize(SolverOptions & options = _solver_no_options); + virtual void setRHS(Array<Real> & rhs); + virtual void solve(); + virtual void solve(Array<Real> & solution); +private: + /// clean the petsc data + virtual void destroyInternalData(); + +private: + + /// specify if the petsc_data is initialized or not + bool is_petsc_data_initialized; + + /// store the PETSc structures + PETScSolverWrapper * petsc_solver_wrapper; + + + +}; + // SolverPETSc(int argc, char *argv[]) : allocated_(false) { - -// PetscInitialize(&argc, &argv,NULL,NULL); -// PetscErrorCode ierr; - -// // create linear solver context -// ierr = KSPCreate(PETSC_COMM_WORLD, &ksp_);CHKERRCONTINUE(ierr); - -// // initial nonzero guess -// ierr = KSPSetInitialGuessNonzero(ksp_,PETSC_TRUE); CHKERRCONTINUE(ierr); - -// // set runtime options -// ierr = KSPSetFromOptions(ksp_);CHKERRCONTINUE(ierr); - // /* // Set linear solver defaults for this problem (optional). // - By extracting the KSP and PC contexts from the KSP context, // we can then directly call any KSP and PC routines to set // various options. // - The following four statements are optional; all of these // parameters could alternatively be specified at runtime via // KSPSetFromOptions(); // */ // // ierr = KSPGetPC(ksp_,&pc);CHKERRCONTINUE(ierr); // // ierr = PCSetType(pc,PCILU);CHKERRCONTINUE(ierr); // // ierr = PCSetType(pc,PCJACOBI);CHKERRCONTINUE(ierr); // ierr = KSPSetTolerances(ksp_,1.e-5,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRCONTINUE(ierr); // } // //! Overload operator() to solve system of linear equations // sparse_vector_type operator()(const sparse_matrix_type& AA, const sparse_vector_type& bb); // //! Overload operator() to obtain reaction vector // sparse_vector_type operator()(const sparse_matrix_type& Kpf, const sparse_matrix_type& Kpp, const sparse_vector_type& Up); // //! Overload operator() to obtain the addition two vectors // sparse_vector_type operator()(const sparse_vector_type& aa, const sparse_vector_type& bb); // value_type norm(const sparse_matrix_type& aa, Element_insertion_type it = Add_t); // value_type norm(const sparse_vector_type& aa, Element_insertion_type it = Add_t); // // NOTE: the destructor will return an error if it is called after MPI_Finalize is // // called because it uses collect communication to free-up allocated memory. // ~SolverPETSc() { // static bool exit = false; // if (!exit) { // // add finalize PETSc function at exit // atexit(finalize); // exit = true; // } // if (allocated_) { // PetscErrorCode ierr = MatDestroy(&A_);CHKERRCONTINUE(ierr); // ierr = VecDestroy(&x_);CHKERRCONTINUE(ierr); // ierr = KSPDestroy(&ksp_);CHKERRCONTINUE(ierr); // } // } // /* from the PETSc library, these are the options that can be passed // to the command line // Options Database Keys // -options_table - Calls PetscOptionsView() // -options_left - Prints unused options that remain in the database // -objects_left - Prints list of all objects that have not been freed // -mpidump - Calls PetscMPIDump() // -malloc_dump - Calls PetscMallocDump() // -malloc_info - Prints total memory usage // -malloc_log - Prints summary of memory usage // Options Database Keys for Profiling // -log_summary [filename] - Prints summary of flop and timing information to screen. // If the filename is specified the summary is written to the file. See PetscLogView(). // -log_summary_python [filename] - Prints data on of flop and timing usage to a file or screen. // -log_all [filename] - Logs extensive profiling information See PetscLogDump(). // -log [filename] - Logs basic profiline information See PetscLogDump(). // -log_sync - Log the synchronization in scatters, inner products and norms // -log_mpe [filename] - Creates a logfile viewable by the utility Upshot/Nupshot (in MPICH distribution) -// */ -// static void finalize() { - -// static bool finalized = false; -// if (!finalized) { - -// cout<<"*** INFO *** PETSc is finalizing..."<<endl; - -// // finalize PETSc -// PetscErrorCode ierr = PetscFinalize();CHKERRCONTINUE(ierr); -// finalized = true; - -// cout<<"*** INFO *** Process "<<Parallel_base::rank_<<" is finalizing..."<<endl; - -// // finalize MPI -// MPI_Finalize(); // } // } // }; -// class SolverPETSc : public Solver, public CommunicatorEventHandler { -// /* ------------------------------------------------------------------------ */ -// /* Constructors/Destructors */ -// /* ------------------------------------------------------------------------ */ -// public: - -// SolverPETSc(SparseMatrix & sparse_matrix, -// const ID & id = "solver_petsc", -// const MemoryID & memory_id = 0); - -// virtual SolverPETSc(); - -// /* ------------------------------------------------------------------------ */ -// /* Methods */ -// /* ------------------------------------------------------------------------ */ -// public: - -// /// build the profile and do the analysis part -// void initialize(SolverOptions & options = _solver_no_options); - -// void initializeSlave(SolverOptions & options = _solver_no_options); - - -// /// factorize and solve the system -// void solve(Array<Real> & solution); -// void solve(); - -// void solveSlave(); - -// virtual void setRHS(Array<Real> & rhs); - -// /// function to print the contain of the class -// // virtual void printself(std::ostream & stream, int indent = 0) const; - -// virtual void onCommunicatorFinalize(const StaticCommunicator & communicator); - -// private: - -// void destroyMumpsData(); - -// inline Int & icntl(UInt i) { -// return mumps_data.icntl[i - 1]; -// } - -// inline Int & info(UInt i) { -// return mumps_data.info[i - 1]; -// } - -// void initMumpsData(SolverMumpsOptions::ParallelMethod parallel_method); - -// /* ------------------------------------------------------------------------ */ -// /* Accessors */ -// /* ------------------------------------------------------------------------ */ -// public: - -// /* ------------------------------------------------------------------------ */ -// /* Class Members */ -// /* ------------------------------------------------------------------------ */ -// private: - -// /// mumps data -// DMUMPS_STRUC_C mumps_data; - -// /// specify if the mumps_data are initialized or not -// bool is_mumps_data_initialized; - -// UInt prank; - -// /* ------------------------------------------------------------------------ */ -// /* Local types */ -// /* ------------------------------------------------------------------------ */ - -// private: -// SolverMumpsOptions::ParallelMethod parallel_method; - -// bool rhs_is_local; - -// enum SolverMumpsJob { -// _smj_initialize = -1, -// _smj_analyze = 1, -// _smj_factorize = 2, -// _smj_solve = 3, -// _smj_analyze_factorize = 4, -// _smj_factorize_solve = 5, -// _smj_complete = 6, // analyze, factorize, solve -// _smj_destroy = -2 -// }; -// }; - - -// /* -------------------------------------------------------------------------- */ -// /* inline functions */ -// /* -------------------------------------------------------------------------- */ - -// //#include "solver_mumps_inline_impl.cc" - -// /// standard output stream operator -// // inline std::ostream & operator <<(std::ostream & stream, const SolverMumps & _this) -// // { -// // _this.printself(stream); -// // return stream; -// // } -// __END_AKANTU__ +__END_AKANTU__ -// #endif /* __AKANTU_SOLVER_PETSC_HH__ */ +#endif /* __AKANTU_SOLVER_PETSC_HH__ */ diff --git a/src/solver/sparse_matrix.hh b/src/solver/sparse_matrix.hh index 60a03e966..fad877951 100644 --- a/src/solver/sparse_matrix.hh +++ b/src/solver/sparse_matrix.hh @@ -1,251 +1,259 @@ /** * @file sparse_matrix.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Mon Dec 13 2010 * @date last modification: Mon Sep 15 2014 * * @brief sparse matrix storage class (distributed assembled matrix) * This is a COO format (Coordinate List) * * @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_SPARSE_MATRIX_HH__ #define __AKANTU_SPARSE_MATRIX_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __INTEL_COMPILER namespace std { namespace tr1 { template<typename a, typename b> struct hash< std::pair<a, b> > { private: const hash<a> ah; const hash<b> bh; public: hash() : ah(), bh() {} size_t operator()(const std::pair<a, b> &p) const { size_t seed = ah(p.first); return bh(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2); } }; } } // namespaces #endif __BEGIN_AKANTU__ class DOFSynchronizer; -class SparseMatrix : private Memory { +class SparseMatrix : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseMatrix(UInt size, const SparseMatrixType & sparse_matrix_type, const ID & id = "sparse_matrix", const MemoryID & memory_id = 0); SparseMatrix(const SparseMatrix & matrix, const ID & id = "sparse_matrix", const MemoryID & memory_id = 0); virtual ~SparseMatrix(); typedef std::pair<UInt, UInt> KeyCOO; typedef unordered_map<KeyCOO, UInt>::type coordinate_list_map; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// remove the existing profile inline void clearProfile(); /// add a non-zero element virtual UInt addToProfile(UInt i, UInt j); /// set the matrix to 0 inline void clear(); /// assemble a local matrix in the sparse one inline void addToMatrix(UInt i, UInt j, Real value); /// set the size of the matrix void resize(UInt size) { this->size = size; } virtual void buildProfile(const Mesh & mesh, const DOFSynchronizer & dof_synchronizer, UInt nb_degree_of_freedom); /// modify the matrix to "remove" the blocked dof virtual void applyBoundary(const Array<bool> & boundary, Real block_val = 1.); // /// modify the matrix to "remove" the blocked dof // void applyBoundaryNormal(Array<bool> & boundary_normal, Array<Real> & EulerAngles, Array<Real> & rhs, const Array<Real> & matrix, Array<Real> & rhs_rotated); /// save the profil in a file using the MatrixMarket file format virtual void saveProfile(const std::string & filename) const; /// save the matrix in a file using the MatrixMarket file format virtual void saveMatrix(const std::string & filename) const; /// copy assuming the profile are the same virtual void copyContent(const SparseMatrix & matrix); /// copy profile // void copyProfile(const SparseMatrix & matrix); /// add matrix assuming the profile are the same virtual void add(const SparseMatrix & matrix, Real alpha); /// diagonal lumping virtual void lump(Array<Real> & lumped); /// function to print the contain of the class //virtual void printself(std::ostream & stream, int indent = 0) const; protected: inline KeyCOO key(UInt i, UInt j) const { if(sparse_matrix_type == _symmetric && (i > j)) return std::make_pair(j, i); return std::make_pair(i, j); } /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the values at potition i, j inline Real operator()(UInt i, UInt j) const; inline Real & operator()(UInt i, UInt j); AKANTU_GET_MACRO(IRN, irn, const Array<Int> &); AKANTU_GET_MACRO(JCN, jcn, const Array<Int> &); AKANTU_GET_MACRO(A, a, const Array<Real> &); AKANTU_GET_MACRO(NbNonZero, nb_non_zero, UInt); AKANTU_GET_MACRO(Size, size, UInt); AKANTU_GET_MACRO(SparseMatrixType, sparse_matrix_type, const SparseMatrixType &); AKANTU_GET_MACRO(Offset, offset, UInt); const DOFSynchronizer & getDOFSynchronizer() const { AKANTU_DEBUG_ASSERT(dof_synchronizer != NULL, "DOFSynchronizer not initialized in the SparseMatrix!"); return *dof_synchronizer; } + DOFSynchronizer & getDOFSynchronizer() { + AKANTU_DEBUG_ASSERT(dof_synchronizer != NULL, + "DOFSynchronizer not initialized in the SparseMatrix!"); + return *dof_synchronizer; + } + private: AKANTU_GET_MACRO(DOFSynchronizerPointer, dof_synchronizer, DOFSynchronizer *); friend Array<Real> & operator*=(Array<Real> & vect, const SparseMatrix & mat); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the SparseMatrix ID id; /// sparce matrix type SparseMatrixType sparse_matrix_type; /// Mesh corresponding to the profile // const Mesh * mesh; /// Size of the matrix UInt size; /// number of processors UInt nb_proc; /// number of non zero element UInt nb_non_zero; /// row indexes Array<Int> irn; /// column indexes Array<Int> jcn; /// values : A[k] = Matrix[irn[k]][jcn[k]] Array<Real> a; /// saved row indexes Array<Int> * irn_save; /// saved column indexes Array<Int> * jcn_save; /// saved size UInt size_save; /// information to know where to assemble an element in a global sparse matrix // ElementTypeMapArray<UInt> element_to_sparse_profile; /* map for (i,j) -> k correspondence \warning std::map are slow * \todo improve with hash_map (non standard in stl) or unordered_map (boost or C++0x) */ coordinate_list_map irn_jcn_k; DOFSynchronizer * dof_synchronizer; // std::map<std::pair<UInt, UInt>, UInt> * irn_jcn_to_k; /// offset to inidcate whether row and column indices start at 0 (C/C++) or 1 (Fortran) UInt offset; + + }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "sparse_matrix_inline_impl.cc" #endif // /// standard output stream operator // inline std::ostream & operator <<(std::ostream & stream, const SparseMatrix & _this) // { // _this.printself(stream); // return stream; // } Array<Real> & operator*=(Array<Real> & vect, const SparseMatrix & mat); __END_AKANTU__ #endif /* __AKANTU_SPARSE_MATRIX_HH__ */ diff --git a/src/synchronizer/data_accessor.hh b/src/synchronizer/data_accessor.hh index 8324bdc8c..9d8001934 100644 --- a/src/synchronizer/data_accessor.hh +++ b/src/synchronizer/data_accessor.hh @@ -1,217 +1,268 @@ /** * @file data_accessor.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jun 16 2011 * @date last modification: Thu Jun 05 2014 * * @brief Interface of accessors for pack_unpack system * * @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_DATA_ACCESSOR_HH__ #define __AKANTU_DATA_ACCESSOR_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "fe_engine.hh" #include "communication_buffer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class DataAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DataAccessor(); virtual ~DataAccessor(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /** * @brief get the number of data to exchange for a given akantu::Element and a * given akantu::SynchronizationTag */ virtual UInt getNbDataForElements(__attribute__((unused)) const Array<Element> & elements, __attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } + /** + * @brief get the number of data to exchange for a given degree of freedom and a + * given akantu::SynchronizationTag + */ + virtual UInt getNbDataForDOFs(__attribute__((unused)) const Array<UInt> & dofs, + __attribute__((unused)) SynchronizationTag tag) const { + AKANTU_DEBUG_TO_IMPLEMENT(); + } + /** * @brief get the number of data to send for a given * akantu::SynchronizationTag */ virtual UInt getNbDataToPack(__attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief get the number of data to receive for a given * akantu::SynchronizationTag */ virtual UInt getNbDataToUnpack(__attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief pack the data for a given akantu::Element and a given * akantu::SynchronizationTag */ virtual void packElementData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const Array<Element> & element, __attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief pack the data for a given index and a given * akantu::SynchronizationTag */ virtual void packData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const UInt index, __attribute__((unused)) SynchronizationTag tag) const { AKANTU_DEBUG_TO_IMPLEMENT(); } + /** + * @brief pack the data for the dofs and a given + * akantu::SynchronizationTag + */ + virtual void packDOFData(__attribute__((unused)) CommunicationBuffer & buffer, + __attribute__((unused)) const Array<UInt> & dofs, + __attribute__((unused)) SynchronizationTag tag) const { + AKANTU_DEBUG_TO_IMPLEMENT(); + } + /** * @brief unpack the data for a given akantu::Element and a given * akantu::SynchronizationTag */ virtual void unpackElementData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const Array<Element> & element, __attribute__((unused)) SynchronizationTag tag) { AKANTU_DEBUG_TO_IMPLEMENT(); } /** * @brief unpack the data for a given index and a given * akantu::SynchronizationTag */ virtual void unpackData(__attribute__((unused)) CommunicationBuffer & buffer, __attribute__((unused)) const UInt index, __attribute__((unused)) SynchronizationTag tag) { AKANTU_DEBUG_TO_IMPLEMENT(); } + /** + * @brief unpack the data for the dofs and a given + * akantu::SynchronizationTag + */ + virtual void unpackDOFData(__attribute__((unused)) CommunicationBuffer & buffer, + __attribute__((unused)) const Array<UInt> & dofs, + __attribute__((unused)) SynchronizationTag tag) { + AKANTU_DEBUG_TO_IMPLEMENT(); + } + public: template<typename T> static inline void packNodalDataHelper(const Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh) { packUnpackNodalDataHelper<T, true>(const_cast<Array<T> &>(data), buffer, elements, mesh); } template<typename T> static inline void unpackNodalDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh) { packUnpackNodalDataHelper<T, false>(data, buffer, elements, mesh); } template<typename T, bool pack_helper> static inline void packUnpackNodalDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh); template<typename T, bool pack_helper> static inline void packUnpackElementalDataHelper(ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & element, bool per_quadrature_point_data, const FEEngine & fem); - template<typename T> static inline void packElementalDataHelper(const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements, bool per_quadrature_point, const FEEngine & fem) { packUnpackElementalDataHelper<T, true>(const_cast<ElementTypeMapArray<T> &>(data_to_pack), buffer, elements, per_quadrature_point, fem); } template<typename T> - inline void unpackElementalDataHelper(ElementTypeMapArray<T> & data_to_unpack, + static inline void unpackElementalDataHelper(ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements, bool per_quadrature_point, const FEEngine & fem) { packUnpackElementalDataHelper<T, false>(data_to_unpack, buffer, elements, per_quadrature_point, fem); } + template<typename T, bool pack_helper> + static inline void packUnpackDOFDataHelper(Array<T> & data, + CommunicationBuffer & buffer, + const Array<UInt> & dofs); + + template<typename T> + static inline void packDOFDataHelper(const Array<T> & data_to_pack, + CommunicationBuffer & buffer, + const Array<UInt> & dofs) { + packUnpackDOFDataHelper<T, true>(const_cast<Array<T> &>(data_to_pack), + buffer, + dofs); + } + + template<typename T> + static inline void unpackDOFDataHelper(Array<T> & data_to_unpack, + CommunicationBuffer & buffer, + const Array<UInt> & dofs) { + packUnpackDOFDataHelper<T, false>(data_to_unpack, + buffer, + dofs); + } + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "data_accessor_inline_impl.cc" // /// standard output stream operator // inline std::ostream & operator <<(std::ostream & stream, const DataAccessor & _this) // { // _this.printself(stream); // return stream; // } __END_AKANTU__ #endif /* __AKANTU_DATA_ACCESSOR_HH__ */ diff --git a/src/synchronizer/data_accessor_inline_impl.cc b/src/synchronizer/data_accessor_inline_impl.cc index dc8c0b6dc..8bba84c11 100644 --- a/src/synchronizer/data_accessor_inline_impl.cc +++ b/src/synchronizer/data_accessor_inline_impl.cc @@ -1,107 +1,125 @@ /** * @file data_accessor_inline_impl.cc * * @author David Simon Kammer <david.kammer@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 18 2013 * @date last modification: Thu Jun 05 2014 * * @brief Implementation of the inline functions of the DataAccessor 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/>. * */ /* -------------------------------------------------------------------------- */ template<typename T, bool pack_helper> inline void DataAccessor::packUnpackNodalDataHelper(Array<T> & data, CommunicationBuffer & buffer, const Array<Element> & elements, const Mesh & mesh) { UInt nb_component = data.getNbComponent(); UInt nb_nodes_per_element = 0; ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt * conn = NULL; Array<Element>::const_iterator<Element> it = elements.begin(); Array<Element>::const_iterator<Element> end = elements.end(); for (; it != end; ++it) { const 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; conn = mesh.getConnectivity(el.type, el.ghost_type).storage(); nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type); } UInt el_offset = el.element * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt offset_conn = conn[el_offset + n]; Vector<T> data_vect(data.storage() + offset_conn * nb_component, nb_component); if(pack_helper) buffer << data_vect; else buffer >> data_vect; } } } /* -------------------------------------------------------------------------- */ template<typename T, bool pack_helper> inline void DataAccessor::packUnpackElementalDataHelper(ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & element, bool per_quadrature_point_data, const FEEngine & fem) { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt nb_quad_per_elem = 0; UInt nb_component = 0; Array<T> * vect = NULL; Array<Element>::const_iterator<Element> it = element.begin(); Array<Element>::const_iterator<Element> end = element.end(); for (; it != end; ++it) { const 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; vect = &data_to_pack(el.type, el.ghost_type); if(per_quadrature_point_data) nb_quad_per_elem = fem.getNbQuadraturePoints(el.type, el.ghost_type); else nb_quad_per_elem = 1; nb_component = vect->getNbComponent(); } Vector<T> data(vect->storage() + el.element * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem); if(pack_helper) buffer << data; else buffer >> data; } } + +/* -------------------------------------------------------------------------- */ +template<typename T, bool pack_helper> +inline void DataAccessor::packUnpackDOFDataHelper(Array<T> & data, + CommunicationBuffer & buffer, + const Array<UInt> & dofs) { + Array<UInt>::const_scalar_iterator it_dof = dofs.begin(); + Array<UInt>::const_scalar_iterator end_dof = dofs.end(); + T * data_ptr = data.storage(); + + for (; it_dof != end_dof; ++it_dof) { + if(pack_helper) + buffer << data_ptr[*it_dof]; + else + buffer >> data_ptr[*it_dof]; + } +} + diff --git a/src/synchronizer/distributed_synchronizer.cc b/src/synchronizer/distributed_synchronizer.cc index c497e7069..d698c9fea 100644 --- a/src/synchronizer/distributed_synchronizer.cc +++ b/src/synchronizer/distributed_synchronizer.cc @@ -1,1652 +1,1651 @@ /** * @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), - static_communicator(&StaticCommunicator::getStaticCommunicator()), 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)) <= 0 && std::abs(barycenter(i)) <= tolerance)) continue; + (std::abs(barycenter_loc(i)) <= tolerance && std::abs(barycenter(i)) <= tolerance)) continue; AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: " << element << "(barycenter[" << i << "] = " << barycenter_loc(i) << " and buffer[" << i << "] = " << barycenter(i) << ") [" << std::abs((barycenter(i) - barycenter_loc(i))/barycenter_loc(i)) << "] - tag: " << tag); } } #endif data_accessor.unpackElementData(buffer, recv_element[proc], tag); buffer.resize(0); AKANTU_DEBUG_ASSERT(buffer.getLeftToUnpack() == 0, "all data have not been unpacked: " << buffer.getLeftToUnpack() << " bytes left"); static_communicator->freeCommunicationRequest(req); } else { req_not_finished_tmp->push_back(req); } } std::vector<CommunicationRequest *> * swap = req_not_finished_tmp; req_not_finished_tmp = recv_requests_tmp; recv_requests_tmp = swap; req_not_finished_tmp->clear(); } AKANTU_DEBUG_INFO("Waiting that every send requests are received"); static_communicator->waitAll(communication.send_requests); for (std::vector<CommunicationRequest *>::iterator req_it = communication.send_requests.begin(); req_it != communication.send_requests.end() ; ++req_it) { CommunicationRequest & req = *(*req_it); if(static_communicator->testRequest(&req)) { UInt proc = req.getDestination(); CommunicationBuffer & buffer = communication.send_buffer[proc]; buffer.resize(0); static_communicator->freeCommunicationRequest(&req); } } communication.send_requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); communications[tag].resize(nb_proc); for (UInt p = 0; p < nb_proc; ++p) { UInt ssend = 0; UInt sreceive = 0; if(p != rank) { if(send_element[p].getSize() != 0) { #ifndef AKANTU_NDEBUG ssend += send_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real); #endif ssend += data_accessor.getNbDataForElements(send_element[p], tag); AKANTU_DEBUG_INFO("I have " << ssend << "(" << ssend / 1024. << "kB - "<< send_element[p].getSize() <<" element(s)) data to send to " << p << " for tag " << tag); } if(recv_element[p].getSize() != 0) { #ifndef AKANTU_NDEBUG sreceive += recv_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real); #endif sreceive += data_accessor.getNbDataForElements(recv_element[p], tag); AKANTU_DEBUG_INFO("I have " << sreceive << "(" << sreceive / 1024. << "kB - "<< recv_element[p].getSize() <<" element(s)) data to receive for tag " << tag); } } communications[tag].size_to_send [p] = ssend; communications[tag].size_to_receive[p] = sreceive; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); Int prank = StaticCommunicator::getStaticCommunicator().whoAmI(); Int psize = StaticCommunicator::getStaticCommunicator().getNbProc(); stream << "[" << prank << "/" << psize << "]" << space << "DistributedSynchronizer [" << std::endl; for (UInt p = 0; p < nb_proc; ++p) { if (p == UInt(prank)) continue; stream << "[" << prank << "/" << psize << "]" << space << " + Communication to proc " << p << " [" << std::endl; if(AKANTU_DEBUG_TEST(dblDump)) { stream << "[" << prank << "/" << psize << "]" << space << " - Element to send to proc " << p << " [" << std::endl; Array<Element>::iterator<Element> it_el = send_element[p].begin(); Array<Element>::iterator<Element> end_el = send_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " - Element to recv from proc " << p << " [" << std::endl; it_el = recv_element[p].begin(); end_el = recv_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; } std::map< SynchronizationTag, Communication>::const_iterator it = communications.begin(); std::map< SynchronizationTag, Communication>::const_iterator end = communications.end(); for (; it != end; ++it) { const SynchronizationTag & tag = it->first; const Communication & communication = it->second; UInt ssend = communication.size_to_send[p]; UInt sreceive = communication.size_to_receive[p]; stream << "[" << prank << "/" << psize << "]" << space << " - Tag " << tag << " -> " << ssend << "byte(s) -- <- " << sreceive << "byte(s)" << std::endl; } } } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::onElementsRemoved(const Array<Element> & element_to_remove, const ElementTypeMapArray<UInt> & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt psize = comm.getNbProc(); UInt prank = comm.whoAmI(); std::vector<CommunicationRequest *> isend_requests; Array<UInt> * list_of_el = new Array<UInt>[nb_proc]; // Handling ghost elements for (UInt p = 0; p < psize; ++p) { if (p == prank) continue; Array<Element> & recv = recv_element[p]; if(recv.getSize() == 0) continue; Array<Element>::iterator<Element> recv_begin = recv.begin(); Array<Element>::iterator<Element> recv_end = recv.end(); Array<Element>::const_iterator<Element> er_it = element_to_remove.begin(); Array<Element>::const_iterator<Element> er_end = element_to_remove.end(); Array<UInt> & list = list_of_el[p]; for (UInt i = 0; recv_begin != recv_end; ++i, ++recv_begin) { const Element & el = *recv_begin; Array<Element>::const_iterator<Element> pos = std::find(er_it, er_end, el); if(pos == er_end) { list.push_back(i); } } if(list.getSize() == recv.getSize()) list.push_back(UInt(0)); else list.push_back(UInt(-1)); AKANTU_DEBUG_INFO("Sending a message of size " << list.getSize() << " to proc " << p << " TAG(" << Tag::genTag(prank, 0, 0) << ")"); isend_requests.push_back(comm.asyncSend(list.storage(), list.getSize(), p, Tag::genTag(prank, 0, 0))); list.erase(list.getSize() - 1); if(list.getSize() == recv.getSize()) continue; Array<Element> new_recv; for (UInt nr = 0; nr < list.getSize(); ++nr) { Element & el = recv(list(nr)); el.element = new_numbering(el.type, el.ghost_type)(el.element); new_recv.push_back(el); } AKANTU_DEBUG_INFO("I had " << recv.getSize() << " elements to recv from proc " << p << " and " << list.getSize() << " elements to keep. I have " << new_recv.getSize() << " elements left."); recv.copy(new_recv); } for (UInt p = 0; p < psize; ++p) { if (p == prank) continue; Array<Element> & send = send_element[p]; if(send.getSize() == 0) continue; CommunicationStatus status; AKANTU_DEBUG_INFO("Getting number of elements of proc " << p << " not needed anymore TAG("<< Tag::genTag(p, 0, 0) <<")"); comm.probe<UInt>(p, Tag::genTag(p, 0, 0), status); Array<UInt> list(status.getSize()); AKANTU_DEBUG_INFO("Receiving list of elements (" << status.getSize() - 1 << " elements) no longer needed by proc " << p << " TAG("<< Tag::genTag(p, 0, 0) <<")"); comm.receive(list.storage(), list.getSize(), p, Tag::genTag(p, 0, 0)); if(list.getSize() == 1 && list(0) == 0) continue; list.erase(list.getSize() - 1); Array<Element> new_send; for (UInt ns = 0; ns < list.getSize(); ++ns) { new_send.push_back(send(list(ns))); } AKANTU_DEBUG_INFO("I had " << send.getSize() << " elements to send to proc " << p << " and " << list.getSize() << " elements to keep. I have " << new_send.getSize() << " elements left."); send.copy(new_send); } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); delete [] list_of_el; AKANTU_DEBUG_OUT(); } // void DistributedSynchronizer::checkCommunicationScheme() { // for (UInt p = 0; p < psize; ++p) { // if (p == prank) continue; // for(UInt e(0), e < recv_element.getSize()) // } // } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::buildPrankToElement() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); mesh.initElementTypeMapArray(prank_to_element, 1, spatial_dimension, false, _ek_not_defined, true); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, _not_ghost, _ek_not_defined); /// assign prank to all not ghost elements for (; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); Array<UInt> & prank_to_el = prank_to_element(*it); for (UInt el = 0; el < nb_element; ++el) { prank_to_el(el) = rank; } } /// assign prank to all ghost elements for (UInt p = 0; p < nb_proc; ++p) { UInt nb_ghost_element = recv_element[p].getSize(); for (UInt el = 0; el < nb_ghost_element; ++el) { UInt element = recv_element[p](el).element; ElementType type = recv_element[p](el).type; GhostType ghost_type = recv_element[p](el).ghost_type; Array<UInt> & prank_to_el = prank_to_element(type, ghost_type); prank_to_el(element) = p; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::filterElementsByKind(DistributedSynchronizer * new_synchronizer, ElementKind kind) { AKANTU_DEBUG_IN(); Array<Element> * newsy_send_element = new_synchronizer->send_element; Array<Element> * newsy_recv_element = new_synchronizer->recv_element; Array<Element> * new_send_element = new Array<Element>[nb_proc]; Array<Element> * new_recv_element = new Array<Element>[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { /// send element copying part new_send_element[p].resize(0); for (UInt el = 0; el < send_element[p].getSize(); ++el) { Element & element = send_element[p](el); if (element.kind == kind) newsy_send_element[p].push_back(element); else new_send_element[p].push_back(element); } /// recv element copying part new_recv_element[p].resize(0); for (UInt el = 0; el < recv_element[p].getSize(); ++el) { Element & element = recv_element[p](el); if (element.kind == kind) newsy_recv_element[p].push_back(element); else new_recv_element[p].push_back(element); } } /// deleting and reassigning old pointers delete [] send_element; delete [] recv_element; send_element = new_send_element; recv_element = new_recv_element; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::reset() { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { send_element[p].resize(0); recv_element[p].resize(0); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeTagsSend(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_local_element, UInt nb_ghost_element) { AKANTU_DEBUG_IN(); static UInt count = 0; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); if(nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } UInt mesh_data_sizes_buffer_length; MeshData & mesh_data = mesh.getMeshData(); /// tag info std::vector<std::string> tag_names; mesh.getMeshData().getTagNames(tag_names, type); // Make sure the tags are sorted (or at least not in random order), // because they come from a map !! std::sort(tag_names.begin(), tag_names.end()); // Sending information about the tags in mesh_data: name, data type and // number of components of the underlying array associated to the current type DynamicCommunicationBuffer mesh_data_sizes_buffer; std::vector<std::string>::const_iterator names_it = tag_names.begin(); std::vector<std::string>::const_iterator names_end = tag_names.end(); for(;names_it != names_end; ++names_it) { mesh_data_sizes_buffer << *names_it; mesh_data_sizes_buffer << mesh_data.getTypeCode(*names_it); mesh_data_sizes_buffer << mesh_data.getNbComponent(*names_it, type); } mesh_data_sizes_buffer_length = mesh_data_sizes_buffer.getSize(); AKANTU_DEBUG_INFO("Broadcasting the size of the information about the mesh data tags: (" << mesh_data_sizes_buffer_length << ")." ); comm.broadcast(&mesh_data_sizes_buffer_length, 1, root); AKANTU_DEBUG_INFO("Broadcasting the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage()); if(mesh_data_sizes_buffer_length !=0) comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer.getSize(), root); if(mesh_data_sizes_buffer_length !=0) { //Sending the actual data to each processor DynamicCommunicationBuffer buffers[nb_proc]; std::vector<std::string>::const_iterator names_it = tag_names.begin(); std::vector<std::string>::const_iterator names_end = tag_names.end(); // Loop over each tag for the current type for(;names_it != names_end; ++names_it) { // Type code of the current tag (i.e. the tag named *names_it) communicator.fillTagBuffer(mesh_data, buffers, *names_it, type, partition_num, ghost_partition); } std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Sending " << buffers[p].getSize() << " bytes of mesh data to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_MESH_DATA) <<")"); requests.push_back(comm.asyncSend(buffers[p].storage(), buffers[p].getSize(), p, Tag::genTag(my_rank, count, TAG_MESH_DATA))); } } names_it = tag_names.begin(); // Loop over each tag for the current type for(;names_it != names_end; ++names_it) { // Reinitializing the mesh data on the master communicator.populateMeshData(mesh_data, buffers[root], *names_it, type, mesh_data.getTypeCode(*names_it), mesh_data.getNbComponent(*names_it, type), nb_local_element, nb_ghost_element); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); } ++count; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeTagsRecv(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, UInt nb_local_element, UInt nb_ghost_element) { AKANTU_DEBUG_IN(); static UInt count = 0; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); if(nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } /* --------<<<<-TAGS------------------------------------------------- */ UInt mesh_data_sizes_buffer_length = 0; CommunicationBuffer mesh_data_sizes_buffer; MeshData & mesh_data = mesh.getMeshData(); AKANTU_DEBUG_INFO("Receiving the size of the information about the mesh data tags."); comm.broadcast(&mesh_data_sizes_buffer_length, 1, root); if(mesh_data_sizes_buffer_length != 0) { mesh_data_sizes_buffer.resize(mesh_data_sizes_buffer_length); AKANTU_DEBUG_INFO("Receiving the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage()); comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer_length, root); AKANTU_DEBUG_INFO("Size of the information about the mesh data: " << mesh_data_sizes_buffer_length); std::vector<std::string> tag_names; std::vector<MeshDataTypeCode> tag_type_codes; std::vector<UInt> tag_nb_component; tag_names.resize(nb_tags); tag_type_codes.resize(nb_tags); tag_nb_component.resize(nb_tags); CommunicationBuffer mesh_data_buffer; UInt type_code_int; for(UInt i(0); i < nb_tags; ++i) { mesh_data_sizes_buffer >> tag_names[i]; mesh_data_sizes_buffer >> type_code_int; tag_type_codes[i] = static_cast<MeshDataTypeCode>(type_code_int); mesh_data_sizes_buffer >> tag_nb_component[i]; } std::vector<std::string>::const_iterator names_it = tag_names.begin(); std::vector<std::string>::const_iterator names_end = tag_names.end(); CommunicationStatus mesh_data_comm_status; AKANTU_DEBUG_INFO("Checking size of data to receive for mesh data TAG(" << Tag::genTag(root, count, TAG_MESH_DATA) << ")"); comm.probe<char>(root, Tag::genTag(root, count, TAG_MESH_DATA), mesh_data_comm_status); UInt mesh_data_buffer_size(mesh_data_comm_status.getSize()); AKANTU_DEBUG_INFO("Receiving " << mesh_data_buffer_size << " bytes of mesh data TAG(" << Tag::genTag(root, count, TAG_MESH_DATA) << ")"); mesh_data_buffer.resize(mesh_data_buffer_size); comm.receive(mesh_data_buffer.storage(), mesh_data_buffer_size, root, Tag::genTag(root, count, TAG_MESH_DATA)); // Loop over each tag for the current type UInt k(0); for(; names_it != names_end; ++names_it, ++k) { communicator.populateMeshData(mesh_data, mesh_data_buffer, *names_it, type, tag_type_codes[k], tag_nb_component[k], nb_local_element, nb_ghost_element); } } ++count; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<class CommunicationBuffer> void DistributedSynchronizer::fillElementGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, const ElementType & type, CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); Element el; el.type = type; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { UInt nb_element = mesh.getNbElement(type, *gt); el.ghost_type = *gt; for (UInt e = 0; e < nb_element; ++e) { el.element = e; std::vector<std::string> element_to_group; buffer >> element_to_group; AKANTU_DEBUG_ASSERT(e < mesh.getNbElement(type, *gt), "The mesh does not have the element " << e); std::vector<std::string>::iterator it = element_to_group.begin(); std::vector<std::string>::iterator end = element_to_group.end(); for (; it != end; ++it) { mesh.getElementGroup(*it).add(el, false, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeElementGroups(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_element) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); DynamicCommunicationBuffer buffers[nb_proc]; typedef std::vector< std::vector<std::string> > ElementToGroup; ElementToGroup element_to_group; element_to_group.resize(nb_element); GroupManager::const_element_group_iterator egi = mesh.element_group_begin(); GroupManager::const_element_group_iterator ege = mesh.element_group_end(); for (; egi != ege; ++egi) { ElementGroup & eg = *(egi->second); std::string name = egi->first; ElementGroup::const_element_iterator eit = eg.element_begin(type, _not_ghost); ElementGroup::const_element_iterator eend = eg.element_end(type, _not_ghost); for (; eit != eend; ++eit) { element_to_group[*eit].push_back(name); } eit = eg.element_begin(type, _not_ghost); if(eit != eend) const_cast<Array<UInt> &>(eg.getElements(type)).empty(); } /// preparing the buffers const UInt * part = partition_num.storage(); /// copying the data, element by element ElementToGroup::const_iterator data_it = element_to_group.begin(); ElementToGroup::const_iterator data_end = element_to_group.end(); for (; data_it != data_end; ++part, ++data_it) { buffers[*part] << *data_it; } data_it = element_to_group.begin(); /// copying the data for the ghost element for (UInt el(0); data_it != data_end; ++data_it, ++el) { CSR<UInt>::const_iterator it = ghost_partition.begin(el); CSR<UInt>::const_iterator end = ghost_partition.end(el); for (;it != end; ++it) { UInt proc = *it; buffers[proc] << *data_it; } } std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; AKANTU_DEBUG_INFO("Sending element groups to proc " << p << " TAG("<< Tag::genTag(my_rank, p, TAG_ELEMENT_GROUP) <<")"); requests.push_back(comm.asyncSend(buffers[p].storage(), buffers[p].getSize(), p, Tag::genTag(my_rank, p, TAG_ELEMENT_GROUP))); } fillElementGroupsFromBuffer(communicator, mesh, type, buffers[my_rank]); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeElementGroups(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt my_rank = comm.whoAmI(); AKANTU_DEBUG_INFO("Receiving element groups from proc " << root << " TAG("<< Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP) <<")"); CommunicationStatus status; comm.probe<char>(root, Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP), status); CommunicationBuffer buffer(status.getSize()); comm.receive(buffer.storage(), buffer.getSize(), root, Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP)); fillElementGroupsFromBuffer(communicator, mesh, type, buffer); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<class CommunicationBuffer> void DistributedSynchronizer::fillNodeGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); std::vector< std::vector<std::string> > node_to_group; buffer >> node_to_group; AKANTU_DEBUG_ASSERT(node_to_group.size() == mesh.getNbGlobalNodes(), "Not the good amount of nodes where transmitted"); const Array<UInt> & global_nodes = mesh.getGlobalNodesIds(); Array<UInt>::const_scalar_iterator nbegin = global_nodes.begin(); Array<UInt>::const_scalar_iterator nit = global_nodes.begin(); Array<UInt>::const_scalar_iterator nend = global_nodes.end(); for (; nit != nend; ++nit) { std::vector<std::string>::iterator it = node_to_group[*nit].begin(); std::vector<std::string>::iterator end = node_to_group[*nit].end(); for (; it != end; ++it) { mesh.getNodeGroup(*it).add(nit - nbegin, false); } } GroupManager::const_node_group_iterator ngi = mesh.node_group_begin(); GroupManager::const_node_group_iterator nge = mesh.node_group_end(); for (; ngi != nge; ++ngi) { NodeGroup & ng = *(ngi->second); ng.optimize(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeNodeGroupsMaster(DistributedSynchronizer & communicator, UInt root, Mesh & mesh) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); UInt nb_total_nodes = mesh.getNbGlobalNodes(); DynamicCommunicationBuffer buffer; typedef std::vector< std::vector<std::string> > NodeToGroup; NodeToGroup node_to_group; node_to_group.resize(nb_total_nodes); GroupManager::const_node_group_iterator ngi = mesh.node_group_begin(); GroupManager::const_node_group_iterator nge = mesh.node_group_end(); for (; ngi != nge; ++ngi) { NodeGroup & ng = *(ngi->second); std::string name = ngi->first; NodeGroup::const_node_iterator nit = ng.begin(); NodeGroup::const_node_iterator nend = ng.end(); for (; nit != nend; ++nit) { node_to_group[*nit].push_back(name); } nit = ng.begin(); if(nit != nend) ng.empty(); } buffer << node_to_group; std::vector<CommunicationRequest *> requests; for (UInt p = 0; p < nb_proc; ++p) { if(p == my_rank) continue; AKANTU_DEBUG_INFO("Sending node groups to proc " << p << " TAG("<< Tag::genTag(my_rank, p, TAG_NODE_GROUP) <<")"); requests.push_back(comm.asyncSend(buffer.storage(), buffer.getSize(), p, Tag::genTag(my_rank, p, TAG_NODE_GROUP))); } fillNodeGroupsFromBuffer(communicator, mesh, buffer); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::synchronizeNodeGroupsSlaves(DistributedSynchronizer & communicator, UInt root, Mesh & mesh) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt my_rank = comm.whoAmI(); AKANTU_DEBUG_INFO("Receiving node groups from proc " << root << " TAG("<< Tag::genTag(root, my_rank, TAG_NODE_GROUP) <<")"); CommunicationStatus status; comm.probe<char>(root, Tag::genTag(root, my_rank, TAG_NODE_GROUP), status); CommunicationBuffer buffer(status.getSize()); comm.receive(buffer.storage(), buffer.getSize(), root, Tag::genTag(root, my_rank, TAG_NODE_GROUP)); fillNodeGroupsFromBuffer(communicator, mesh, buffer); AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/synchronizer/distributed_synchronizer.hh b/src/synchronizer/distributed_synchronizer.hh index 64976adad..2edd12ab1 100644 --- a/src/synchronizer/distributed_synchronizer.hh +++ b/src/synchronizer/distributed_synchronizer.hh @@ -1,293 +1,268 @@ /** * @file distributed_synchronizer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Dana Christen <dana.christen@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Thu Jun 16 2011 * @date last modification: Fri Sep 05 2014 * * @brief wrapper to the static communicator * * @section LICENSE * * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ #define __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_array.hh" -#include "static_communicator.hh" #include "synchronizer.hh" #include "mesh.hh" #include "mesh_partition.hh" #include "communication_buffer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class DistributedSynchronizer : public Synchronizer, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DistributedSynchronizer(Mesh & mesh, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); public: virtual ~DistributedSynchronizer(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get a mesh and a partition and create the local mesh and the associated /// DistributedSynchronizer static DistributedSynchronizer * createDistributedSynchronizerMesh(Mesh & mesh, const MeshPartition * partition, UInt root = 0, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); /* ------------------------------------------------------------------------ */ /* Inherited from Synchronizer */ /* ------------------------------------------------------------------------ */ /// asynchronous synchronization of ghosts void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// wait end of asynchronous synchronization of ghosts void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// build processor to element corrispondance void buildPrankToElement(); virtual void printself(std::ostream & stream, int indent = 0) const; /// mesh event handler onRemovedElement virtual void onElementsRemoved(const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event); /// filter elements of a certain kind and copy them into a new synchronizer void filterElementsByKind(DistributedSynchronizer * new_synchronizer, ElementKind kind); /// reset send and recv element lists void reset(); /// compute buffer size for a given tag and data accessor void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag); protected: /// fill the nodes type vector void fillNodesType(Mesh & mesh); void fillNodesType(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num); template<typename T> void fillTagBufferTemplated(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition); void fillTagBuffer(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition); template<typename T, typename BufferType> void populateMeshDataTemplated(MeshData & mesh_data, BufferType & buffer, const std::string & tag_name, const ElementType & el_type, UInt nb_component, UInt nb_local_element, UInt nb_ghost_element); template <typename BufferType> void populateMeshData(MeshData & mesh_data, BufferType & buffer, const std::string & tag_name, const ElementType & el_type, const MeshDataTypeCode & type_code, UInt nb_component, UInt nb_local_element, UInt nb_ghost_element); /// fill the communications array of a distributedSynchronizer based on a partition array void fillCommunicationScheme(const UInt * partition, UInt nb_local_element, UInt nb_ghost_element, ElementType type); /// function that handels the MeshData to be split (root side) static void synchronizeTagsSend(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_local_element, UInt nb_ghost_element); /// function that handles the MeshData to be split (other nodes) static void synchronizeTagsRecv(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, UInt nb_tags, const ElementType & type, UInt nb_local_element, UInt nb_ghost_element); /// function that handles the preexisting groups in the mesh static void synchronizeElementGroups(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type, const Array<UInt> & partition_num, const CSR<UInt> & ghost_partition, UInt nb_element); /// function that handles the preexisting groups in the mesh static void synchronizeElementGroups(DistributedSynchronizer & communicator, UInt root, Mesh & mesh, const ElementType & type); template<class CommunicationBuffer> static void fillElementGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, const ElementType & type, CommunicationBuffer & buffer); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsMaster(DistributedSynchronizer & communicator, UInt root, Mesh & mesh); /// function that handles the preexisting groups in the mesh static void synchronizeNodeGroupsSlaves(DistributedSynchronizer & communicator, UInt root, Mesh & mesh); template<class CommunicationBuffer> static void fillNodeGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, CommunicationBuffer & buffer); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(PrankToElement, prank_to_element, const ElementTypeMapArray<UInt> &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: enum CommTags { TAG_SIZES = 0, TAG_CONNECTIVITY = 1, TAG_DATA = 2, TAG_PARTITIONS = 3, TAG_NB_NODES = 4, TAG_NODES = 5, TAG_COORDINATES = 6, TAG_NODES_TYPE = 7, TAG_MESH_DATA = 8, TAG_ELEMENT_GROUP = 9, TAG_NODE_GROUP = 10, }; protected: /// reference to the underlying mesh Mesh & mesh; - /// the static memory instance - StaticCommunicator * static_communicator; - - class Communication { - public: - void resize(UInt size) { - send_buffer.resize(size); - recv_buffer.resize(size); - size_to_send .resize(size); - size_to_receive.resize(size); - } - - public: - /// size of data to send to each processor - std::vector<UInt> size_to_send; - /// size of data to recv to each processor - std::vector<UInt> size_to_receive; - std::vector< CommunicationBuffer > send_buffer; - std::vector< CommunicationBuffer > recv_buffer; - - std::vector<CommunicationRequest *> send_requests; - std::vector<CommunicationRequest *> recv_requests; - }; - std::map<SynchronizationTag, Communication> communications; /// list of element to send to proc p Array<Element> * send_element; /// list of element to receive from proc p Array<Element> * recv_element; UInt nb_proc; UInt rank; friend class FilteredSynchronizer; friend class FacetSynchronizer; ElementTypeMapArray<UInt> prank_to_element; }; __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "distributed_synchronizer_tmpl.hh" #endif /* __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/dof_synchronizer.cc b/src/synchronizer/dof_synchronizer.cc index d15d02d0a..4b986fe97 100644 --- a/src/synchronizer/dof_synchronizer.cc +++ b/src/synchronizer/dof_synchronizer.cc @@ -1,258 +1,501 @@ /** * @file dof_synchronizer.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> + * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Fri Jun 17 2011 * @date last modification: Thu Mar 27 2014 * * @brief DOF synchronizing object implementation * * @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 "dof_synchronizer.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ +/** + * A DOFSynchronizer needs a mesh and the number of degrees of freedom + * per node to be created. In the constructor computes the local and global dof + * number for each dof. The member + * proc_informations (std vector) is resized with the number of mpi + * processes. Each entry in the vector is a PerProcInformations object + * that contains the interactions of the current mpi process (prank) with the + * mpi process corresponding to the position of that entry. Every + * ProcInformations object contains one array with the dofs that have + * to be sent to prank and a second one with dofs that willl be received form prank. + * This information is needed for the asychronous communications. The + * constructor sets up this information. + * @param mesh mesh discretizing the domain we want to analyze + * @param nb_degree_of_freedom number of degrees of freedom per node + */ DOFSynchronizer::DOFSynchronizer(const Mesh & mesh, UInt nb_degree_of_freedom) : global_dof_equation_numbers(0, 1, "global_equation_number"), local_dof_equation_numbers(0, 1, "local_equation_number"), dof_global_ids(0, 1, "global_ids"), dof_types(0, 1, "types") { - gather_scatter_scheme_initialized = false; - communicator = &StaticCommunicator::getStaticCommunicator(); + gather_scatter_scheme_initialized = false; - prank = communicator->whoAmI(); - psize = communicator->getNbProc(); + prank = static_communicator->whoAmI(); + psize = static_communicator->getNbProc(); proc_informations.resize(psize); UInt nb_nodes = mesh.getNbNodes(); nb_dofs = nb_nodes * nb_degree_of_freedom; dof_global_ids.resize(nb_dofs); dof_types.resize(nb_dofs); nb_global_dofs = mesh.getNbGlobalNodes() * nb_degree_of_freedom; + /// compute the global id for each dof and store the dof type (pure ghost, slave, master or local) UInt * dof_global_id = dof_global_ids.storage(); Int * dof_type = dof_types.storage(); for(UInt n = 0, ld = 0; n < nb_nodes; ++n) { UInt node_global_id = mesh.getNodeGlobalId(n); UInt node_type = mesh.getNodeType(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d, ++ld) { *dof_global_id = node_global_id * nb_degree_of_freedom + d; global_dof_to_local[*dof_global_id] = ld; *(dof_type++) = node_type; dof_global_id++; } } if(psize == 1) return; /// creating communication scheme dof_global_id = dof_global_ids.storage(); dof_type = dof_types.storage(); for (UInt n = 0; n < nb_dofs; ++n) { + /// check if dof is slave. In that case the value stored in + /// dof_type corresponds to the process that has the corresponding + /// master dof if(*dof_type >= 0) { + /// has to receive n from proc[*dof_type] proc_informations[*dof_type].master_dofs.push_back(n); } dof_type++; } + /// at this point the master nodes in PerProcInfo are known /// exchanging information for (UInt p = 1; p < psize; ++p) { UInt sendto = (psize + prank + p) % psize; UInt recvfrom = (psize + prank - p) % psize; + /// send the master nodes UInt nb_master_dofs = proc_informations[sendto].master_dofs.getSize(); UInt * master_dofs = proc_informations[sendto].master_dofs.storage(); UInt * send_buffer = new UInt[nb_master_dofs]; for (UInt d = 0; d < nb_master_dofs; ++d) { send_buffer[d] = dof_global_id[master_dofs[d]]; } UInt nb_slave_dofs = 0; UInt * recv_buffer; std::vector<CommunicationRequest *> requests; - requests.push_back(communicator->asyncSend(&nb_master_dofs, 1, sendto, 0)); + requests.push_back(static_communicator->asyncSend(&nb_master_dofs, 1, sendto, 0)); if(nb_master_dofs != 0) { - AKANTU_DEBUG(dblInfo, "Sending "<< nb_master_dofs << " nodes to " << sendto + 1); - requests.push_back(communicator->asyncSend(send_buffer, nb_master_dofs, sendto, 1)); + AKANTU_DEBUG(dblInfo, "Sending "<< nb_master_dofs << " dofs to " << sendto + 1); + requests.push_back(static_communicator->asyncSend(send_buffer, nb_master_dofs, sendto, 1)); } - communicator->receive(&nb_slave_dofs, 1, recvfrom, 0); + + /// Receive the info and store them as slave nodes + static_communicator->receive(&nb_slave_dofs, 1, recvfrom, 0); if(nb_slave_dofs != 0) { - AKANTU_DEBUG(dblInfo, "Receiving "<< nb_slave_dofs << " nodes from " << recvfrom + 1); + AKANTU_DEBUG(dblInfo, "Receiving "<< nb_slave_dofs << " dofs from " << recvfrom + 1); proc_informations[recvfrom].slave_dofs.resize(nb_slave_dofs); recv_buffer = proc_informations[recvfrom].slave_dofs.storage(); - communicator->receive(recv_buffer, nb_slave_dofs, recvfrom, 1); + static_communicator->receive(recv_buffer, nb_slave_dofs, recvfrom, 1); } for (UInt d = 0; d < nb_slave_dofs; ++d) { recv_buffer[d] = global_dof_to_local[recv_buffer[d]]; } - communicator->waitAll(requests); - communicator->freeCommunicationRequest(requests); + static_communicator->waitAll(requests); + static_communicator->freeCommunicationRequest(requests); requests.clear(); delete [] send_buffer; } } /* -------------------------------------------------------------------------- */ DOFSynchronizer::~DOFSynchronizer() { } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::initLocalDOFEquationNumbers() { AKANTU_DEBUG_IN(); local_dof_equation_numbers.resize(nb_dofs); Int * dof_equation_number = local_dof_equation_numbers.storage(); for (UInt d = 0; d < nb_dofs; ++d) { *(dof_equation_number++) = d; } //local_dof_equation_numbers.resize(nb_dofs); AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +void DOFSynchronizer::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 < psize; ++p) { + UInt ssize = communication.size_to_send[p]; + if(p == prank || ssize == 0) continue; + + CommunicationBuffer & buffer = communication.send_buffer[p]; + buffer.resize(ssize); +#ifndef AKANTU_NDEBUG + UInt nb_dofs = proc_informations[p].slave_dofs.getSize(); + AKANTU_DEBUG_INFO("Packing data for proc " << p + << " (" << ssize << "/" << nb_dofs + <<" data to send/dofs)"); + + /// pack global equation numbers in debug mode + Array<UInt>::const_iterator<UInt> bit = proc_informations[p].slave_dofs.begin(); + Array<UInt>::const_iterator<UInt> bend = proc_informations[p].slave_dofs.end(); + for (; bit != bend; ++bit) { + buffer << global_dof_equation_numbers[*bit]; + } +#endif + + + /// dof synchronizer needs to send the data corresponding to the + data_accessor.packDOFData(buffer, proc_informations[p].slave_dofs, tag); + + AKANTU_DEBUG_ASSERT(buffer.getPackedSize() == ssize, + "a problem has 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(prank, counter, tag) << "]"); + communication.send_requests.push_back(static_communicator->asyncSend(buffer.storage(), + ssize, + p, + Tag::genTag(prank, counter, tag))); + } + + AKANTU_DEBUG_ASSERT(communication.recv_requests.size() == 0, + "There must be some pending receive communications"); + + for (UInt p = 0; p < psize; ++p) { + UInt rsize = communication.size_to_receive[p]; + if(p == prank || 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))); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void DOFSynchronizer::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<UInt>::const_iterator<UInt> bit = proc_informations[proc].master_dofs.begin(); + Array<UInt>::const_iterator<UInt> bend = proc_informations[proc].master_dofs.end(); + + for (; bit != bend; ++bit) { + Int global_dof_eq_nb_loc = global_dof_equation_numbers[*bit]; + Int global_dof_eq_nb = 0; + buffer >> global_dof_eq_nb; + Real tolerance = Math::getTolerance(); + if(std::abs(global_dof_eq_nb - global_dof_eq_nb_loc) <= tolerance) continue; + AKANTU_DEBUG_ERROR("Unpacking an unknown global dof equation number for dof: " + << *bit + << "(global dof equation number = " << global_dof_eq_nb + << " and buffer = " << global_dof_eq_nb << ") [" + << std::abs(global_dof_eq_nb - global_dof_eq_nb_loc) + << "] - tag: " << tag); + } + +#endif + + data_accessor.unpackDOFData(buffer, proc_informations[proc].master_dofs, 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(); + + +} + +/* -------------------------------------------------------------------------- */ +/** + * This function computes the buffer size needed for in order to send data or receive data. + * @param data_accessor object of a class that needs to use the DOFSynchronizer. This class has to inherit from the * DataAccessor interface. + * @param tag synchronization tag: indicates what variable should be sychronized, e.g. mass, nodal residual, etc. + * for the SolidMechanicsModel + */ +void DOFSynchronizer::computeBufferSize(DataAccessor & data_accessor, + SynchronizationTag tag) { + AKANTU_DEBUG_IN(); + + communications[tag].resize(psize); + + for (UInt p = 0; p < psize; ++p) { + /// initialize the size of data that we be sent and received + UInt ssend = 0; + UInt sreceive = 0; + if(p != prank) { + /// check if processor prank has to send dof information to p + if(proc_informations[p].slave_dofs.getSize() != 0) { + + +#ifndef AKANTU_NDEBUG + /// in debug mode increase buffer size to send the positions + /// of nodes in the direction that correspond to the dofs + ssend += proc_informations[p].slave_dofs.getSize() * sizeof(Int); +#endif + ssend += data_accessor.getNbDataForDOFs(proc_informations[p].slave_dofs, tag); + AKANTU_DEBUG_INFO("I have " << ssend << "(" << ssend / 1024. + << "kB - "<< proc_informations[p].slave_dofs.getSize() <<" dof(s)) data to send to " << p << " for tag " + << tag); + } + + /// check if processor prank has to receive dof information from p + if(proc_informations[p].master_dofs.getSize() != 0) { +#ifndef AKANTU_NDEBUG + /// in debug mode increase buffer size to receive the + /// positions of nodes in the direction that correspond to the + /// dofs + sreceive += proc_informations[p].master_dofs.getSize() * sizeof(Int); +#endif + sreceive += data_accessor.getNbDataForDOFs(proc_informations[p].master_dofs, tag); + AKANTU_DEBUG_INFO("I have " << sreceive << "(" << sreceive / 1024. + << "kB - "<< proc_informations[p].master_dofs.getSize() <<" dof(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 DOFSynchronizer::initGlobalDOFEquationNumbers() { AKANTU_DEBUG_IN(); global_dof_equation_numbers.resize(nb_dofs); Int * dof_type = dof_types.storage(); UInt * dof_global_id = dof_global_ids.storage(); Int * dof_equation_number = global_dof_equation_numbers.storage(); for(UInt d = 0; d < nb_dofs; ++d) { /// if ghost dof the equation_number is greater than nb_global_dofs Int global_eq_num = *dof_global_id + (*dof_type > -3 ? 0 : nb_global_dofs); *(dof_equation_number) = global_eq_num; global_dof_equation_number_to_local[global_eq_num] = d; dof_equation_number++; dof_global_id++; dof_type++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::initScatterGatherCommunicationScheme() { AKANTU_DEBUG_IN(); if(psize == 1 || gather_scatter_scheme_initialized) { if(psize == 1) gather_scatter_scheme_initialized = true; AKANTU_DEBUG_OUT(); return; } /// creating communication scheme UInt * dof_global_id = dof_global_ids.storage(); Int * dof_type = dof_types.storage(); Array<UInt> * local_dofs = new Array<UInt>(0,2); UInt local_dof_val[2]; nb_needed_dofs = 0; nb_local_dofs = 0; for (UInt n = 0; n < nb_dofs; ++n) { if(*dof_type != -3) { local_dof_val[0] = *dof_global_id; if(*dof_type == -1 || *dof_type == -2) { local_dof_val[1] = 0; // master for this node, shared or not nb_local_dofs++; } else if (*dof_type >= 0) { nb_needed_dofs++; local_dof_val[1] = 1; // slave node } local_dofs->push_back(local_dof_val); } dof_type++; dof_global_id++; } Int * nb_dof_per_proc = new Int[psize]; nb_dof_per_proc[prank] = local_dofs->getSize(); - communicator->allGather(nb_dof_per_proc, 1); + static_communicator->allGather(nb_dof_per_proc, 1); AKANTU_DEBUG(dblDebug, "I have " << local_dofs->getSize() << " not ghost dofs (" << nb_local_dofs << " local and " << nb_needed_dofs << " slave)"); UInt pos = 0; for (UInt p = 0; p < prank; ++p) pos += nb_dof_per_proc[p]; UInt nb_total_dofs = pos; for (UInt p = prank; p < psize; ++p) nb_total_dofs += nb_dof_per_proc[p]; Int * nb_values = new Int[psize]; for (UInt p = 0; p < psize; ++p) nb_values[p] = nb_dof_per_proc[p] * 2; UInt * buffer = new UInt[2*nb_total_dofs]; memcpy(buffer + 2 * pos, local_dofs->storage(), local_dofs->getSize() * 2 * sizeof(UInt)); delete local_dofs; - communicator->allGatherV(buffer, nb_values); + static_communicator->allGatherV(buffer, nb_values); UInt * tmp_buffer = buffer; for (UInt p = 0; p < psize; ++p) { UInt proc_p_nb_dof = nb_dof_per_proc[p]; if (p != prank){ AKANTU_DEBUG(dblDebug, "I get " << proc_p_nb_dof << "(" << nb_values[p] << ") dofs from " << p + 1); proc_informations[p].dofs.resize(0); for (UInt dd = 0; dd < proc_p_nb_dof; ++dd) { UInt dof = tmp_buffer[2*dd]; if(tmp_buffer[2*dd + 1] == 0) proc_informations[p].dofs.push_back(dof); else proc_informations[p].needed_dofs.push_back(dof); } AKANTU_DEBUG(dblDebug, "Proc " << p + 1 << " sends me " << proc_informations[p].dofs.getSize() << " local dofs, and " << proc_informations[p].needed_dofs.getSize() << " slave dofs"); } tmp_buffer += 2*proc_p_nb_dof; } delete [] nb_dof_per_proc; delete [] buffer; delete [] nb_values; gather_scatter_scheme_initialized = true; AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/synchronizer/dof_synchronizer.hh b/src/synchronizer/dof_synchronizer.hh index 731820c60..16f2f9a77 100644 --- a/src/synchronizer/dof_synchronizer.hh +++ b/src/synchronizer/dof_synchronizer.hh @@ -1,224 +1,237 @@ /** * @file dof_synchronizer.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> + * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Fri Jun 17 2011 * @date last modification: Fri Mar 21 2014 * * @brief Synchronize Array of DOFs * * @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_array.hh" #include "static_communicator.hh" +#include "synchronizer.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DOF_SYNCHRONIZER_HH__ #define __AKANTU_DOF_SYNCHRONIZER_HH__ __BEGIN_AKANTU__ class Mesh; template<typename T> class AddOperation { public: inline T operator()(T & b, T & a) { return a + b; }; }; -class DOFSynchronizer { +class DOFSynchronizer : public Synchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DOFSynchronizer(const Mesh & mesh, UInt nb_degree_of_freedom); virtual ~DOFSynchronizer(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: + /// asynchronous synchronization of ghosts + virtual void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); + + /// wait end of asynchronous synchronization of ghosts + virtual void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); + + /// compute buffer size for a given tag and data accessor + virtual void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag); + /// init the scheme for scatter and gather operation, need extra memory void initScatterGatherCommunicationScheme(); /// initialize the equation number with local ids void initLocalDOFEquationNumbers(); /// initialize the equation number with local ids void initGlobalDOFEquationNumbers(); /** * Gather the DOF value on the root proccessor * * @param to_gather data to gather * @param root processor on which data are gathered * @param gathered Array containing the gathered data, only valid on root processor */ template<typename T> void gather(const Array<T> & to_gather, UInt root, Array<T> * gathered = NULL) const; /** * Scatter a DOF Array form root to all processors * * @param scattered data to scatter, only valid on root processor * @param root processor scattering data * @param to_scatter result of scattered data */ template<typename T> void scatter(Array<T> & scattered, UInt root, const Array<T> * to_scatter = NULL) const; template<typename T> void synchronize(Array<T> & vector) const ; template<template <class> class Op, typename T> void reduceSynchronize(Array<T> & vector) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the equation_number Array AKANTU_GET_MACRO(LocalDOFEquationNumbers, local_dof_equation_numbers, const Array<Int> &); AKANTU_GET_MACRO(GlobalDOFEquationNumbers, global_dof_equation_numbers, const Array<Int> &); Array<Int> * getLocalDOFEquationNumbersPointer(){return &local_dof_equation_numbers;}; Array<Int> * getGlobalDOFEquationNumbersPointer(){return &global_dof_equation_numbers;}; typedef unordered_map<Int, UInt>::type GlobalEquationNumberMap; AKANTU_GET_MACRO(GlobalEquationNumberToLocal, global_dof_equation_number_to_local, const GlobalEquationNumberMap &) /// get the Array of global ids of the dofs AKANTU_GET_MACRO(DOFGlobalIDs, dof_global_ids, const Array<UInt> &); /// get the global id of a dof inline UInt getDOFGlobalID(UInt local_id) const { return dof_global_ids(local_id); } /// get the local id of a global dof inline UInt getDOFLocalID(UInt global_id) const { return global_dof_to_local.find(global_id)->second; } /// get the DOF type Array AKANTU_GET_MACRO(DOFTypes, dof_types, const Array<Int> &); AKANTU_GET_MACRO(NbDOFs, nb_dofs, UInt); AKANTU_GET_MACRO(NbGlobalDOFs, nb_global_dofs, UInt); /// say if a node is a pure ghost node inline bool isPureGhostDOF(UInt n) const; /// say if a node is pure local or master node inline bool isLocalOrMasterDOF(UInt n) const; inline bool isLocalDOF(UInt n) const; inline bool isMasterDOF(UInt n) const; inline bool isSlaveDOF(UInt n) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// equation number position where a dof is synchronized in the matrix (by default = global id) Array<Int> global_dof_equation_numbers; Array<Int> local_dof_equation_numbers; GlobalEquationNumberMap global_dof_equation_number_to_local; /// DOF global id Array<UInt> dof_global_ids; /* * DOF type -3 pure ghost, -2 master for the dof, -1 normal dof, i in * [0-N] slave dof and master is proc i */ Array<Int> dof_types; /// number of dofs UInt nb_dofs; UInt nb_global_dofs; unordered_map<UInt, UInt>::type global_dof_to_local; UInt prank; UInt psize; - StaticCommunicator * communicator; struct PerProcInformations { /// dofs to send to the proc Array<UInt> slave_dofs; /// dofs to recvs from the proc Array<UInt> master_dofs; /* ---------------------------------------------------------------------- */ /* Data for gather/scatter */ /* ---------------------------------------------------------------------- */ /// the dof that the node handle Array<UInt> dofs; /// the dof that the proc need Array<UInt> needed_dofs; }; std::vector<PerProcInformations> proc_informations; /// nb dofs with type -1 or -2 UInt nb_local_dofs; /// nb dof with type >= 0 UInt nb_needed_dofs; bool gather_scatter_scheme_initialized; + + + std::map<SynchronizationTag, Communication> communications; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "dof_synchronizer_inline_impl.cc" #endif /// standard output stream operator // inline std::ostream & operator <<(std::ostream & stream, const DOFSynchronizer & _this) // { // _this.printself(stream); // return stream; // } __END_AKANTU__ #endif /* __AKANTU_DOF_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/dof_synchronizer_inline_impl.cc b/src/synchronizer/dof_synchronizer_inline_impl.cc index 399be4abe..ee040e3b4 100644 --- a/src/synchronizer/dof_synchronizer_inline_impl.cc +++ b/src/synchronizer/dof_synchronizer_inline_impl.cc @@ -1,315 +1,315 @@ /** * @file dof_synchronizer_inline_impl.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Fri Jun 17 2011 * @date last modification: Thu Jun 05 2014 * * @brief DOFSynchronizer inline implementation * * @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<typename T> void DOFSynchronizer::gather(const Array<T> & to_gather, UInt root, Array<T> * gathered) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(gather_scatter_scheme_initialized == true, "You should call initScatterGatherCommunicationScheme before trying to gather a Array !!"); if(psize == 1) { gathered->copy(to_gather, true); AKANTU_DEBUG_OUT(); return; } UInt * dof_global_id = dof_global_ids.storage(); Int * dof_type = dof_types.storage(); T * to_gather_val = to_gather.storage(); T * buffer; if(prank == root) { gathered->resize(nb_global_dofs / gathered->getNbComponent()); buffer = gathered->storage(); } else buffer = new T[nb_local_dofs]; UInt dof = 0; for (UInt d = 0; d < nb_dofs; ++d) { if(*dof_type != -3) { if(*dof_type == -1 || *dof_type == -2) { if (prank == root) dof = *dof_global_id; buffer[dof++] = *to_gather_val; } } dof_type++; dof_global_id++; to_gather_val++; } if (prank == root) { for (UInt p = 0; p < psize; ++p) { if(p == root) continue; UInt nb_dofs = proc_informations[p].dofs.getSize(); AKANTU_DEBUG_INFO("Gather - Receiving " << nb_dofs << " from " << p); if(nb_dofs) { buffer = new T[nb_dofs]; - communicator->receive(buffer, nb_dofs, p, 0); + static_communicator->receive(buffer, nb_dofs, p, 0); T * buffer_tmp = buffer; UInt * remote_dofs = proc_informations[p].dofs.storage(); for (UInt d = 0; d < nb_dofs; ++d) { gathered->storage()[*remote_dofs++] = *(buffer_tmp++); } delete [] buffer; } } } else { AKANTU_DEBUG_INFO("Gather - Sending " << nb_local_dofs << " to " << root); if(nb_local_dofs) - communicator->send(buffer, nb_local_dofs, root, 0); + static_communicator->send(buffer, nb_local_dofs, root, 0); delete [] buffer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<typename T> void DOFSynchronizer::scatter(Array<T> & scattered, UInt root, const Array<T> * to_scatter) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(gather_scatter_scheme_initialized == true, "You should call initScatterGatherCommunicationScheme before trying to scatter a Array !!"); if(psize == 1) { scattered.copy(*to_scatter, true); AKANTU_DEBUG_OUT(); return; } scattered.resize(nb_dofs / scattered.getNbComponent()); UInt * dof_global_id = dof_global_ids.storage(); Int * dof_type = dof_types.storage(); if (prank == root) { for (UInt p = 0; p < psize; ++p) { if(p == root) continue; UInt nb_needed_dof = proc_informations[p].needed_dofs.getSize(); UInt nb_local_dof = proc_informations[p].dofs.getSize(); AKANTU_DEBUG_INFO("Scatter - Sending " << nb_local_dof + nb_needed_dof << " to " << p); if(nb_local_dof + nb_needed_dof) { T * send_buffer = new T[nb_local_dof + nb_needed_dof]; T * buffer_tmp = send_buffer; UInt * remote_dofs = proc_informations[p].dofs.storage(); for (UInt d = 0; d < nb_local_dof; ++d) { *(buffer_tmp++) = to_scatter->storage()[*remote_dofs++]; } remote_dofs = proc_informations[p].needed_dofs.storage(); for (UInt d = 0; d < nb_needed_dof; ++d) { *(buffer_tmp++) = to_scatter->storage()[*remote_dofs++]; } - communicator->send(send_buffer, nb_local_dof + nb_needed_dof, p, 0); + static_communicator->send(send_buffer, nb_local_dof + nb_needed_dof, p, 0); delete [] send_buffer; } } T * scattered_val = scattered.storage(); for (UInt d = 0; d < nb_dofs; ++d) { if(*dof_type != -3) { if(*dof_type >= -2) *scattered_val = to_scatter->storage()[*dof_global_id]; } scattered_val++; dof_type++; dof_global_id++; } } else { T * buffer; AKANTU_DEBUG_INFO("Scatter - Receiving " << nb_dofs << " from " << root); if(nb_local_dofs + nb_needed_dofs) { buffer = new T[nb_local_dofs + nb_needed_dofs]; - communicator->receive(buffer, nb_local_dofs + nb_needed_dofs, root, 0); + static_communicator->receive(buffer, nb_local_dofs + nb_needed_dofs, root, 0); T * scattered_val = scattered.storage(); UInt local_dofs = 0; UInt needed_dofs = nb_local_dofs; for (UInt d = 0; d < nb_dofs; ++d) { if(*dof_type != -3) { if(*dof_type == -1 || *dof_type == -2) *scattered_val = buffer[local_dofs++]; else if(*dof_type >= 0) *scattered_val = buffer[needed_dofs++]; } scattered_val++; dof_type++; } delete [] buffer; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<typename T> void DOFSynchronizer::synchronize(Array<T> & dof_vector) const { AKANTU_DEBUG_IN(); if(psize == 1) { AKANTU_DEBUG_OUT(); return; } for (UInt p = 1; p < psize; ++p) { UInt sendto = (psize + prank + p) % psize; UInt recvfrom = (psize + prank - p) % psize; UInt nb_slave_dofs = proc_informations[sendto].slave_dofs.getSize(); UInt * slave_dofs = proc_informations[sendto].slave_dofs.storage(); UInt nb_master_dofs = proc_informations[recvfrom].master_dofs.getSize(); UInt * master_dofs = proc_informations[recvfrom].master_dofs.storage(); T * send_buffer = new T[nb_slave_dofs]; T * recv_buffer = new T[nb_master_dofs]; for (UInt d = 0; d < nb_slave_dofs; ++d) { AKANTU_DEBUG_ASSERT(dof_types(slave_dofs[d]) == -2, "Sending node " << slave_dofs[d] << "(gid" << dof_global_ids(d) << ") to proc " << sendto << " but it is not a master node."); send_buffer[d] = dof_vector.storage()[slave_dofs[d]]; } /// ring blocking communications CommunicationRequest * request = NULL; - if(nb_slave_dofs != 0) request = communicator->asyncSend(send_buffer, nb_slave_dofs, sendto , 0); - if(nb_master_dofs != 0) communicator->receive(recv_buffer, nb_master_dofs, recvfrom, 0); + if(nb_slave_dofs != 0) request = static_communicator->asyncSend(send_buffer, nb_slave_dofs, sendto , 0); + if(nb_master_dofs != 0) static_communicator->receive(recv_buffer, nb_master_dofs, recvfrom, 0); for (UInt d = 0; d < nb_master_dofs; ++d) { AKANTU_DEBUG_ASSERT(dof_types(master_dofs[d]) >= 0, "Received node " << master_dofs[d] << "(gid" << dof_global_ids(d) << ") from proc " << recvfrom << " but it is not a slave node."); dof_vector.storage()[master_dofs[d]] = recv_buffer[d]; } if(nb_slave_dofs != 0) { - communicator->wait(request); - communicator->freeCommunicationRequest(request); + static_communicator->wait(request); + static_communicator->freeCommunicationRequest(request); } delete [] send_buffer; delete [] recv_buffer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<template <class> class Op, typename T> void DOFSynchronizer::reduceSynchronize(Array<T> & dof_vector) const { AKANTU_DEBUG_IN(); if(psize == 1) { AKANTU_DEBUG_OUT(); return; } for (UInt p = 1; p < psize; ++p) { UInt sendto = (psize + prank + p) % psize; UInt recvfrom = (psize + prank - p) % psize; UInt nb_slave_dofs = proc_informations[recvfrom].slave_dofs.getSize(); UInt * slave_dofs = proc_informations[recvfrom].slave_dofs.storage(); UInt nb_master_dofs = proc_informations[sendto].master_dofs.getSize(); UInt * master_dofs = proc_informations[sendto].master_dofs.storage(); T * send_buffer = new T[nb_master_dofs]; T * recv_buffer = new T[nb_slave_dofs]; for (UInt d = 0; d < nb_master_dofs; ++d) { send_buffer[d] = dof_vector.storage()[master_dofs[d]]; } CommunicationRequest * request = NULL; - if(nb_master_dofs != 0) request = communicator->asyncSend(send_buffer, nb_master_dofs, sendto , 0); - if(nb_slave_dofs != 0) communicator->receive(recv_buffer, nb_slave_dofs, recvfrom, 0); + if(nb_master_dofs != 0) request = static_communicator->asyncSend(send_buffer, nb_master_dofs, sendto , 0); + if(nb_slave_dofs != 0) static_communicator->receive(recv_buffer, nb_slave_dofs, recvfrom, 0); Op<T> oper; for (UInt d = 0; d < nb_slave_dofs; ++d) { dof_vector.storage()[slave_dofs[d]] = oper(dof_vector.storage()[slave_dofs[d]], recv_buffer[d]); } if(nb_master_dofs != 0) { - communicator->wait(request); - communicator->freeCommunicationRequest(request); + static_communicator->wait(request); + static_communicator->freeCommunicationRequest(request); } delete [] send_buffer; delete [] recv_buffer; } synchronize(dof_vector); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline bool DOFSynchronizer::isPureGhostDOF(UInt n) const { return dof_types.getSize() ? (dof_types(n) == -3) : false; } /* -------------------------------------------------------------------------- */ inline bool DOFSynchronizer::isLocalOrMasterDOF(UInt n) const { return dof_types.getSize() ? (dof_types(n) == -2) || (dof_types(n) == -1) : true; } /* -------------------------------------------------------------------------- */ inline bool DOFSynchronizer::isLocalDOF(UInt n) const { return dof_types.getSize() ? dof_types(n) == -1 : true; } /* -------------------------------------------------------------------------- */ inline bool DOFSynchronizer::isMasterDOF(UInt n) const { return dof_types.getSize() ? dof_types(n) == -2 : false; } /* -------------------------------------------------------------------------- */ inline bool DOFSynchronizer::isSlaveDOF(UInt n) const { return dof_types.getSize() ? dof_types(n) >= 0 : false; } diff --git a/src/synchronizer/synchronizer.cc b/src/synchronizer/synchronizer.cc index beab3974c..bcd018f79 100644 --- a/src/synchronizer/synchronizer.cc +++ b/src/synchronizer/synchronizer.cc @@ -1,56 +1,57 @@ /** * @file synchronizer.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Wed Sep 01 2010 * @date last modification: Wed Nov 13 2013 * * @brief implementation of the common part * * @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 "synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ Synchronizer::Synchronizer(SynchronizerID id, MemoryID memory_id) : - Memory(id, memory_id) { + Memory(id, memory_id), + static_communicator(&StaticCommunicator::getStaticCommunicator()) { } /* -------------------------------------------------------------------------- */ void Synchronizer::synchronize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); asynchronousSynchronize(data_accessor,tag); waitEndSynchronize(data_accessor,tag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/synchronizer/synchronizer.hh b/src/synchronizer/synchronizer.hh index a4b4c232f..46c01892b 100644 --- a/src/synchronizer/synchronizer.hh +++ b/src/synchronizer/synchronizer.hh @@ -1,133 +1,163 @@ /** * @file synchronizer.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> + * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch> * * @date creation: Wed Sep 01 2010 * @date last modification: Tue Apr 30 2013 * * @brief interface for communicator and pbc synchronizers * * @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_SYNCHRONIZER_HH__ #define __AKANTU_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_memory.hh" #include "data_accessor.hh" +#include "real_static_communicator.hh" +#include "static_communicator.hh" + /* -------------------------------------------------------------------------- */ #include <map> /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class Synchronizer : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Synchronizer(SynchronizerID id = "synchronizer", MemoryID memory_id = 0); virtual ~Synchronizer() { }; virtual void printself(__attribute__((unused)) std::ostream & stream, __attribute__((unused)) int indent = 0) const {}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronize ghosts void synchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// asynchronous synchronization of ghosts virtual void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag) = 0; /// wait end of asynchronous synchronization of ghosts virtual void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag) = 0; /// compute buffer size for a given tag and data accessor virtual void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag)=0; /** * tag = |__________20_________|___8____|_4_| * | proc | num mes| ct| */ class Tag { public: operator int() { return int(tag); } template<typename CommTag> static inline Tag genTag(int proc, UInt msg_count, CommTag tag) { Tag t; t.tag = (((proc & 0xFFFFF) << 12) + ((msg_count & 0xFF) << 4) + ((Int)tag & 0xF)); return t; } virtual void printself(std::ostream & stream, __attribute__((unused)) int indent = 0) const { stream << (tag >> 12) << ":" << (tag >> 4 & 0xFF) << ":" << (tag & 0xF); } private: UInt tag; }; protected: /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: + + class Communication { + public: + void resize(UInt size) { + send_buffer.resize(size); + recv_buffer.resize(size); + size_to_send .resize(size); + size_to_receive.resize(size); + } + + public: + /// size of data to send to each processor + std::vector<UInt> size_to_send; + /// size of data to recv to each processor + std::vector<UInt> size_to_receive; + std::vector< CommunicationBuffer > send_buffer; + std::vector< CommunicationBuffer > recv_buffer; + + std::vector<CommunicationRequest *> send_requests; + std::vector<CommunicationRequest *> recv_requests; + }; + /// id of the synchronizer SynchronizerID id; /// message counter per tag std::map<SynchronizationTag, UInt> tag_counter; + + + /// the static memory instance + StaticCommunicator * static_communicator; }; /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Synchronizer & _this) { _this.printself(stream); return stream; } inline std::ostream & operator <<(std::ostream & stream, const Synchronizer::Tag & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/synchronizer_registry.hh b/src/synchronizer/synchronizer_registry.hh index 7b116afef..5e7e09617 100644 --- a/src/synchronizer/synchronizer_registry.hh +++ b/src/synchronizer/synchronizer_registry.hh @@ -1,115 +1,115 @@ /** * @file synchronizer_registry.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date creation: Thu Jun 16 2011 * @date last modification: Tue Nov 06 2012 * * @brief Registry of synchronizers * * @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_SYNCHRONIZER_REGISTRY_HH__ #define __AKANTU_SYNCHRONIZER_REGISTRY_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "data_accessor.hh" #include "synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class SynchronizerRegistry { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SynchronizerRegistry(DataAccessor & data_accessor); virtual ~SynchronizerRegistry(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// synchronize operation void synchronize(SynchronizationTag tag); /// asynchronous synchronization void asynchronousSynchronize(SynchronizationTag tag); /// wait end of asynchronous synchronization void waitEndSynchronize(SynchronizationTag tag); /// register a new synchronization void registerSynchronizer(Synchronizer & synchronizer,SynchronizationTag tag); - + /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: // /// number of tags registered // UInt nb_synchronization_tags; typedef std::multimap<SynchronizationTag, Synchronizer *> Tag2Sync; /// list of registered synchronization Tag2Sync synchronizers; /// data accessor that will permit to do the pack/unpack things DataAccessor & data_accessor; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ // #include "synchronizer_registry_inline_impl.cc" /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const SynchronizerRegistry & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_SYNCHRONIZER_REGISTRY_HH__ */ diff --git a/test/test_solver/CMakeLists.txt b/test/test_solver/CMakeLists.txt index 42f17633c..ee414464d 100644 --- a/test/test_solver/CMakeLists.txt +++ b/test/test_solver/CMakeLists.txt @@ -1,54 +1,64 @@ #=============================================================================== # @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) register_test(test_sparse_matrix_profile SOURCES test_sparse_matrix_profile.cc DEPENDENCIES test_solver_mesh ) register_test(test_sparse_matrix_assemble SOURCES test_sparse_matrix_assemble.cc DEPENDENCIES test_solver_mesh ) register_test(test_sparse_matrix_product SOURCES test_sparse_matrix_product.cc FILES_TO_COPY bar.msh ) register_test(test_petsc_matrix_profile SOURCES test_petsc_matrix_profile.cc DEPENDENCIES test_solver_mesh + ) + +register_test(test_petsc_matrix_apply_boundary + SOURCES test_petsc_matrix_apply_boundary.cc + DEPENDENCIES test_solver_mesh + ) + +register_test(test_solver_petsc + SOURCES test_solver_petsc.cc + DEPENDENCIES profile.mtx ) \ No newline at end of file diff --git a/test/test_solver/test_petsc_matrix_profile.cc b/test/test_solver/test_petsc_matrix_profile.cc index 04b32cbfe..1a8f2f4e7 100644 --- a/test/test_solver/test_petsc_matrix_profile.cc +++ b/test/test_solver/test_petsc_matrix_profile.cc @@ -1,126 +1,137 @@ /** * @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 "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); + 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); 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, _symmetric); - - petsc_matrix.resize(dof_synchronizer); + PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _unsymmetric); + petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension); petsc_matrix.add(K, 1); - petsc_matrix.performAssembly(); + // 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.mtx"); + petsc_matrix.saveMatrix("profile.dat"); delete communicator; finalize(); return EXIT_SUCCESS; } diff --git a/test/test_synchronizer/CMakeLists.txt b/test/test_synchronizer/CMakeLists.txt index 52a6c6b31..971dbc550 100644 --- a/test/test_synchronizer/CMakeLists.txt +++ b/test/test_synchronizer/CMakeLists.txt @@ -1,62 +1,68 @@ #=============================================================================== # @file CMakeLists.txt # # @author Nicolas Richart <nicolas.richart@epfl.ch> # # @date creation: Sun Sep 12 2010 # @date last modification: Fri Sep 05 2014 # # @brief configuration for synchronizer 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_mesh(test_synchronizer_communication_mesh cube.geo 3 2) register_test(test_synchronizer_communication SOURCES test_synchronizer_communication.cc DEPENDENCIES test_synchronizer_communication_mesh PACKAGE parallel ) if(AKANTU_DAMAGE_NON_LOCAL) add_executable(test_grid_synchronizer_check_neighbors test_grid_synchronizer_check_neighbors.cc) target_link_libraries(test_grid_synchronizer_check_neighbors akantu) endif() register_test(test_grid_synchronizer SOURCES test_grid_synchronizer.cc test_data_accessor.hh DEPENDENCIES test_synchronizer_communication_mesh test_grid_synchronizer_check_neighbors EXTRA_FILES test_grid_synchronizer_check_neighbors.cc test_grid_tools.hh PACKAGE damage_non_local ) register_test(test_dof_synchronizer SOURCES test_dof_synchronizer.cc test_data_accessor.hh FILES_TO_COPY bar.msh) +register_test(test_dof_synchronizer_communication + SOURCES test_dof_synchronizer_communication.cc test_dof_data_accessor.hh + DEPENDENCIES test_synchronizer_communication_mesh + PACKAGE parallel + ) + register_test(test_data_distribution SOURCES test_data_distribution.cc FILES_TO_COPY data_split.msh PACKAGE parallel )