diff --git a/packages/core.cmake b/packages/core.cmake index c8a07a8e0..9c70eb6b2 100644 --- a/packages/core.cmake +++ b/packages/core.cmake @@ -1,516 +1,523 @@ #=============================================================================== # @file core.cmake # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Mon Nov 21 2011 # @date last modification: Mon Jan 18 2016 # # @brief package description for core # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== package_declare(core NOT_OPTIONAL DESCRIPTION "core package for Akantu") package_declare_sources(core 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_element_classes_info_inline_impl.cc 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_hexahedron_20_inline_impl.cc fe_engine/element_classes/element_class_pentahedron_6_inline_impl.cc fe_engine/element_classes/element_class_pentahedron_15_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_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/integration_point.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_dummy.hh 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_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_real.cc io/parser/parser_random.cc io/parser/parser_types.cc io/parser/parser_input_files.cc io/parser/parser.hh io/parser/parser_tmpl.hh io/parser/parser_grammar_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_accessor.hh mesh/mesh_events.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_utils_pbc.cc mesh_utils/mesh_utils.cc mesh_utils/mesh_utils.hh mesh_utils/mesh_utils_inline_impl.cc mesh_utils/global_ids_updater.hh mesh_utils/global_ids_updater.cc mesh_utils/global_ids_updater_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/dof_manager.cc model/dof_manager.hh model/dof_manager_inline_impl.cc model/model_solver.cc model/model_solver.hh model/non_linear_solver.cc model/non_linear_solver.hh model/non_linear_solver_default.hh model/non_linear_solver_lumped.cc model/non_linear_solver_lumped.hh model/solver_callback.hh model/time_step_solver.hh model/time_step_solvers/time_step_solver.cc model/time_step_solvers/time_step_solver_default.cc model/time_step_solvers/time_step_solver_default.hh model/time_step_solvers/time_step_solver_default_explicit.hh model/non_linear_solver_callback.hh model/time_step_solvers/time_step_solver_default_solver_callback.hh model/integration_scheme/generalized_trapezoidal.cc model/integration_scheme/generalized_trapezoidal.hh model/integration_scheme/integration_scheme.cc model/integration_scheme/integration_scheme.hh model/integration_scheme/integration_scheme_1st_order.cc model/integration_scheme/integration_scheme_1st_order.hh model/integration_scheme/integration_scheme_2nd_order.cc model/integration_scheme/integration_scheme_2nd_order.hh model/integration_scheme/newmark-beta.cc model/integration_scheme/newmark-beta.hh model/integration_scheme/pseudo_time.cc model/integration_scheme/pseudo_time.hh 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_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_core_includes.hh model/solid_mechanics/materials/material_elastic.cc model/solid_mechanics/materials/material_elastic.hh model/solid_mechanics/materials/material_elastic_inline_impl.cc model/solid_mechanics/materials/material_thermal.cc model/solid_mechanics/materials/material_thermal.hh model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh model/solid_mechanics/materials/material_elastic_orthotropic.cc model/solid_mechanics/materials/material_elastic_orthotropic.hh model/solid_mechanics/materials/material_damage/material_damage.hh model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh model/solid_mechanics/materials/material_damage/material_marigo.cc model/solid_mechanics/materials/material_damage/material_marigo.hh model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc model/solid_mechanics/materials/material_damage/material_mazars.cc model/solid_mechanics/materials/material_damage/material_mazars.hh model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc model/solid_mechanics/materials/material_plastic/material_plastic.cc model/solid_mechanics/materials/material_plastic/material_plastic.hh model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh model/common/neighborhood_base.hh model/common/neighborhood_base.cc model/common/neighborhood_base_inline_impl.cc model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.hh model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion.cc model/common/neighborhoods_criterion_evaluation/neighborhood_max_criterion_inline_impl.cc solver/sparse_solver.cc solver/sparse_solver.hh solver/sparse_solver_inline_impl.cc solver/sparse_matrix.cc solver/sparse_matrix.hh solver/sparse_matrix_inline_impl.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/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 synchronizer/grid_synchronizer.cc synchronizer/grid_synchronizer.hh - + synchronizer/element_info_per_processor.cc + synchronizer/element_info_per_processor.hh + synchronizer/element_info_per_processor_tmpl.hh + synchronizer/master_element_info_per_processor.cc + synchronizer/slave_element_info_per_processor.cc + synchronizer/node_info_per_processor.cc + synchronizer/node_info_per_processor.hh ) package_declare_elements(core ELEMENT_TYPES _point_1 _segment_2 _segment_3 _triangle_3 _triangle_6 _quadrangle_4 _quadrangle_8 _tetrahedron_4 _tetrahedron_10 _pentahedron_6 _pentahedron_15 _hexahedron_8 _hexahedron_20 KIND regular GEOMETRICAL_TYPES _gt_point _gt_segment_2 _gt_segment_3 _gt_triangle_3 _gt_triangle_6 _gt_quadrangle_4 _gt_quadrangle_8 _gt_tetrahedron_4 _gt_tetrahedron_10 _gt_hexahedron_8 _gt_hexahedron_20 _gt_pentahedron_6 _gt_pentahedron_15 INTERPOLATION_TYPES _itp_lagrange_point_1 _itp_lagrange_segment_2 _itp_lagrange_segment_3 _itp_lagrange_triangle_3 _itp_lagrange_triangle_6 _itp_lagrange_quadrangle_4 _itp_serendip_quadrangle_8 _itp_lagrange_tetrahedron_4 _itp_lagrange_tetrahedron_10 _itp_lagrange_hexahedron_8 _itp_serendip_hexahedron_20 _itp_lagrange_pentahedron_6 _itp_lagrange_pentahedron_15 GEOMETRICAL_SHAPES _gst_point _gst_triangle _gst_square _gst_prism GAUSS_INTEGRATION_TYPES _git_point _git_segment _git_triangle _git_tetrahedron _git_pentahedron INTERPOLATION_KIND _itk_lagrangian FE_ENGINE_LISTS gradient_on_integration_points interpolate_on_integration_points interpolate compute_normals_on_integration_points inverse_map contains compute_shapes compute_shapes_derivatives get_shapes_derivatives ) package_declare_material_infos(core LIST AKANTU_CORE_MATERIAL_LIST INCLUDE material_core_includes.hh ) package_declare_documentation_files(core manual.sty manual.cls manual.tex manual-macros.sty manual-titlepages.tex manual-introduction.tex manual-gettingstarted.tex manual-io.tex manual-feengine.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 ) package_declare_documentation(core "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 cmake libboost-dev zlib1g-dev g++" "\\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}" ) find_program(READLINK_COMMAND readlink) find_program(ADDR2LINE_COMMAND addr2line) find_program(PATCH_COMMAND patch) mark_as_advanced(READLINK_COMMAND) mark_as_advanced(ADDR2LINE_COMMAND) include(CheckFunctionExists) check_function_exists(clock_gettime _clock_gettime) include(CheckCXXSymbolExists) check_cxx_symbol_exists(strdup cstring AKANTU_HAS_STRDUP) if(NOT _clock_gettime) set(AKANTU_USE_OBSOLETE_GETTIMEOFDAY ON CACHE INTERNAL "" FORCE) else() set(AKANTU_USE_OBSOLETE_GETTIMEOFDAY OFF CACHE INTERNAL "" FORCE) endif() package_declare_extra_files_to_package(core SOURCES common/aka_element_classes_info.hh.in common/aka_config.hh.in model/solid_mechanics/material_list.hh.in ) diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh index 631a6d501..b2ee87889 100644 --- a/src/common/aka_common.hh +++ b/src/common/aka_common.hh @@ -1,430 +1,437 @@ /** * @file aka_common.hh * * @author Nicolas Richart * * @date creation: Mon Jun 14 2010 * @date last modification: Thu Jan 21 2016 * * @brief common type descriptions for akantu * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * * @section DESCRIPTION * * All common things to be included in the projects files * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMON_HH__ #define __AKANTU_COMMON_HH__ /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ #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 std::string ID; #ifdef AKANTU_NDEBUG static const Real REAL_INIT_VALUE = Real(0.); #else static const Real REAL_INIT_VALUE = std::numeric_limits::quiet_NaN(); #endif /* -------------------------------------------------------------------------- */ /* Memory types */ /* -------------------------------------------------------------------------- */ typedef UInt MemoryID; typedef std::string Surface; typedef std::pair SurfacePair; typedef std::list SurfacePairList; /* -------------------------------------------------------------------------- */ extern const UInt _all_dimensions; /* -------------------------------------------------------------------------- */ /* Mesh/FEM/Model types */ /* -------------------------------------------------------------------------- */ __END_AKANTU__ #include "aka_element_classes_info.hh" __BEGIN_AKANTU__ /// 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 = 0, _implicit_dynamic = 1, _explicit_lumped_mass = 2, _explicit_lumped_capacity = 2, _explicit_consistent_mass = 3 }; /// enum DOFSupportType defines which kind of dof that can exists enum DOFSupportType { _dst_nodal, _dst_generic }; /// Type of non linear resolution available in akantu enum NonLinearSolverType { _nls_linear, ///< No non linear convergence loop _nls_newton_raphson, ///< Regular Newton-Raphson _nls_newton_raphson_modified, ///< Newton-Raphson with initial tangent _nls_lumped, ///< Case of lumped mass or equivalent matrix _nls_auto, ///< This will take a default value that make sense in case of ///model::getNewSolver }; +/// Define the node/dof type +enum NodeType { + _nt_pure_gost = -3, + _nt_master = -2, + _nt_normal = -1, +}; + /// Type of time stepping solver enum TimeStepSolverType { _tsst_static, ///< Static solution _tsst_dynamic, ///< Dynamic solver _tsst_dynamic_lumped, ///< Dynamic solver with lumped mass }; /// Type of integration scheme enum IntegrationSchemeType { _ist_pseudo_time, ///< Pseudo Time _ist_forward_euler, ///< GeneralizedTrapezoidal(0) _ist_trapezoidal_rule_1, ///< GeneralizedTrapezoidal(1/2) _ist_backward_euler, ///< GeneralizedTrapezoidal(1) _ist_central_difference, ///< NewmarkBeta(0, 1/2) _ist_fox_goodwin, ///< NewmarkBeta(1/6, 1/2) _ist_trapezoidal_rule_2, ///< NewmarkBeta(1/2, 1/2) _ist_linear_acceleration, ///< NewmarkBeta(1/3, 1/2) _ist_newmark_beta, ///< generic NewmarkBeta with user defined /// alpha and beta _ist_generalized_trapezoidal, ///< generic GeneralizedTrapezoidal with user /// defined alpha }; /// enum SolveConvergenceCriteria different convergence criteria enum SolveConvergenceCriteria { _scc_residual, ///< Use residual to test the convergence _scc_solution, ///< Use solution 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 }; /// @enum SparseMatrixType type of sparse matrix used enum MatrixType { _unsymmetric, _symmetric }; /* -------------------------------------------------------------------------- */ /* 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 // --- GlobalIdsUpdater tags --- _gst_giu_global_conn, ///< synchronization of global connectivities // --- CohesiveElementInserter tags --- _gst_ce_groups, ///< synchronization of cohesive element insertion depending /// on facet groups // --- 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 --- _gst_htm_phi, ///< synchronization of the nodal level set value phi _gst_htm_gradient_phi, ///< synchronization of the element 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 // --- NeighborhoodSynchronization tags --- _gst_nh_criterion, // --- General tags --- _gst_test, ///< Test tag _gst_user_1, ///< tag for user simulations _gst_user_2, ///< tag for user simulations _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 // --- 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 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_prod, _so_land, _so_band, _so_lor, _so_bor, _so_lxor, _so_bxor, _so_min_loc, _so_max_loc, _so_null }; /* -------------------------------------------------------------------------- */ /* Global defines */ /* -------------------------------------------------------------------------- */ #define AKANTU_MIN_ALLOCATION 2000 #define AKANTU_INDENT " " #define AKANTU_INCLUDE_INLINE_IMPL /* -------------------------------------------------------------------------- */ template struct is_scalar { enum { value = false }; }; #define AKANTU_SPECIFY_IS_SCALAR(type) \ template <> struct is_scalar { \ enum { value = true }; \ } AKANTU_SPECIFY_IS_SCALAR(Real); AKANTU_SPECIFY_IS_SCALAR(UInt); AKANTU_SPECIFY_IS_SCALAR(Int); AKANTU_SPECIFY_IS_SCALAR(bool); template struct is_same { enum { value = false }; // is_same represents a bool. }; template struct is_same { 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 & 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(); /* -------------------------------------------------------------------------- */ /// Read an new input file void readInputFile(const std::string & input_file); /* -------------------------------------------------------------------------- */ /* * 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 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__ #include "aka_common_inline_impl.cc" /* -------------------------------------------------------------------------- */ #if defined(AKANTU_UNORDERED_MAP_IS_CXX11) __BEGIN_AKANTU_UNORDERED_MAP__ #if AKANTU_INTEGER_SIZE == 4 #define AKANTU_HASH_COMBINE_MAGIC_NUMBER 0x9e3779b9 #elif AKANTU_INTEGER_SIZE == 8 #define AKANTU_HASH_COMBINE_MAGIC_NUMBER 0x9e3779b97f4a7c13LL #endif /** * Hashing function for pairs based on hash_combine from boost The magic number * is coming from the golden number @f[\phi = \frac{1 + \sqrt5}{2}@f] * @f[\frac{2^32}{\phi} = 0x9e3779b9@f] * http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine * http://burtleburtle.net/bob/hash/doobs.html */ template struct hash > { public: hash() : ah(), bh() {} size_t operator()(const std::pair & p) const { size_t seed = ah(p.first); return bh(p.second) + AKANTU_HASH_COMBINE_MAGIC_NUMBER + (seed << 6) + (seed >> 2); } private: const hash ah; const hash bh; }; __END_AKANTU_UNORDERED_MAP__ #endif #endif /* __AKANTU_COMMON_HH__ */ diff --git a/src/io/dumper/dumper_iohelper.cc b/src/io/dumper/dumper_iohelper.cc index 7e431f426..a4f4a0a0e 100644 --- a/src/io/dumper/dumper_iohelper.cc +++ b/src/io/dumper/dumper_iohelper.cc @@ -1,295 +1,300 @@ /** * @file dumper_iohelper.cc * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Fri Oct 26 2012 * @date last modification: Thu Sep 17 2015 * * @brief implementation of DumperIOHelper * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include "dumper_iohelper.hh" #include "dumper_elemental_field.hh" #include "dumper_nodal_field.hh" #include "dumper_filtered_connectivity.hh" #include "dumper_variable.hh" #include "mesh.hh" #if defined(AKANTU_IGFEM) #include "dumper_igfem_connectivity.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ DumperIOHelper::DumperIOHelper() : count(0), time_activated(false) {} /* -------------------------------------------------------------------------- */ DumperIOHelper::~DumperIOHelper() { for (Fields::iterator it = fields.begin(); it != fields.end(); ++it) { delete it->second; } delete dumper; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setParallelContext(bool is_parallel) { UInt whoami = StaticCommunicator::getStaticCommunicator().whoAmI(); UInt nb_proc = StaticCommunicator::getStaticCommunicator().getNbProc(); if(is_parallel) dumper->setParallelContext(whoami, nb_proc); else dumper->setParallelContext(0, 1); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setDirectory(const std::string & directory) { this->directory = directory; dumper->setPrefix(directory); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setBaseName(const std::string & basename) { filename = basename; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setTimeStep(Real time_step) { if(!time_activated) this->dumper->activateTimeDescFiles(time_step); else this->dumper->setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump() { try { dumper->dump(filename, count); } catch (iohelper::IOHelperException & e) { AKANTU_DEBUG_ERROR("I was not able to dump your data with a Dumper: " << e.what()); } ++count; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(UInt step) { this->count = step; this->dump(); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(Real current_time, UInt step) { this->dumper->setCurrentTime(current_time); this->dump(step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerMesh(const Mesh & mesh, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { #if defined(AKANTU_IGFEM) if (element_kind == _ek_igfem) { registerField("connectivities", new dumper::IGFEMConnectivityField(mesh.getConnectivities(), spatial_dimension, ghost_type)); } else #endif registerField("connectivities", new dumper::ElementalField(mesh.getConnectivities(), spatial_dimension, ghost_type, element_kind)); registerField("positions", new dumper::NodalField(mesh.getNodes())); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerFilteredMesh(const Mesh & mesh, const ElementTypeMapArray & elements_filter, const Array & nodes_filter, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { ElementTypeMapArrayFilter * f_connectivities = new ElementTypeMapArrayFilter(mesh.getConnectivities(), elements_filter); this->registerField("connectivities", new dumper::FilteredConnectivityField(*f_connectivities, nodes_filter, spatial_dimension, ghost_type, element_kind)); this->registerField("positions",new dumper::NodalField( mesh.getNodes(), 0, 0, &nodes_filter)); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerField(const std::string & field_id, dumper::Field * field) { Fields::iterator it = fields.find(field_id); if(it != fields.end()) { AKANTU_DEBUG_WARNING("The field " << field_id << " is already registered in this Dumper. Field ignored."); return; } fields[field_id] = field; field->registerToDumper(field_id, *dumper); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::unRegisterField(const std::string & field_id) { Fields::iterator it = fields.find(field_id); if(it == fields.end()) { AKANTU_DEBUG_WARNING("The field " << field_id << " is not registered in this Dumper. Nothing to do."); return; } delete it->second; fields.erase(it); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerVariable(const std::string & variable_id, dumper::VariableBase * variable) { Variables::iterator it = variables.find(variable_id); if(it != variables.end()) { AKANTU_DEBUG_WARNING("The Variable " << variable_id << " is already registered in this Dumper. Variable ignored."); return; } variables[variable_id] = variable; variable->registerToDumper(variable_id, *dumper); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::unRegisterVariable(const std::string & variable_id) { Variables::iterator it = variables.find(variable_id); if(it == variables.end()) { AKANTU_DEBUG_WARNING("The variable " << variable_id << " is not registered in this Dumper. Nothing to do."); return; } delete it->second; variables.erase(it); } /* -------------------------------------------------------------------------- */ template iohelper::ElemType getIOHelperType() { AKANTU_DEBUG_TO_IMPLEMENT(); return iohelper::MAX_ELEM_TYPE; } template <> iohelper::ElemType getIOHelperType<_segment_2>() { return iohelper::LINE1; } template <> iohelper::ElemType getIOHelperType<_segment_3>() { return iohelper::LINE2; } template <> iohelper::ElemType getIOHelperType<_triangle_3>() { return iohelper::TRIANGLE1; } template <> iohelper::ElemType getIOHelperType<_triangle_6>() { return iohelper::TRIANGLE2; } template <> iohelper::ElemType getIOHelperType<_quadrangle_4>() { return iohelper::QUAD1; } template <> iohelper::ElemType getIOHelperType<_quadrangle_8>() { return iohelper::QUAD2; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_4>() { return iohelper::TETRA1; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_10>() { return iohelper::TETRA2; } template <> iohelper::ElemType getIOHelperType<_hexahedron_8>() { return iohelper::HEX1; } template <> iohelper::ElemType getIOHelperType<_hexahedron_20>() { return iohelper::HEX2; } template <> iohelper::ElemType getIOHelperType<_pentahedron_6>() { return iohelper::PRISM1; } template <> iohelper::ElemType getIOHelperType<_pentahedron_15>() { return iohelper::PRISM2; } #if defined(AKANTU_COHESIVE_ELEMENT) template <> iohelper::ElemType getIOHelperType<_cohesive_2d_4>() { return iohelper::COH2D4; } template <> iohelper::ElemType getIOHelperType<_cohesive_2d_6>() { return iohelper::COH2D6; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_6>() { return iohelper::COH3D6; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_12>() { return iohelper::COH3D12; } template <> iohelper::ElemType getIOHelperType<_cohesive_3d_8>() { return iohelper::COH3D8; } //template <> //iohelper::ElemType getIOHelperType<_cohesive_3d_16>() { return iohelper::COH3D16; } #endif #if defined(AKANTU_STRUCTURAL_MECHANICS) template <> iohelper::ElemType getIOHelperType<_bernoulli_beam_2>() { return iohelper::BEAM2; } template <> iohelper::ElemType getIOHelperType<_bernoulli_beam_3>() { return iohelper::BEAM3; } #endif /* -------------------------------------------------------------------------- */ UInt getIOHelperType(ElementType type) { UInt ioh_type = iohelper::MAX_ELEM_TYPE; #define GET_IOHELPER_TYPE(type) \ ioh_type = getIOHelperType(); AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_IOHELPER_TYPE); #undef GET_IOHELPER_TYPE return ioh_type; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ + +namespace iohelper { + template<> + DataType getDataType() { return _int; } +} diff --git a/src/io/dumper/dumper_text.cc b/src/io/dumper/dumper_text.cc index b4f679e84..df3ae7a48 100644 --- a/src/io/dumper/dumper_text.cc +++ b/src/io/dumper/dumper_text.cc @@ -1,113 +1,113 @@ /** * @file dumper_text.cc * * @author David Simon Kammer * * @date creation: Fri Jun 18 2010 * @date last modification: Sun Oct 19 2014 * * @brief implementation of text dumper * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include "dumper_text.hh" #include "dumper_nodal_field.hh" #include "mesh.hh" #include "static_communicator.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ DumperText::DumperText(const std::string & basename, iohelper::TextDumpMode mode, bool parallel) : DumperIOHelper() { AKANTU_DEBUG_IN(); iohelper::DumperText * dumper_text = new iohelper::DumperText(mode); this->dumper = dumper_text; this->setBaseName(basename); this->setParallelContext(parallel); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DumperText::registerMesh(const Mesh & mesh, __attribute__((unused)) UInt spatial_dimension, __attribute__((unused)) const GhostType & ghost_type, __attribute__((unused)) const ElementKind & element_kind) { registerField("position", new dumper::NodalField(mesh.getNodes())); // in parallel we need node type UInt nb_proc = StaticCommunicator::getStaticCommunicator().getNbProc(); if (nb_proc > 1) { registerField("nodes_type", - new dumper::NodalField(mesh.getNodesType())); + new dumper::NodalField(mesh.getNodesType())); } } /* -------------------------------------------------------------------------- */ void DumperText::registerFilteredMesh( const Mesh & mesh, __attribute__((unused)) const ElementTypeMapArray & elements_filter, const Array & nodes_filter, __attribute__((unused)) UInt spatial_dimension, __attribute__((unused)) const GhostType & ghost_type, __attribute__((unused)) const ElementKind & element_kind) { registerField("position", new dumper::NodalField( mesh.getNodes(), 0, 0, &nodes_filter)); // in parallel we need node type UInt nb_proc = StaticCommunicator::getStaticCommunicator().getNbProc(); if (nb_proc > 1) { - registerField("nodes_type", new dumper::NodalField( + registerField("nodes_type", new dumper::NodalField( mesh.getNodesType(), 0, 0, &nodes_filter)); } } /* -------------------------------------------------------------------------- */ void DumperText::setBaseName(const std::string & basename) { AKANTU_DEBUG_IN(); DumperIOHelper::setBaseName(basename); static_cast(this->dumper) ->setDataSubDirectory(this->filename + "-DataFiles"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DumperText::setPrecision(UInt prec) { AKANTU_DEBUG_IN(); static_cast(this->dumper)->setPrecision(prec); AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/io/mesh_io.cc b/src/io/mesh_io.cc index 97694ab27..9235a8d3b 100644 --- a/src/io/mesh_io.cc +++ b/src/io/mesh_io.cc @@ -1,154 +1,156 @@ /** * @file mesh_io.cc * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Mon Jun 01 2015 * * @brief common part for all mesh io classes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh_io.hh" /* -------------------------------------------------------------------------- */ - __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ MeshIO::MeshIO() { - canReadSurface = false; + canReadSurface = false; canReadExtendedData = false; } /* -------------------------------------------------------------------------- */ -MeshIO::~MeshIO() { - -} +MeshIO::~MeshIO() {} /* -------------------------------------------------------------------------- */ -MeshIO * MeshIO::getMeshIO(const std::string & filename, const MeshIOType & type) { +MeshIO * MeshIO::getMeshIO(const std::string & filename, + const MeshIOType & type) { MeshIOType t = type; - if(type == _miot_auto) { + if (type == _miot_auto) { std::string::size_type idx = filename.rfind('.'); std::string ext; - if(idx != std::string::npos) { - ext = filename.substr(idx+1); + if (idx != std::string::npos) { + ext = filename.substr(idx + 1); } - if(ext == "msh") { t = _miot_gmsh; - } else if(ext == "diana") { t = _miot_diana; - } else if(ext == "inp") { t = _miot_abaqus; - } else AKANTU_EXCEPTION("Cannot guess the type of file of " - << filename << " (ext "<< ext <<"). " - << "Please provide the MeshIOType to the read function"); + if (ext == "msh") { + t = _miot_gmsh; + } else if (ext == "diana") { + t = _miot_diana; + } else if (ext == "inp") { + t = _miot_abaqus; + } else + AKANTU_EXCEPTION("Cannot guess the type of file of " + << filename << " (ext " << ext << "). " + << "Please provide the MeshIOType to the read function"); } - switch(t) { - case _miot_gmsh : return new MeshIOMSH(); + switch (t) { + case _miot_gmsh: + return new MeshIOMSH(); #if defined(AKANTU_STRUCTURAL_MECHANICS) - case _miot_gmsh_struct : return new MeshIOMSHStruct(); + case _miot_gmsh_struct: + return new MeshIOMSHStruct(); #endif - case _miot_diana : return new MeshIODiana(); - case _miot_abaqus : return new MeshIOAbaqus(); + case _miot_diana: + return new MeshIODiana(); + case _miot_abaqus: + return new MeshIOAbaqus(); default: return NULL; } } /* -------------------------------------------------------------------------- */ -void MeshIO::read(const std::string & filename, Mesh & mesh, const MeshIOType & type) { +void MeshIO::read(const std::string & filename, Mesh & mesh, + const MeshIOType & type) { MeshIO * mesh_io = getMeshIO(filename, type); mesh_io->read(filename, mesh); delete mesh_io; } /* -------------------------------------------------------------------------- */ -void MeshIO::write(const std::string & filename, Mesh & mesh, const MeshIOType & type) { +void MeshIO::write(const std::string & filename, Mesh & mesh, + const MeshIOType & type) { MeshIO * mesh_io = getMeshIO(filename, type); mesh_io->write(filename, mesh); delete mesh_io; } /* -------------------------------------------------------------------------- */ -void MeshIO::constructPhysicalNames(const std::string & tag_name, - Mesh & mesh) { - - if(!phys_name_map.empty()) { - for(Mesh::type_iterator type_it = mesh.firstType(); - type_it != mesh.lastType(); - ++type_it) { - +void MeshIO::constructPhysicalNames(const std::string & tag_name, Mesh & mesh) { + + if (!phys_name_map.empty()) { + for (Mesh::type_iterator type_it = mesh.firstType(); + type_it != mesh.lastType(); ++type_it) { + Array * name_vec = - mesh.getDataPointer("physical_names", *type_it); + mesh.getDataPointer("physical_names", *type_it); - const Array & tags_vec = - mesh.getData(tag_name, *type_it); - - for(UInt i(0); i < tags_vec.getSize(); i++) { - std::map::const_iterator map_it - = phys_name_map.find(tags_vec(i)); + const Array & tags_vec = mesh.getData(tag_name, *type_it); - if(map_it == phys_name_map.end()) { + for (UInt i(0); i < tags_vec.getSize(); i++) { + std::map::const_iterator map_it = + phys_name_map.find(tags_vec(i)); + + if (map_it == phys_name_map.end()) { std::stringstream sstm; sstm << tags_vec(i); name_vec->operator()(i) = sstm.str(); } else { name_vec->operator()(i) = map_it->second; } } } } } /* -------------------------------------------------------------------------- */ - -void MeshIO::printself(std::ostream & stream, int indent) const{ +void MeshIO::printself(std::ostream & stream, int indent) const { std::string space; - for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); + for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) + ; - if (phys_name_map.size()){ + if (phys_name_map.size()) { stream << space << "Physical map:" << std::endl; - + std::map::const_iterator it = phys_name_map.begin(); std::map::const_iterator end = phys_name_map.end(); - - for (; it!=end; ++it) { + for (; it != end; ++it) { stream << space << it->first << ": " << it->second << std::endl; } } - } /* -------------------------------------------------------------------------- */ - __END_AKANTU__ diff --git a/src/io/mesh_io.hh b/src/io/mesh_io.hh index 6420037c3..6327e7288 100644 --- a/src/io/mesh_io.hh +++ b/src/io/mesh_io.hh @@ -1,127 +1,118 @@ /** * @file mesh_io.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Mon Jun 01 2015 * * @brief interface of a mesh io class, reader and writer * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_IO_HH__ #define __AKANTU_MESH_IO_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class MeshIO { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - MeshIO(); virtual ~MeshIO(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - void read(const std::string & filename, Mesh & mesh, const MeshIOType & type); - void write(const std::string & filename, Mesh & mesh, const MeshIOType & type); + void write(const std::string & filename, Mesh & mesh, + const MeshIOType & type); /// read a mesh from the file virtual void read(__attribute__((unused)) const std::string & filename, - __attribute__((unused)) Mesh & mesh) { - } + __attribute__((unused)) Mesh & mesh) {} /// write a mesh to a file virtual void write(__attribute__((unused)) const std::string & filename, - __attribute__((unused)) const Mesh & mesh) {} - + __attribute__((unused)) const Mesh & mesh) {} /// function to request the manual construction of the physical names maps virtual void constructPhysicalNames(const std::string & tag_name, - Mesh & mesh); - + Mesh & mesh); /// method to permit to be printed to a generic stream virtual void printself(std::ostream & stream, int indent = 0) const; /// static contruction of a meshio object - static MeshIO * getMeshIO(const std::string & filename, const MeshIOType & type); - + static MeshIO * getMeshIO(const std::string & filename, + const MeshIOType & type); + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: + std::map & getPhysicalNameMap() { return phys_name_map; } - std::map & getPhysicalNameMap(){ - return phys_name_map; - } - /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: bool canReadSurface; bool canReadExtendedData; /// correspondance between a tag and physical names (if applicable) std::map phys_name_map; - }; /* -------------------------------------------------------------------------- */ -inline std::ostream & operator <<(std::ostream & stream, const MeshIO &_this) { +inline std::ostream & operator<<(std::ostream & stream, const MeshIO & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ - - __END_AKANTU__ #include "mesh_io_msh.hh" #include "mesh_io_diana.hh" #include "mesh_io_abaqus.hh" #if defined(AKANTU_STRUCTURAL_MECHANICS) -# include "mesh_io_msh_struct.hh" +#include "mesh_io_msh_struct.hh" #endif #endif /* __AKANTU_MESH_IO_HH__ */ diff --git a/src/io/mesh_io/mesh_io_abaqus.cc b/src/io/mesh_io/mesh_io_abaqus.cc index 0e01e4be9..8c08680aa 100644 --- a/src/io/mesh_io/mesh_io_abaqus.cc +++ b/src/io/mesh_io/mesh_io_abaqus.cc @@ -1,540 +1,542 @@ /** * @file mesh_io_abaqus.cc * * @author Daniel Pino Muñoz * @author Nicolas Richart * * @date creation: Fri Jan 04 2013 * @date last modification: Fri Dec 11 2015 * * @brief read a mesh from an abaqus input file * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ // std library header files #include // akantu header files #include "mesh_io_abaqus.hh" #include "mesh.hh" #include "mesh_utils.hh" #include "element_group.hh" #include "node_group.hh" /* -------------------------------------------------------------------------- */ //#define BOOST_SPIRIT_USE_PHOENIX_V3 1 //#define BOOST_RESULT_OF_USE_TR1 #include #include #include // #include // #include // #include // #include // #include // #include // #include /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ MeshIOAbaqus::MeshIOAbaqus() {} /* -------------------------------------------------------------------------- */ MeshIOAbaqus::~MeshIOAbaqus() {} /* -------------------------------------------------------------------------- */ namespace spirit = boost::spirit; namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace lbs = boost::spirit::qi::labels; namespace phx = boost::phoenix; namespace mesh_io_abaqus_lazy_eval { struct mesh_abaqus_error_handler_ { template struct result { typedef void type; }; template void operator()(qi::info const & what, Iterator err_pos, Iterator last) const { AKANTU_EXCEPTION( "Error! Expecting " << what // what failed? << " here: \"" << std::string(err_pos, last) // iterators to error-pos, end << "\""); } }; struct lazy_element_read_ { template struct result { typedef void type; }; template void operator()(Mesh & mesh, const ET & type, const ID & id, const V & conn, const NodeMap & nodes_mapping, ElemMap & elements_mapping) const { Vector tmp_conn(Mesh::getNbNodesPerElement(type)); AKANTU_DEBUG_ASSERT(conn.size() == tmp_conn.size(), "The nodes in the Abaqus file have too many coordinates" << " for the mesh you try to fill."); mesh.addConnectivityType(type); Array & connectivity = mesh.getConnectivity(type); UInt i = 0; for (typename V::const_iterator it = conn.begin(); it != conn.end(); ++it) { typename NodeMap::const_iterator nit = nodes_mapping.find(*it); AKANTU_DEBUG_ASSERT(nit != nodes_mapping.end(), "There is an unknown node in the connectivity."); tmp_conn[i++] = nit->second; } Element el(type, connectivity.getSize()); elements_mapping[id] = el; connectivity.push_back(tmp_conn); } }; struct lazy_node_read_ { template struct result { typedef void type; }; template void operator()(Mesh & mesh, const ID & id, const V & pos, Map & nodes_mapping) const { Vector tmp_pos(mesh.getSpatialDimension()); UInt i = 0; for (typename V::const_iterator it = pos.begin(); it != pos.end() || i < mesh.getSpatialDimension(); ++it) tmp_pos[i++] = *it; nodes_mapping[id] = mesh.getNbNodes(); mesh.getNodes().push_back(tmp_pos); } }; /* ------------------------------------------------------------------------ */ struct lazy_element_group_create_ { template struct result { typedef ElementGroup & type; }; template ElementGroup & operator()(Mesh & mesh, const S & name) const { typename Mesh::element_group_iterator eg_it = mesh.element_group_find(name); if (eg_it != mesh.element_group_end()) { return *eg_it->second; } else { return mesh.createElementGroup(name, _all_dimensions); } } }; struct lazy_add_element_to_group_ { template struct result { typedef void type; }; template void operator()(EG * el_grp, const ID & element, const Map & elements_mapping) const { typename Map::const_iterator eit = elements_mapping.find(element); AKANTU_DEBUG_ASSERT(eit != elements_mapping.end(), "There is an unknown element (" << element << ") in the in the ELSET " << el_grp->getName() << "."); el_grp->add(eit->second, true, false); } }; /* ------------------------------------------------------------------------ */ struct lazy_node_group_create_ { template struct result { typedef NodeGroup & type; }; template NodeGroup & operator()(Mesh & mesh, const S & name) const { typename Mesh::node_group_iterator ng_it = mesh.node_group_find(name); if (ng_it != mesh.node_group_end()) { return *ng_it->second; } else { return mesh.createNodeGroup(name, mesh.getSpatialDimension()); } } }; struct lazy_add_node_to_group_ { template struct result { typedef void type; }; template void operator()(NG * node_grp, const ID & node, const Map & nodes_mapping) const { typename Map::const_iterator nit = nodes_mapping.find(node); AKANTU_DEBUG_ASSERT(nit != nodes_mapping.end(), "There is an unknown node in the in the NSET " << node_grp->getName() << "."); node_grp->add(nit->second, false); } }; struct lazy_optimize_group_ { template struct result { typedef void type; }; template void operator()(G * grp) const { grp->optimize(); } }; } /* -------------------------------------------------------------------------- */ template struct AbaqusSkipper : qi::grammar { AbaqusSkipper() : AbaqusSkipper::base_type(skip, "abaqus_skipper") { /* clang-format off */ skip = (ascii::space - spirit::eol) | "**" >> *(qi::char_ - spirit::eol) >> spirit::eol ; /* clang-format on */ } qi::rule skip; }; /* -------------------------------------------------------------------------- */ template > struct AbaqusMeshGrammar : qi::grammar { public: AbaqusMeshGrammar(Mesh & mesh) : AbaqusMeshGrammar::base_type(start, "abaqus_mesh_reader"), mesh(mesh) { phx::function const error_handler = mesh_io_abaqus_lazy_eval::mesh_abaqus_error_handler_(); phx::function lazy_element_read; phx::function lazy_node_read; phx::function lazy_element_group_create; phx::function lazy_add_element_to_group; phx::function lazy_node_group_create; phx::function lazy_add_node_to_group; phx::function lazy_optimize_group; /* clang-format off */ start = *( (qi::char_('*') > ( (qi::no_case[ qi::lit("node output") ] > any_section) | (qi::no_case[ qi::lit("element output") ] > any_section) | (qi::no_case[ qi::lit("node") ] > nodes) | (qi::no_case[ qi::lit("element") ] > elements) | (qi::no_case[ qi::lit("heading") ] > header) | (qi::no_case[ qi::lit("elset") ] > elements_set) | (qi::no_case[ qi::lit("nset") ] > nodes_set) | (qi::no_case[ qi::lit("material") ] > material) | (keyword > any_section) ) ) | spirit::eol ) ; header = spirit::eol > *any_line ; nodes = *(qi::char_(',') >> option) >> spirit::eol >> *( (qi::int_ > node_position) [ lazy_node_read(phx::ref(mesh), lbs::_1, lbs::_2, phx::ref(abaqus_nodes_to_akantu)) ] >> spirit::eol ) ; elements = ( ( qi::char_(',') >> qi::no_case[qi::lit("type")] >> '=' >> abaqus_element_type [ lbs::_a = lbs::_1 ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol >> *( (qi::int_ > connectivity) [ lazy_element_read(phx::ref(mesh), lbs::_a, lbs::_1, lbs::_2, phx::cref(abaqus_nodes_to_akantu), phx::ref(abaqus_elements_to_akantu)) ] >> spirit::eol ) ; elements_set = ( ( ( qi::char_(',') >> qi::no_case[ qi::lit("elset") ] >> '=' >> value [ lbs::_a = &lazy_element_group_create(phx::ref(mesh), lbs::_1) ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol >> qi::skip (qi::char_(',') | qi::space) [ +(qi::int_ [ lazy_add_element_to_group(lbs::_a, lbs::_1, phx::cref(abaqus_elements_to_akantu) ) ] ) ] ) [ lazy_optimize_group(lbs::_a) ] ; nodes_set = ( ( ( qi::char_(',') >> qi::no_case[ qi::lit("nset") ] >> '=' >> value [ lbs::_a = &lazy_node_group_create(phx::ref(mesh), lbs::_1) ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol >> qi::skip (qi::char_(',') | qi::space) [ +(qi::int_ [ lazy_add_node_to_group(lbs::_a, lbs::_1, phx::cref(abaqus_nodes_to_akantu) ) ] ) ] ) [ lazy_optimize_group(lbs::_a) ] ; material = ( ( qi::char_(',') >> qi::no_case[ qi::lit("name") ] >> '=' >> value [ phx::push_back(phx::ref(material_names), lbs::_1) ] ) ^ *(qi::char_(',') >> option) ) >> spirit::eol; ; node_position = +(qi::char_(',') > real [ phx::push_back(lbs::_val, lbs::_1) ]) ; connectivity = +(qi::char_(',') > qi::int_ [ phx::push_back(lbs::_val, lbs::_1) ]) ; any_section = *(qi::char_(',') >> option) > spirit::eol > *any_line ; any_line = *(qi::char_ - spirit::eol - qi::char_('*')) >> spirit::eol ; keyword = qi::lexeme[ +(qi::char_ - (qi::char_('*') | spirit::eol)) ] ; option = key > -( '=' >> value ); key = qi::char_("a-zA-Z_") >> *(qi::char_("a-zA-Z_0-9") | qi::char_('-')) ; value = key.alias() ; BOOST_SPIRIT_DEBUG_NODE(start); abaqus_element_type.add #if defined(AKANTU_STRUCTURAL_MECHANICS) ("BE21" , _bernoulli_beam_2) ("BE31" , _bernoulli_beam_3) #endif ("T3D2" , _segment_2) // Gmsh generates this elements ("T3D3" , _segment_3) // Gmsh generates this elements ("CPE3" , _triangle_3) ("CPS3" , _triangle_3) ("DC2D3" , _triangle_3) ("CPE6" , _triangle_6) ("CPS6" , _triangle_6) ("DC2D6" , _triangle_6) ("CPE4" , _quadrangle_4) ("CPS4" , _quadrangle_4) ("DC2D4" , _quadrangle_4) ("CPE8" , _quadrangle_8) ("CPS8" , _quadrangle_8) ("DC2D8" , _quadrangle_8) ("C3D4" , _tetrahedron_4) ("DC3D4" , _tetrahedron_4) ("C3D8" , _hexahedron_8) ("C3D8R" , _hexahedron_8) ("DC3D8" , _hexahedron_8) ("C3D10" , _tetrahedron_10) ("DC3D10", _tetrahedron_10); qi::on_error(start, error_handler(lbs::_4, lbs::_3, lbs::_2)); start .name("abaqus-start-rule"); connectivity .name("abaqus-connectivity"); node_position .name("abaqus-nodes-position"); nodes .name("abaqus-nodes"); any_section .name("abaqus-any_section"); header .name("abaqus-header"); material .name("abaqus-material"); elements .name("abaqus-elements"); elements_set .name("abaqus-elements-set"); nodes_set .name("abaqus-nodes-set"); key .name("abaqus-key"); value .name("abaqus-value"); option .name("abaqus-option"); keyword .name("abaqus-keyword"); any_line .name("abaqus-any-line"); abaqus_element_type.name("abaqus-element-type"); /* clang-format on */ } public: AKANTU_GET_MACRO(MaterialNames, material_names, const std::vector &); /* ------------------------------------------------------------------------ */ /* Rules */ /* ------------------------------------------------------------------------ */ private: qi::rule start; qi::rule(), Skipper> connectivity; qi::rule(), Skipper> node_position; qi::rule nodes, any_section, header, material; qi::rule, Skipper> elements; qi::rule, Skipper> elements_set; qi::rule, Skipper> nodes_set; qi::rule key, value, option, keyword, any_line; qi::real_parser > real; qi::symbols abaqus_element_type; /* ------------------------------------------------------------------------ */ /* Mambers */ /* ------------------------------------------------------------------------ */ private: /// reference to the mesh to read Mesh & mesh; /// correspondance between the numbering of nodes in the abaqus file and in /// the akantu mesh std::map abaqus_nodes_to_akantu; /// correspondance between the element number in the abaqus file and the /// Element in the akantu mesh std::map abaqus_elements_to_akantu; /// list of the material names std::vector material_names; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void MeshIOAbaqus::read(const std::string & filename, Mesh & mesh) { namespace spirit = boost::spirit; namespace qi = boost::spirit::qi; namespace lbs = boost::spirit::qi::labels; namespace ascii = boost::spirit::ascii; namespace phx = boost::phoenix; std::ifstream infile; infile.open(filename.c_str()); if (!infile.good()) { AKANTU_DEBUG_ERROR("Cannot open file " << filename); } std::string storage; // We will read the contents here. infile.unsetf(std::ios::skipws); // No white space skipping! std::copy(std::istream_iterator(infile), std::istream_iterator(), std::back_inserter(storage)); typedef std::string::const_iterator iterator_t; typedef AbaqusSkipper skipper; typedef AbaqusMeshGrammar grammar; grammar g(mesh); skipper ws; iterator_t iter = storage.begin(); iterator_t end = storage.end(); qi::phrase_parse(iter, end, g, ws); std::vector::const_iterator mnit = g.getMaterialNames().begin(); std::vector::const_iterator mnend = g.getMaterialNames().end(); + MeshAccessor mesh_accessor(mesh); + for (; mnit != mnend; ++mnit) { Mesh::element_group_iterator eg_it = mesh.element_group_find(*mnit); ElementGroup & eg = *eg_it->second; if (eg_it != mesh.element_group_end()) { ElementGroup::type_iterator tit = eg.firstType(); ElementGroup::type_iterator tend = eg.lastType(); for (; tit != tend; ++tit) { Array & abaqus_material = - this->getData(mesh, "abaqus_material", *tit); + mesh_accessor.getData("abaqus_material", *tit); ElementGroup::const_element_iterator eit = eg.element_begin(*tit); ElementGroup::const_element_iterator eend = eg.element_end(*tit); for (; eit != eend; ++eit) { abaqus_material(*eit) = *mnit; } } } } - this->setNbGlobalNodes(mesh, mesh.getNodes().getSize()); + mesh_accessor.setNbGlobalNodes(mesh.getNodes().getSize()); MeshUtils::fillElementToSubElementsData(mesh); } __END_AKANTU__ diff --git a/src/io/mesh_io/mesh_io_abaqus.hh b/src/io/mesh_io/mesh_io_abaqus.hh index 3cd861fec..9500115fc 100644 --- a/src/io/mesh_io/mesh_io_abaqus.hh +++ b/src/io/mesh_io/mesh_io_abaqus.hh @@ -1,60 +1,60 @@ /** * @file mesh_io_abaqus.hh * * @author Nicolas Richart * * @date creation: Sun Sep 26 2010 * @date last modification: Tue Jun 30 2015 * * @brief read a mesh from an abaqus input file * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "mesh_accessor.hh" #ifndef __AKANTU_MESH_IO_ABAQUS_HH__ #define __AKANTU_MESH_IO_ABAQUS_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -class MeshIOAbaqus : public MeshIO, private MeshAccessor { +class MeshIOAbaqus : public MeshIO { public: MeshIOAbaqus(); virtual ~MeshIOAbaqus(); /// read a mesh from the file virtual void read(const std::string & filename, Mesh & mesh); /// write a mesh to a file // virtual void write(const std::string & filename, const Mesh & mesh); private: /// correspondence between msh element types and akantu element types std::map _abaqus_to_akantu_element_types; }; __END_AKANTU__ #endif /* __AKANTU_MESH_IO_ABAQUS_HH__ */ diff --git a/src/mesh/group_manager.cc b/src/mesh/group_manager.cc index 3f992471c..55ec91269 100644 --- a/src/mesh/group_manager.cc +++ b/src/mesh/group_manager.cc @@ -1,1015 +1,1015 @@ /** * @file group_manager.cc * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Wed Nov 13 2013 * @date last modification: Mon Aug 17 2015 * * @brief Stores information about ElementGroup and NodeGroup * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "group_manager.hh" #include "mesh.hh" #include "aka_csr.hh" #include "mesh_utils.hh" #include "element_group.hh" #include "node_group.hh" #include "data_accessor.hh" #include "distributed_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include #include #include /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ GroupManager::GroupManager(const Mesh & mesh, const ID & id, const MemoryID & mem_id) : id(id), memory_id(mem_id), mesh(mesh) { AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ GroupManager::~GroupManager() { ElementGroups::iterator eit = element_groups.begin(); ElementGroups::iterator eend = element_groups.end(); for(; eit != eend ; ++eit) delete (eit->second); NodeGroups::iterator nit = node_groups.begin(); NodeGroups::iterator nend = node_groups.end(); for(; nit != nend ; ++nit) delete (nit->second); } /* -------------------------------------------------------------------------- */ NodeGroup & GroupManager::createNodeGroup(const std::string & group_name, bool replace_group) { AKANTU_DEBUG_IN(); NodeGroups::iterator it = node_groups.find(group_name); if(it != node_groups.end()) { if (replace_group) { it->second->empty(); AKANTU_DEBUG_OUT(); return *(it->second); } else AKANTU_EXCEPTION("Trying to create a node group that already exists:" << group_name); } std::stringstream sstr; sstr << this->id << ":" << group_name << "_node_group"; NodeGroup * node_group = new NodeGroup(group_name, mesh, sstr.str(), memory_id); node_groups[group_name] = node_group; AKANTU_DEBUG_OUT(); return *node_group; } /* -------------------------------------------------------------------------- */ template NodeGroup & GroupManager::createFilteredNodeGroup(const std::string & group_name, const NodeGroup & source_node_group, T & filter) { AKANTU_DEBUG_IN(); NodeGroup & node_group = this->createNodeGroup(group_name); node_group.append(source_node_group); if (T::type == FilterFunctor::_node_filter_functor) { node_group.applyNodeFilter(filter); } else { AKANTU_DEBUG_ERROR("ElementFilter cannot be applied to NodeGroup yet." << " Needs to be implemented."); } AKANTU_DEBUG_OUT(); return node_group; } /* -------------------------------------------------------------------------- */ void GroupManager::destroyNodeGroup(const std::string & group_name) { AKANTU_DEBUG_IN(); NodeGroups::iterator nit = node_groups.find(group_name); NodeGroups::iterator nend = node_groups.end(); if (nit != nend) { delete (nit->second); node_groups.erase(nit); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementGroup & GroupManager::createElementGroup(const std::string & group_name, UInt dimension, bool replace_group) { AKANTU_DEBUG_IN(); NodeGroup & new_node_group = createNodeGroup(group_name + "_nodes", replace_group); ElementGroups::iterator it = element_groups.find(group_name); if(it != element_groups.end()) { if (replace_group) { it->second->empty(); AKANTU_DEBUG_OUT(); return *(it->second); } else AKANTU_EXCEPTION("Trying to create a element group that already exists:" << group_name); } std::stringstream sstr; sstr << this->id << ":" << group_name << "_element_group"; ElementGroup * element_group = new ElementGroup(group_name, mesh, new_node_group, dimension, sstr.str(), memory_id); std::stringstream sstr_nodes; sstr_nodes << group_name << "_nodes"; node_groups[sstr_nodes.str()] = &new_node_group; element_groups[group_name] = element_group; AKANTU_DEBUG_OUT(); return *element_group; } /* -------------------------------------------------------------------------- */ void GroupManager::destroyElementGroup(const std::string & group_name, bool destroy_node_group) { AKANTU_DEBUG_IN(); ElementGroups::iterator eit = element_groups.find(group_name); ElementGroups::iterator eend = element_groups.end(); if (eit != eend) { if (destroy_node_group) destroyNodeGroup(eit->second->getNodeGroup().getName()); delete (eit->second); element_groups.erase(eit); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GroupManager::destroyAllElementGroups(bool destroy_node_groups) { AKANTU_DEBUG_IN(); ElementGroups::iterator eit = element_groups.begin(); ElementGroups::iterator eend = element_groups.end(); for(; eit != eend ; ++eit) { if (destroy_node_groups) destroyNodeGroup(eit->second->getNodeGroup().getName()); delete (eit->second); } element_groups.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementGroup & GroupManager::createElementGroup(const std::string & group_name, UInt dimension, NodeGroup & node_group) { AKANTU_DEBUG_IN(); if(element_groups.find(group_name) != element_groups.end()) AKANTU_EXCEPTION("Trying to create a element group that already exists:" << group_name); ElementGroup * element_group = new ElementGroup(group_name, mesh, node_group, dimension, id + ":" + group_name + "_element_group", memory_id); element_groups[group_name] = element_group; AKANTU_DEBUG_OUT(); return *element_group; } /* -------------------------------------------------------------------------- */ template ElementGroup & GroupManager::createFilteredElementGroup(const std::string & group_name, UInt dimension, const NodeGroup & node_group, T & filter) { AKANTU_DEBUG_IN(); ElementGroup * element_group = NULL; if (T::type == FilterFunctor::_node_filter_functor) { NodeGroup & filtered_node_group = this->createFilteredNodeGroup(group_name + "_nodes", node_group, filter); element_group = &(this->createElementGroup(group_name, dimension, filtered_node_group)); } else if (T::type == FilterFunctor::_element_filter_functor) { AKANTU_DEBUG_ERROR("Cannot handle an ElementFilter yet. Needs to be implemented."); } AKANTU_DEBUG_OUT(); return *element_group; } /* -------------------------------------------------------------------------- */ class ClusterSynchronizer : public DataAccessor { typedef std::set< std::pair > DistantIDs; public: ClusterSynchronizer(GroupManager & group_manager, UInt element_dimension, std::string cluster_name_prefix, ElementTypeMapArray & element_to_fragment, DistributedSynchronizer & distributed_synchronizer, UInt nb_cluster) : group_manager(group_manager), element_dimension(element_dimension), cluster_name_prefix(cluster_name_prefix), element_to_fragment(element_to_fragment), distributed_synchronizer(distributed_synchronizer), nb_cluster(nb_cluster) { } UInt synchronize() { StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt rank = comm.whoAmI(); UInt nb_proc = comm.getNbProc(); /// find starting index to renumber local clusters Array nb_cluster_per_proc(nb_proc); nb_cluster_per_proc(rank) = nb_cluster; - comm.allGather(nb_cluster_per_proc.storage(), 1); + comm.allGather(nb_cluster_per_proc); starting_index = std::accumulate(nb_cluster_per_proc.begin(), nb_cluster_per_proc.begin() + rank, 0); UInt global_nb_fragment = std::accumulate(nb_cluster_per_proc.begin() + rank, nb_cluster_per_proc.end(), starting_index); /// create the local to distant cluster pairs with neighbors distributed_synchronizer.computeBufferSize(*this, _gst_gm_clusters); distributed_synchronizer.asynchronousSynchronize(*this, _gst_gm_clusters); distributed_synchronizer.waitEndSynchronize(*this, _gst_gm_clusters); /// count total number of pairs Array nb_pairs(nb_proc); // This is potentially a bug for more than // 2**31 pairs, but due to a all gatherv after // it must be int to match MPI interfaces nb_pairs(rank) = distant_ids.size(); - comm.allGather(nb_pairs.storage(), 1); + comm.allGather(nb_pairs); UInt total_nb_pairs = std::accumulate(nb_pairs.begin(), nb_pairs.end(), 0); /// generate pairs global array UInt local_pair_index = std::accumulate(nb_pairs.storage(), nb_pairs.storage() + rank, 0); Array total_pairs(total_nb_pairs, 2); DistantIDs::iterator ids_it = distant_ids.begin(); DistantIDs::iterator ids_end = distant_ids.end(); for (; ids_it != ids_end; ++ids_it, ++local_pair_index) { total_pairs(local_pair_index, 0) = ids_it->first; total_pairs(local_pair_index, 1) = ids_it->second; } /// communicate pairs to all processors nb_pairs *= 2; - comm.allGatherV(total_pairs.storage(), nb_pairs.storage()); + comm.allGatherV(total_pairs, nb_pairs); /// renumber clusters /// generate fragment list std::vector< std::set > global_clusters; UInt total_nb_cluster = 0; Array is_fragment_in_cluster(global_nb_fragment, 1, false); std::queue fragment_check_list; while (total_pairs.getSize() != 0) { /// create a new cluster ++total_nb_cluster; global_clusters.resize(total_nb_cluster); std::set & current_cluster = global_clusters[total_nb_cluster - 1]; UInt first_fragment = total_pairs(0, 0); UInt second_fragment = total_pairs(0, 1); total_pairs.erase(0); fragment_check_list.push(first_fragment); fragment_check_list.push(second_fragment); while (!fragment_check_list.empty()) { UInt current_fragment = fragment_check_list.front(); UInt * total_pairs_end = total_pairs.storage() + total_pairs.getSize() * 2; UInt * fragment_found = std::find(total_pairs.storage(), total_pairs_end, current_fragment); if (fragment_found != total_pairs_end) { UInt position = fragment_found - total_pairs.storage(); UInt pair = position / 2; UInt other_index = (position + 1) % 2; fragment_check_list.push(total_pairs(pair, other_index)); total_pairs.erase(pair); } else { fragment_check_list.pop(); current_cluster.insert(current_fragment); is_fragment_in_cluster(current_fragment) = true; } } } /// add to FragmentToCluster all local fragments for (UInt c = 0; c < global_nb_fragment; ++c) { if (!is_fragment_in_cluster(c)) { ++total_nb_cluster; global_clusters.resize(total_nb_cluster); std::set & current_cluster = global_clusters[total_nb_cluster - 1]; current_cluster.insert(c); } } /// reorganize element groups to match global clusters for (UInt c = 0; c < global_clusters.size(); ++c) { /// create new element group corresponding to current cluster std::stringstream sstr; sstr << cluster_name_prefix << "_" << c; ElementGroup & cluster = group_manager.createElementGroup(sstr.str(), element_dimension, true); std::set::iterator it = global_clusters[c].begin(); std::set::iterator end = global_clusters[c].end(); /// append to current element group all fragments that belong to /// the same cluster if they exist for (; it != end; ++it) { Int local_index = *it - starting_index; if (local_index < 0 || local_index >= Int(nb_cluster)) continue; std::stringstream tmp_sstr; tmp_sstr << "tmp_" << cluster_name_prefix << "_" << local_index; GroupManager::element_group_iterator eg_it = group_manager.element_group_find(tmp_sstr.str()); AKANTU_DEBUG_ASSERT(eg_it != group_manager.element_group_end(), "Temporary fragment \""<< tmp_sstr.str() << "\" not found"); cluster.append(*(eg_it->second)); group_manager.destroyElementGroup(tmp_sstr.str(), true); } } return total_nb_cluster; } private: /// functions for parallel communications inline UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const { if (tag == _gst_gm_clusters) return elements.getSize() * sizeof(UInt); return 0; } inline void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const { if (tag != _gst_gm_clusters) return; Array::const_iterator<> el_it = elements.begin(); Array::const_iterator<> el_end = elements.end(); for (; el_it != el_end; ++el_it) { const Element & el = *el_it; /// for each element pack its global cluster index buffer << element_to_fragment(el.type, el.ghost_type)(el.element) + starting_index; } } inline void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) { if (tag != _gst_gm_clusters) return; Array::const_iterator<> el_it = elements.begin(); Array::const_iterator<> el_end = elements.end(); for (; el_it != el_end; ++el_it) { UInt distant_cluster; buffer >> distant_cluster; const Element & el = *el_it; UInt local_cluster = element_to_fragment(el.type, el.ghost_type)(el.element) + starting_index; distant_ids.insert(std::make_pair(local_cluster, distant_cluster)); } } private: GroupManager & group_manager; UInt element_dimension; std::string cluster_name_prefix; ElementTypeMapArray & element_to_fragment; DistributedSynchronizer & distributed_synchronizer; UInt nb_cluster; DistantIDs distant_ids; UInt starting_index; }; /* -------------------------------------------------------------------------- */ /// \todo this function doesn't work in 1D UInt GroupManager::createBoundaryGroupFromGeometry() { UInt spatial_dimension = mesh.getSpatialDimension(); return createClusters(spatial_dimension - 1, "boundary"); } /* -------------------------------------------------------------------------- */ //// \todo if needed element list construction can be optimized by //// templating the filter class UInt GroupManager::createClusters(UInt element_dimension, std::string cluster_name_prefix, const GroupManager::ClusteringFilter & filter, DistributedSynchronizer * distributed_synchronizer, Mesh * mesh_facets) { AKANTU_DEBUG_IN(); UInt nb_proc = StaticCommunicator::getStaticCommunicator().getNbProc(); std::string tmp_cluster_name_prefix = cluster_name_prefix; ElementTypeMapArray * element_to_fragment = NULL; if (nb_proc > 1 && distributed_synchronizer) { element_to_fragment = new ElementTypeMapArray; mesh.initElementTypeMapArray(*element_to_fragment, 1, element_dimension, false, _ek_not_defined, true); tmp_cluster_name_prefix = "tmp_" + tmp_cluster_name_prefix; } /// Get facets bool mesh_facets_created = false; if (!mesh_facets && element_dimension > 0) { mesh_facets = new Mesh(mesh.getSpatialDimension(), mesh.getNodes().getID(), "mesh_facets_for_clusters"); mesh_facets->defineMeshParent(mesh); MeshUtils::buildAllFacets(mesh, *mesh_facets, element_dimension, element_dimension - 1, distributed_synchronizer); } ElementTypeMapArray seen_elements("seen_elements"); mesh.initElementTypeMapArray(seen_elements, 1, element_dimension, false, _ek_not_defined, true); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Element el; el.ghost_type = ghost_type; Mesh::type_iterator type_it = mesh.firstType(element_dimension, ghost_type, _ek_not_defined); Mesh::type_iterator type_end = mesh.lastType (element_dimension, ghost_type, _ek_not_defined); for (; type_it != type_end; ++type_it) { el.type = *type_it; el.kind = Mesh::getKind(*type_it); UInt nb_element = mesh.getNbElement(*type_it, ghost_type); Array & seen_elements_array = seen_elements(el.type, ghost_type); for (UInt e = 0; e < nb_element; ++e) { el.element = e; if (!filter(el)) seen_elements_array(e) = true; } } } Array checked_node(mesh.getNbNodes(), 1, false); UInt nb_cluster = 0; /// keep looping until all elements are seen for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Element uns_el; uns_el.ghost_type = ghost_type; Mesh::type_iterator type_it = mesh.firstType(element_dimension, ghost_type, _ek_not_defined); Mesh::type_iterator type_end = mesh.lastType(element_dimension, ghost_type, _ek_not_defined); for (; type_it != type_end; ++type_it) { uns_el.type = *type_it; Array & seen_elements_vec = seen_elements(uns_el.type, uns_el.ghost_type); for (UInt e = 0; e < seen_elements_vec.getSize(); ++e) { // skip elements that have been already seen if (seen_elements_vec(e) == true) continue; // set current element uns_el.element = e; seen_elements_vec(e) = true; /// create a new cluster std::stringstream sstr; sstr << tmp_cluster_name_prefix << "_" << nb_cluster; ElementGroup & cluster = createElementGroup(sstr.str(), element_dimension, true); ++nb_cluster; // point element are cluster by themself if(element_dimension == 0) { cluster.add(uns_el); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(uns_el.type); Vector connect = mesh.getConnectivity(uns_el.type, uns_el.ghost_type).begin(nb_nodes_per_element)[uns_el.element]; for (UInt n = 0; n < nb_nodes_per_element; ++n) { /// add element's nodes to the cluster UInt node = connect[n]; if (!checked_node(node)) { cluster.addNode(node); checked_node(node) = true; } } continue; } std::queue element_to_add; element_to_add.push(uns_el); /// keep looping until current cluster is complete (no more /// connected elements) while(!element_to_add.empty()) { /// take first element and erase it in the queue Element el = element_to_add.front(); element_to_add.pop(); /// if parallel, store cluster index per element if (nb_proc > 1 && distributed_synchronizer) (*element_to_fragment)(el.type, el.ghost_type)(el.element) = nb_cluster - 1; /// add current element to the cluster cluster.add(el); const Array & element_to_facet = mesh_facets->getSubelementToElement(el.type, el.ghost_type); UInt nb_facet_per_element = element_to_facet.getNbComponent(); for (UInt f = 0; f < nb_facet_per_element; ++f) { const Element & facet = element_to_facet(el.element, f); if (facet == ElementNull) continue; const std::vector & connected_elements = mesh_facets->getElementToSubelement(facet.type, facet.ghost_type)(facet.element); for (UInt elem = 0; elem < connected_elements.size(); ++elem) { const Element & check_el = connected_elements[elem]; // check if this element has to be skipped if (check_el == ElementNull || check_el == el) continue; Array & seen_elements_vec_current = seen_elements(check_el.type, check_el.ghost_type); if (seen_elements_vec_current(check_el.element) == false) { seen_elements_vec_current(check_el.element) = true; element_to_add.push(check_el); } } } UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type); Vector connect = mesh.getConnectivity(el.type, el.ghost_type).begin(nb_nodes_per_element)[el.element]; for (UInt n = 0; n < nb_nodes_per_element; ++n) { /// add element's nodes to the cluster UInt node = connect[n]; if (!checked_node(node)) { cluster.addNode(node, false); checked_node(node) = true; } } } } } } if (nb_proc > 1 && distributed_synchronizer) { ClusterSynchronizer cluster_synchronizer(*this, element_dimension, cluster_name_prefix, *element_to_fragment, *distributed_synchronizer, nb_cluster); nb_cluster = cluster_synchronizer.synchronize(); delete element_to_fragment; } if (mesh_facets_created) delete mesh_facets; if(mesh.isDistributed()) this->synchronizeGroupNames(); AKANTU_DEBUG_OUT(); return nb_cluster; } /* -------------------------------------------------------------------------- */ template void GroupManager::createGroupsFromMeshData(const std::string & dataset_name) { std::set group_names; const ElementTypeMapArray & datas = mesh.getData(dataset_name); typedef typename ElementTypeMapArray::type_iterator type_iterator; std::map group_dim; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { type_iterator type_it = datas.firstType(_all_dimensions, *gt); type_iterator type_end = datas.lastType(_all_dimensions, *gt); for (; type_it != type_end; ++type_it) { const Array & dataset = datas(*type_it, *gt); UInt nb_element = mesh.getNbElement(*type_it, *gt); AKANTU_DEBUG_ASSERT(dataset.getSize() == nb_element, "Not the same number of elements ("<< *type_it << ":" << *gt << ") in the map from MeshData (" << dataset.getSize() << ") " << dataset_name <<" and in the mesh (" << nb_element << ")!"); for(UInt e(0); e < nb_element; ++e) { std::stringstream sstr; sstr << dataset(e); std::string gname = sstr.str(); group_names.insert(gname); std::map::iterator it = group_dim.find(gname); if(it == group_dim.end()) { group_dim[gname] = mesh.getSpatialDimension(*type_it); } else { it->second = std::max(it->second, mesh.getSpatialDimension(*type_it)); } } } } std::set::iterator git = group_names.begin(); std::set::iterator gend = group_names.end(); for (;git != gend; ++git) createElementGroup(*git, group_dim[*git]); if(mesh.isDistributed()) this->synchronizeGroupNames(); Element el; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { el.ghost_type = *gt; type_iterator type_it = datas.firstType(_all_dimensions, *gt); type_iterator type_end = datas.lastType(_all_dimensions, *gt); for (; type_it != type_end; ++type_it) { el.type = *type_it; const Array & dataset = datas(*type_it, *gt); UInt nb_element = mesh.getNbElement(*type_it, *gt); AKANTU_DEBUG_ASSERT(dataset.getSize() == nb_element, "Not the same number of elements in the map from MeshData and in the mesh!"); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(el.type); Array::const_iterator< Vector > cit = mesh.getConnectivity(*type_it, *gt).begin(nb_nodes_per_element); for(UInt e(0); e < nb_element; ++e, ++cit) { el.element = e; std::stringstream sstr; sstr << dataset(e); ElementGroup & group = getElementGroup(sstr.str()); group.add(el, false, false); const Vector & connect = *cit; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connect[n]; group.addNode(node, false); } } } } git = group_names.begin(); for (;git != gend; ++git) { getElementGroup(*git).optimize(); } } template void GroupManager::createGroupsFromMeshData(const std::string & dataset_name); template void GroupManager::createGroupsFromMeshData(const std::string & dataset_name); /* -------------------------------------------------------------------------- */ void GroupManager::createElementGroupFromNodeGroup(const std::string & name, const std::string & node_group_name, UInt dimension) { NodeGroup & node_group = getNodeGroup(node_group_name); ElementGroup & group = createElementGroup(name, dimension, node_group); group.fillFromNodeGroup(); } /* -------------------------------------------------------------------------- */ void GroupManager::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "GroupManager [" << std::endl; std::set node_group_seen; for(const_element_group_iterator it(element_group_begin()); it != element_group_end(); ++it) { it->second->printself(stream, indent + 1); node_group_seen.insert(it->second->getNodeGroup().getName()); } for(const_node_group_iterator it(node_group_begin()); it != node_group_end(); ++it) { if(node_group_seen.find(it->second->getName()) == node_group_seen.end()) it->second->printself(stream, indent + 1); } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ UInt GroupManager::getNbElementGroups(UInt dimension) const { if(dimension == _all_dimensions) return element_groups.size(); ElementGroups::const_iterator it = element_groups.begin(); ElementGroups::const_iterator end = element_groups.end(); UInt count = 0; for(;it != end; ++it) count += (it->second->getDimension() == dimension); return count; } /* -------------------------------------------------------------------------- */ void GroupManager::checkAndAddGroups(CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); UInt nb_node_group; buffer >> nb_node_group; AKANTU_DEBUG_INFO("Received " << nb_node_group << " node group names"); for (UInt ng = 0; ng < nb_node_group; ++ng) { std::string node_group_name; buffer >> node_group_name; if(node_groups.find(node_group_name) == node_groups.end()) { this->createNodeGroup(node_group_name); } AKANTU_DEBUG_INFO("Received node goup name: " << node_group_name); } UInt nb_element_group; buffer >> nb_element_group; AKANTU_DEBUG_INFO("Received " << nb_element_group << " element group names"); for (UInt eg = 0; eg < nb_element_group; ++eg) { std::string element_group_name; buffer >> element_group_name; std::string node_group_name; buffer >> node_group_name; UInt dim; buffer >> dim; AKANTU_DEBUG_INFO("Received element group name: " << element_group_name << " corresponding to a " << Int(dim) << "D group with node group " << node_group_name); NodeGroup & node_group = *node_groups[node_group_name]; if(element_groups.find(element_group_name) == element_groups.end()) { this->createElementGroup(element_group_name, dim, node_group); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GroupManager::fillBufferWithGroupNames(DynamicCommunicationBuffer & comm_buffer) const { AKANTU_DEBUG_IN(); // packing node group names; UInt nb_groups = this->node_groups.size(); comm_buffer << nb_groups; AKANTU_DEBUG_INFO("Sending " << nb_groups << " node group names"); NodeGroups::const_iterator nnames_it = node_groups.begin(); NodeGroups::const_iterator nnames_end = node_groups.end(); for (; nnames_it != nnames_end; ++nnames_it) { std::string node_group_name = nnames_it->first; comm_buffer << node_group_name; AKANTU_DEBUG_INFO("Sending node goupe name: " << node_group_name); } // packing element group names with there associated node group name nb_groups = this->element_groups.size(); comm_buffer << nb_groups; AKANTU_DEBUG_INFO("Sending " << nb_groups << " element group names"); ElementGroups::const_iterator gnames_it = this->element_groups.begin(); ElementGroups::const_iterator gnames_end = this->element_groups.end(); for (; gnames_it != gnames_end; ++gnames_it) { ElementGroup & element_group = *(gnames_it->second); std::string element_group_name = gnames_it->first; std::string node_group_name = element_group.getNodeGroup().getName(); UInt dim = element_group.getDimension(); comm_buffer << element_group_name; comm_buffer << node_group_name; comm_buffer << dim; AKANTU_DEBUG_INFO("Sending element group name: " << element_group_name << " corresponding to a " << Int(dim) << "D group with the node group " << node_group_name); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void GroupManager::synchronizeGroupNames() { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - UInt nb_proc = comm.getNbProc(); - UInt my_rank = comm.whoAmI(); + Int nb_proc = comm.getNbProc(); + Int my_rank = comm.whoAmI(); if(nb_proc == 1) return; if(my_rank == 0) { - for (UInt p = 1; p < nb_proc; ++p) { + for (Int p = 1; p < nb_proc; ++p) { CommunicationStatus status; comm.probe(p, p, status); AKANTU_DEBUG_INFO("Got " << printMemorySize(status.getSize()) << " from proc " << p); CommunicationBuffer recv_buffer(status.getSize()); - comm.receive(recv_buffer.storage(), recv_buffer.getSize(), p, p); + comm.receive(recv_buffer, p, p); this->checkAndAddGroups(recv_buffer); } DynamicCommunicationBuffer comm_buffer; this->fillBufferWithGroupNames(comm_buffer); UInt buffer_size = comm_buffer.getSize(); - comm.broadcast(&buffer_size, 1, 0); + comm.broadcast(buffer_size, 0); AKANTU_DEBUG_INFO("Initiating broadcast with " << printMemorySize(comm_buffer.getSize())); - comm.broadcast(comm_buffer.storage(), buffer_size, 0); + comm.broadcast(comm_buffer, 0); } else { DynamicCommunicationBuffer comm_buffer; this->fillBufferWithGroupNames(comm_buffer); AKANTU_DEBUG_INFO("Sending " << printMemorySize(comm_buffer.getSize()) << " to proc " << 0); - comm.send(comm_buffer.storage(), comm_buffer.getSize(), 0, my_rank); + comm.send(comm_buffer, 0, my_rank); UInt buffer_size = 0; - comm.broadcast(&buffer_size, 1, 0); + comm.broadcast(buffer_size, 0); AKANTU_DEBUG_INFO("Receiving broadcast with " << printMemorySize(comm_buffer.getSize())); CommunicationBuffer recv_buffer(buffer_size); - comm.broadcast(recv_buffer.storage(), recv_buffer.getSize(), 0); + comm.broadcast(recv_buffer, 0); this->checkAndAddGroups(recv_buffer); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ const ElementGroup & GroupManager::getElementGroup(const std::string & name) const { const_element_group_iterator it = element_group_find(name); if(it == element_group_end()) { AKANTU_EXCEPTION("There are no element groups named " << name << " associated to the group manager: " << id); } return *(it->second); } /* -------------------------------------------------------------------------- */ ElementGroup & GroupManager::getElementGroup(const std::string & name) { element_group_iterator it = element_group_find(name); if(it == element_group_end()) { AKANTU_EXCEPTION("There are no element groups named " << name << " associated to the group manager: " << id); } return *(it->second); } /* -------------------------------------------------------------------------- */ const NodeGroup & GroupManager::getNodeGroup(const std::string & name) const { const_node_group_iterator it = node_group_find(name); if(it == node_group_end()) { AKANTU_EXCEPTION("There are no node groups named " << name << " associated to the group manager: " << id); } return *(it->second); } /* -------------------------------------------------------------------------- */ NodeGroup & GroupManager::getNodeGroup(const std::string & name) { node_group_iterator it = node_group_find(name); if(it == node_group_end()) { AKANTU_EXCEPTION("There are no node groups named " << name << " associated to the group manager: " << id); } return *(it->second); } __END_AKANTU__ diff --git a/src/mesh/group_manager.hh b/src/mesh/group_manager.hh index 28d484fba..f3a67b0cf 100644 --- a/src/mesh/group_manager.hh +++ b/src/mesh/group_manager.hh @@ -1,305 +1,299 @@ /** * @file group_manager.hh * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Wed Nov 13 2013 * @date last modification: Mon Nov 16 2015 * - * @brief Stores information relevent to the notion of element and nodes groups. + * @brief Stores information relevent to the notion of element and nodes + *groups. * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_GROUP_MANAGER_HH__ #define __AKANTU_GROUP_MANAGER_HH__ -#include +/* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "element_type_map.hh" -//#include "dumpable.hh" +/* -------------------------------------------------------------------------- */ +#include +/* -------------------------------------------------------------------------- */ -__BEGIN_AKANTU__ -/* -------------------------------------------------------------------------- */ -class FEM; -class ElementGroup; -class NodeGroup; -class Mesh; -class Element; -class DistributedSynchronizer; -template class CommunicationBufferTemplated; - -namespace dumper { - class Field; +namespace akantu { + class FEM; + class ElementGroup; + class NodeGroup; + class Mesh; + class Element; + class DistributedSynchronizer; + template class CommunicationBufferTemplated; + namespace dumper { + class Field; + } } -/* -------------------------------------------------------------------------- */ +__BEGIN_AKANTU__ + +/* -------------------------------------------------------------------------- */ class GroupManager { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ private: typedef std::map ElementGroups; typedef std::map NodeGroups; public: typedef std::set GroupManagerTypeSet; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - GroupManager(const Mesh & mesh, - const ID & id = "group_manager", - const MemoryID & memory_id = 0); + GroupManager(const Mesh & mesh, const ID & id = "group_manager", + const MemoryID & memory_id = 0); virtual ~GroupManager(); /* ------------------------------------------------------------------------ */ /* Groups iterators */ /* ------------------------------------------------------------------------ */ public: typedef NodeGroups::iterator node_group_iterator; typedef ElementGroups::iterator element_group_iterator; typedef NodeGroups::const_iterator const_node_group_iterator; typedef ElementGroups::const_iterator const_element_group_iterator; #ifndef SWIG -#define AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(group_type, \ - function, \ - param_in, \ - param_out) \ - inline BOOST_PP_CAT(BOOST_PP_CAT(const_, group_type), _iterator) \ - BOOST_PP_CAT(BOOST_PP_CAT(group_type, _), function)(param_in) const { \ - return BOOST_PP_CAT(group_type, s).function(param_out); \ - }; \ - \ - inline BOOST_PP_CAT(group_type, _iterator) \ - BOOST_PP_CAT(BOOST_PP_CAT(group_type, _), function)(param_in) { \ - return BOOST_PP_CAT(group_type, s).function(param_out); \ +#define AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(group_type, function, \ + param_in, param_out) \ + inline BOOST_PP_CAT(BOOST_PP_CAT(const_, group_type), _iterator) \ + BOOST_PP_CAT(BOOST_PP_CAT(group_type, _), function)(param_in) const { \ + return BOOST_PP_CAT(group_type, s).function(param_out); \ + }; \ + \ + inline BOOST_PP_CAT(group_type, _iterator) \ + BOOST_PP_CAT(BOOST_PP_CAT(group_type, _), function)(param_in) { \ + return BOOST_PP_CAT(group_type, s).function(param_out); \ } #define AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(group_type, function) \ - AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(group_type, function, BOOST_PP_EMPTY(), BOOST_PP_EMPTY()) + AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION( \ + group_type, function, BOOST_PP_EMPTY(), BOOST_PP_EMPTY()) AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(node_group, begin); - AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(node_group, end ); + AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(node_group, end); AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(element_group, begin); - AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(element_group, end ); - AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(element_group, find, const std::string & name, name); - AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(node_group, find, const std::string & name, name); + AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION_NP(element_group, end); + AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(element_group, find, + const std::string & name, name); + AKANTU_GROUP_MANAGER_DEFINE_ITERATOR_FUNCTION(node_group, find, + const std::string & name, name); #endif /* ------------------------------------------------------------------------ */ /* Clustering filter */ /* ------------------------------------------------------------------------ */ public: - class ClusteringFilter { public: - virtual bool operator() (const Element &) const { - return true; - } + virtual bool operator()(const Element &) const { return true; } }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - /// create an empty node group NodeGroup & createNodeGroup(const std::string & group_name, - bool replace_group = false); - + bool replace_group = false); + /// create a node group from another node group but filtered template NodeGroup & createFilteredNodeGroup(const std::string & group_name, - const NodeGroup & node_group, - T & filter); + const NodeGroup & node_group, T & filter); /// destroy a node group void destroyNodeGroup(const std::string & group_name); - /// create an element group and the associated node group ElementGroup & createElementGroup(const std::string & group_name, - UInt dimension = _all_dimensions, - bool replace_group = false); + UInt dimension = _all_dimensions, + bool replace_group = false); /// create an element group from another element group but filtered template - ElementGroup & createFilteredElementGroup(const std::string & group_name, - UInt dimension, - const NodeGroup & node_group, - T & filter); + ElementGroup & + createFilteredElementGroup(const std::string & group_name, UInt dimension, + const NodeGroup & node_group, T & filter); /// destroy an element group and the associated node group void destroyElementGroup(const std::string & group_name, - bool destroy_node_group = false); + bool destroy_node_group = false); /// destroy all element groups and the associated node groups void destroyAllElementGroups(bool destroy_node_groups = false); /// create a element group using an existing node group ElementGroup & createElementGroup(const std::string & group_name, - UInt dimension, - NodeGroup & node_group); + UInt dimension, NodeGroup & node_group); /// create groups based on values stored in a given mesh data template void createGroupsFromMeshData(const std::string & dataset_name); /// create boundaries group by a clustering algorithm \todo extend to parallel UInt createBoundaryGroupFromGeometry(); /// create element clusters for a given dimension UInt createClusters(UInt element_dimension, - std::string cluster_name_prefix = "cluster", - const ClusteringFilter & filter = ClusteringFilter(), - DistributedSynchronizer * distributed_synchronizer = NULL, - Mesh * mesh_facets = NULL); + std::string cluster_name_prefix = "cluster", + const ClusteringFilter & filter = ClusteringFilter(), + DistributedSynchronizer * distributed_synchronizer = NULL, + Mesh * mesh_facets = NULL); /// Create an ElementGroup based on a NodeGroup void createElementGroupFromNodeGroup(const std::string & name, - const std::string & node_group, - UInt dimension = _all_dimensions); + const std::string & node_group, + UInt dimension = _all_dimensions); virtual void printself(std::ostream & stream, int indent = 0) const; /// this function insure that the group names are present on all processors /// /!\ it is a SMP call void synchronizeGroupNames(); - /// register an elemental field to the given group name (overloading for ElementalPartionField) +/// register an elemental field to the given group name (overloading for +/// ElementalPartionField) #ifndef SWIG template class dump_type> - inline dumper::Field * createElementalField(const ElementTypeMapArray & field, - const std::string & group_name, - UInt spatial_dimension, - const ElementKind & kind, - ElementTypeMap nb_data_per_elem = ElementTypeMap()); - - /// register an elemental field to the given group name (overloading for ElementalField) - template class ret_type, template class,bool> class dump_type> - inline dumper::Field * createElementalField(const ElementTypeMapArray & field, - const std::string & group_name, - UInt spatial_dimension, - const ElementKind & kind, - ElementTypeMap nb_data_per_elem = ElementTypeMap()); - - /// register an elemental field to the given group name (overloading for MaterialInternalField) + inline dumper::Field * createElementalField( + const ElementTypeMapArray & field, const std::string & group_name, + UInt spatial_dimension, const ElementKind & kind, + ElementTypeMap nb_data_per_elem = ElementTypeMap()); + + /// register an elemental field to the given group name (overloading for + /// ElementalField) + template class ret_type, + template class, bool> class dump_type> + inline dumper::Field * createElementalField( + const ElementTypeMapArray & field, const std::string & group_name, + UInt spatial_dimension, const ElementKind & kind, + ElementTypeMap nb_data_per_elem = ElementTypeMap()); + + /// register an elemental field to the given group name (overloading for + /// MaterialInternalField) template class dump_type> - inline dumper::Field * createElementalField(const ElementTypeMapArray & field, - const std::string & group_name, - UInt spatial_dimension, - const ElementKind & kind, - ElementTypeMap nb_data_per_elem); - - template class ftype> - inline dumper::Field * createNodalField(const ftype * field, - const std::string & group_name, - UInt padding_size = 0); - - template class ftype> - inline dumper::Field * createStridedNodalField(const ftype * field, - const std::string & group_name, - UInt size, UInt stride, - UInt padding_size); + /// type of InternalMaterialField + template class dump_type> + inline dumper::Field * + createElementalField(const ElementTypeMapArray & field, + const std::string & group_name, UInt spatial_dimension, + const ElementKind & kind, + ElementTypeMap nb_data_per_elem); + + template class ftype> + inline dumper::Field * createNodalField(const ftype * field, + const std::string & group_name, + UInt padding_size = 0); + + template class ftype> + inline dumper::Field * + createStridedNodalField(const ftype * field, + const std::string & group_name, UInt size, + UInt stride, UInt padding_size); protected: /// fill a buffer with all the group names - void fillBufferWithGroupNames(CommunicationBufferTemplated & comm_buffer) const; + void fillBufferWithGroupNames( + CommunicationBufferTemplated & comm_buffer) const; /// take a buffer and create the missing groups localy void checkAndAddGroups(CommunicationBufferTemplated & buffer); - - /// register an elemental field to the given group name - template - inline dumper::Field * createElementalField(const field_type & field, - const std::string & group_name, - UInt spatial_dimension, - const ElementKind & kind, - ElementTypeMap nb_data_per_elem); - + template + inline dumper::Field * + createElementalField(const field_type & field, const std::string & group_name, + UInt spatial_dimension, const ElementKind & kind, + ElementTypeMap nb_data_per_elem); /// register an elemental field to the given group name - template - inline dumper::Field * createElementalFilteredField(const field_type & field, - const std::string & group_name, - UInt spatial_dimension, - const ElementKind & kind, - ElementTypeMap nb_data_per_elem); + template + inline dumper::Field * + createElementalFilteredField(const field_type & field, + const std::string & group_name, + UInt spatial_dimension, const ElementKind & kind, + ElementTypeMap nb_data_per_elem); #endif /* ------------------------------------------------------------------------ */ /* Accessor */ /* ------------------------------------------------------------------------ */ public: const ElementGroup & getElementGroup(const std::string & name) const; - const NodeGroup & getNodeGroup(const std::string & name) const; + const NodeGroup & getNodeGroup(const std::string & name) const; ElementGroup & getElementGroup(const std::string & name); - NodeGroup & getNodeGroup(const std::string & name); - + NodeGroup & getNodeGroup(const std::string & name); UInt getNbElementGroups(UInt dimension = _all_dimensions) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id to create element and node groups ID id; /// memory_id to create element and node groups MemoryID memory_id; /// list of the node groups managed NodeGroups node_groups; /// list of the element groups managed ElementGroups element_groups; /// Mesh to which the element belongs const Mesh & mesh; }; /// standard output stream operator -inline std::ostream & operator <<(std::ostream & stream, const GroupManager & _this) -{ +inline std::ostream & operator<<(std::ostream & stream, + const GroupManager & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_GROUP_MANAGER_HH__ */ diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc index 370c81e91..7365f1ca0 100644 --- a/src/mesh/mesh.cc +++ b/src/mesh/mesh.cc @@ -1,467 +1,467 @@ /** * @file mesh.cc * * @author Guillaume Anciaux * @author David Simon Kammer * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Jan 22 2016 * * @brief class handling meshes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include "aka_config.hh" /* -------------------------------------------------------------------------- */ #include "mesh.hh" #include "group_manager_inline_impl.cc" #include "mesh_io.hh" #include "element_class.hh" #include "static_communicator.hh" #include "element_group.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumper_field.hh" #include "dumper_internal_material_field.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const Element ElementNull(_not_defined, 0); /* -------------------------------------------------------------------------- */ void Element::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Element [" << type << ", " << element << ", " << ghost_type << "]"; } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), GroupManager(*this, id + ":group_manager", memory_id), nodes_global_ids(NULL), nodes_type(0, 1, id + ":nodes_type"), created_nodes(true), connectivities("connectivities", id), normals("normals", id), spatial_dimension(spatial_dimension), types_offsets(Array((UInt)_max_element_type + 1, 1)), ghost_types_offsets(Array((UInt)_max_element_type + 1, 1)), lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.), size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.), local_upper_bounds(spatial_dimension, 0.), mesh_data("mesh_data", id, memory_id), mesh_facets(NULL) { AKANTU_DEBUG_IN(); this->nodes = &(alloc(id + ":coordinates", 0, this->spatial_dimension)); nb_global_nodes = 0; init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), GroupManager(*this, id + ":group_manager", memory_id), nodes_global_ids(NULL), nodes_type(0, 1, id + ":nodes_type"), created_nodes(false), connectivities("connectivities", id), normals("normals", id), spatial_dimension(spatial_dimension), types_offsets(Array((UInt)_max_element_type + 1, 1)), ghost_types_offsets(Array((UInt)_max_element_type + 1, 1)), lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.), size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.), local_upper_bounds(spatial_dimension, 0.), mesh_data("mesh_data", id, memory_id), mesh_facets(NULL) { AKANTU_DEBUG_IN(); this->nodes = &(getArray(nodes_id)); nb_global_nodes = nodes->getSize(); init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, Array & nodes, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), GroupManager(*this, id + ":group_manager", memory_id), nodes_global_ids(NULL), nodes_type(0, 1, id + ":nodes_type"), created_nodes(false), connectivities("connectivities", id), normals("normals", id), spatial_dimension(spatial_dimension), types_offsets(Array(_max_element_type + 1, 1)), ghost_types_offsets(Array(_max_element_type + 1, 1)), lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.), size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.), local_upper_bounds(spatial_dimension, 0.), mesh_data("mesh_data", id, memory_id), mesh_facets(NULL) { AKANTU_DEBUG_IN(); this->nodes = &(nodes); nb_global_nodes = nodes.getSize(); init(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh & Mesh::initMeshFacets(const ID & id) { AKANTU_DEBUG_IN(); if (!mesh_facets) { mesh_facets = new Mesh(spatial_dimension, *(this->nodes), getID() + ":" + id, getMemoryID()); mesh_facets->mesh_parent = this; mesh_facets->is_mesh_facets = true; } AKANTU_DEBUG_OUT(); return *mesh_facets; } /* -------------------------------------------------------------------------- */ void Mesh::defineMeshParent(const Mesh & mesh) { AKANTU_DEBUG_IN(); this->mesh_parent = &mesh; this->is_mesh_facets = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::init() { this->is_mesh_facets = false; this->mesh_parent = NULL; this->is_distributed = false; // computeBoundingBox(); } /* -------------------------------------------------------------------------- */ Mesh::~Mesh() { AKANTU_DEBUG_IN(); delete mesh_facets; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::read(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.read(filename, *this, mesh_io_type); type_iterator it = this->firstType(spatial_dimension, _not_ghost, _ek_not_defined); type_iterator last = this->lastType(spatial_dimension, _not_ghost, _ek_not_defined); if (it == last) AKANTU_EXCEPTION( "The mesh contained in the file " << filename << " does not seem to be of the good dimension." << " No element of dimension " << spatial_dimension << " where read."); } /* -------------------------------------------------------------------------- */ void Mesh::write(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.write(filename, *this, mesh_io_type); } /* -------------------------------------------------------------------------- */ void Mesh::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Mesh [" << std::endl; stream << space << " + id : " << getID() << std::endl; stream << space << " + spatial dimension : " << this->spatial_dimension << std::endl; stream << space << " + nodes [" << std::endl; nodes->printself(stream, indent + 2); stream << space << " + connectivities [" << std::endl; connectivities.printself(stream, indent + 2); stream << space << " ]" << std::endl; GroupManager::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void Mesh::computeBoundingBox() { AKANTU_DEBUG_IN(); for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::numeric_limits::max(); local_upper_bounds(k) = -std::numeric_limits::max(); } for (UInt i = 0; i < nodes->getSize(); ++i) { // if(!isPureGhostNode(i)) for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::min(local_lower_bounds[k], (*nodes)(i, k)); local_upper_bounds(k) = std::max(local_upper_bounds[k], (*nodes)(i, k)); } } if (this->is_distributed) { StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Matrix reduce_bounds(spatial_dimension, 2); for (UInt k = 0; k < spatial_dimension; ++k) { reduce_bounds(k, 0) = local_lower_bounds(k); reduce_bounds(k, 1) = -local_upper_bounds(k); } - comm.allReduce(reduce_bounds.storage(), reduce_bounds.size(), _so_min); + comm.allReduce(reduce_bounds, _so_min); for (UInt k = 0; k < spatial_dimension; ++k) { lower_bounds(k) = reduce_bounds(k, 0); upper_bounds(k) = -reduce_bounds(k, 1); } } else { this->lower_bounds = this->local_lower_bounds; this->upper_bounds = this->local_upper_bounds; } size = upper_bounds - lower_bounds; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Mesh::initElementTypeMapArray(ElementTypeMapArray & vect, UInt nb_component, UInt dim, const bool & flag_nb_node_per_elem_multiply, ElementKind element_kind, bool size_to_nb_element) const { AKANTU_DEBUG_IN(); for (UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType)g; this->initElementTypeMapArray(vect, nb_component, dim, gt, flag_nb_node_per_elem_multiply, element_kind, size_to_nb_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Mesh::initElementTypeMapArray(ElementTypeMapArray & vect, UInt nb_component, UInt dim, GhostType gt, const bool & flag_nb_node_per_elem_multiply, ElementKind element_kind, bool size_to_nb_element) const { AKANTU_DEBUG_IN(); this->initElementTypeMapArray(vect, nb_component, dim, gt, T(), flag_nb_node_per_elem_multiply, element_kind, size_to_nb_element); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Mesh::initElementTypeMapArray(ElementTypeMapArray & vect, UInt nb_component, UInt dim, GhostType gt, const T & default_value, const bool & flag_nb_node_per_elem_multiply, ElementKind element_kind, bool size_to_nb_element) const { AKANTU_DEBUG_IN(); Mesh::type_iterator it = firstType(dim, gt, element_kind); Mesh::type_iterator end = lastType(dim, gt, element_kind); for (; it != end; ++it) { ElementType type = *it; UInt nb_comp = nb_component; if (flag_nb_node_per_elem_multiply) nb_comp *= Mesh::getNbNodesPerElement(*it); UInt size = 0; if (size_to_nb_element) size = this->getNbElement(type, gt); vect.alloc(size, nb_comp, type, gt, default_value); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::initNormals() { this->initElementTypeMapArray(normals, spatial_dimension, spatial_dimension, false, _ek_not_defined); } /* -------------------------------------------------------------------------- */ void Mesh::getGlobalConnectivity( ElementTypeMapArray & global_connectivity, UInt dimension, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = firstType(dimension, ghost_type); Mesh::type_iterator end = lastType(dimension, ghost_type); for (; it != end; ++it) { ElementType type = *it; Array & local_conn = connectivities(type, ghost_type); Array & g_connectivity = global_connectivity(type, ghost_type); if (!nodes_global_ids) nodes_global_ids = mesh_parent->nodes_global_ids; UInt * local_c = local_conn.storage(); UInt * global_c = g_connectivity.storage(); UInt nb_terms = local_conn.getSize() * local_conn.getNbComponent(); for (UInt i = 0; i < nb_terms; ++i, ++local_c, ++global_c) *global_c = (*nodes_global_ids)(*local_c); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Mesh::getGroupDumper(const std::string & dumper_name, const std::string & group_name) { if (group_name == "all") return this->getDumper(dumper_name); else return element_groups[group_name]->getDumper(dumper_name); } /* -------------------------------------------------------------------------- */ #define AKANTU_INSTANTIATE_INIT(type) \ template void Mesh::initElementTypeMapArray( \ ElementTypeMapArray & vect, UInt nb_component, UInt dim, \ const bool & flag_nb_elem_multiply, ElementKind element_kind, \ bool size_to_nb_element) const; \ template void Mesh::initElementTypeMapArray( \ ElementTypeMapArray & vect, UInt nb_component, UInt dim, \ GhostType gt, const bool & flag_nb_elem_multiply, \ ElementKind element_kind, bool size_to_nb_element) const; \ template void Mesh::initElementTypeMapArray( \ ElementTypeMapArray & vect, UInt nb_component, UInt dim, \ GhostType gt, const type & default_value, \ const bool & flag_nb_elem_multiply, ElementKind element_kind, \ bool size_to_nb_element) const AKANTU_INSTANTIATE_INIT(Real); AKANTU_INSTANTIATE_INIT(UInt); AKANTU_INSTANTIATE_INIT(Int); AKANTU_INSTANTIATE_INIT(bool); /* -------------------------------------------------------------------------- */ template ElementTypeMap Mesh::getNbDataPerElem(ElementTypeMapArray & array, const ElementKind & element_kind) { ElementTypeMap nb_data_per_elem; typename ElementTypeMapArray::type_iterator it = array.firstType(spatial_dimension, _not_ghost, element_kind); typename ElementTypeMapArray::type_iterator last_type = array.lastType(spatial_dimension, _not_ghost, element_kind); for (; it != last_type; ++it) { UInt nb_elements = this->getNbElement(*it); nb_data_per_elem(*it) = array(*it).getNbComponent() * array(*it).getSize(); nb_data_per_elem(*it) /= nb_elements; } return nb_data_per_elem; } /* -------------------------------------------------------------------------- */ template ElementTypeMap Mesh::getNbDataPerElem(ElementTypeMapArray & array, const ElementKind & element_kind); template ElementTypeMap Mesh::getNbDataPerElem(ElementTypeMapArray & array, const ElementKind & element_kind); /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER template dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind) { dumper::Field * field = NULL; ElementTypeMapArray * internal = NULL; try { internal = &(this->getData(field_id)); } catch (...) { return NULL; } ElementTypeMap nb_data_per_elem = this->getNbDataPerElem(*internal, element_kind); field = this->createElementalField( *internal, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); return field; } template dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); template dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); #endif /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh index 9bb75e316..aeb6fc52b 100644 --- a/src/mesh/mesh.hh +++ b/src/mesh/mesh.hh @@ -1,575 +1,571 @@ /** * @file mesh.hh * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Jan 14 2016 * * @brief the class representing the meshes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_HH__ #define __AKANTU_MESH_HH__ /* -------------------------------------------------------------------------- */ - -#include "aka_config.hh" -#include "aka_common.hh" #include "aka_memory.hh" #include "aka_array.hh" #include "element_class.hh" #include "element_type_map.hh" #include "aka_event_handler_manager.hh" #include "group_manager.hh" #include "element.hh" #include "mesh_data.hh" #include "dumpable.hh" /* -------------------------------------------------------------------------- */ /* Mesh modifications events */ /* -------------------------------------------------------------------------- */ #include "mesh_events.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Mesh */ /* -------------------------------------------------------------------------- */ /** * @class Mesh this contain the coordinates of the nodes in the Mesh.nodes * Array, and the connectivity. The connectivity are stored in by element * types. * * To know all the element types present in a mesh you can get the * Mesh::ConnectivityTypeList * * In order to loop on all element you have to loop on all types like this : * @code{.cpp} Mesh::type_iterator it = mesh.firstType(dim, ghost_type); Mesh::type_iterator end = mesh.lastType(dim, ghost_type); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); const Array & conn = mesh.getConnectivity(*it); for(UInt e = 0; e < nb_element; ++e) { ... } } @endcode */ class Mesh : protected Memory, public EventHandlerManager, public GroupManager, public Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// constructor that create nodes coordinates array Mesh(UInt spatial_dimension, const ID & id = "mesh", const MemoryID & memory_id = 0); /// constructor that use an existing nodes coordinates array, by knowing its ID Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, const MemoryID & memory_id = 0); /** * constructor that use an existing nodes coordinates * array, by getting the vector of coordinates */ Mesh(UInt spatial_dimension, Array & nodes, const ID & id = "mesh", const MemoryID & memory_id = 0); virtual ~Mesh(); /// @typedef ConnectivityTypeList list of the types present in a Mesh typedef std::set ConnectivityTypeList; /// read the mesh from a file void read (const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); /// write the mesh to a file void write(const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); private: /// initialize the connectivity to NULL and other stuff void init(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// function that computes the bounding box (fills xmin, xmax) void computeBoundingBox(); #ifdef AKANTU_CORE_CXX11 /// translate the mesh by the given amount in x[, y[, z]] directions template void translate(Args... params); #endif /// init a by-element-type real vector with provided ids template void initElementTypeMapArray(ElementTypeMapArray & v, UInt nb_component, UInt spatial_dimension, const bool & flag_nb_node_per_elem_multiply = false, ElementKind element_kind = _ek_regular, bool size_to_nb_element = false) const; /// @todo: think about nicer way to do it template void initElementTypeMapArray(ElementTypeMapArray & v, UInt nb_component, UInt spatial_dimension, GhostType ghost_type, const bool & flag_nb_node_per_elem_multiply = false, ElementKind element_kind = _ek_regular, bool size_to_nb_element = false) const; /// @todo: think about nicer way to do it template void initElementTypeMapArray(ElementTypeMapArray & v, UInt nb_component, UInt spatial_dimension, GhostType ghost_type, const T & default_value, const bool & flag_nb_node_per_elem_multiply = false, ElementKind element_kind = _ek_regular, bool size_to_nb_element = false) const; /// @todo: think about nicer way to do it /// extract coordinates of nodes from an element template inline void extractNodalValuesFromElement(const Array & nodal_values, T * elemental_values, UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const; // /// extract coordinates of nodes from a reversed element // inline void extractNodalCoordinatesFromPBCElement(Real * local_coords, // UInt * connectivity, // UInt n_nodes); /// convert a element to a linearized element inline UInt elementToLinearized(const Element & elem) const; /// convert a linearized element to an element inline Element linearizedToElement (UInt linearized_element) const; /// update the types offsets array for the conversions inline void updateTypesOffsets(const GhostType & ghost_type); /// add a Array of connectivity for the type . inline void addConnectivityType(const ElementType & type, const GhostType & ghost_type = _not_ghost); /* ------------------------------------------------------------------------ */ template inline void sendEvent(Event & event) { // if(event.getList().getSize() != 0) EventHandlerManager::sendEvent(event); } /* ------------------------------------------------------------------------ */ template inline void removeNodesFromArray(Array & vect, const Array & new_numbering); /// initialize normals void initNormals(); /// init facets' mesh Mesh & initMeshFacets(const ID & id = "mesh_facets"); /// define parent mesh void defineMeshParent(const Mesh & mesh); /// get global connectivity array void getGlobalConnectivity(ElementTypeMapArray & global_connectivity, UInt dimension, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the id of the mesh AKANTU_GET_MACRO(ID, Memory::id, const ID &); /// get the spatial dimension of the mesh = number of component of the coordinates AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the nodes Array aka coordinates AKANTU_GET_MACRO(Nodes, *nodes, const Array &); AKANTU_GET_MACRO_NOT_CONST(Nodes, *nodes, Array &); /// get the normals for the elements AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Normals, normals, Real); /// get the number of nodes AKANTU_GET_MACRO(NbNodes, nodes->getSize(), UInt); /// get the Array of global ids of the nodes (only used in parallel) AKANTU_GET_MACRO(GlobalNodesIds, *nodes_global_ids, const Array &); AKANTU_GET_MACRO_NOT_CONST(GlobalNodesIds, *nodes_global_ids, Array &); /// get the global id of a node inline UInt getNodeGlobalId(UInt local_id) const; /// get the global number of nodes inline UInt getNbGlobalNodes() const; /// get the nodes type Array - AKANTU_GET_MACRO(NodesType, nodes_type, const Array &); + AKANTU_GET_MACRO(NodesType, nodes_type, const Array &); protected: - AKANTU_GET_MACRO_NOT_CONST(NodesType, nodes_type, Array &); + AKANTU_GET_MACRO_NOT_CONST(NodesType, nodes_type, Array &); public: - inline Int getNodeType(UInt local_id) const; + inline NodeType getNodeType(UInt local_id) const; /// say if a node is a pure ghost node inline bool isPureGhostNode(UInt n) const; /// say if a node is pur local or master node inline bool isLocalOrMasterNode(UInt n) const; inline bool isLocalNode(UInt n) const; inline bool isMasterNode(UInt n) const; inline bool isSlaveNode(UInt n) const; AKANTU_GET_MACRO(LowerBounds, lower_bounds, const Vector &); AKANTU_GET_MACRO(UpperBounds, upper_bounds, const Vector &); AKANTU_GET_MACRO(LocalLowerBounds, local_lower_bounds, const Vector &); AKANTU_GET_MACRO(LocalUpperBounds, local_upper_bounds, const Vector &); /// get the connectivity Array for a given type AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Connectivity, connectivities, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Connectivity, connectivities, UInt); AKANTU_GET_MACRO(Connectivities, connectivities, const ElementTypeMapArray &); /// get the number of element of a type in the mesh inline UInt getNbElement(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /// get the number of element for a given ghost_type and a given dimension inline UInt getNbElement(const UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & kind = _ek_not_defined) const; /// get the connectivity list either for the elements or the ghost elements inline const ConnectivityTypeList & getConnectivityTypeList(const GhostType & ghost_type = _not_ghost) const; /// compute the barycenter of a given element inline void getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type = _not_ghost) const; inline void getBarycenter(const Element & element, Vector & barycenter) const; /// get the element connected to a subelement const Array< std::vector > & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the element connected to a subelement Array< std::vector > & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get the subelement connected to an element const Array & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the subelement connected to an element Array & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get a name field associated to the mesh template inline const Array & getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template inline Array & getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// register a new ElementalTypeMap in the MeshData template inline ElementTypeMapArray & registerData(const std::string & data_name); /// get a name field associated to the mesh template inline const ElementTypeMapArray & getData(const std::string & data_name) const; /// get a name field associated to the mesh template inline ElementTypeMapArray & getData(const std::string & data_name); template ElementTypeMap getNbDataPerElem(ElementTypeMapArray & array, const ElementKind & element_kind); template dumper::Field * createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); /// templated getter returning the pointer to data in MeshData (modifiable) template inline Array * getDataPointer(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost, UInt nb_component = 1, bool size_to_nb_element = true, bool resize_with_parent = false); /// Facets mesh accessor AKANTU_GET_MACRO(MeshFacets, *mesh_facets, const Mesh &); AKANTU_GET_MACRO_NOT_CONST(MeshFacets, *mesh_facets, Mesh &); /// Parent mesh accessor AKANTU_GET_MACRO(MeshParent, *mesh_parent, const Mesh &); inline bool isMeshFacets() const { return this->is_mesh_facets; } /// defines is the mesh is distributed or not inline bool isDistributed() const { return this->is_distributed; } #ifndef SWIG /// return the dumper from a group and and a dumper name DumperIOHelper & getGroupDumper(const std::string & dumper_name, const std::string & group_name); #endif /* ------------------------------------------------------------------------ */ /* Wrappers on ElementClass functions */ /* ------------------------------------------------------------------------ */ public: /// get the number of nodes per element for a given element type static inline UInt getNbNodesPerElement(const ElementType & type); /// get the number of nodes per element for a given element type considered as /// a first order element static inline ElementType getP1ElementType(const ElementType & type); /// get the kind of the element type static inline ElementKind getKind(const ElementType & type); /// get spatial dimension of a type of element static inline UInt getSpatialDimension(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type, UInt t); /// get local connectivity of a facet for a given facet type static inline MatrixProxy getFacetLocalConnectivity(const ElementType & type, UInt t = 0); /// get connectivity of facets for a given element inline Matrix getFacetConnectivity(const Element & element, UInt t = 0) const; /// get the number of type of the surface element associated to a given element type static inline UInt getNbFacetTypes(const ElementType & type, UInt t = 0); /// get the type of the surface element associated to a given element static inline ElementType getFacetType(const ElementType & type, UInt t = 0); /// get all the type of the surface element associated to a given element static inline VectorProxy getAllFacetTypes(const ElementType & type); /// get the number of nodes in the given element list static inline UInt getNbNodesPerElementList(const Array & elements); /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ typedef ElementTypeMapArray::type_iterator type_iterator; inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.firstType(dim, ghost_type, kind); } inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.lastType(dim, ghost_type, kind); } /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshAccessor; friend class MeshIOMSH; friend class MeshIOMSHStruct; friend class MeshIODiana; friend class MeshUtils; - friend class DistributedSynchronizer; template friend class SpatialGrid; #if defined(AKANTU_COHESIVE_ELEMENT) friend class CohesiveElementInserter; #endif #if defined(AKANTU_IGFEM) template friend class MeshIgfemSphericalGrowingGel; #endif AKANTU_GET_MACRO(NodesPointer, nodes, Array *); /// get a pointer to the nodes_global_ids Array and create it if necessary inline Array * getNodesGlobalIdsPointer(); /// get a pointer to the nodes_type Array and create it if necessary - inline Array * getNodesTypePointer(); + inline Array * getNodesTypePointer(); /// get a pointer to the connectivity Array for the given type and create it if necessary inline Array * getConnectivityPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get a pointer to the element_to_subelement Array for the given type and create it if necessary inline Array< std::vector > * getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get a pointer to the subelement_to_element Array for the given type and create it if necessary inline Array * getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); AKANTU_GET_MACRO_NOT_CONST(MeshData, mesh_data, MeshData &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// array of the nodes coordinates Array * nodes; /// global node ids Array * nodes_global_ids; /// node type, -3 pure ghost, -2 master for the node, -1 normal node, i in /// [0-N] slave node and master is proc i - Array nodes_type; + Array nodes_type; /// global number of nodes; UInt nb_global_nodes; /// boolean to know if the nodes have to be deleted with the mesh or not bool created_nodes; /// all class of elements present in this mesh (for heterogenous meshes) ElementTypeMapArray connectivities; /// map to normals for all class of elements present in this mesh ElementTypeMapArray normals; /// list of all existing types in the mesh ConnectivityTypeList type_set; /// the spatial dimension of this mesh UInt spatial_dimension; /// types offsets Array types_offsets; /// list of all existing types in the mesh ConnectivityTypeList ghost_type_set; /// ghost types offsets Array ghost_types_offsets; /// min of coordinates Vector lower_bounds; /// max of coordinates Vector upper_bounds; /// size covered by the mesh on each direction Vector size; /// local min of coordinates Vector local_lower_bounds; /// local max of coordinates Vector local_upper_bounds; /// Extra data loaded from the mesh file MeshData mesh_data; /// facets' mesh Mesh * mesh_facets; /// parent mesh (this is set for mesh_facets meshes) const Mesh * mesh_parent; /// defines if current mesh is mesh_facets or not bool is_mesh_facets; /// defines if the mesh is centralized or distributed bool is_distributed; }; /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Element & _this) { _this.printself(stream); return stream; } /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Mesh & _this) { _this.printself(stream); return stream; } __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ #include "mesh_inline_impl.cc" #include "element_type_map_tmpl.hh" //#include "group_manager_inline_impl.cc" //#include "element_group_inline_impl.cc" #endif /* __AKANTU_MESH_HH__ */ diff --git a/src/mesh/mesh_accessor.hh b/src/mesh/mesh_accessor.hh index 95126bd52..e43b55ec1 100644 --- a/src/mesh/mesh_accessor.hh +++ b/src/mesh/mesh_accessor.hh @@ -1,107 +1,118 @@ /** * @file mesh_accessor.hh * * @author Nicolas Richart * * @date creation: Tue Jun 30 2015 * * @brief this class allow to access some private member of mesh it is used for * IO for examples * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ +/* -------------------------------------------------------------------------- */ +#include "mesh.hh" +/* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_ACCESSOR_HH__ #define __AKANTU_MESH_ACCESSOR_HH__ __BEGIN_AKANTU__ class MeshAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - MeshAccessor() {}; - virtual ~MeshAccessor() {}; + MeshAccessor(Mesh & mesh) : _mesh(mesh){}; + virtual ~MeshAccessor(){}; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the global number of nodes - inline UInt getNbGlobalNodes(const Mesh & mesh) const { return mesh.nb_global_nodes; }; + inline UInt getNbGlobalNodes() const { return this->_mesh.nb_global_nodes; }; /// set the global number of nodes - inline void setNbGlobalNodes(Mesh & mesh, UInt nb_global_nodes) const - { mesh.nb_global_nodes = nb_global_nodes; }; + inline void setNbGlobalNodes(UInt nb_global_nodes) { + this->_mesh.nb_global_nodes = nb_global_nodes; + }; - /// get a pointer to the nodes_global_ids Array and create it if necessary - inline Array & getNodesGlobalIds(Mesh & mesh) { - return *(mesh.getNodesGlobalIdsPointer()); + /// set the mesh as being distributed + inline void setDistributed() { this->_mesh.is_distributed = true; } + + /// get a pointer to the nodes_global_ids Array and create it if + /// necessary + inline Array & getNodesGlobalIds() { + return *(this->_mesh.getNodesGlobalIdsPointer()); } /// get a pointer to the nodes_type Array and create it if necessary - inline Array & getNodesType(Mesh & mesh) { - return *(mesh.getNodesTypePointer()); + inline Array & getNodesType() { + return *(this->_mesh.getNodesTypePointer()); } - /// get a pointer to the connectivity Array for the given type and create it if necessary - inline Array & getConnectivity(Mesh & mesh, - const ElementType & type, - const GhostType & ghost_type = _not_ghost) { - return *(mesh.getConnectivityPointer(type, ghost_type)); + /// get a pointer to the coordinates Array + inline Array & getNodes() { return *(this->_mesh.getNodesPointer()); } + + /// get a pointer to the connectivity Array for the given type and create it + /// if necessary + inline Array & + getConnectivity(const ElementType & type, + const GhostType & ghost_type = _not_ghost) { + return *(this->_mesh.getConnectivityPointer(type, ghost_type)); } - /// get a pointer to the element_to_subelement Array for the given type and create it if necessary - inline Array< std::vector > & getElementToSubelement(Mesh & mesh, - const ElementType & type, - const GhostType & ghost_type = _not_ghost) { - return *(mesh.getElementToSubelementPointer(type, ghost_type)); + /// get a pointer to the element_to_subelement Array for the given type and + /// create it if necessary + inline Array > & + getElementToSubelement(const ElementType & type, + const GhostType & ghost_type = _not_ghost) { + return *(this->_mesh.getElementToSubelementPointer(type, ghost_type)); } - /// get a pointer to the subelement_to_element Array for the given type and create it if necessary - inline Array & getSubelementToElement(Mesh & mesh, - const ElementType & type, - const GhostType & ghost_type = _not_ghost) { - return *(mesh.getSubelementToElementPointer(type, ghost_type)); + /// get a pointer to the subelement_to_element Array for the given type and + /// create it if necessary + inline Array & + getSubelementToElement(const ElementType & type, + const GhostType & ghost_type = _not_ghost) { + return *(this->_mesh.getSubelementToElementPointer(type, ghost_type)); } - template - inline Array & getData(Mesh & mesh, - const std::string & data_name, - const ElementType & el_type, - const GhostType & ghost_type = _not_ghost, - UInt nb_component = 1, - bool size_to_nb_element = true, - bool resize_with_parent = false) { - return *(mesh.getDataPointer(data_name, - el_type, - ghost_type, - nb_component, - size_to_nb_element, - resize_with_parent)); + template + inline Array & + getData(const std::string & data_name, const ElementType & el_type, + const GhostType & ghost_type = _not_ghost, UInt nb_component = 1, + bool size_to_nb_element = true, bool resize_with_parent = false) { + return *(this->_mesh.getDataPointer(data_name, el_type, ghost_type, + nb_component, size_to_nb_element, + resize_with_parent)); } -}; + MeshData & getMeshData() { return this->_mesh.getMeshData(); } -__END_AKANTU__ +private: + Mesh & _mesh; +}; +__END_AKANTU__ #endif /* __AKANTU_MESH_ACCESSOR_HH__ */ diff --git a/src/mesh/mesh_inline_impl.cc b/src/mesh/mesh_inline_impl.cc index 2ff3f4a48..bccc50ad4 100644 --- a/src/mesh/mesh_inline_impl.cc +++ b/src/mesh/mesh_inline_impl.cc @@ -1,611 +1,611 @@ /** * @file mesh_inline_impl.cc * * @author Guillaume Anciaux * @author Dana Christen * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Thu Jul 15 2010 * @date last modification: Thu Jan 21 2016 * * @brief Implementation of the inline functions of the mesh class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) #include "cohesive_element.hh" #endif #ifndef __AKANTU_MESH_INLINE_IMPL_CC__ #define __AKANTU_MESH_INLINE_IMPL_CC__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ inline RemovedNodesEvent::RemovedNodesEvent(const Mesh & mesh) : new_numbering(mesh.getNbNodes(), 1, "new_numbering") {} /* -------------------------------------------------------------------------- */ inline RemovedElementsEvent::RemovedElementsEvent(const Mesh & mesh, ID new_numbering_id) : new_numbering(new_numbering_id, mesh.getID()) {} /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(RemovedElementsEvent & event) { this->connectivities.onElementsRemoved(event.getNewNumbering()); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(RemovedNodesEvent & event) { if (created_nodes) this->removeNodesFromArray(*nodes, event.getNewNumbering()); if (nodes_global_ids) this->removeNodesFromArray(*nodes_global_ids, event.getNewNumbering()); if (nodes_type.getSize() != 0) this->removeNodesFromArray(nodes_type, event.getNewNumbering()); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template inline void Mesh::removeNodesFromArray(Array & vect, const Array & new_numbering) { Array tmp(vect.getSize(), vect.getNbComponent()); UInt nb_component = vect.getNbComponent(); UInt new_nb_nodes = 0; for (UInt i = 0; i < new_numbering.getSize(); ++i) { UInt new_i = new_numbering(i); if (new_i != UInt(-1)) { T * to_copy = vect.storage() + i * nb_component; - std::uninitialized_copy(to_copy, - to_copy + nb_component, + std::uninitialized_copy(to_copy, to_copy + nb_component, tmp.storage() + new_i * nb_component); ++new_nb_nodes; } } tmp.resize(new_nb_nodes); vect.copy(tmp); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_CORE_CXX11 template inline void Mesh::translate(Args... params) { // check that the number of parameters corresponds to the dimension AKANTU_DEBUG_ASSERT(sizeof...(Args) <= spatial_dimension, "Number of arguments greater than dimension."); // unpack parameters Real s[] = {params...}; Array & nodes = getNodes(); for (UInt i = 0; i < nodes.getSize(); ++i) for (UInt k = 0; k < sizeof...(Args); ++k) nodes(i, k) += s[k]; } #endif /* -------------------------------------------------------------------------- */ inline UInt Mesh::elementToLinearized(const Element & elem) const { AKANTU_DEBUG_ASSERT(elem.type < _max_element_type && elem.element < types_offsets.storage()[elem.type + 1], "The element " << elem << "does not exists in the mesh " << getID()); return types_offsets.storage()[elem.type] + elem.element; } /* -------------------------------------------------------------------------- */ inline Element Mesh::linearizedToElement(UInt linearized_element) const { UInt t; for (t = _not_defined; t != _max_element_type && linearized_element >= types_offsets(t); ++t) ; AKANTU_DEBUG_ASSERT(linearized_element < types_offsets(t), "The linearized element " << linearized_element << "does not exists in the mesh " << getID()); --t; ElementType type = ElementType(t); return Element(type, linearized_element - types_offsets.storage()[t], _not_ghost, getKind(type)); } /* -------------------------------------------------------------------------- */ inline void Mesh::updateTypesOffsets(const GhostType & ghost_type) { Array * types_offsets_ptr = &this->types_offsets; if (ghost_type == _ghost) types_offsets_ptr = &this->ghost_types_offsets; Array & types_offsets = *types_offsets_ptr; types_offsets.clear(); type_iterator it = firstType(_all_dimensions, ghost_type, _ek_not_defined); type_iterator last = lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != last; ++it) types_offsets(*it) = connectivities(*it, ghost_type).getSize(); for (UInt t = _not_defined + 1; t < _max_element_type; ++t) types_offsets(t) += types_offsets(t - 1); for (UInt t = _max_element_type; t > _not_defined; --t) types_offsets(t) = types_offsets(t - 1); types_offsets(0) = 0; } /* -------------------------------------------------------------------------- */ inline const Mesh::ConnectivityTypeList & Mesh::getConnectivityTypeList(const GhostType & ghost_type) const { if (ghost_type == _not_ghost) return type_set; else return ghost_type_set; } /* -------------------------------------------------------------------------- */ inline Array * Mesh::getNodesGlobalIdsPointer() { AKANTU_DEBUG_IN(); if (nodes_global_ids == NULL) { std::stringstream sstr; sstr << getID() << ":nodes_global_ids"; nodes_global_ids = &(alloc(sstr.str(), nodes->getSize(), 1)); } AKANTU_DEBUG_OUT(); return nodes_global_ids; } /* -------------------------------------------------------------------------- */ -inline Array * Mesh::getNodesTypePointer() { +inline Array * Mesh::getNodesTypePointer() { AKANTU_DEBUG_IN(); if (nodes_type.getSize() == 0) { nodes_type.resize(nodes->getSize()); - nodes_type.set(-1); + nodes_type.set(_nt_normal); } AKANTU_DEBUG_OUT(); return &nodes_type; } /* -------------------------------------------------------------------------- */ inline Array * Mesh::getConnectivityPointer(const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Array * tmp; if (!connectivities.exists(type, ghost_type)) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); tmp = &(connectivities.alloc(0, nb_nodes_per_element, type, ghost_type)); AKANTU_DEBUG_INFO("The connectivity vector for the type " << type << " created"); if (ghost_type == _not_ghost) type_set.insert(type); else ghost_type_set.insert(type); updateTypesOffsets(ghost_type); } else { tmp = &connectivities(type, ghost_type); } AKANTU_DEBUG_OUT(); return tmp; } /* -------------------------------------------------------------------------- */ inline Array > * Mesh::getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type) { Array > * tmp = getDataPointer >( "element_to_subelement", type, ghost_type, 1, true); return tmp; } /* -------------------------------------------------------------------------- */ inline Array * Mesh::getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type) { Array * tmp = getDataPointer( "subelement_to_element", type, ghost_type, getNbFacetsPerElement(type), true, is_mesh_facets); return tmp; } /* -------------------------------------------------------------------------- */ inline const Array > & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) const { return getData >("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array > & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) { return getData >("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline const Array & Mesh::getSubelementToElement(const ElementType & type, const GhostType & ghost_type) const { return getData("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getSubelementToElement(const ElementType & type, const GhostType & ghost_type) { return getData("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ template inline Array * Mesh::getDataPointer(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type, UInt nb_component, bool size_to_nb_element, bool resize_with_parent) { Array & tmp = mesh_data.getElementalDataArrayAlloc( data_name, el_type, ghost_type, nb_component); if (size_to_nb_element) { if (resize_with_parent) tmp.resize(mesh_parent->getNbElement(el_type, ghost_type)); else tmp.resize(this->getNbElement(el_type, ghost_type)); } else { tmp.resize(0); } return &tmp; } /* -------------------------------------------------------------------------- */ template inline const Array & Mesh::getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type) const { return mesh_data.getElementalDataArray(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template inline Array & Mesh::getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type) { return mesh_data.getElementalDataArray(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template inline const ElementTypeMapArray & Mesh::getData(const std::string & data_name) const { return mesh_data.getElementalData(data_name); } /* -------------------------------------------------------------------------- */ template inline ElementTypeMapArray & Mesh::getData(const std::string & data_name) { return mesh_data.getElementalData(data_name); } /* -------------------------------------------------------------------------- */ template inline ElementTypeMapArray & Mesh::registerData(const std::string & data_name) { this->mesh_data.registerElementalData(data_name); return this->getData(data_name); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const ElementType & type, const GhostType & ghost_type) const { try { const Array & conn = connectivities(type, ghost_type); return conn.getSize(); } catch (...) { return 0; } } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & kind) const { UInt nb_element = 0; type_iterator it = firstType(spatial_dimension, ghost_type, kind); type_iterator last = lastType(spatial_dimension, ghost_type, kind); for (; it != last; ++it) nb_element += getNbElement(*it, ghost_type); return nb_element; } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type) const { UInt * conn_val = getConnectivity(type, ghost_type).storage(); UInt nb_nodes_per_element = getNbNodesPerElement(type); Real * local_coord = new Real[spatial_dimension * nb_nodes_per_element]; UInt offset = element * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { memcpy(local_coord + n * spatial_dimension, nodes->storage() + conn_val[offset + n] * spatial_dimension, spatial_dimension * sizeof(Real)); } Math::barycenter(local_coord, nb_nodes_per_element, spatial_dimension, barycenter); - delete [] local_coord; + delete[] local_coord; } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(const Element & element, Vector & barycenter) const { getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElement(const ElementType & type) { UInt nb_nodes_per_element = 0; #define GET_NB_NODES_PER_ELEMENT(type) \ nb_nodes_per_element = ElementClass::getNbNodesPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_NODES_PER_ELEMENT); #undef GET_NB_NODES_PER_ELEMENT return nb_nodes_per_element; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getP1ElementType(const ElementType & type) { ElementType p1_type = _not_defined; #define GET_P1_TYPE(type) p1_type = ElementClass::getP1ElementType() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_P1_TYPE); #undef GET_P1_TYPE return p1_type; } /* -------------------------------------------------------------------------- */ inline ElementKind Mesh::getKind(const ElementType & type) { ElementKind kind = _ek_not_defined; #define GET_KIND(type) kind = ElementClass::getKind() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_KIND); #undef GET_KIND return kind; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getSpatialDimension(const ElementType & type) { UInt spatial_dimension = 0; #define GET_SPATIAL_DIMENSION(type) \ spatial_dimension = ElementClass::getSpatialDimension() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SPATIAL_DIMENSION); #undef GET_SPATIAL_DIMENSION return spatial_dimension; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetTypes(const ElementType & type, __attribute__((unused)) UInt t) { UInt nb = 0; #define GET_NB_FACET_TYPE(type) nb = ElementClass::getNbFacetTypes() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET_TYPE); #undef GET_NB_FACET_TYPE return nb; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getFacetType(const ElementType & type, UInt t) { ElementType surface_type = _not_defined; #define GET_FACET_TYPE(type) surface_type = ElementClass::getFacetType(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_TYPE); #undef GET_FACET_TYPE return surface_type; } /* -------------------------------------------------------------------------- */ inline VectorProxy Mesh::getAllFacetTypes(const ElementType & type) { #define GET_FACET_TYPE(type) \ UInt nb = ElementClass::getNbFacetTypes(); \ ElementType * elt_ptr = \ const_cast(ElementClass::getFacetTypeInternal()); \ return VectorProxy(elt_ptr, nb); AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_TYPE); #undef GET_FACET_TYPE } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(const ElementType & type) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) n_facet = ElementClass::getNbFacetsPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(const ElementType & type, UInt t) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) \ n_facet = ElementClass::getNbFacetsPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline MatrixProxy Mesh::getFacetLocalConnectivity(const ElementType & type, UInt t) { AKANTU_DEBUG_IN(); #define GET_FACET_CON(type) \ AKANTU_DEBUG_OUT(); \ return ElementClass::getFacetLocalConnectivityPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_CON); #undef GET_FACET_CON AKANTU_DEBUG_OUT(); return Matrix(); // This avoid a compilation warning but will certainly // also cause a segfault if reached } /* -------------------------------------------------------------------------- */ inline Matrix Mesh::getFacetConnectivity(const Element & element, UInt t) const { AKANTU_DEBUG_IN(); Matrix local_facets(getFacetLocalConnectivity(element.type, t), false); Matrix facets(local_facets.rows(), local_facets.cols()); const Array & conn = connectivities(element.type, element.ghost_type); for (UInt f = 0; f < facets.rows(); ++f) { for (UInt n = 0; n < facets.cols(); ++n) { facets(f, n) = conn(element.element, local_facets(f, n)); } } AKANTU_DEBUG_OUT(); return facets; } /* -------------------------------------------------------------------------- */ template inline void Mesh::extractNodalValuesFromElement( const Array & nodal_values, T * local_coord, UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const { for (UInt n = 0; n < n_nodes; ++n) { memcpy(local_coord + n * nb_degree_of_freedom, nodal_values.storage() + connectivity[n] * nb_degree_of_freedom, nb_degree_of_freedom * sizeof(T)); } } /* -------------------------------------------------------------------------- */ inline void Mesh::addConnectivityType(const ElementType & type, const GhostType & ghost_type) { getConnectivityPointer(type, ghost_type); } /* -------------------------------------------------------------------------- */ inline bool Mesh::isPureGhostNode(UInt n) const { - return nodes_type.getSize() ? (nodes_type(n) == -3) : false; + return nodes_type.getSize() ? (nodes_type(n) == _nt_pure_gost) : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalOrMasterNode(UInt n) const { - return nodes_type.getSize() ? (nodes_type(n) == -2) || (nodes_type(n) == -1) - : true; + return nodes_type.getSize() + ? (nodes_type(n) == _nt_master) || (nodes_type(n) == _nt_normal) + : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalNode(UInt n) const { - return nodes_type.getSize() ? nodes_type(n) == -1 : true; + return nodes_type.getSize() ? nodes_type(n) == _nt_normal : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isMasterNode(UInt n) const { - return nodes_type.getSize() ? nodes_type(n) == -2 : false; + return nodes_type.getSize() ? nodes_type(n) == _nt_master : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isSlaveNode(UInt n) const { return nodes_type.getSize() ? nodes_type(n) >= 0 : false; } /* -------------------------------------------------------------------------- */ -inline Int Mesh::getNodeType(UInt local_id) const { - return nodes_type.getSize() ? nodes_type(local_id) : -1; +inline NodeType Mesh::getNodeType(UInt local_id) const { + return nodes_type.getSize() ? nodes_type(local_id) : _nt_normal; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeGlobalId(UInt local_id) const { return nodes_global_ids ? (*nodes_global_ids)(local_id) : local_id; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbGlobalNodes() const { return nodes_global_ids ? nb_global_nodes : nodes->getSize(); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElementList(const Array & elements) { UInt nb_nodes_per_element = 0; UInt nb_nodes = 0; ElementType current_element_type = _not_defined; Array::const_iterator el_it = elements.begin(); Array::const_iterator el_end = elements.end(); for (; el_it != el_end; ++el_it) { const Element & el = *el_it; if (el.type != current_element_type) { current_element_type = el.type; nb_nodes_per_element = Mesh::getNbNodesPerElement(current_element_type); } nb_nodes += nb_nodes_per_element; } return nb_nodes; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ #endif /* __AKANTU_MESH_INLINE_IMPL_CC__ */ diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 3aee622be..e1dc4cc83 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2241 +1,2240 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Leonardo Snozzi * @author Marco Vocialta * * @date creation: Fri Aug 20 2010 * @date last modification: Fri Jan 22 2016 * * @brief All mesh utils necessary for various tasks * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_utils.hh" #include "aka_safe_enum.hh" #include "fe_engine.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); /// count number of occurrence of each node UInt nb_nodes = mesh.getNbNodes(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); AKANTU_DEBUG_ASSERT( mesh.firstType(spatial_dimension) != mesh.lastType(spatial_dimension), "Some elements must be found in right dimension to compute facets!"); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); for (; first != last; ++first) { ElementType type = *first; UInt nb_element = mesh.getNbElement(type, *gt); Array::const_iterator > conn_it = mesh.getConnectivity(type, *gt) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) for (UInt n = 0; n < conn_it->size(); ++n) ++node_to_elem.rowOffset((*conn_it)(n)); } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); /// rearrange element to get the node-element list Element e; node_to_elem.beginInsertions(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); e.ghost_type = *gt; for (; first != last; ++first) { ElementType type = *first; e.type = type; e.kind = Mesh::getKind(type); UInt nb_element = mesh.getNbElement(type, *gt); Array::const_iterator > conn_it = mesh.getConnectivity(type, *gt) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; for (UInt n = 0; n < conn_it->size(); ++n) node_to_elem.insertInRow((*conn_it)(n), e); } } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This function should disappear in the future (used in mesh partitioning) */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes = mesh.getNbNodes(); const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; UInt nb_types = type_list.size(); UInt nb_good_types = 0; Vector nb_nodes_per_element(nb_types); UInt ** conn_val = new UInt *[nb_types]; Vector nb_element(nb_types); for (it = type_list.begin(); it != type_list.end(); ++it) { ElementType type = *it; if (Mesh::getSpatialDimension(type) != spatial_dimension) continue; nb_nodes_per_element[nb_good_types] = Mesh::getNbNodesPerElement(type); conn_val[nb_good_types] = mesh.getConnectivity(type, _not_ghost).storage(); nb_element[nb_good_types] = mesh.getConnectivity(type, _not_ghost).getSize(); nb_good_types++; } AKANTU_DEBUG_ASSERT( nb_good_types != 0, "Some elements must be found in right dimension to compute facets!"); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt t = 0; t < nb_good_types; ++t) { for (UInt el = 0; el < nb_element[t]; ++el) { UInt el_offset = el * nb_nodes_per_element[t]; for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) { ++node_to_elem.rowOffset(conn_val[t][el_offset + n]); } } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// rearrange element to get the node-element list for (UInt t = 0, linearized_el = 0; t < nb_good_types; ++t) for (UInt el = 0; el < nb_element[t]; ++el, ++linearized_el) { UInt el_offset = el * nb_nodes_per_element[t]; for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) node_to_elem.insertInRow(conn_val[t][el_offset + n], linearized_el); } node_to_elem.endInsertions(); delete [] conn_val; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR & node_to_elem, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, ghost_type).getSize(); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) ++node_to_elem.rowOffset(conn_val[el_offset + n]); } /// convert the occurrence array in a csr one node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { node_to_elem.insertInRow(conn_val[el_offset + n], el); } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { mesh.getConnectivity(*it, *gt).resize(0); // \todo inform the mesh event handler } } buildFacetsDimension(mesh, mesh, true, spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension, DistributedSynchronizer * synchronizer) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension, synchronizer); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension, DistributedSynchronizer * synchronizer) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT( mesh_facets.isMeshFacets(), "The mesh_facets should be initialized with initMeshFacets"); const ElementTypeMapArray * prank_to_element = NULL; if (synchronizer) { synchronizer->buildPrankToElement(); prank_to_element = &synchronizer->getPrankToElement(); } /// generate facets buildFacetsDimension(mesh, mesh_facets, false, from_dimension, prank_to_element); /// copy nodes type mesh_facets.nodes_type.resize(mesh.nodes_type.getSize()); mesh_facets.nodes_type.copy(mesh.nodes_type); /// sort facets and generate subfacets for (UInt i = from_dimension - 1; i > to_dimension; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i, prank_to_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension( const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, const ElementTypeMapArray * prank_to_element) { AKANTU_DEBUG_IN(); // save the current parent of mesh_facets and set it temporarly to mesh since // mesh is the one containing the elements for which mesh_facets has the // subelements // example: if the function is called with mesh = mesh_facets const Mesh & mesh_facets_parent = mesh_facets.getMeshParent(); mesh_facets.defineMeshParent(mesh); UInt spatial_dimension = mesh.getSpatialDimension(); const Array & mesh_facets_nodes = mesh_facets.getNodes(); const Array::const_vector_iterator mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); CSR node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array counter; std::vector connected_elements; // init the SubelementToElement data to improve performance for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator first = mesh.firstType(dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(dimension, ghost_type); for (; first != last; ++first) { ElementType type = *first; mesh_facets.getSubelementToElementPointer(type, ghost_type); Vector facet_types = mesh.getAllFacetTypes(type); for (UInt ft = 0; ft < facet_types.size(); ++ft) { ElementType facet_type = facet_types(ft); mesh_facets.getElementToSubelementPointer(facet_type, ghost_type); mesh_facets.getConnectivityPointer(facet_type, ghost_type); } } } Element current_element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; GhostType facet_ghost_type = ghost_type; current_element.ghost_type = ghost_type; Mesh::type_iterator first = mesh.firstType(dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(dimension, ghost_type); for (; first != last; ++first) { ElementType type = *first; Vector facet_types = mesh.getAllFacetTypes(type); current_element.type = type; for (UInt ft = 0; ft < facet_types.size(); ++ft) { ElementType facet_type = facet_types(ft); UInt nb_element = mesh.getNbElement(type, ghost_type); Array > * element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, ghost_type); Array * connectivity_facets = &mesh_facets.getConnectivity(facet_type, ghost_type); UInt nb_facet_per_element = mesh.getNbFacetsPerElement(type, ft); const Array & element_connectivity = mesh.getConnectivity(type, ghost_type); const Matrix facet_local_connectivity = mesh.getFacetLocalConnectivity(type, ft); UInt nb_nodes_per_facet = connectivity_facets->getNbComponent(); Vector facet(nb_nodes_per_facet); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; for (UInt f = 0; f < nb_facet_per_element; ++f) { for (UInt n = 0; n < nb_nodes_per_facet; ++n) facet(n) = element_connectivity(el, facet_local_connectivity(f, n)); UInt first_node_nb_elements = node_to_elem.getNbCols(facet(0)); counter.resize(first_node_nb_elements); counter.clear(); // loop over the other nodes to search intersecting elements, // which are the elements that share another node with the // starting element after first_node CSR::iterator first_node_elements = node_to_elem.begin(facet(0)); CSR::iterator first_node_elements_end = node_to_elem.end(facet(0)); UInt local_el = 0; for (; first_node_elements != first_node_elements_end; ++first_node_elements, ++local_el) { for (UInt n = 1; n < nb_nodes_per_facet; ++n) { CSR::iterator node_elements_begin = node_to_elem.begin(facet(n)); CSR::iterator node_elements_end = node_to_elem.end(facet(n)); counter(local_el) += std::count(node_elements_begin, node_elements_end, *first_node_elements); } } // counting the number of elements connected to the facets and // taking the minimum element number, because the facet should // be inserted just once UInt nb_element_connected_to_facet = 0; Element minimum_el = ElementNull; connected_elements.clear(); for (UInt el_f = 0; el_f < first_node_nb_elements; el_f++) { Element real_el = node_to_elem(facet(0), el_f); if (counter(el_f) == nb_nodes_per_facet - 1) { ++nb_element_connected_to_facet; minimum_el = std::min(minimum_el, real_el); connected_elements.push_back(real_el); } } if (minimum_el == current_element) { bool full_ghost_facet = false; UInt n = 0; while (n < nb_nodes_per_facet && mesh.isPureGhostNode(facet(n))) ++n; if (n == nb_nodes_per_facet) full_ghost_facet = true; if (!full_ghost_facet) { if (!boundary_only || (boundary_only && nb_element_connected_to_facet == 1)) { std::vector elements; // build elements_on_facets: linearized_el must come first // in order to store the facet in the correct direction // and avoid to invert the sign in the normal computation elements.push_back(current_element); /// boundary facet if (nb_element_connected_to_facet == 1) elements.push_back(ElementNull); /// internal facet else if (nb_element_connected_to_facet == 2) { elements.push_back(connected_elements[1]); /// check if facet is in between ghost and normal /// elements: if it's the case, the facet is either /// ghost or not ghost. The criterion to decide this /// is arbitrary. It was chosen to check the processor /// id (prank) of the two neighboring elements. If /// prank of the ghost element is lower than prank of /// the normal one, the facet is not ghost, otherwise /// it's ghost GhostType gt[2] = {_not_ghost, _not_ghost}; for (UInt el = 0; el < connected_elements.size(); ++el) gt[el] = connected_elements[el].ghost_type; if (gt[0] + gt[1] == 1) { if (prank_to_element) { UInt prank[2]; for (UInt el = 0; el < 2; ++el) { UInt current_el = connected_elements[el].element; ElementType current_type = connected_elements[el].type; GhostType current_gt = connected_elements[el].ghost_type; const Array & prank_to_el = (*prank_to_element)(current_type, current_gt); prank[el] = prank_to_el(current_el); } bool ghost_one = (gt[0] != _ghost); if (prank[ghost_one] > prank[!ghost_one]) facet_ghost_type = _not_ghost; else facet_ghost_type = _ghost; connectivity_facets = &mesh_facets.getConnectivity( facet_type, facet_ghost_type); element_to_subelement = &mesh_facets.getElementToSubelement( facet_type, facet_ghost_type); } } } /// facet of facet else { for (UInt i = 1; i < nb_element_connected_to_facet; ++i) { elements.push_back(connected_elements[i]); } } element_to_subelement->push_back(elements); connectivity_facets->push_back(facet); /// current facet index UInt current_facet = connectivity_facets->getSize() - 1; /// loop on every element connected to current facet and /// insert current facet in the first free spot of the /// subelement_to_element vector for (UInt elem = 0; elem < elements.size(); ++elem) { Element loc_el = elements[elem]; if (loc_el.type != _not_defined) { Array & subelement_to_element = mesh_facets.getSubelementToElement(loc_el.type, loc_el.ghost_type); UInt nb_facet_per_loc_element = subelement_to_element.getNbComponent(); for (UInt f_in = 0; f_in < nb_facet_per_loc_element; ++f_in) { if (subelement_to_element(loc_el.element, f_in).type == _not_defined) { subelement_to_element(loc_el.element, f_in).type = facet_type; subelement_to_element(loc_el.element, f_in).element = current_facet; subelement_to_element(loc_el.element, f_in) .ghost_type = facet_ghost_type; break; } } } } /// reset connectivity in case a facet was found in /// between ghost and normal elements if (facet_ghost_type != ghost_type) { facet_ghost_type = ghost_type; connectivity_facets = mesh_facets.getConnectivityPointer( facet_type, facet_ghost_type); element_to_subelement = mesh_facets.getElementToSubelementPointer( facet_type, facet_ghost_type); } } } } } } } } } // restore the parent of mesh_facet mesh_facets.defineMeshParent(mesh_facets_parent); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -void MeshUtils::renumberMeshNodes(Mesh & mesh, UInt * local_connectivities, +void MeshUtils::renumberMeshNodes(Mesh & mesh, Array & local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array & old_nodes_numbers) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map renumbering_map; for (UInt i = 0; i < old_nodes_numbers.getSize(); ++i) { renumbering_map[old_nodes_numbers(i)] = i; } /// renumber the nodes renumberNodesInConnectivity(local_connectivities, (nb_local_element + nb_ghost_element) * nb_nodes_per_element, renumbering_map); std::map::iterator it = renumbering_map.begin(); std::map::iterator end = renumbering_map.end(); old_nodes_numbers.resize(renumbering_map.size()); for (; it != end; ++it) { old_nodes_numbers(it->second) = it->first; } renumbering_map.clear(); /// copy the renumbered connectivity to the right place Array * local_conn = mesh.getConnectivityPointer(type); local_conn->resize(nb_local_element); - memcpy(local_conn->storage(), local_connectivities, + memcpy(local_conn->storage(), local_connectivities.storage(), nb_local_element * nb_nodes_per_element * sizeof(UInt)); Array * ghost_conn = mesh.getConnectivityPointer(type, _ghost); ghost_conn->resize(nb_ghost_element); memcpy(ghost_conn->storage(), - local_connectivities + nb_local_element * nb_nodes_per_element, + local_connectivities.storage() + nb_local_element * nb_nodes_per_element, nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity( - UInt * list_nodes, UInt nb_nodes, std::map & renumbering_map) { + Array & list_nodes, UInt nb_nodes, std::map & renumbering_map) { AKANTU_DEBUG_IN(); - UInt * connectivity = list_nodes; + UInt * connectivity = list_nodes.storage(); UInt new_node_num = renumbering_map.size(); for (UInt n = 0; n < nb_nodes; ++n, ++connectivity) { UInt & node = *connectivity; std::map::iterator it = renumbering_map.find(node); if (it == renumbering_map.end()) { UInt old_node = node; renumbering_map[old_node] = new_node_num; node = new_node_num; ++new_node_num; } else { node = it->second; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::purifyMesh(Mesh & mesh) { AKANTU_DEBUG_IN(); std::map renumbering_map; RemovedNodesEvent remove_nodes(mesh); Array & nodes_removed = remove_nodes.getList(); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType)gt; Mesh::type_iterator it = mesh.firstType(_all_dimensions, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != end; ++it) { ElementType type(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); - const Array & connectivity_vect = + Array & connectivity = mesh.getConnectivity(type, ghost_type); - UInt nb_element(connectivity_vect.getSize()); - UInt * connectivity = connectivity_vect.storage(); + UInt nb_element(connectivity.getSize()); renumberNodesInConnectivity( connectivity, nb_element * nb_nodes_per_element, renumbering_map); } } Array & new_numbering = remove_nodes.getNewNumbering(); std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); std::map::iterator it = renumbering_map.begin(); std::map::iterator end = renumbering_map.end(); for (; it != end; ++it) { new_numbering(it->first) = it->second; } for (UInt i = 0; i < new_numbering.getSize(); ++i) { if (new_numbering(i) == UInt(-1)) nodes_removed.push_back(i); } mesh.sendEvent(remove_nodes); AKANTU_DEBUG_OUT(); } #if defined(AKANTU_COHESIVE_ELEMENT) /* -------------------------------------------------------------------------- */ UInt MeshUtils::insertCohesiveElements( Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray & facet_insertion, Array & doubled_nodes, Array & new_elements, bool only_double_facets) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt elements_to_insert = updateFacetToDouble(mesh_facets, facet_insertion); if (elements_to_insert > 0) { if (spatial_dimension == 1) { doublePointFacet(mesh, mesh_facets, doubled_nodes); } else { doubleFacet(mesh, mesh_facets, spatial_dimension - 1, doubled_nodes, true); findSubfacetToDouble(mesh, mesh_facets); if (spatial_dimension == 2) { doubleSubfacet<2>(mesh, mesh_facets, doubled_nodes); } else if (spatial_dimension == 3) { doubleFacet(mesh, mesh_facets, 1, doubled_nodes, false); findSubfacetToDouble(mesh, mesh_facets); doubleSubfacet<3>(mesh, mesh_facets, doubled_nodes); } } if (!only_double_facets) updateCohesiveData(mesh, mesh_facets, new_elements); } return elements_to_insert; } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doubleNodes(Mesh & mesh, const std::vector & old_nodes, Array & doubled_nodes) { AKANTU_DEBUG_IN(); Array & position = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt old_nb_nodes = position.getSize(); UInt new_nb_nodes = old_nb_nodes + old_nodes.size(); UInt old_nb_doubled_nodes = doubled_nodes.getSize(); UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.size(); position.resize(new_nb_nodes); doubled_nodes.resize(new_nb_doubled_nodes); Array::iterator > position_begin = position.begin(spatial_dimension); for (UInt n = 0; n < old_nodes.size(); ++n) { UInt new_node = old_nb_nodes + n; /// store doubled nodes doubled_nodes(old_nb_doubled_nodes + n, 0) = old_nodes[n]; doubled_nodes(old_nb_doubled_nodes + n, 1) = new_node; /// update position std::copy(position_begin + old_nodes[n], position_begin + old_nodes[n] + 1, position_begin + new_node); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array & doubled_nodes, bool facet_mode) { AKANTU_DEBUG_IN(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(facet_dimension, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(facet_dimension, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); const UInt nb_subfacet_per_facet = Mesh::getNbFacetsPerElement(type_facet); GhostType gt_subfacet = _casper; Array > * f_to_subfacet = NULL; Array & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); UInt nb_nodes_per_facet = conn_facet.getNbComponent(); UInt old_nb_facet = conn_facet.getSize(); UInt new_nb_facet = old_nb_facet + nb_facet_to_double; conn_facet.resize(new_nb_facet); subfacet_to_facet.resize(new_nb_facet); UInt new_facet = old_nb_facet - 1; Element new_facet_el(type_facet, 0, gt_facet); Array::iterator > subfacet_to_facet_begin = subfacet_to_facet.begin(nb_subfacet_per_facet); Array::iterator > conn_facet_begin = conn_facet.begin(nb_nodes_per_facet); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); ++new_facet; /// adding a new facet by copying original one /// copy connectivity in new facet std::copy(conn_facet_begin + old_facet, conn_facet_begin + old_facet + 1, conn_facet_begin + new_facet); /// update subfacet_to_facet std::copy(subfacet_to_facet_begin + old_facet, subfacet_to_facet_begin + old_facet + 1, subfacet_to_facet_begin + new_facet); new_facet_el.element = new_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet_per_facet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; f_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, subfacet.ghost_type); } /// update facet_to_subfacet array (*f_to_subfacet)(subfacet.element).push_back(new_facet_el); } } /// update facet_to_subfacet and _segment_3 facets if any if (!facet_mode) { updateSubfacetToFacet(mesh_facets, type_facet, gt_facet, true); updateFacetToSubfacet(mesh_facets, type_facet, gt_facet, true); updateQuadraticSegments(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } else updateQuadraticSegments(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateFacetToDouble( Mesh & mesh_facets, const ElementTypeMapArray & facet_insertion) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); UInt nb_facets_to_double = 0.; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; const Array & f_insertion = facet_insertion(type_facet, gt_facet); Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); Array > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); ElementType el_type = _not_defined; GhostType el_gt = _casper; UInt nb_facet_per_element = 0; Element old_facet_el(type_facet, 0, gt_facet); Array * facet_to_element = NULL; for (UInt f = 0; f < f_insertion.getSize(); ++f) { if (f_insertion(f) == false) continue; ++nb_facets_to_double; if (element_to_facet(f)[1].type == _not_defined #if defined(AKANTU_COHESIVE_ELEMENT) || element_to_facet(f)[1].kind == _ek_cohesive #endif ) { AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary"); continue; } f_to_double.push_back(f); UInt new_facet = mesh_facets.getNbElement(type_facet, gt_facet) + f_to_double.getSize() - 1; old_facet_el.element = f; /// update facet_to_element vector Element & elem_to_update = element_to_facet(f)[1]; UInt el = elem_to_update.element; if (elem_to_update.ghost_type != el_gt || elem_to_update.type != el_type) { el_type = elem_to_update.type; el_gt = elem_to_update.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(el_type, el_gt); nb_facet_per_element = facet_to_element->getNbComponent(); } Element * f_update = std::find(facet_to_element->storage() + el * nb_facet_per_element, facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, old_facet_el); AKANTU_DEBUG_ASSERT( facet_to_element->storage() + el * nb_facet_per_element != facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, "Facet not found"); f_update->element = new_facet; /// update elements connected to facet std::vector first_facet_list = element_to_facet(f); element_to_facet.push_back(first_facet_list); /// set new and original facets as boundary facets element_to_facet(new_facet)[0] = element_to_facet(new_facet)[1]; element_to_facet(f)[1] = ElementNull; element_to_facet(new_facet)[1] = ElementNull; } } } AKANTU_DEBUG_OUT(); return nb_facets_to_double; } /* -------------------------------------------------------------------------- */ void MeshUtils::resetFacetToDouble(Mesh & mesh_facets) { AKANTU_DEBUG_IN(); for (UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType)g; Mesh::type_iterator it = mesh_facets.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh_facets.lastType(_all_dimensions, gt); for (; it != end; ++it) { ElementType type = *it; mesh_facets.getDataPointer("facet_to_double", type, gt, 1, false); mesh_facets.getDataPointer >( "facets_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer >( "elements_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer >( "subfacets_to_subsubfacet_double", type, gt, 1, false); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MeshUtils::findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); GhostType gt_subfacet = _casper; ElementType type_subsubfacet = Mesh::getFacetType(type_subfacet); GhostType gt_subsubfacet = _casper; Array * conn_subfacet = NULL; Array * sf_to_double = NULL; Array > * sf_to_subfacet_double = NULL; Array > * f_to_subfacet_double = NULL; Array > * el_to_subfacet_double = NULL; UInt nb_subfacet = Mesh::getNbFacetsPerElement(type_facet); UInt nb_subsubfacet; UInt nb_nodes_per_sf_el; if (subsubfacet_mode) { nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subsubfacet); nb_subsubfacet = Mesh::getNbFacetsPerElement(type_subfacet); } else nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subfacet); Array & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array * subsubfacet_to_subfacet = NULL; UInt old_nb_facet = subfacet_to_facet.getSize() - nb_facet_to_double; Element current_facet(type_facet, 0, gt_facet); std::vector element_list; std::vector facet_list; std::vector * subfacet_list; if (subsubfacet_mode) subfacet_list = new std::vector; /// map to filter subfacets Array > * facet_to_subfacet = NULL; /// this is used to make sure that both new and old facets are /// checked UInt facets[2]; /// loop on every facet for (UInt f_index = 0; f_index < 2; ++f_index) { for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { facets[bool(f_index)] = f_to_double(facet); facets[!bool(f_index)] = old_nb_facet + facet; UInt old_facet = facets[0]; UInt new_facet = facets[1]; Element & starting_element = element_to_facet(new_facet)[0]; current_facet.element = old_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; if (subsubfacet_mode) { subsubfacet_to_subfacet = &mesh_facets.getSubelementToElement( type_subfacet, gt_subfacet); } else { conn_subfacet = &mesh_facets.getConnectivity(type_subfacet, gt_subfacet); sf_to_double = &mesh_facets.getData( "facet_to_double", type_subfacet, gt_subfacet); f_to_subfacet_double = &mesh_facets.getData >( "facets_to_subfacet_double", type_subfacet, gt_subfacet); el_to_subfacet_double = &mesh_facets.getData >( "elements_to_subfacet_double", type_subfacet, gt_subfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subfacet, gt_subfacet); } } if (subsubfacet_mode) { /// loop on every subsubfacet for (UInt ssf = 0; ssf < nb_subsubfacet; ++ssf) { Element & subsubfacet = (*subsubfacet_to_subfacet)(subfacet.element, ssf); if (subsubfacet == ElementNull) continue; if (gt_subsubfacet != subsubfacet.ghost_type) { gt_subsubfacet = subsubfacet.ghost_type; conn_subfacet = &mesh_facets.getConnectivity(type_subsubfacet, gt_subsubfacet); sf_to_double = &mesh_facets.getData( "facet_to_double", type_subsubfacet, gt_subsubfacet); sf_to_subfacet_double = &mesh_facets.getData >( "subfacets_to_subsubfacet_double", type_subsubfacet, gt_subsubfacet); f_to_subfacet_double = &mesh_facets.getData >( "facets_to_subfacet_double", type_subsubfacet, gt_subsubfacet); el_to_subfacet_double = &mesh_facets.getData >( "elements_to_subfacet_double", type_subsubfacet, gt_subsubfacet); facet_to_subfacet = &mesh_facets.getElementToSubelement( type_subsubfacet, gt_subsubfacet); } UInt global_ssf = subsubfacet.element; Vector subsubfacet_connectivity( conn_subfacet->storage() + global_ssf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subsubfacet is to be doubled if (findElementsAroundSubfacet( mesh, mesh_facets, starting_element, current_facet, subsubfacet_connectivity, element_list, facet_list, subfacet_list) == false && removeElementsInVector(*subfacet_list, (*facet_to_subfacet)(global_ssf)) == false) { sf_to_double->push_back(global_ssf); sf_to_subfacet_double->push_back(*subfacet_list); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } else { const UInt global_sf = subfacet.element; Vector subfacet_connectivity( conn_subfacet->storage() + global_sf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subfacet is to be doubled if (findElementsAroundSubfacet( mesh, mesh_facets, starting_element, current_facet, subfacet_connectivity, element_list, facet_list) == false && removeElementsInVector( facet_list, (*facet_to_subfacet)(global_sf)) == false) { sf_to_double->push_back(global_sf); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } } } if (subsubfacet_mode) delete subfacet_list; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); Array * facet_to_coh_element = mesh_facets.getSubelementToElementPointer(type_cohesive, gt_facet); Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array * conn_cohesive = mesh.getConnectivityPointer(type_cohesive, gt_facet); UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet); Array > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); UInt old_nb_cohesive_elements = conn_cohesive->getSize(); UInt new_nb_cohesive_elements = conn_cohesive->getSize() + nb_facet_to_double; UInt old_nb_facet = element_to_facet.getSize() - nb_facet_to_double; facet_to_coh_element->resize(new_nb_cohesive_elements); conn_cohesive->resize(new_nb_cohesive_elements); UInt new_elements_old_size = new_elements.getSize(); new_elements.resize(new_elements_old_size + nb_facet_to_double); Element c_element(type_cohesive, 0, gt_facet, _ek_cohesive); Element f_element(type_facet, 0, gt_facet); UInt facets[2]; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { /// (in 3D cohesive elements connectivity is inverted) facets[third_dimension] = f_to_double(facet); facets[!third_dimension] = old_nb_facet + facet; UInt cohesive_element = old_nb_cohesive_elements + facet; /// store doubled facets f_element.element = facets[0]; (*facet_to_coh_element)(cohesive_element, 0) = f_element; f_element.element = facets[1]; (*facet_to_coh_element)(cohesive_element, 1) = f_element; /// modify cohesive elements' connectivity for (UInt n = 0; n < nb_nodes_per_facet; ++n) { (*conn_cohesive)(cohesive_element, n) = conn_facet(facets[0], n); (*conn_cohesive)(cohesive_element, n + nb_nodes_per_facet) = conn_facet(facets[1], n); } /// update element_to_facet vectors c_element.element = cohesive_element; element_to_facet(facets[0])[1] = c_element; element_to_facet(facets[1])[1] = c_element; /// add cohesive element to the element event list new_elements(new_elements_old_size + facet) = c_element; } } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); if (spatial_dimension != 1) return; Array & position = mesh.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for (; it != end; ++it) { ElementType type_facet = *it; Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); const Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); UInt old_nb_facet = element_to_facet.getSize() - nb_facet_to_double; UInt new_nb_facet = element_to_facet.getSize(); UInt old_nb_nodes = position.getSize(); UInt new_nb_nodes = old_nb_nodes + nb_facet_to_double; position.resize(new_nb_nodes); conn_facet.resize(new_nb_facet); UInt old_nb_doubled_nodes = doubled_nodes.getSize(); doubled_nodes.resize(old_nb_doubled_nodes + nb_facet_to_double); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt new_facet = old_nb_facet + facet; ElementType type = element_to_facet(new_facet)[0].type; UInt el = element_to_facet(new_facet)[0].element; GhostType gt = element_to_facet(new_facet)[0].ghost_type; UInt old_node = conn_facet(old_facet); UInt new_node = old_nb_nodes + facet; /// update position position(new_node) = position(old_node); conn_facet(new_facet) = new_node; Array & conn_segment = mesh.getConnectivity(type, gt); UInt nb_nodes_per_segment = conn_segment.getNbComponent(); /// update facet connectivity UInt i; for (i = 0; conn_segment(el, i) != old_node && i <= nb_nodes_per_segment; ++i) ; conn_segment(el, i) = new_node; doubled_nodes(old_nb_doubled_nodes + facet, 0) = old_node; doubled_nodes(old_nb_doubled_nodes + facet, 1) = new_node; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MeshUtils::updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array & doubled_nodes) { AKANTU_DEBUG_IN(); if (type_facet != _segment_3) return; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); UInt old_nb_facet = mesh_facets.getNbElement(type_facet, gt_facet) - nb_facet_to_double; Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); /// this ones matter only for segments in 3D Array > * el_to_subfacet_double = NULL; Array > * f_to_subfacet_double = NULL; if (third_dim_segments) { el_to_subfacet_double = &mesh_facets.getData >( "elements_to_subfacet_double", type_facet, gt_facet); f_to_subfacet_double = &mesh_facets.getData >( "facets_to_subfacet_double", type_facet, gt_facet); } std::vector middle_nodes; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt node = conn_facet(old_facet, 2); if (!mesh.isPureGhostNode(node)) middle_nodes.push_back(node); } UInt n = doubled_nodes.getSize(); doubleNodes(mesh, middle_nodes, doubled_nodes); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt old_node = conn_facet(old_facet, 2); if (mesh.isPureGhostNode(old_node)) continue; UInt new_node = doubled_nodes(n, 1); UInt new_facet = old_nb_facet + facet; conn_facet(new_facet, 2) = new_node; if (third_dim_segments) { updateElementalConnectivity(mesh_facets, old_node, new_node, element_to_facet(new_facet)); updateElementalConnectivity(mesh, old_node, new_node, (*el_to_subfacet_double)(facet), &(*f_to_subfacet_double)(facet)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_facet(new_facet)); } ++n; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array & sf_to_double = mesh_facets.getData("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); /// update subfacet_to_facet vector ElementType type_facet = _not_defined; GhostType gt_facet = _casper; Array * subfacet_to_facet = NULL; UInt nb_subfacet_per_facet = 0; UInt old_nb_subfacet = mesh_facets.getNbElement(type_subfacet, gt_subfacet) - nb_subfacet_to_double; Array > * facet_list = NULL; if (facet_mode) facet_list = &mesh_facets.getData >( "facets_to_subfacet_double", type_subfacet, gt_subfacet); else facet_list = &mesh_facets.getData >( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); Element old_subfacet_el(type_subfacet, 0, gt_subfacet); Element new_subfacet_el(type_subfacet, 0, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { old_subfacet_el.element = sf_to_double(sf); new_subfacet_el.element = old_nb_subfacet + sf; for (UInt f = 0; f < (*facet_list)(sf).size(); ++f) { Element & facet = (*facet_list)(sf)[f]; if (facet.type != type_facet || facet.ghost_type != gt_facet) { type_facet = facet.type; gt_facet = facet.ghost_type; subfacet_to_facet = &mesh_facets.getSubelementToElement(type_facet, gt_facet); nb_subfacet_per_facet = subfacet_to_facet->getNbComponent(); } Element * sf_update = std::find( subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet, subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, old_subfacet_el); AKANTU_DEBUG_ASSERT(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet != subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, "Subfacet not found"); *sf_update = new_subfacet_el; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array & sf_to_double = mesh_facets.getData("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); Array > & facet_to_subfacet = mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); Array > * facet_to_subfacet_double = NULL; if (facet_mode) { facet_to_subfacet_double = &mesh_facets.getData >( "facets_to_subfacet_double", type_subfacet, gt_subfacet); } else { facet_to_subfacet_double = &mesh_facets.getData >( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); } UInt old_nb_subfacet = facet_to_subfacet.getSize(); facet_to_subfacet.resize(old_nb_subfacet + nb_subfacet_to_double); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) facet_to_subfacet(old_nb_subfacet + sf) = (*facet_to_subfacet_double)(sf); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MeshUtils::doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes) { AKANTU_DEBUG_IN(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_subfacet = *gt; Mesh::type_iterator it = mesh_facets.firstType(0, gt_subfacet); Mesh::type_iterator end = mesh_facets.lastType(0, gt_subfacet); for (; it != end; ++it) { ElementType type_subfacet = *it; Array & sf_to_double = mesh_facets.getData( "facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); if (nb_subfacet_to_double == 0) continue; AKANTU_DEBUG_ASSERT( type_subfacet == _point_1, "Only _point_1 subfacet doubling is supported at the moment"); Array & conn_subfacet = mesh_facets.getConnectivity(type_subfacet, gt_subfacet); UInt old_nb_subfacet = conn_subfacet.getSize(); UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double; conn_subfacet.resize(new_nb_subfacet); std::vector nodes_to_double; UInt old_nb_doubled_nodes = doubled_nodes.getSize(); /// double nodes for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_subfacet = sf_to_double(sf); nodes_to_double.push_back(conn_subfacet(old_subfacet)); } doubleNodes(mesh, nodes_to_double, doubled_nodes); /// add new nodes in connectivity for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt new_subfacet = old_nb_subfacet + sf; UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); conn_subfacet(new_subfacet) = new_node; } /// update facet and element connectivity Array > & f_to_subfacet_double = mesh_facets.getData >( "facets_to_subfacet_double", type_subfacet, gt_subfacet); Array > & el_to_subfacet_double = mesh_facets.getData >( "elements_to_subfacet_double", type_subfacet, gt_subfacet); Array > * sf_to_subfacet_double = NULL; if (spatial_dimension == 3) sf_to_subfacet_double = &mesh_facets.getData >( "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_node = doubled_nodes(old_nb_doubled_nodes + sf, 0); UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); updateElementalConnectivity(mesh, old_node, new_node, el_to_subfacet_double(sf), &f_to_subfacet_double(sf)); updateElementalConnectivity(mesh_facets, old_node, new_node, f_to_subfacet_double(sf)); if (spatial_dimension == 3) updateElementalConnectivity(mesh_facets, old_node, new_node, (*sf_to_subfacet_double)(sf)); } if (spatial_dimension == 2) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, true); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, true); } else if (spatial_dimension == 3) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, false); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::flipFacets( Mesh & mesh_facets, const ElementTypeMapArray & global_connectivity, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); /// get global connectivity for local mesh ElementTypeMapArray global_connectivity_tmp; mesh_facets.initElementTypeMapArray(global_connectivity_tmp, 1, spatial_dimension - 1, gt_facet, true, _ek_regular, true); mesh_facets.getGlobalConnectivity(global_connectivity_tmp, spatial_dimension - 1, gt_facet); Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); /// loop on every facet for (; it != end; ++it) { ElementType type_facet = *it; Array & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet); const Array & g_connectivity = global_connectivity(type_facet, gt_facet); Array > & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); UInt nb_subfacet_per_facet = subfacet_to_facet.getNbComponent(); UInt nb_nodes_per_facet = connectivity.getNbComponent(); UInt nb_facet = connectivity.getSize(); UInt nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); Array & global_conn_tmp = global_connectivity_tmp(type_facet, gt_facet); Array::iterator > conn_it = connectivity.begin(nb_nodes_per_facet); Array::iterator > gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet); Array::const_iterator > conn_glob_it = g_connectivity.begin(nb_nodes_per_facet); Array::iterator > subf_to_f = subfacet_to_facet.begin(nb_subfacet_per_facet); UInt * conn_tmp_pointer = new UInt[nb_nodes_per_facet]; Vector conn_tmp(conn_tmp_pointer, nb_nodes_per_facet); Element el_tmp; Element * subf_tmp_pointer = new Element[nb_subfacet_per_facet]; Vector subf_tmp(subf_tmp_pointer, nb_subfacet_per_facet); for (UInt f = 0; f < nb_facet; ++f, ++conn_it, ++gconn_tmp_it, ++subf_to_f, ++conn_glob_it) { Vector & gconn_tmp = *gconn_tmp_it; const Vector & conn_glob = *conn_glob_it; Vector & conn_local = *conn_it; /// skip facet if connectivities are the same if (gconn_tmp == conn_glob) continue; /// re-arrange connectivity conn_tmp = conn_local; UInt * begin = conn_glob.storage(); UInt * end = conn_glob.storage() + nb_nodes_per_facet; for (UInt n = 0; n < nb_nodes_per_facet; ++n) { UInt * new_node = std::find(begin, end, gconn_tmp(n)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; conn_local(new_position) = conn_tmp(n); } /// if 3D, check if facets are just rotated if (spatial_dimension == 3) { /// find first node UInt * new_node = std::find(begin, end, gconn_tmp(0)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; UInt n = 1; /// count how many nodes in the received connectivity follow /// the same order of those in the local connectivity for (; n < nb_nodes_per_P1_facet && gconn_tmp(n) == conn_glob((new_position + n) % nb_nodes_per_P1_facet); ++n) ; /// skip the facet inversion if facet is just rotated if (n == nb_nodes_per_P1_facet) continue; } /// update data to invert facet el_tmp = el_to_f(f)[0]; el_to_f(f)[0] = el_to_f(f)[1]; el_to_f(f)[1] = el_tmp; subf_tmp = (*subf_to_f); (*subf_to_f)(0) = subf_tmp(1); (*subf_to_f)(1) = subf_tmp(0); } delete[] subf_tmp_pointer; delete[] conn_tmp_pointer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::fillElementToSubElementsData(Mesh & mesh) { AKANTU_DEBUG_IN(); if (mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) { AKANTU_DEBUG_INFO("There are not facets, add them in the mesh file or call " "the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray barycenters("barycenter_tmp", mesh.getID()); mesh.initElementTypeMapArray(barycenters, spatial_dimension, _all_dimensions); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator it = mesh.firstType(_all_dimensions, *gt); Mesh::type_iterator end = mesh.lastType(_all_dimensions, *gt); for (; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, *gt); Array & barycenters_arr = barycenters(*it, *gt); barycenters_arr.resize(nb_element); Array::vector_iterator bary = barycenters_arr.begin(spatial_dimension); Array::vector_iterator bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { mesh.getBarycenter(el, *it, bary->storage(), *gt); } } } for (Int sp(spatial_dimension); sp >= 1; --sp) { if (mesh.getNbElement(sp) == 0) continue; for (ghost_type_t::iterator git = ghost_type_t::begin(); git != ghost_type_t::end(); ++git) { Mesh::type_iterator tit = mesh.firstType(sp, *git); Mesh::type_iterator tend = mesh.lastType(sp, *git); for (; tit != tend; ++tit) { mesh.getSubelementToElementPointer(*tit, *git) ->resize(mesh.getNbElement(*tit, *git)); mesh.getSubelementToElement(*tit, *git).clear(); } tit = mesh.firstType(sp - 1, *git); tend = mesh.lastType(sp - 1, *git); for (; tit != tend; ++tit) { mesh.getElementToSubelementPointer(*tit, *git) ->resize(mesh.getNbElement(*tit, *git)); mesh.getElementToSubelement(*tit, *git).clear(); } } CSR nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (ghost_type_t::iterator git = ghost_type_t::begin(); git != ghost_type_t::end(); ++git) { Mesh::type_iterator tit = mesh.firstType(sp - 1, *git); Mesh::type_iterator tend = mesh.lastType(sp - 1, *git); facet_element.ghost_type = *git; for (; tit != tend; ++tit) { facet_element.type = *tit; Array > & element_to_subelement = mesh.getElementToSubelement(*tit, *git); const Array & connectivity = mesh.getConnectivity(*tit, *git); Array::const_iterator > fit = connectivity.begin(mesh.getNbNodesPerElement(*tit)); Array::const_iterator > fend = connectivity.end(mesh.getNbNodesPerElement(*tit)); UInt fid = 0; for (; fit != fend; ++fit, ++fid) { const Vector & facet = *fit; facet_element.element = fid; std::map element_seen_counter; UInt nb_nodes_per_facet = mesh.getNbNodesPerElement(Mesh::getP1ElementType(*tit)); for (UInt n(0); n < nb_nodes_per_facet; ++n) { CSR::iterator eit = nodes_to_elements.begin(facet(n)); CSR::iterator eend = nodes_to_elements.end(facet(n)); for (; eit != eend; ++eit) { Element & elem = *eit; std::map::iterator cit = element_seen_counter.find(elem); if (cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } std::vector connected_elements; std::map::iterator cit = element_seen_counter.begin(); std::map::iterator cend = element_seen_counter.end(); for (; cit != cend; ++cit) { if (cit->second == nb_nodes_per_facet) connected_elements.push_back(cit->first); } std::vector::iterator ceit = connected_elements.begin(); std::vector::iterator ceend = connected_elements.end(); for (; ceit != ceend; ++ceit) element_to_subelement(fid).push_back(*ceit); for (UInt ce = 0; ce < connected_elements.size(); ++ce) { Element & elem = connected_elements[ce]; Array & subelement_to_element = *(mesh.getSubelementToElementPointer(elem.type, elem.ghost_type)); UInt f(0); for (; f < mesh.getNbFacetsPerElement(elem.type) && subelement_to_element(elem.element, f) != ElementNull; ++f) ; AKANTU_DEBUG_ASSERT( f < mesh.getNbFacetsPerElement(elem.type), "The element " << elem << " seems to have too many facets!! (" << f << " < " << mesh.getNbFacetsPerElement(elem.type) << ")"); subelement_to_element(elem.element, f) = facet_element; } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template bool MeshUtils::findElementsAroundSubfacet( const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector & subfacet_connectivity, std::vector & elem_list, std::vector & facet_list, std::vector * subfacet_list) { AKANTU_DEBUG_IN(); /// preallocated stuff before starting bool facet_matched = false; elem_list.clear(); facet_list.clear(); if (third_dim_points) subfacet_list->clear(); elem_list.push_back(starting_element); const Array * facet_connectivity = NULL; const Array * sf_connectivity = NULL; const Array * facet_to_element = NULL; const Array * subfacet_to_facet = NULL; ElementType current_type = _not_defined; GhostType current_ghost_type = _casper; ElementType current_facet_type = _not_defined; GhostType current_facet_ghost_type = _casper; ElementType current_subfacet_type = _not_defined; GhostType current_subfacet_ghost_type = _casper; const Array > * element_to_facet = NULL; const Element * opposing_el = NULL; std::queue elements_to_check; elements_to_check.push(starting_element); /// keep going until there are elements to check while (!elements_to_check.empty()) { /// check current element Element & current_el = elements_to_check.front(); if (current_el.type != current_type || current_el.ghost_type != current_ghost_type) { current_type = current_el.type; current_ghost_type = current_el.ghost_type; facet_to_element = &mesh_facets.getSubelementToElement(current_type, current_ghost_type); } /// loop over each facet of the element for (UInt f = 0; f < facet_to_element->getNbComponent(); ++f) { const Element & current_facet = (*facet_to_element)(current_el.element, f); if (current_facet == ElementNull) continue; if (current_facet_type != current_facet.type || current_facet_ghost_type != current_facet.ghost_type) { current_facet_type = current_facet.type; current_facet_ghost_type = current_facet.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( current_facet_type, current_facet_ghost_type); facet_connectivity = &mesh_facets.getConnectivity( current_facet_type, current_facet_ghost_type); if (third_dim_points) subfacet_to_facet = &mesh_facets.getSubelementToElement( current_facet_type, current_facet_ghost_type); } /// check if end facet is reached if (current_facet == end_facet) facet_matched = true; /// add this facet if not already passed if (std::find(facet_list.begin(), facet_list.end(), current_facet) == facet_list.end() && hasElement(*facet_connectivity, current_facet, subfacet_connectivity)) { facet_list.push_back(current_facet); if (third_dim_points) { /// check subfacets for (UInt sf = 0; sf < subfacet_to_facet->getNbComponent(); ++sf) { const Element & current_subfacet = (*subfacet_to_facet)(current_facet.element, sf); if (current_subfacet == ElementNull) continue; if (current_subfacet_type != current_subfacet.type || current_subfacet_ghost_type != current_subfacet.ghost_type) { current_subfacet_type = current_subfacet.type; current_subfacet_ghost_type = current_subfacet.ghost_type; sf_connectivity = &mesh_facets.getConnectivity( current_subfacet_type, current_subfacet_ghost_type); } if (std::find(subfacet_list->begin(), subfacet_list->end(), current_subfacet) == subfacet_list->end() && hasElement(*sf_connectivity, current_subfacet, subfacet_connectivity)) subfacet_list->push_back(current_subfacet); } } } else continue; /// consider opposing element if ((*element_to_facet)(current_facet.element)[0] == current_el) opposing_el = &(*element_to_facet)(current_facet.element)[1]; else opposing_el = &(*element_to_facet)(current_facet.element)[0]; /// skip null elements since they are on a boundary if (*opposing_el == ElementNull) continue; /// skip this element if already added if (std::find(elem_list.begin(), elem_list.end(), *opposing_el) != elem_list.end()) continue; /// only regular elements have to be checked if (opposing_el->kind == _ek_regular) elements_to_check.push(*opposing_el); elem_list.push_back(*opposing_el); #ifndef AKANTU_NDEBUG const Array & conn_elem = mesh.getConnectivity(opposing_el->type, opposing_el->ghost_type); AKANTU_DEBUG_ASSERT( hasElement(conn_elem, *opposing_el, subfacet_connectivity), "Subfacet doesn't belong to this element"); #endif } /// erased checked element from the list elements_to_check.pop(); } AKANTU_DEBUG_OUT(); return facet_matched; } /* -------------------------------------------------------------------------- */ void MeshUtils::buildSegmentToNodeType(const Mesh & mesh, Mesh & mesh_facets, DistributedSynchronizer * synchronizer) { buildAllFacets(mesh, mesh_facets, 1, synchronizer); UInt spatial_dimension = mesh.getSpatialDimension(); const ElementTypeMapArray & element_to_rank = synchronizer->getPrankToElement(); Int local_rank = StaticCommunicator::getStaticCommunicator().whoAmI(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(1, ghost_type); for (; it != end; ++it) { ElementType type = *it; UInt nb_segments = mesh_facets.getNbElement(type, ghost_type); // allocate the data Array & segment_to_nodetype = *(mesh_facets.getDataPointer( "segment_to_nodetype", type, ghost_type)); std::set connected_elements; const Array > & segment_to_2Delement = mesh_facets.getElementToSubelement(type, ghost_type); // loop over segments for (UInt s = 0; s < nb_segments; ++s) { // determine the elements connected to the segment connected_elements.clear(); const std::vector & twoD_elements = segment_to_2Delement(s); if (spatial_dimension == 2) { // if 2D just take the elements connected to the segments connected_elements.insert(twoD_elements.begin(), twoD_elements.end()); } else if (spatial_dimension == 3) { // if 3D a second loop is needed to get to the 3D elements std::vector::const_iterator facet = twoD_elements.begin(); for (; facet != twoD_elements.end(); ++facet) { const std::vector & threeD_elements = mesh_facets.getElementToSubelement( facet->type, facet->ghost_type)(facet->element); connected_elements.insert(threeD_elements.begin(), threeD_elements.end()); } } // get the minimum processor rank associated to the connected // elements and verify if ghost and not ghost elements are // found Int minimum_rank = std::numeric_limits::max(); // two booleans saying if not ghost and ghost elements are found in the // loop bool ghost_found[2]; ghost_found[0] = false; ghost_found[1] = false; std::set::iterator connected_elements_it = connected_elements.begin(); for (; connected_elements_it != connected_elements.end(); ++connected_elements_it) { if (*connected_elements_it == ElementNull) continue; ghost_found[connected_elements_it->ghost_type] = true; const Array & el_to_rank_array = element_to_rank( connected_elements_it->type, connected_elements_it->ghost_type); minimum_rank = std::min(minimum_rank, Int(el_to_rank_array(connected_elements_it->element))); } // if no ghost elements are found the segment is local if (!ghost_found[1]) segment_to_nodetype(s) = -1; // if no not ghost elements are found the segment is pure ghost else if (!ghost_found[0]) segment_to_nodetype(s) = -3; // if the minimum rank is equal to the local rank, the segment is master else if (local_rank == minimum_rank) segment_to_nodetype(s) = -2; // if the minimum rank is less than the local rank, the segment is slave else if (local_rank > minimum_rank) segment_to_nodetype(s) = minimum_rank; else AKANTU_DEBUG_ERROR("The local rank cannot be smaller than the " "minimum rank if both ghost and not ghost " "elements are found"); } } } } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateLocalMasterGlobalConnectivity(Mesh & mesh, UInt local_nb_new_nodes) { StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int rank = comm.whoAmI(); Int nb_proc = comm.getNbProc(); if (nb_proc == 1) return local_nb_new_nodes; /// resize global ids array Array & nodes_global_ids = mesh.getGlobalNodesIds(); UInt old_nb_nodes = mesh.getNbNodes() - local_nb_new_nodes; nodes_global_ids.resize(mesh.getNbNodes()); /// compute the number of global nodes based on the number of old nodes Vector old_local_master_nodes(nb_proc); for (UInt n = 0; n < old_nb_nodes; ++n) if (mesh.isLocalOrMasterNode(n)) ++old_local_master_nodes(rank); - comm.allGather(old_local_master_nodes.storage(), 1); + comm.allGather(old_local_master_nodes); UInt old_global_nodes = std::accumulate(old_local_master_nodes.storage(), old_local_master_nodes.storage() + nb_proc, 0); /// compute amount of local or master doubled nodes Vector local_master_nodes(nb_proc); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) if (mesh.isLocalOrMasterNode(n)) ++local_master_nodes(rank); - comm.allGather(local_master_nodes.storage(), 1); + comm.allGather(local_master_nodes); /// update global number of nodes UInt total_nb_new_nodes = std::accumulate( local_master_nodes.storage(), local_master_nodes.storage() + nb_proc, 0); if (total_nb_new_nodes == 0) return 0; /// set global ids of local and master nodes UInt starting_index = std::accumulate(local_master_nodes.storage(), local_master_nodes.storage() + rank, old_global_nodes); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) { nodes_global_ids(n) = starting_index; ++starting_index; } } mesh.nb_global_nodes = old_global_nodes + total_nb_new_nodes; return total_nb_new_nodes; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ // LocalWords: ElementType diff --git a/src/mesh_utils/mesh_utils.hh b/src/mesh_utils/mesh_utils.hh index 2f3e2fc7e..a050623e5 100644 --- a/src/mesh_utils/mesh_utils.hh +++ b/src/mesh_utils/mesh_utils.hh @@ -1,249 +1,249 @@ /** * @file mesh_utils.hh * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Leonardo Snozzi * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Oct 02 2015 * * @brief All mesh utils necessary for various tasks * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "aka_csr.hh" #include "distributed_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_UTILS_HH__ #define __AKANTU_MESH_UTILS_HH__ /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class MeshUtils { /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// build a CSR that contains for each node the linearized number of /// the connected elements of a given spatial dimension static void buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension = _all_dimensions); /// build a CSR that contains for each node the list of connected /// elements of a given spatial dimension static void buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension = _all_dimensions); /// build a CSR that contains for each node the number of /// the connected elements of a given ElementType static void buildNode2ElementsElementTypeMap(const Mesh & mesh, CSR & node_to_elem, const ElementType & type, const GhostType & ghost_type = _not_ghost); /// build the facets elements on the boundaries of a mesh static void buildFacets(Mesh & mesh); /// build all the facets elements: boundary and internals and store them in /// the mesh_facets for element of dimension from_dimension to to_dimension static void buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension, DistributedSynchronizer * synchronizer = NULL); /// build all the facets elements: boundary and internals and store them in /// the mesh_facets static void buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension = 0, DistributedSynchronizer * synchronizer = NULL); /// build facets for a given spatial dimension static void buildFacetsDimension( const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, const ElementTypeMapArray * prank_to_element = NULL); /// take the local_connectivity array as the array of local and ghost /// connectivity, renumber the nodes and set the connectivity of the mesh - static void renumberMeshNodes(Mesh & mesh, UInt * local_connectivities, + static void renumberMeshNodes(Mesh & mesh, Array & local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array & old_nodes); /// compute pbc pair for a given direction static void computePBCMap(const Mesh & mymesh, const UInt dir, std::map & pbc_pair); /// compute pbc pair for a surface pair static void computePBCMap(const Mesh & mymesh, const std::pair & surface_pair, std::map & pbc_pair); /// remove not connected nodes /!\ this functions renumbers the nodes. static void purifyMesh(Mesh & mesh); #if defined(AKANTU_COHESIVE_ELEMENT) /// function to insert cohesive elements on the selected facets /// @return number of facets that have been doubled static UInt insertCohesiveElements(Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray & facet_insertion, Array & doubled_nodes, Array & new_elements, bool only_double_facets); #endif /// fill the subelement to element and the elements to subelements data static void fillElementToSubElementsData(Mesh & mesh); /// flip facets based on global connectivity static void flipFacets(Mesh & mesh_facets, const ElementTypeMapArray & global_connectivity, GhostType gt_facet); /// provide list of elements around a node and check if a given /// facet is reached template static bool findElementsAroundSubfacet( const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector & subfacet_connectivity, std::vector & elem_list, std::vector & facet_list, std::vector * subfacet_list = NULL); /// function to check if a node belongs to a given element static inline bool hasElement(const Array & connectivity, const Element & el, const Vector & nodes); /// reset facet_to_double arrays in the Mesh static void resetFacetToDouble(Mesh & mesh_facets); /// associate a node type to each segment in the mesh static void buildSegmentToNodeType(const Mesh & mesh, Mesh & mesh_facets, DistributedSynchronizer * synchronizer); /// update local and master global connectivity when new nodes are added static UInt updateLocalMasterGlobalConnectivity(Mesh & mesh, UInt old_nb_nodes); private: /// match pairs that are on the associated pbc's static void matchPBCPairs(const Mesh & mymesh, const UInt dir, Array & selected_left, Array & selected_right, std::map & pbc_pair); /// function used by all the renumbering functions static void - renumberNodesInConnectivity(UInt * list_nodes, UInt nb_nodes, + renumberNodesInConnectivity(Array & list_nodes, UInt nb_nodes, std::map & renumbering_map); /// update facet_to_subfacet static void updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// update subfacet_to_facet static void updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// function to double a given facet and update the list of doubled /// nodes static void doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array & doubled_nodes, bool facet_mode); /// function to double a subfacet given start and end index for /// local facet_to_subfacet vector, and update the list of doubled /// nodes template static void doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes); /// double a node static void doubleNodes(Mesh & mesh, const std::vector & old_nodes, Array & doubled_nodes); /// fill facet_to_double array in the mesh /// returns the number of facets to be doubled static UInt updateFacetToDouble(Mesh & mesh_facets, const ElementTypeMapArray & facet_insertion); /// find subfacets to be doubled template static void findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets); /// double facets (points) in 1D static void doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes); #if defined(AKANTU_COHESIVE_ELEMENT) /// update cohesive element data static void updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array & new_elements); #endif /// update elemental connectivity after doubling a node inline static void updateElementalConnectivity(Mesh & mesh, UInt old_node, UInt new_node, const std::vector & element_list, const std::vector * facet_list = NULL); /// double middle nodes if facets are _segment_3 template static void updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array & doubled_nodes); /// remove elements on a vector inline static bool removeElementsInVector(const std::vector & elem_to_remove, std::vector & elem_list); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "mesh_utils_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MESH_UTILS_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index f212d4fef..d4fd26917 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1463 +1,1463 @@ /** * @file solid_mechanics_model.cc * * @author Ramin Aghababaei * @author Guillaume Anciaux * @author Aurelia Isabel Cuba Ramos * @author David Simon Kammer * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Clement Roux * @author Marco Vocialta * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Jan 19 2016 * * @brief Implementation of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_math.hh" #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "group_manager_inline_impl.cc" #include "element_group.hh" #include "static_communicator.hh" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_field.hh" #include "dumper_paraview.hh" #include "dumper_homogenizing_field.hh" #include "dumper_internal_material_field.hh" #include "dumper_elemental_field.hh" #include "dumper_material_padders.hh" #include "dumper_element_partition.hh" #include "dumper_iohelper.hh" #endif #ifdef AKANTU_DAMAGE_NON_LOCAL #include "non_local_manager.hh" #endif /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ __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(), time_step(NAN), f_m2a(1.0), displacement(NULL), previous_displacement(NULL), increment(NULL), mass(NULL), velocity(NULL), acceleration(NULL), increment_acceleration(NULL), external_force(NULL), internal_force(NULL), blocked_dofs(NULL), current_position(NULL), material_index("material index", id), material_local_numbering("material local numbering", id), materials(0), material_selector(new DefaultMaterialSelector(material_index)), is_default_material_selector(true), increment_flag(false), synch_parallel(NULL), are_materials_instantiated(false) { AKANTU_DEBUG_IN(); this->createSynchronizerRegistry(this); this->registerFEEngineObject("SolidMechanicsFEEngine", mesh, spatial_dimension); this->mesh.registerEventHandler(*this); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper("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::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { delete *mat_it; } materials.clear(); delete synch_parallel; if (is_default_material_selector) { delete material_selector; material_selector = NULL; } flatten_internal_map::iterator fl_it = this->registered_internals.begin(); flatten_internal_map::iterator fl_end = this->registered_internals.end(); for (; fl_it != fl_end; ++fl_it) { delete fl_it->second; } #ifdef AKANTU_DAMAGE_NON_LOCAL delete non_local_manager; non_local_manager = NULL; #endif delete pbc_synch; 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 } /* -------------------------------------------------------------------------- */ /* Initialization */ /* -------------------------------------------------------------------------- */ /** * 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(options); this->method = smm_options.analysis_method; // initialize the vectors this->initArrays(); // set the initial condition to 0 external_force->clear(); velocity->clear(); acceleration->clear(); displacement->clear(); // initialize pbc if (this->pbc_pair.size() != 0) this->initPBC(); // initialize the time integration schemes // switch (this->method) { // case _explicit_lumped_mass: // this->initExplicit(); // break; // case _explicit_consistent_mass: // this->initSolver(); // this->initExplicit(); // break; // case _implicit_dynamic: // this->initImplicit(true); // break; // case _static: // this->initImplicit(false); // this->initArraysPreviousDisplacment(); // break; // default: // AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel"); // break; // } #ifdef AKANTU_DAMAGE_NON_LOCAL /// create the non-local manager object for non-local damage computations this->non_local_manager = new NonLocalManager(*this); #endif // initialize the materials if (this->parser->getLastParsedFile() != "") { this->instantiateMaterials(); } if (!smm_options.no_init_materials) { this->initMaterials(); } if (increment_flag) this->initBC(*this, *displacement, *increment, *external_force); else this->initBC(*this, *displacement, *external_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); synch_registry->registerSynchronizer(*synch_parallel, _gst_for_dump); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_not_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_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(sstr.str(), nb_nodes, nb_degree_of_freedom, Real())); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initArraysPreviousDisplacment() { AKANTU_DEBUG_IN(); this->setIncrementFlagOn(); if (not this->previous_displacement) { UInt nb_nodes = this->mesh.getNbNodes(); std::stringstream sstr_disp_t; sstr_disp_t << this->id << ":previous_displacement"; this->previous_displacement = &(this->alloc( sstr_disp_t.str(), nb_nodes, this->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_forc; sstr_forc << id << ":force"; std::stringstream sstr_ifor; sstr_forc << id << ":internal_force"; std::stringstream sstr_boun; sstr_boun << id << ":blocked_dofs"; /* ------------------------------------------------------------------------ */ // for static this->displacement = &(alloc(sstr_disp.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); this->internal_force = &(alloc(sstr_ifor.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); this->external_force = &(alloc(sstr_forc.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); this->blocked_dofs = &(alloc(sstr_boun.str(), nb_nodes, spatial_dimension, false)); this->getDOFManager().registerDOFs("displacements", *this->displacement, _dst_nodal); this->getDOFManager().registerBlockedDOFs("displacements", *this->blocked_dofs); std::stringstream sstr_curp; sstr_curp << id << ":current_position"; this->current_position = &(alloc(sstr_curp.str(), 0, spatial_dimension, REAL_INIT_VALUE)); /* ------------------------------------------------------------------------ */ // for dynamic std::stringstream sstr_velo; sstr_velo << id << ":velocity"; std::stringstream sstr_acce; sstr_acce << id << ":acceleration"; this->velocity = &(alloc(sstr_velo.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); this->acceleration = &(alloc(sstr_acce.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); this->getDOFManager().registerDOFsDerivative("displacements", 1, *this->velocity); this->getDOFManager().registerDOFsDerivative("displacements", 2, *this->acceleration); 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); this->material_index.alloc(nb_element, 1, *it, gt); this->material_local_numbering.alloc(nb_element, 1, *it, gt); } } 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::iterator it = pbc_pair.begin(); std::map::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() { pbc_synch = new PBCSynchronizer(pbc_pair); synch_registry->registerSynchronizer(*pbc_synch, _gst_smm_uv); synch_registry->registerSynchronizer(*pbc_synch, _gst_smm_mass); synch_registry->registerSynchronizer(*pbc_synch, _gst_smm_res); synch_registry->registerSynchronizer(*pbc_synch, _gst_for_dump); // changeLocalEquationNumberForPBC(pbc_pair, mesh.getSpatialDimension()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleResidual() { AKANTU_DEBUG_IN(); this->assembleInternalForces(); this->getDOFManager().assembleToResidual("displacements", *this->external_force, 1); this->getDOFManager().assembleToResidual("displacements", *this->internal_force, -1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This function computes the internal forces as F_{int} = \int_{\Omega} N * \sigma d\Omega@f$ */ void SolidMechanicsModel::assembleInternalForces() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); this->internal_force->clear(); AKANTU_DEBUG_INFO("Compute local stresses"); std::vector::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 */ this->non_local_manager->computeAllNonLocalStresses(); #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.assembleInternalForces(_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.assembleInternalForces(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleJacobian() { this->assembleStiffnessMatrix(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); // call compute stiffness matrix on each local elements std::vector::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->assembleStiffnessMatrix(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { AKANTU_DEBUG_IN(); this->current_position->copy(this->mesh.getNodes()); Array::vector_iterator cpos_it = this->current_position->begin(spatial_dimension); Array::vector_iterator cpos_end = this->current_position->end(spatial_dimension); Array::const_vector_iterator disp_it = this->displacement->begin(spatial_dimension); for (; cpos_it != cpos_end; ++cpos_it, ++disp_it) { *cpos_it += *disp_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ // void SolidMechanicsModel::initializeUpdateResidualData() { // AKANTU_DEBUG_IN(); // UInt nb_nodes = mesh.getNbNodes(); // internal_force->resize(nb_nodes); // /// copy the forces in residual for boundary conditions // this->getDOFManager().assembleToResidual("displacements", // *this->external_force); // // start synchronization // synch_registry->asynchronousSynchronize(_gst_smm_uv); // synch_registry->waitEndSynchronize(_gst_smm_uv); // this->updateCurrentPosition(); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ /* Explicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ // 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::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 */ // this->non_local_manager->computeAllNonLocalStresses(); // #endif // } else { // std::vector::iterator mat_it; // for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { // Material & mat = **mat_it; // mat.computeAllStressesFromTangentModuli(_not_ghost); // } // } // } /* -------------------------------------------------------------------------- */ /* Implicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ // /** // * Initialize the solver and create the sparse matrices needed. // * // */ // void SolidMechanicsModel::initSolver(__attribute__((unused)) // SolverOptions & options) { // UInt nb_global_nodes = mesh.getNbGlobalNodes(); // jacobian_matrix = &(this->getDOFManager().getNewMatrix("jacobian", // _symmetric)); // // jacobian_matrix->buildProfile(mesh, *dof_synchronizer, // spatial_dimension); // if (!isExplicit()) { // delete stiffness_matrix; // std::stringstream sstr_sti; // sstr_sti << id << ":stiffness_matrix"; // stiffness_matrix = &(this->getDOFManager().getNewMatrix("stiffness", // _symmetric)); // } // if (solver) solver->initialize(options); // } // /* -------------------------------------------------------------------------- // */ // void SolidMechanicsModel::initJacobianMatrix() { // // @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; // jacobian_matrix = &(this->getDOFManager().getNewMatrix("jacobian", // "stiffness")); // 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); // } /* -------------------------------------------------------------------------- */ /** * Initialize the implicit solver, either for dynamic or static cases, * * @param dynamic */ // void SolidMechanicsModel::initImplicit(bool dynamic) { // AKANTU_DEBUG_IN(); // method = dynamic ? _implicit_dynamic : _static; // if (!increment) // setIncrementFlagOn(); // initSolver(); // // if(method == _implicit_dynamic) { // // if(integrator) delete integrator; // // integrator = new TrapezoidalRule2(); // // } // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ // SparseMatrix & SolidMechanicsModel::initVelocityDampingMatrix() { // return this->getDOFManager().getNewMatrix("velocity_damping", "jacobian"); // } // /* -------------------------------------------------------------------------- // */ // 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(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); + StaticCommunicator::getStaticCommunicator().allReduce(min_dt, _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::max(); this->updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; elem.kind = _ek_regular; 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) { elem.type = *it; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); UInt nb_element = mesh.getNbElement(*it); Array::const_scalar_iterator mat_indexes = material_index(*it, ghost_type).begin(); Array::const_scalar_iterator mat_loc_num = material_local_numbering(*it, ghost_type).begin(); Array X(0, nb_nodes_per_element * spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, *it, _not_ghost); Array::matrix_iterator X_el = X.begin(spatial_dimension, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++X_el, ++mat_indexes, ++mat_loc_num) { elem.element = *mat_loc_num; Real el_h = getFEEngine().getElementInradius(*X_el, *it); Real el_c = mat_val[*mat_indexes]->getCelerity(elem); Real el_dt = el_h / el_c; min_dt = std::min(min_dt, el_dt); } } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::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); + StaticCommunicator::getStaticCommunicator().allReduce(ekin, _so_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); Array vel_on_quad(nb_quadrature_points, spatial_dimension); Array filter_element(1, 1, index); getFEEngine().interpolateOnIntegrationPoints(*velocity, vel_on_quad, spatial_dimension, type, _not_ghost, filter_element); Array::vector_iterator vit = vel_on_quad.begin(spatial_dimension); Array::vector_iterator vend = vel_on_quad.end(spatial_dimension); Vector rho_v2(nb_quadrature_points); Real rho = materials[material_index(type)(index)]->getRho(); for (UInt q = 0; vit != vend; ++vit, ++q) { rho_v2(q) = rho * vit->dot(*vit); } AKANTU_DEBUG_OUT(); return .5 * getFEEngine().integrate(rho_v2, type, index); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); Real * incr_or_velo = NULL; if (this->method == _static) { incr_or_velo = this->increment->storage(); } else { incr_or_velo = this->velocity->storage(); } Real * forc = external_force->storage(); Real * resi = internal_force->storage(); bool * boun = blocked_dofs->storage(); Real work = 0.; UInt nb_nodes = this->mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = this->mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !this->isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < this->spatial_dimension; ++i) { if (count_node) { if (*boun) work -= *resi * *incr_or_velo; else work += *forc * *incr_or_velo; } ++incr_or_velo; ++forc; ++resi; ++boun; } } - StaticCommunicator::getStaticCommunicator().allReduce(&work, 1, _so_sum); + StaticCommunicator::getStaticCommunicator().allReduce(work, _so_sum); if (this->method != _static) work *= this->time_step; 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::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); + StaticCommunicator::getStaticCommunicator().allReduce(energy, _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::iterator mat_it; UInt mat_index = this->material_index(type, _not_ghost)(index); UInt mat_loc_num = this->material_local_numbering(type, _not_ghost)(index); Real energy = this->materials[mat_index]->getEnergy(energy_id, type, mat_loc_num); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Array & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); for (UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType)g; Mesh::type_iterator it = this->mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = this->mesh.lastType(spatial_dimension, gt, _ek_not_defined); for (; it != end; ++it) { UInt nb_element = this->mesh.getNbElement(*it, gt); if (!material_index.exists(*it, gt)) { this->material_index.alloc(nb_element, 1, *it, gt); this->material_local_numbering.alloc(nb_element, 1, *it, gt); } else { this->material_index(*it, gt).resize(nb_element); this->material_local_numbering(*it, gt).resize(nb_element); } } } Array::const_iterator it = element_list.begin(); Array::const_iterator end = element_list.end(); ElementTypeMapArray filter("new_element_filter", this->getID()); for (UInt el = 0; it != end; ++it, ++el) { const Element & elem = *it; if (!filter.exists(elem.type, elem.ghost_type)) filter.alloc(0, 1, elem.type, elem.ghost_type); filter(elem.type, elem.ghost_type).push_back(elem.element); } this->assignMaterialToElements(&filter); std::vector::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsAdded(element_list, event); } if (method == _explicit_lumped_mass) this->assembleMassLumped(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved( __attribute__((unused)) const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) { this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); std::vector::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array & 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 (external_force) external_force->resize(nb_nodes); if (internal_force) internal_force->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); std::vector::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onNodesAdded(nodes_list, event); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesRemoved(__attribute__((unused)) const Array & element_list, const Array & 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 (internal_force) mesh.removeNodesFromArray(*internal_force, new_numbering); if (external_force) mesh.removeNodesFromArray(*external_force, 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); // if (method != _explicit_lumped_mass) { // this->initSolver(); // } } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::isInternal(const std::string & field_name, const ElementKind & element_kind) { bool is_internal = false; /// check if at least one material contains field_id as an internal for (UInt m = 0; m < materials.size() && !is_internal; ++m) { is_internal |= materials[m]->isInternal(field_name, element_kind); } return is_internal; } /* -------------------------------------------------------------------------- */ ElementTypeMap 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(); } /* -------------------------------------------------------------------------- */ ElementTypeMapArray & SolidMechanicsModel::flattenInternal(const std::string & field_name, const ElementKind & kind, const GhostType ghost_type) { std::pair key(field_name, kind); if (this->registered_internals.count(key) == 0) { this->registered_internals[key] = new ElementTypeMapArray(field_name, this->id); } ElementTypeMapArray * internal_flat = this->registered_internals[key]; typedef ElementTypeMapArray::type_iterator iterator; iterator tit = internal_flat->firstType(spatial_dimension, ghost_type, kind); iterator end = internal_flat->lastType(spatial_dimension, ghost_type, kind); for (; tit != end; ++tit) { ElementType type = *tit; (*internal_flat)(type, ghost_type).clear(); } for (UInt m = 0; m < materials.size(); ++m) { if (materials[m]->isInternal(field_name, kind)) materials[m]->flattenInternal(field_name, *internal_flat, ghost_type, kind); } return *internal_flat; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::flattenAllRegisteredInternals( const ElementKind & kind) { typedef std::map, ElementTypeMapArray *>::iterator iterator; iterator it = this->registered_internals.begin(); 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 UInt & spatial_dimension, const ElementKind & kind) { dumper::Field * field = NULL; if (field_name == "partitions") field = mesh.createElementalField( mesh.getConnectivities(), group_name, spatial_dimension, kind); else if (field_name == "material_index") field = mesh.createElementalField( material_index, group_name, spatial_dimension, kind); else { // this copy of field_name is used to compute derivated data such as // strain and von mises stress that are based on grad_u and stress std::string field_name_copy(field_name); if (field_name == "strain" || field_name == "Green strain" || field_name == "principal strain" || field_name == "principal Green strain") field_name_copy = "grad_u"; else if (field_name == "Von Mises stress") field_name_copy = "stress"; bool is_internal = this->isInternal(field_name_copy, kind); if (is_internal) { ElementTypeMap nb_data_per_elem = this->getInternalDataPerElem(field_name_copy, kind); ElementTypeMapArray & internal_flat = this->flattenInternal(field_name_copy, kind); field = mesh.createElementalField( internal_flat, group_name, spatial_dimension, kind, nb_data_per_elem); if (field_name == "strain") { dumper::ComputeStrain * foo = new dumper::ComputeStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "Von Mises stress") { dumper::ComputeVonMisesStress * foo = new dumper::ComputeVonMisesStress(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "Green strain") { dumper::ComputeStrain * foo = new dumper::ComputeStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "principal strain") { dumper::ComputePrincipalStrain * foo = new dumper::ComputePrincipalStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } else if (field_name == "principal Green strain") { dumper::ComputePrincipalStrain * foo = new dumper::ComputePrincipalStrain(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } // treat the paddings if (padding_flag) { if (field_name == "stress") { if (spatial_dimension == 2) { dumper::StressPadder<2> * foo = new dumper::StressPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field, *foo); } } else if (field_name == "strain" || field_name == "Green strain") { if (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 *> real_nodal_fields; real_nodal_fields["displacement"] = this->displacement; real_nodal_fields["mass"] = this->mass; real_nodal_fields["velocity"] = this->velocity; real_nodal_fields["acceleration"] = this->acceleration; real_nodal_fields["force"] = this->external_force; real_nodal_fields["residual"] = this->internal_force; real_nodal_fields["increment"] = this->increment; dumper::Field * field = NULL; if (padding_flag) field = this->mesh.createNodalField(real_nodal_fields[field_name], group_name, 3); else field = this->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 *> 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( __attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag, __attribute__((unused)) const UInt & spatial_dimension, __attribute__((unused)) const ElementKind & kind) { return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal( __attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool( __attribute__((unused)) const std::string & field_name, __attribute__((unused)) const std::string & group_name, __attribute__((unused)) bool padding_flag) { return NULL; } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); 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::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); external_force->printself(stream, indent + 2); internal_force->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + material information [" << std::endl; material_index.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + materials [" << std::endl; std::vector::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/synchronizer/distributed_synchronizer.cc b/src/synchronizer/distributed_synchronizer.cc index 04f2cef93..5e1d65502 100644 --- a/src/synchronizer/distributed_synchronizer.cc +++ b/src/synchronizer/distributed_synchronizer.cc @@ -1,1786 +1,836 @@ /** * @file distributed_synchronizer.cc * * @author Guillaume Anciaux * @author Dana Christen * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Wed Sep 01 2010 * @date last modification: Fri Jan 22 2016 * * @brief implementation of a communicator using a static_communicator for * real * send/receive * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "distributed_synchronizer.hh" +#include "element_info_per_processor.hh" +#include "node_info_per_processor.hh" #include "static_communicator.hh" #include "mesh_utils.hh" -#include "mesh_data.hh" -#include "element_group.hh" /* -------------------------------------------------------------------------- */ #include #include #include +/* -------------------------------------------------------------------------- */ #if defined(AKANTU_DEBUG_TOOLS) #include "aka_debug_tools.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ DistributedSynchronizer::DistributedSynchronizer( Mesh & mesh, SynchronizerID id, MemoryID memory_id, const bool register_to_event_manager) : Synchronizer(id, memory_id), mesh(mesh), prank_to_element("prank_to_element", id) { AKANTU_DEBUG_IN(); nb_proc = static_communicator->getNbProc(); rank = static_communicator->whoAmI(); send_element = new Array[nb_proc]; recv_element = new Array[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { std::stringstream sstr; sstr << p; send_element[p].setID(id + ":send_elements_" + sstr.str()); recv_element[p].setID(id + ":recv_elements_" + sstr.str()); } if (register_to_event_manager) 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(); } /* -------------------------------------------------------------------------- */ /// TODO check what it would imply to rewrite this creation as a distributed /// process 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 = + DistributedSynchronizer & synchronizer = *(new DistributedSynchronizer(mesh, id, memory_id)); if (nb_proc == 1) - return &communicator; + return &synchronizer; - UInt * local_connectivity = NULL; - UInt * local_partitions = NULL; - Array * old_nodes = mesh.getNodesGlobalIdsPointer(); - old_nodes->resize(0); - Array * nodes = mesh.getNodesPointer(); - UInt spatial_dimension = nodes->getNbComponent(); + MeshAccessor mesh_accessor(mesh); + mesh_accessor.getNodesGlobalIds().resize(0); 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); - Vector nb_local_element(nb_proc, 0); - Vector nb_ghost_element(nb_proc, 0); - Vector nb_element_to_send(nb_proc, 0); - /// \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 * tmp_partition_num = NULL; try { - tmp_partition_num = &partition->getPartition(type, _not_ghost); + partition->getPartition(type, _not_ghost); } catch (...) { continue; } - const Array & partition_num = *tmp_partition_num; - - const CSR & 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::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 = new UInt *[nb_proc]; - UInt ** buffers_tmp = new UInt *[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::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 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 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 - Vector count_by_proc(nb_proc, 0); - for (UInt el = 0; el < nb_element; ++el) { - *(buffers_tmp[partition_num(el)]++) = ghost_partition.getNbCols(el); - UInt i(0); - for (CSR::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::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]; - } - - delete [] buffers; - delete [] buffers_tmp; - /* -------------------------------------------------------------------- */ - /// 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); + MasterElementInfoPerProc proc_infos(synchronizer, comm, count, root, mesh, type, + *partition); + proc_infos.synchronizeConnectivities(); + proc_infos.synchronizePartitions(); + proc_infos.synchronizeTags(); + proc_infos.synchronizeGroups(); ++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)); - } + { /// Ending the synchronization of elements by sending a stop message + MasterElementInfoPerProc proc_infos(synchronizer, comm, count, root, mesh, + _not_defined, *partition); + ++count; } - /* ---------------------------------------------------------------------- */ - /* ---------------------------------------------------------------------- */ /** - * Nodes coordinate construction and synchronization + * Nodes synchronization */ - std::multimap > nodes_to_proc; - /// get the list of nodes to send and send them - Real * local_nodes = NULL; - Vector nb_nodes_per_proc(nb_proc); - UInt ** nodes_per_proc = new UInt *[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 ** nodes_type_per_proc = new Array *[nb_proc]; - for (UInt p = 0; p < nb_proc; ++p) { - nodes_type_per_proc[p] = new Array(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))); - } - } + MasterNodeInfoPerProc node_proc_infos(synchronizer, comm, count, root, mesh); - std::multimap >::iterator it_node; - std::pair >::iterator, - std::multimap >::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 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]; - } - delete [] nodes_per_proc; - delete [] nodes_type_per_proc; - /* -------->>>>-NODE GROUPS --------------------------------------------- */ - synchronizeNodeGroupsMaster(communicator, root, mesh); + node_proc_infos.synchronizeNodes(); + node_proc_infos.synchronizeTypes(); + node_proc_infos.synchronizeGroups(); /* ---------------------------------------------------------------------- */ /* Distant (rank != root) */ /* ---------------------------------------------------------------------- */ } else { /** * connectivity and communications scheme construction on distant processors */ - ElementType type = _not_defined; UInt count = 0; + bool need_synchronize = true; 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); + SlaveElementInfoPerProc proc_infos(synchronizer, comm, count, root, mesh); + need_synchronize = proc_infos.needSynchronize(); + + if (need_synchronize) { + proc_infos.synchronizeConnectivities(); + proc_infos.synchronizePartitions(); + proc_infos.synchronizeTags(); + proc_infos.synchronizeGroups(); } ++count; - } while (type != _not_defined); + } while (need_synchronize); /** - * Nodes coordinate construction and synchronization on distant processors + * Nodes synchronization */ - 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 & partition_num, const CSR & ghost_partition) { -#define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ - case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ - fillTagBufferTemplated( \ - 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(); + SlaveNodeInfoPerProc node_proc_infos(synchronizer, comm, count, root, mesh); - 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::iterator > conn_it = - mesh.getConnectivity(type, gt).begin(nb_nodes_per_element); - - for (UInt e = 0; e < nb_element; ++e, ++conn_it) { - Vector & 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; - } - } - } - } + node_proc_infos.synchronizeNodes(); + node_proc_infos.synchronizeTypes(); + node_proc_infos.synchronizeGroups(); } - 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(); + MeshUtils::fillElementToSubElementsData(mesh); - 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); - } + mesh_accessor.setDistributed(); AKANTU_DEBUG_OUT(); + return &synchronizer; } /* -------------------------------------------------------------------------- */ 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::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); Tag comm_tag = Tag::genTag(rank, counter, tag); buffer << int(comm_tag); #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::const_iterator bit = send_element[p].begin(); Array::const_iterator bend = send_element[p].end(); for (; bit != bend; ++bit) { const Element & element = *bit; Vector 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)" << " [ " << comm_tag << ":" << std::hex << int(this->genTagFromID(tag)) << " ]"); communication.send_requests.push_back(static_communicator->asyncSend( - buffer.storage(), ssize, p, this->genTagFromID(tag))); + buffer, p, this->genTagFromID(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); Tag comm_tag = Tag::genTag(rank, counter, tag); buffer << int(comm_tag); AKANTU_DEBUG_INFO("Posting receive from proc " << p << " (tag: " << tag << " - " << rsize << " data to receive) " << " [ " << comm_tag << ":" << std::hex << int(this->genTagFromID(tag)) << " ]"); communication.recv_requests.push_back(static_communicator->asyncReceive( - buffer.storage(), rsize, p, this->genTagFromID(tag))); + buffer, p, this->genTagFromID(tag))); } 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 req_not_finished; std::vector * req_not_finished_tmp = &req_not_finished; std::vector * recv_requests_tmp = &(communication.recv_requests); // static_communicator->waitAll(recv_requests); while (!recv_requests_tmp->empty()) { for (std::vector::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]; int _tag; buffer >> _tag; Tag comm_tag(_tag); #ifndef AKANTU_NDEBUG Array::const_iterator bit = recv_element[proc].begin(); Array::const_iterator bend = recv_element[proc].end(); UInt spatial_dimension = mesh.getSpatialDimension(); for (; bit != bend; ++bit) { const Element & element = *bit; Vector barycenter_loc(spatial_dimension); mesh.getBarycenter(element.element, element.type, barycenter_loc.storage(), element.ghost_type); Vector 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_loc(i)) <= tolerance && std::abs(barycenter(i)) <= tolerance) || (std::abs((barycenter(i) - barycenter_loc(i)) / bary_norm) <= tolerance)) continue; AKANTU_DEBUG_ERROR( "Unpacking an unknown value for the element: " << element << "(barycenter[" << i << "] = " << barycenter_loc(i) << " and buffer[" << i << "] = " << barycenter(i) << ") [" << std::abs((barycenter(i) - barycenter_loc(i)) / bary_norm) << "] - tag: " << tag << " comm_tag[ " << comm_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" << " [ " << comm_tag << " ]"); static_communicator->freeCommunicationRequest(req); } else { req_not_finished_tmp->push_back(req); } } std::vector * 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::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) { ssend += sizeof(int); // sizeof(int) is for the communication tag #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) { sreceive += sizeof(int); // sizeof(int) is for the communication tag #ifndef AKANTU_NDEBUG sreceive += recv_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real); #endif sreceive += data_accessor.getNbDataForElements(recv_element[p], tag); AKANTU_DEBUG_INFO("I have " << sreceive << "(" << sreceive / 1024. << "kB - " << recv_element[p].getSize() << " element(s)) data to receive for tag " << tag); } } communications[tag].size_to_send[p] = ssend; communications[tag].size_to_receive[p] = sreceive; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::computeAllBufferSizes( DataAccessor & data_accessor) { std::map::iterator it = this->communications.begin(); std::map::iterator end = this->communications.end(); for (; it != end; ++it) { SynchronizationTag tag = it->first; this->computeBufferSize(data_accessor, tag); } } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; Int prank = StaticCommunicator::getStaticCommunicator().whoAmI(); Int psize = StaticCommunicator::getStaticCommunicator().getNbProc(); stream << "[" << prank << "/" << psize << "]" << space << "DistributedSynchronizer [" << std::endl; for (UInt p = 0; p < nb_proc; ++p) { if (p == UInt(prank)) continue; stream << "[" << prank << "/" << psize << "]" << space << " + Communication to proc " << p << " [" << std::endl; if (AKANTU_DEBUG_TEST(dblDump)) { stream << "[" << prank << "/" << psize << "]" << space << " - Element to send to proc " << p << " [" << std::endl; Array::iterator it_el = send_element[p].begin(); Array::iterator 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::const_iterator it = communications.begin(); std::map::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::substituteElements( const std::map & old_to_new_elements) { // substitute old elements with new ones std::map::const_iterator found_element_it; std::map::const_iterator found_element_end = old_to_new_elements.end(); for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; Array & recv = recv_element[p]; for (UInt el = 0; el < recv.getSize(); ++el) { found_element_it = old_to_new_elements.find(recv(el)); if (found_element_it != found_element_end) recv(el) = found_element_it->second; } Array & send = send_element[p]; for (UInt el = 0; el < send.getSize(); ++el) { found_element_it = old_to_new_elements.find(send(el)); if (found_element_it != found_element_end) send(el) = found_element_it->second; } } } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::onElementsChanged( const Array & old_elements_list, const Array & new_elements_list, __attribute__((unused)) const ElementTypeMapArray & new_numbering, __attribute__((unused)) const ChangedElementsEvent & event) { // create a map to link old elements to new ones std::map old_to_new_elements; for (UInt el = 0; el < old_elements_list.getSize(); ++el) { AKANTU_DEBUG_ASSERT(old_to_new_elements.find(old_elements_list(el)) == old_to_new_elements.end(), "The same element cannot appear twice in the list"); old_to_new_elements[old_elements_list(el)] = new_elements_list(el); } substituteElements(old_to_new_elements); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::onElementsRemoved( const Array & element_to_remove, const ElementTypeMapArray & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); this->removeElements(element_to_remove); this->renumberElements(new_numbering); 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 & 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 & 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 * newsy_send_element = new_synchronizer->send_element; Array * newsy_recv_element = new_synchronizer->recv_element; Array * new_send_element = new Array[nb_proc]; Array * new_recv_element = new Array[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 & partition_num, - const CSR & 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 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::const_iterator names_it = tag_names.begin(); - std::vector::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 = - new DynamicCommunicationBuffer[nb_proc]; - std::vector::const_iterator names_it = tag_names.begin(); - std::vector::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 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(); - delete[] buffers; - } - - ++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 tag_names; - std::vector tag_type_codes; - std::vector 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(type_code_int); - mesh_data_sizes_buffer >> tag_nb_component[i]; - } - - std::vector::const_iterator names_it = tag_names.begin(); - std::vector::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(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 -void DistributedSynchronizer::fillElementGroupsFromBuffer( - __attribute__((unused)) 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 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::iterator it = element_to_group.begin(); - std::vector::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, __attribute__((unused)) UInt root, - Mesh & mesh, const ElementType & type, const Array & partition_num, - const CSR & ghost_partition, UInt nb_element) { - AKANTU_DEBUG_IN(); - - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - - UInt nb_proc = comm.getNbProc(); - UInt my_rank = comm.whoAmI(); - - DynamicCommunicationBuffer * buffers = - new DynamicCommunicationBuffer[nb_proc]; - - typedef std::vector > 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 &>(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::const_iterator it = ghost_partition.begin(el); - CSR::const_iterator end = ghost_partition.end(el); - for (; it != end; ++it) { - UInt proc = *it; - buffers[proc] << *data_it; - } - } - - std::vector 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(); - delete[] buffers; - - 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(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 -void DistributedSynchronizer::fillNodeGroupsFromBuffer( - __attribute__((unused)) DistributedSynchronizer & communicator, Mesh & mesh, - CommunicationBuffer & buffer) { - AKANTU_DEBUG_IN(); - - std::vector > 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 & global_nodes = mesh.getGlobalNodesIds(); - - Array::const_scalar_iterator nbegin = global_nodes.begin(); - Array::const_scalar_iterator nit = global_nodes.begin(); - Array::const_scalar_iterator nend = global_nodes.end(); - - for (; nit != nend; ++nit) { - std::vector::iterator it = node_to_group[*nit].begin(); - std::vector::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, __attribute__((unused)) 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 > 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 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(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(); -} - /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::removeElements( const Array & element_to_remove) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); std::vector isend_requests; Array * list_of_el = new Array[nb_proc]; // Handling ghost elements for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; Array & recv = recv_element[p]; if (recv.getSize() == 0) continue; Array::iterator recv_begin = recv.begin(); Array::iterator recv_end = recv.end(); Array::const_iterator er_it = element_to_remove.begin(); Array::const_iterator er_end = element_to_remove.end(); Array & list = list_of_el[p]; for (UInt i = 0; recv_begin != recv_end; ++i, ++recv_begin) { const Element & el = *recv_begin; Array::const_iterator 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(" << this->genTagFromID(0) << ")"); - isend_requests.push_back(comm.asyncSend(list.storage(), list.getSize(), p, - this->genTagFromID(0))); + isend_requests.push_back(comm.asyncSend(list, p, this->genTagFromID(0))); list.erase(list.getSize() - 1); if (list.getSize() == recv.getSize()) continue; Array new_recv; for (UInt nr = 0; nr < list.getSize(); ++nr) { Element & el = recv(list(nr)); 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 < nb_proc; ++p) { if (p == rank) continue; Array & 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(" << this->genTagFromID(0) << ")"); comm.probe(p, this->genTagFromID(0), status); Array list(status.getSize()); AKANTU_DEBUG_INFO("Receiving list of elements (" << status.getSize() - 1 << " elements) no longer needed by proc " << p << " TAG(" << this->genTagFromID(0) << ")"); - comm.receive(list.storage(), list.getSize(), p, this->genTagFromID(0)); + comm.receive(list, p, this->genTagFromID(0)); if (list.getSize() == 1 && list(0) == 0) continue; list.erase(list.getSize() - 1); if (list.getSize() == send.getSize()) continue; Array new_send; for (UInt ns = 0; ns < list.getSize(); ++ns) { Element & el = send(list(ns)); new_send.push_back(el); } 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::renumberElements( const ElementTypeMapArray & new_numbering) { // Handling ghost elements for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; Array & recv = recv_element[p]; for (UInt i = 0; i < recv.getSize(); ++i) { Element & el = recv(i); el.element = new_numbering(el.type, el.ghost_type)(el.element); } Array & send = send_element[p]; for (UInt i = 0; i < send.getSize(); ++i) { Element & el = send(i); el.element = new_numbering(el.type, el.ghost_type)(el.element); } } } __END_AKANTU__ diff --git a/src/synchronizer/distributed_synchronizer.hh b/src/synchronizer/distributed_synchronizer.hh index 40620ad0d..101493465 100644 --- a/src/synchronizer/distributed_synchronizer.hh +++ b/src/synchronizer/distributed_synchronizer.hh @@ -1,286 +1,247 @@ /** * @file distributed_synchronizer.hh * * @author Guillaume Anciaux * @author Dana Christen * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Dec 08 2015 * * @brief Main element synchronizer * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ #define __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_array.hh" #include "synchronizer.hh" #include "mesh.hh" #include "mesh_partition.hh" #include "communication_buffer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class DistributedSynchronizer : public Synchronizer, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DistributedSynchronizer(Mesh & mesh, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0, const bool register_to_event_manager = true); 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 onElementsChanged virtual void onElementsChanged(const Array & old_elements_list, const Array & new_elements_list, const ElementTypeMapArray & new_numbering, const ChangedElementsEvent & event); /// mesh event handler onRemovedElement virtual void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event); /// mesh event handler onNodesAdded virtual void onNodesAdded(__attribute__((unused)) const Array & nodes_list, __attribute__((unused)) const NewNodesEvent & event){}; /// mesh event handler onRemovedNodes virtual void onNodesRemoved(__attribute__((unused)) const Array & nodes_list, __attribute__((unused)) const Array & new_numbering, __attribute__((unused)) const RemovedNodesEvent & event){}; /// mesh event handler onElementsAdded virtual void onElementsAdded(__attribute__((unused)) const Array & elements_list, __attribute__((unused)) const NewElementsEvent & event){}; /// filter elements of a certain kind and copy them into a new synchronizer void filterElementsByKind(DistributedSynchronizer * new_synchronizer, ElementKind kind); /// reset send and recv element lists void reset(); /// compute buffer size for a given tag and data accessor void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag); /// recalculate buffer sizes for all tags void computeAllBufferSizes(DataAccessor & data_accessor); /// remove elements from the synchronizer without renumbering them void removeElements(const Array & element_to_remove); /// renumber the elements in the synchronizer void renumberElements(const ElementTypeMapArray & new_numbering); 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 & partition_num); template void fillTagBufferTemplated(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array & partition_num, const CSR & ghost_partition); void fillTagBuffer(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array & partition_num, const CSR & ghost_partition); - template - 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 - 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 & partition_num, const CSR & 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 & partition_num, const CSR & 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 - 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 static void fillNodeGroupsFromBuffer(DistributedSynchronizer & communicator, Mesh & mesh, CommunicationBuffer & buffer); /// substitute elements in the send and recv arrays void substituteElements(const std::map & old_to_new_elements); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(PrankToElement, prank_to_element, const ElementTypeMapArray &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ -private: - enum CommTags { - TAG_SIZES = 0, - TAG_CONNECTIVITY = 1, - TAG_DATA = 2, - TAG_PARTITIONS = 3, - TAG_NB_NODES = 4, - TAG_NODES = 5, - TAG_COORDINATES = 6, - TAG_NODES_TYPE = 7, - TAG_MESH_DATA = 8, - TAG_ELEMENT_GROUP = 9, - TAG_NODE_GROUP = 10, - }; - protected: /// reference to the underlying mesh Mesh & mesh; std::map communications; + friend class ElementInfoPerProc; + /// list of element to send to proc p Array * send_element; /// list of element to receive from proc p Array * recv_element; UInt nb_proc; UInt rank; friend class FilteredSynchronizer; friend class FacetSynchronizer; ElementTypeMapArray prank_to_element; }; __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "distributed_synchronizer_tmpl.hh" #endif /* __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/distributed_synchronizer_tmpl.hh b/src/synchronizer/distributed_synchronizer_tmpl.hh index b8f86c05f..8518f068f 100644 --- a/src/synchronizer/distributed_synchronizer_tmpl.hh +++ b/src/synchronizer/distributed_synchronizer_tmpl.hh @@ -1,147 +1,42 @@ /** * @file distributed_synchronizer_tmpl.hh * * @author Dana Christen * @author Nicolas Richart * * @date creation: Tue May 07 2013 * @date last modification: Sun Oct 19 2014 * - * @brief Implementation of the templated function of the DistributedSynchronizer + * @brief Implementation of the templated function of the + *DistributedSynchronizer * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DISTRIBUTED_SYNCHRONIZER_TMPL_HH__ #define __AKANTU_DISTRIBUTED_SYNCHRONIZER_TMPL_HH__ __BEGIN_AKANTU__ -template -void DistributedSynchronizer::fillTagBufferTemplated(const MeshData & mesh_data, - DynamicCommunicationBuffer * buffers, - const std::string & tag_name, - const ElementType & el_type, - const Array & partition_num, - const CSR & ghost_partition) { - const Array & data = mesh_data.getElementalDataArray(tag_name, el_type); - // Not possible to use the iterator because it potentially triggers the creation of complex - // type templates (such as akantu::Vector< std::vector > which don't implement the right interface - // (e.g. operator<< in that case). - //typename Array::template const_iterator< Vector > data_it = data.begin(data.getNbComponent()); - //typename Array::template const_iterator< Vector > data_end = data.end(data.getNbComponent()); - - const T * data_it = data.storage(); - const T * data_end = data.storage() + data.getSize()*data.getNbComponent(); - const UInt * part = partition_num.storage(); - - /// copying the data, element by element - for (; data_it != data_end; ++part) { - for(UInt j(0); j < data.getNbComponent(); ++j, ++data_it) { - buffers[*part] << *data_it; - } - } - - data_it = data.storage(); - /// copying the data for the ghost element - for (UInt el(0); data_it != data_end; data_it+=data.getNbComponent(), ++el) { - CSR::const_iterator it = ghost_partition.begin(el); - CSR::const_iterator end = ghost_partition.end(el); - for (;it != end; ++it) { - UInt proc = *it; - for(UInt j(0); j < data.getNbComponent(); ++j) { - buffers[proc] << data_it[j]; - } - } - } -} - -/* -------------------------------------------------------------------------- */ -template -void DistributedSynchronizer::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) { -#define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ - case BOOST_PP_TUPLE_ELEM(2, 0, elem) : { \ - populateMeshDataTemplated(mesh_data, buffer, tag_name, el_type, nb_component, nb_local_element, nb_ghost_element); \ - break; \ - } \ - - switch(type_code) { - BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , AKANTU_MESH_DATA_TYPES) - default : AKANTU_DEBUG_ERROR("Could not determine the type of tag" << tag_name << "!"); break; - } -#undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA -} - -/* -------------------------------------------------------------------------- */ -template -void DistributedSynchronizer::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) { - - AKANTU_DEBUG_ASSERT(mesh.getNbElement(el_type) == nb_local_element, - "Did not got enought informations for the tag " << tag_name << - " and the element type " << el_type << ":" << "_not_ghost." << - " Got " << nb_local_element << " values, expected " << mesh.getNbElement(el_type)); - - - mesh_data.registerElementalData(tag_name); - Array & data = mesh_data.getElementalDataArrayAlloc(tag_name, el_type, _not_ghost, nb_component); - data.resize(nb_local_element); - /// unpacking the data, element by element - for (UInt i(0); i < nb_local_element; ++i) { - for(UInt j(0); j < nb_component; ++j) { - buffer >> data(i,j); - } - } - - AKANTU_DEBUG_ASSERT(mesh.getNbElement(el_type, _ghost) == nb_ghost_element, - "Did not got enought informations for the tag " << tag_name << - " and the element type " << el_type << ":" << "_ghost." << - " Got " << nb_ghost_element << " values, expected " << - mesh.getNbElement(el_type, _ghost)); - - mesh_data.registerElementalData(tag_name); - Array & data_ghost = mesh_data.getElementalDataArrayAlloc(tag_name, el_type, _ghost, nb_component); - data_ghost.resize(nb_ghost_element); - - /// unpacking the ghost data, element by element - for (UInt j(0); j < nb_ghost_element; ++j) { - for(UInt k(0); k < nb_component; ++k) { - buffer >> data_ghost(j, k); - } - } -} __END_AKANTU__ - #endif /* __AKANTU_DISTRIBUTED_SYNCHRONIZER_TMPL_HH__ */ diff --git a/src/synchronizer/dof_synchronizer.cc b/src/synchronizer/dof_synchronizer.cc index 236935486..9f4e75e96 100644 --- a/src/synchronizer/dof_synchronizer.cc +++ b/src/synchronizer/dof_synchronizer.cc @@ -1,502 +1,527 @@ /** * @file dof_synchronizer.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Fri Jun 17 2011 * @date last modification: Wed Oct 21 2015 * * @brief DOF synchronizing object implementation * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #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. + * 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 + * 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") { +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; 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) { + /// 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); + 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_type++) = node_type; dof_global_id++; } } - if(psize == 1) return; + if (psize == 1) + return; /// creating communication scheme - dof_global_id = dof_global_ids.storage(); - dof_type = dof_types.storage(); + 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) { + 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 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]; + Array send_buffer(nb_master_dofs); for (UInt d = 0; d < nb_master_dofs; ++d) { - send_buffer[d] = dof_global_id[master_dofs[d]]; + send_buffer(d) = dof_global_id[master_dofs[d]]; } UInt nb_slave_dofs = 0; - UInt * recv_buffer; std::vector requests; - requests.push_back(static_communicator->asyncSend(&nb_master_dofs, 1, sendto, 0)); - if(nb_master_dofs != 0) { - AKANTU_DEBUG(dblInfo, "Sending "<< nb_master_dofs << " dofs to " << sendto); - requests.push_back(static_communicator->asyncSend(send_buffer, nb_master_dofs, sendto, 1)); + requests.push_back( + static_communicator->asyncSend(nb_master_dofs, sendto, 0)); + if (nb_master_dofs != 0) { + AKANTU_DEBUG(dblInfo, "Sending " << nb_master_dofs << " dofs to " + << sendto); + requests.push_back( + static_communicator->asyncSend(send_buffer, sendto, 1)); } - /// 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 << " dofs from " << recvfrom); + /// Receive the info and store them as slave nodes + static_communicator->receive(nb_slave_dofs, recvfrom, 0); + + Array & recv_buffer = proc_informations[recvfrom].slave_dofs; + + if (nb_slave_dofs != 0) { + AKANTU_DEBUG(dblInfo, "Receiving " << nb_slave_dofs << " dofs from " + << recvfrom); proc_informations[recvfrom].slave_dofs.resize(nb_slave_dofs); - recv_buffer = proc_informations[recvfrom].slave_dofs.storage(); - static_communicator->receive(recv_buffer, nb_slave_dofs, recvfrom, 1); + static_communicator->receive(recv_buffer, recvfrom, 1); } for (UInt d = 0; d < nb_slave_dofs; ++d) { - recv_buffer[d] = global_dof_to_local[recv_buffer[d]]; + recv_buffer(d) = global_dof_to_local[recv_buffer(d)]; } static_communicator->waitAll(requests); static_communicator->freeCommunicationRequest(requests); requests.clear(); - delete [] send_buffer; } } /* -------------------------------------------------------------------------- */ -DOFSynchronizer::~DOFSynchronizer() { - -} - +DOFSynchronizer::~DOFSynchronizer() {} /* -------------------------------------------------------------------------- */ void DOFSynchronizer::initLocalDOFEquationNumbers() { AKANTU_DEBUG_IN(); local_dof_equation_numbers.resize(nb_dofs); - Int * dof_equation_number = local_dof_equation_numbers.storage(); + 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); + // local_dof_equation_numbers.resize(nb_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::asynchronousSynchronize(DataAccessor & data_accessor, - SynchronizationTag tag) { + 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); + AKANTU_DEBUG_ASSERT( + communication.send_requests.size() == 0, + "There must be some pending sending communications. Tag is " << tag); std::map::iterator t_it = tag_counter.find(tag); UInt counter = 0; - if(t_it == tag_counter.end()) { + 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; + 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)"); + 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::const_iterator bit = proc_informations[p].slave_dofs.begin(); - Array::const_iterator bend = proc_informations[p].slave_dofs.end(); + Array::const_iterator bit = + proc_informations[p].slave_dofs.begin(); + Array::const_iterator 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 + /// 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))); + "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, p, Tag::genTag(prank, counter, tag))); } AKANTU_DEBUG_ASSERT(communication.recv_requests.size() == 0, - "There must be some pending receive communications"); + "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; + 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_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, p, Tag::genTag(p, counter, tag))); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::waitEndSynchronize(DataAccessor & data_accessor, - SynchronizationTag tag) { + SynchronizationTag tag) { AKANTU_DEBUG_IN(); - AKANTU_DEBUG_ASSERT(communications.find(tag) != communications.end(), "No communication with the tag \"" - << tag <<"\" started"); + AKANTU_DEBUG_ASSERT(communications.find(tag) != communications.end(), + "No communication with the tag \"" << tag + << "\" started"); Communication & communication = communications[tag]; std::vector req_not_finished; - std::vector * req_not_finished_tmp = &req_not_finished; - std::vector * recv_requests_tmp = &(communication.recv_requests); + std::vector * req_not_finished_tmp = + &req_not_finished; + std::vector * recv_requests_tmp = + &(communication.recv_requests); // static_communicator->waitAll(recv_requests); - while(!recv_requests_tmp->empty()) { - for (std::vector::iterator req_it = recv_requests_tmp->begin(); - req_it != recv_requests_tmp->end() ; ++req_it) { + while (!recv_requests_tmp->empty()) { + for (std::vector::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]; + 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::const_iterator bit = proc_informations[proc].master_dofs.begin(); - Array::const_iterator 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); - } - + Array::const_iterator bit = + proc_informations[proc].master_dofs.begin(); + Array::const_iterator 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); + 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); + 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); + req_not_finished_tmp->push_back(req); } } std::vector * 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::iterator req_it = communication.send_requests.begin(); - req_it != communication.send_requests.end() ; ++req_it) { + for (std::vector::iterator req_it = + communication.send_requests.begin(); + req_it != communication.send_requests.end(); ++req_it) { CommunicationRequest & req = *(*req_it); - if(static_communicator->testRequest(&req)) { + 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(); - - + 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. + * 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) { + 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 ssend = 0; UInt sreceive = 0; - if(p != prank) { + if (p != prank) { /// check if processor prank has to send dof information to p - if(proc_informations[p].slave_dofs.getSize() != 0) { + 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); + /// 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); + 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) { + 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); + /// 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); + 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_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) { + 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; + *(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; + 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(); + Int * dof_type = dof_types.storage(); - Array * local_dofs = new Array(0,2); + Array * local_dofs = new Array(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) { + if (*dof_type != -3) { local_dof_val[0] = *dof_global_id; - if(*dof_type == -1 || *dof_type == -2) { + 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]; + Vector nb_dof_per_proc(psize); nb_dof_per_proc[prank] = local_dofs->getSize(); - 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)"); + static_communicator->allGather(nb_dof_per_proc); + 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]; + 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]; + for (UInt p = prank; p < psize; ++p) + nb_total_dofs += nb_dof_per_proc[p]; - int * nb_values = new int[psize]; - for (unsigned int p = 0; p < psize; ++p) nb_values[p] = nb_dof_per_proc[p] * 2; + Array nb_values(psize); + for (unsigned int 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)); + Array buffer(2 * nb_total_dofs); + memcpy(buffer.storage() + 2 * pos, local_dofs->storage(), + local_dofs->getSize() * 2 * sizeof(UInt)); delete local_dofs; static_communicator->allGatherV(buffer, nb_values); - UInt * tmp_buffer = buffer; + UInt * tmp_buffer = buffer.storage(); 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); + 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) + 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"); + 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; + 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/element_info_per_processor.cc b/src/synchronizer/element_info_per_processor.cc new file mode 100644 index 000000000..16e9d05e7 --- /dev/null +++ b/src/synchronizer/element_info_per_processor.cc @@ -0,0 +1,89 @@ +/** + * @file element_info_per_processor.cc + * + * @author Nicolas Richart + * + * @date Fri Mar 11 14:56:42 2016 + * + * @brief + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "element_info_per_processor.hh" +#include "distributed_synchronizer.hh" +#include "static_communicator.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +#include +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +/* -------------------------------------------------------------------------- */ +ElementInfoPerProc::ElementInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, + UInt message_cnt, UInt root, Mesh & mesh, + ElementType type) + : MeshAccessor(mesh), synchronizer(synchronizer), comm(communicator), + rank(communicator.whoAmI()), nb_proc(communicator.getNbProc()), + root(root), type(type), mesh(mesh),message_count(message_cnt) {} + +/* -------------------------------------------------------------------------- */ +void ElementInfoPerProc::fillCommunicationScheme( + const Array & partition) { + AKANTU_DEBUG_IN(); + + Element element; + element.type = this->type; + element.kind = Mesh::getKind(this->type); + + Array::const_scalar_iterator part = partition.begin(); + for (UInt lel = 0; lel < nb_local_element; ++lel, ++part) { + UInt nb_send = *part; + element.element = lel; + element.ghost_type = _not_ghost; + for (UInt p = 0; p < nb_send; ++p, ++part) { + UInt proc = *part; + + AKANTU_DEBUG(dblAccessory, "Must send : " << element << " to proc " + << proc); + (synchronizer.send_element[proc]).push_back(element); + } + } + + part = partition.begin(); + for (UInt gel = 0; gel < nb_ghost_element; ++gel, ++part) { + UInt proc = *part; + element.element = gel; + element.ghost_type = _ghost; + AKANTU_DEBUG(dblAccessory, "Must recv : " << element << " from proc " + << proc); + synchronizer.recv_element[proc].push_back(element); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +__END_AKANTU__ diff --git a/src/synchronizer/element_info_per_processor.hh b/src/synchronizer/element_info_per_processor.hh new file mode 100644 index 000000000..acc2c63a5 --- /dev/null +++ b/src/synchronizer/element_info_per_processor.hh @@ -0,0 +1,145 @@ +/** + * @file element_info_per_processor.hh + * + * @author Nicolas Richart + * + * @date Fri Mar 11 14:45:15 2016 + * + * @brief Helper classes to create the distributed synchronizer and distribute + * a mesh + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "aka_common.hh" +#include "mesh_accessor.hh" +#include "communication_buffer.hh" +#include "mesh.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ +#define __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ + +namespace akantu { +class DistributedSynchronizer; +class StaticCommunicator; +class MeshPartition; +} + +/* -------------------------------------------------------------------------- */ +__BEGIN_AKANTU__ + +class ElementInfoPerProc : protected MeshAccessor { +public: + ElementInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, UInt message_cnt, + UInt root, Mesh & mesh, ElementType type); + + virtual void synchronizeConnectivities() = 0; + virtual void synchronizePartitions() = 0; + virtual void synchronizeTags() = 0; + virtual void synchronizeGroups() = 0; + +protected: + void fillCommunicationScheme(const Array & partition); + + template + void fillElementGroupsFromBuffer(CommunicationBuffer & buffer); + + template + void fillMeshDataTemplated(BufferType & buffer, const std::string & tag_name); + + template + void fillMeshData(BufferType & buffer, const std::string & tag_name); + +protected: + DistributedSynchronizer & synchronizer; + + StaticCommunicator & comm; + UInt rank; + UInt nb_proc; + + UInt root; + + ElementType type; + Mesh & mesh; + + UInt nb_tags; + UInt nb_nodes_per_element; + UInt nb_element; + + UInt nb_local_element; + UInt nb_ghost_element; + + UInt message_count; +}; + +/* -------------------------------------------------------------------------- */ +class MasterElementInfoPerProc : protected ElementInfoPerProc { +public: + MasterElementInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, UInt message_cnt, + UInt root, Mesh & mesh, ElementType type, + const MeshPartition & partition); + + void synchronizeConnectivities(); + void synchronizePartitions(); + void synchronizeTags(); + void synchronizeGroups(); + +protected: + template + void fillTagBufferTemplated(DynamicCommunicationBuffer * buffers, + const std::string & tag_name); + void fillTagBuffer(DynamicCommunicationBuffer * buffers, + const std::string & tag_name); + +private: + const MeshPartition & partition; + + Vector all_nb_local_element; + Vector all_nb_ghost_element; + Vector all_nb_element_to_send; +}; + +/* -------------------------------------------------------------------------- */ +class SlaveElementInfoPerProc : protected ElementInfoPerProc { +public: + SlaveElementInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, UInt message_cnt, + UInt root, Mesh & mesh); + + void synchronizeConnectivities(); + void synchronizePartitions(); + void synchronizeTags(); + void synchronizeGroups(); + + bool needSynchronize(); + +private: + UInt nb_element_to_receive; +}; + +__END_AKANTU__ + +#include "element_info_per_processor_tmpl.hh" + +#endif /* __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ */ diff --git a/src/synchronizer/element_info_per_processor_tmpl.hh b/src/synchronizer/element_info_per_processor_tmpl.hh new file mode 100644 index 000000000..fc2617994 --- /dev/null +++ b/src/synchronizer/element_info_per_processor_tmpl.hh @@ -0,0 +1,147 @@ +/** + * @file element_info_per_processor_tmpl.hh + * + * @author Nicolas Richart + * + * @date Fri Mar 11 15:03:12 2016 + * + * @brief + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "element_group.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ +#define __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ + +__BEGIN_AKANTU__ + +/* -------------------------------------------------------------------------- */ +template +void ElementInfoPerProc::fillMeshDataTemplated(BufferType & buffer, + const std::string & tag_name) { + + AKANTU_DEBUG_ASSERT(mesh.getNbElement(this->type) == nb_local_element, + "Did not got enought informations for the tag " + << tag_name << " and the element type " << this->type + << ":" + << "_not_ghost." + << " Got " << nb_local_element << " values, expected " + << mesh.getNbElement(this->type)); + MeshData & mesh_data = this->getMeshData(); + + UInt nb_component = mesh_data.getNbComponent(tag_name, this->type); + Array & data = mesh_data.getElementalDataArrayAlloc( + tag_name, this->type, _not_ghost, nb_component); + data.resize(nb_local_element); + /// unpacking the data, element by element + for (UInt i(0); i < nb_local_element; ++i) { + for (UInt j(0); j < nb_component; ++j) { + buffer >> data(i, j); + } + } + + AKANTU_DEBUG_ASSERT(mesh.getNbElement(this->type, _ghost) == nb_ghost_element, + "Did not got enought informations for the tag " + << tag_name << " and the element type " << this->type + << ":" + << "_ghost." + << " Got " << nb_ghost_element << " values, expected " + << mesh.getNbElement(this->type, _ghost)); + + mesh_data.registerElementalData(tag_name); + Array & data_ghost = mesh_data.getElementalDataArrayAlloc( + tag_name, this->type, _ghost, nb_component); + data_ghost.resize(nb_ghost_element); + + /// unpacking the ghost data, element by element + for (UInt j(0); j < nb_ghost_element; ++j) { + for (UInt k(0); k < nb_component; ++k) { + buffer >> data_ghost(j, k); + } + } +} + +/* -------------------------------------------------------------------------- */ +template +void ElementInfoPerProc::fillMeshData(BufferType & buffer, + const std::string & tag_name) { +#define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ + case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ + fillMeshDataTemplated(buffer, tag_name); \ + break; \ + } + + MeshData & mesh_data = this->getMeshData(); + MeshDataTypeCode type_code = mesh_data.getTypeCode(tag_name); + + switch (type_code) { + BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , + AKANTU_MESH_DATA_TYPES) + default: + AKANTU_DEBUG_ERROR("Could not determine the type of tag" << tag_name + << "!"); + break; + } +#undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA +} + +/* -------------------------------------------------------------------------- */ +template +void ElementInfoPerProc::fillElementGroupsFromBuffer( + 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 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::iterator it = element_to_group.begin(); + std::vector::iterator end = element_to_group.end(); + for (; it != end; ++it) { + mesh.getElementGroup(*it).add(el, false, false); + } + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +__END_AKANTU__ + +#endif /* __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ */ diff --git a/src/synchronizer/filtered_synchronizer.cc b/src/synchronizer/filtered_synchronizer.cc index eaa672422..11eaf4291 100644 --- a/src/synchronizer/filtered_synchronizer.cc +++ b/src/synchronizer/filtered_synchronizer.cc @@ -1,197 +1,198 @@ /** * @file filtered_synchronizer.cc * * @author David Simon Kammer * @author Mathilde Radiguet * * @date creation: Wed Sep 18 2013 * @date last modification: Sat Jul 11 2015 * * @brief filtered synchronizer * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "filtered_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ -FilteredSynchronizer::FilteredSynchronizer(Mesh & mesh, - SynchronizerID id, - MemoryID memory_id) : - DistributedSynchronizer(mesh, id, memory_id) { +FilteredSynchronizer::FilteredSynchronizer(Mesh & mesh, SynchronizerID id, + MemoryID memory_id) + : DistributedSynchronizer(mesh, id, memory_id) { AKANTU_DEBUG_IN(); - + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -FilteredSynchronizer * FilteredSynchronizer:: -createFilteredSynchronizer(const DistributedSynchronizer & d_synchronizer, - SynchElementFilter & filter) { +FilteredSynchronizer * FilteredSynchronizer::createFilteredSynchronizer( + const DistributedSynchronizer & d_synchronizer, + SynchElementFilter & filter) { AKANTU_DEBUG_IN(); - - FilteredSynchronizer & f_synchronizer = - *(new FilteredSynchronizer(d_synchronizer.mesh, - d_synchronizer.id + ":filtered", - d_synchronizer.memory_id)); - - f_synchronizer.setupSynchronizer(d_synchronizer, - filter); + + FilteredSynchronizer & f_synchronizer = *(new FilteredSynchronizer( + d_synchronizer.mesh, d_synchronizer.id + ":filtered", + d_synchronizer.memory_id)); + + f_synchronizer.setupSynchronizer(d_synchronizer, filter); AKANTU_DEBUG_OUT(); return &f_synchronizer; } /* -------------------------------------------------------------------------- */ -void FilteredSynchronizer::setupSynchronizer(const DistributedSynchronizer & d_synchronizer, - SynchElementFilter & filter) { +void FilteredSynchronizer::setupSynchronizer( + const DistributedSynchronizer & d_synchronizer, + SynchElementFilter & filter) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - + Array * d_send_element = d_synchronizer.send_element; Array * d_recv_element = d_synchronizer.recv_element; std::vector isend_requests; - Array ** keep_element_recv = new Array*[this->nb_proc]; + Array ** keep_element_recv = new Array * [this->nb_proc]; // loop over procs for (UInt p = 0; p < this->nb_proc; ++p) { keep_element_recv[p] = NULL; - if (p == this->rank) continue; + if (p == this->rank) + continue; // access the element for this proc const Array & unfiltered_elements = d_recv_element[p]; Array & filtered_elements = recv_element[p]; - if (unfiltered_elements.getSize() == 0) continue; + if (unfiltered_elements.getSize() == 0) + continue; - keep_element_recv[p] = new Array(0,1,"keep_element_recv"); + keep_element_recv[p] = new Array(0, 1, "keep_element_recv"); // iterator to loop over all source elements - Array::const_iterator it = unfiltered_elements.begin(); + Array::const_iterator it = unfiltered_elements.begin(); Array::const_iterator end = unfiltered_elements.end(); - + // if filter accepts this element, push it into the destination elements - for (UInt el=0; it != end; ++it, ++el) { + for (UInt el = 0; it != end; ++it, ++el) { const Element & element = *it; if (filter(element)) { - filtered_elements.push_back(element); - keep_element_recv[p]->push_back(el); + filtered_elements.push_back(element); + keep_element_recv[p]->push_back(el); } } keep_element_recv[p]->push_back(-1); // just to be sure to send - // something due to some shitty - // MPI implementation who do not - // know what to do with a 0 size - // send + // something due to some shitty + // MPI implementation who do not + // know what to do with a 0 size + // send AKANTU_DEBUG_INFO("I have " << keep_element_recv[p]->getSize() - 1 - << " elements to still receive from processor " << p - << " (communication tag : " - << Tag::genTag(this->rank, 0, RECEIVE_LIST_TAG) << ")"); - - isend_requests.push_back(comm.asyncSend(keep_element_recv[p]->storage(), - keep_element_recv[p]->getSize(), - p, - Tag::genTag(this->rank, 0, RECEIVE_LIST_TAG))); + << " elements to still receive from processor " + << p << " (communication tag : " + << Tag::genTag(this->rank, 0, RECEIVE_LIST_TAG) + << ")"); + + isend_requests.push_back( + comm.asyncSend(*keep_element_recv[p], p, + Tag::genTag(this->rank, 0, RECEIVE_LIST_TAG))); } for (UInt p = 0; p < this->nb_proc; ++p) { - if (p == this->rank) continue; + if (p == this->rank) + continue; const Array & unfiltered_elements = d_send_element[p]; Array & filtered_elements = send_element[p]; - if (unfiltered_elements.getSize() == 0) continue; + if (unfiltered_elements.getSize() == 0) + continue; - AKANTU_DEBUG_INFO("Waiting list of elements to keep from processor " << p - << " (communication tag : " - << Tag::genTag(p, 0, RECEIVE_LIST_TAG) << ")"); + AKANTU_DEBUG_INFO("Waiting list of elements to keep from processor " + << p << " (communication tag : " + << Tag::genTag(p, 0, RECEIVE_LIST_TAG) << ")"); CommunicationStatus status; comm.probe(p, Tag::genTag(p, 0, RECEIVE_LIST_TAG), status); - Array keep_element(status.getSize(),1,"keep_element_snd"); + Array keep_element(status.getSize(), 1, "keep_element_snd"); - AKANTU_DEBUG_INFO("I have " << keep_element.getSize() - 1 + AKANTU_DEBUG_INFO("I have " + << keep_element.getSize() - 1 << " elements to keep in my send list to processor " << p - << " (communication tag : " - << Tag::genTag(p, 0, RECEIVE_LIST_TAG) << ")"); + << " (communication tag : " + << Tag::genTag(p, 0, RECEIVE_LIST_TAG) << ")"); - comm.receive(keep_element.storage(), - keep_element.getSize(), - p, - Tag::genTag(p, 0, RECEIVE_LIST_TAG)); + comm.receive(keep_element, p, + Tag::genTag(p, 0, RECEIVE_LIST_TAG)); - for(UInt i = 0; i < keep_element.getSize() - 1; ++i) { + for (UInt i = 0; i < keep_element.getSize() - 1; ++i) { filtered_elements.push_back(unfiltered_elements(keep_element(i))); } } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); - for (UInt p=0; p < this->nb_proc; ++p) { + for (UInt p = 0; p < this->nb_proc; ++p) { delete keep_element_recv[p]; } - delete [] keep_element_recv; + delete[] keep_element_recv; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -void FilteredSynchronizer::updateElementList(Array * source_elements, - Array * destination_elements, - SynchElementFilter & filter) { +void FilteredSynchronizer::updateElementList( + Array * source_elements, Array * destination_elements, + SynchElementFilter & filter) { AKANTU_DEBUG_IN(); - + // loop over procs for (UInt p = 0; p < this->nb_proc; ++p) { - if (p == this->rank) continue; + if (p == this->rank) + continue; // access the element for this proc const Array & unfiltered_elements = source_elements[p]; Array & filtered_elements = destination_elements[p]; // iterator to loop over all source elements - Array::const_iterator it = unfiltered_elements.begin(); + Array::const_iterator it = unfiltered_elements.begin(); Array::const_iterator end = unfiltered_elements.end(); - + // if filter accepts this element, push it into the destination elements for (; it != end; ++it) { const Element & element = *it; if (filter(element)) { - filtered_elements.push_back(element); + filtered_elements.push_back(element); } } } AKANTU_DEBUG_OUT(); } - __END_AKANTU__ diff --git a/src/synchronizer/grid_synchronizer.cc b/src/synchronizer/grid_synchronizer.cc index 1951b3517..e6e0c742e 100644 --- a/src/synchronizer/grid_synchronizer.cc +++ b/src/synchronizer/grid_synchronizer.cc @@ -1,594 +1,601 @@ /** * @file grid_synchronizer.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Mon Oct 03 2011 * @date last modification: Fri Jan 22 2016 * * @brief implementation of the grid synchronizer * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "grid_synchronizer.hh" #include "aka_grid_dynamic.hh" #include "mesh.hh" #include "fe_engine.hh" #include "static_communicator.hh" #include "mesh_io.hh" #include /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ GridSynchronizer::GridSynchronizer(Mesh & mesh, const ID & id, MemoryID memory_id, const bool register_to_event_manager) : DistributedSynchronizer(mesh, id, memory_id, register_to_event_manager) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template GridSynchronizer * GridSynchronizer::createGridSynchronizer( Mesh & mesh, const SpatialGrid & grid, SynchronizerID id, SynchronizerRegistry * synchronizer_registry, const std::set & tags_to_register, MemoryID memory_id, const bool register_to_event_manager) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); GridSynchronizer & communicator = *(new GridSynchronizer(mesh, id, memory_id, register_to_event_manager)); if (nb_proc == 1) return &communicator; UInt spatial_dimension = mesh.getSpatialDimension(); - Real * bounding_boxes = new Real[2 * spatial_dimension * nb_proc]; - Real * my_bounding_box = bounding_boxes + 2 * spatial_dimension * my_rank; + Vector bounding_boxes(2 * spatial_dimension * nb_proc); + Vector my_bounding_box(bounding_boxes.storage() + + 2 * spatial_dimension * my_rank, + 2 * spatial_dimension); // mesh.getLocalLowerBounds(my_bounding_box); // mesh.getLocalUpperBounds(my_bounding_box + spatial_dimension); const Vector & lower = grid.getLowerBounds(); const Vector & upper = grid.getUpperBounds(); const Vector & spacing = grid.getSpacing(); for (UInt i = 0; i < spatial_dimension; ++i) { my_bounding_box[i] = lower(i) - spacing(i); my_bounding_box[spatial_dimension + i] = upper(i) + spacing(i); } AKANTU_DEBUG_INFO( "Exchange of bounding box to detect the overlapping regions."); - comm.allGather(bounding_boxes, spatial_dimension * 2); + comm.allGather(bounding_boxes); bool * intersects_proc = new bool[nb_proc]; std::fill_n(intersects_proc, nb_proc, true); Int * first_cells = new Int[3 * nb_proc]; Int * last_cells = new Int[3 * nb_proc]; std::fill_n(first_cells, 3 * nb_proc, 0); std::fill_n(first_cells, 3 * nb_proc, 0); ElementTypeMapArray ** element_per_proc = new ElementTypeMapArray * [nb_proc]; for (UInt p = 0; p < nb_proc; ++p) element_per_proc[p] = NULL; // check the overlapping between my box and the one from other processors for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank) continue; - Real * proc_bounding_box = bounding_boxes + 2 * spatial_dimension * p; + Real * proc_bounding_box = bounding_boxes.storage() + 2 * spatial_dimension * p; bool intersects = false; Int * first_cell_p = first_cells + p * spatial_dimension; Int * last_cell_p = last_cells + p * spatial_dimension; for (UInt s = 0; s < spatial_dimension; ++s) { // check overlapping of grid intersects = Math::intersects( my_bounding_box[s], my_bounding_box[spatial_dimension + s], proc_bounding_box[s], proc_bounding_box[spatial_dimension + s]); intersects_proc[p] &= intersects; if (intersects) { AKANTU_DEBUG_INFO("I intersects with processor " << p << " in direction " << s); // is point 1 of proc p in the dimension s in the range ? bool point1 = Math::is_in_range(proc_bounding_box[s], my_bounding_box[s], my_bounding_box[s + spatial_dimension]); // is point 2 of proc p in the dimension s in the range ? bool point2 = Math::is_in_range( proc_bounding_box[s + spatial_dimension], my_bounding_box[s], my_bounding_box[s + spatial_dimension]); Real start = 0.; Real end = 0.; if (point1 && !point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box[s]; end = my_bounding_box[s + spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 1 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else if (point1 && point2) { /* |-----------------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box[s]; end = proc_bounding_box[s + spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 2 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else if (!point1 && point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box[s]; end = proc_bounding_box[s + spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 3 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else { /* |-----------| my_bounding_box(i) * |-----------------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box[s]; end = my_bounding_box[s + spatial_dimension]; AKANTU_DEBUG_INFO("Intersection scheme 4 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } first_cell_p[s] = grid.getCellID(start, s); last_cell_p[s] = grid.getCellID(end, s); } } // create the list of cells in the overlapping typedef typename SpatialGrid::CellID CellID; std::vector * cell_ids = new std::vector; if (intersects_proc[p]) { AKANTU_DEBUG_INFO("I intersects with processor " << p); CellID cell_id(spatial_dimension); // for (UInt i = 0; i < spatial_dimension; ++i) { // if(first_cell_p[i] != 0) --first_cell_p[i]; // if(last_cell_p[i] != 0) ++last_cell_p[i]; // } for (Int fd = first_cell_p[0]; fd <= last_cell_p[0]; ++fd) { cell_id.setID(0, fd); if (spatial_dimension == 1) { cell_ids->push_back(cell_id); } else { for (Int sd = first_cell_p[1]; sd <= last_cell_p[1]; ++sd) { cell_id.setID(1, sd); if (spatial_dimension == 2) { cell_ids->push_back(cell_id); } else { for (Int ld = first_cell_p[2]; ld <= last_cell_p[2]; ++ld) { cell_id.setID(2, ld); cell_ids->push_back(cell_id); } } } } } // get the list of elements in the cells of the overlapping typename std::vector::iterator cur_cell_id = cell_ids->begin(); typename std::vector::iterator last_cell_id = cell_ids->end(); std::set * to_send = new std::set(); for (; cur_cell_id != last_cell_id; ++cur_cell_id) { typename SpatialGrid::Cell::const_iterator cur_elem = grid.beginCell(*cur_cell_id); typename SpatialGrid::Cell::const_iterator last_elem = grid.endCell(*cur_cell_id); for (; cur_elem != last_elem; ++cur_elem) { to_send->insert(*cur_elem); } } AKANTU_DEBUG_INFO("I have prepared " << to_send->size() << " elements to send to processor " << p); std::stringstream sstr; sstr << "element_per_proc_" << p; element_per_proc[p] = new ElementTypeMapArray(sstr.str(), id); ElementTypeMapArray & elempproc = *(element_per_proc[p]); typename std::set::iterator elem = to_send->begin(); typename std::set::iterator last_elem = to_send->end(); for (; elem != last_elem; ++elem) { ElementType type = elem->type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); // /!\ this part must be slow due to the access in the // ElementTypeMapArray if (!elempproc.exists(type, _not_ghost)) elempproc.alloc(0, nb_nodes_per_element, type, _not_ghost); Vector global_connect(nb_nodes_per_element); UInt * local_connect = mesh.getConnectivity(type).storage() + elem->element * nb_nodes_per_element; for (UInt i = 0; i < nb_nodes_per_element; ++i) { global_connect(i) = mesh.getNodeGlobalId(local_connect[i]); AKANTU_DEBUG_ASSERT( global_connect(i) < mesh.getNbGlobalNodes(), "This global node send in the connectivity does not seem correct " << global_connect(i) << " corresponding to " << local_connect[i] << " from element " << elem->element); } elempproc(type).push_back(global_connect); communicator.send_element[p].push_back(*elem); } delete to_send; } delete cell_ids; } delete[] first_cells; delete[] last_cells; - delete[] bounding_boxes; AKANTU_DEBUG_INFO("I have finished to compute intersection," << " no it's time to communicate with my neighbors"); /** * Sending loop, sends the connectivity asynchronously to all concerned proc */ std::vector isend_requests; + UInt * space = new UInt[2*nb_proc*_max_element_type]; + UInt offset = 0; for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank) continue; if (intersects_proc[p]) { ElementTypeMapArray & elempproc = *(element_per_proc[p]); ElementTypeMapArray::type_iterator it_type = elempproc.firstType(_all_dimensions, _not_ghost); ElementTypeMapArray::type_iterator last_type = elempproc.lastType(_all_dimensions, _not_ghost); UInt count = 0; for (; it_type != last_type; ++it_type) { Array & conn = elempproc(*it_type, _not_ghost); - UInt info[2]; + Vector info(space + offset, 2); + offset += 2; info[0] = (UInt)*it_type; info[1] = conn.getSize() * conn.getNbComponent(); AKANTU_DEBUG_INFO("I have " << conn.getSize() << " elements of type " << *it_type << " to send to processor " << p << " (communication tag : " << Tag::genTag(my_rank, count, DATA_TAG) << ")"); isend_requests.push_back( - comm.asyncSend(info, 2, p, Tag::genTag(my_rank, count, SIZE_TAG))); + comm.asyncSend(info, p, Tag::genTag(my_rank, count, SIZE_TAG))); if (info[1] != 0) isend_requests.push_back( - comm.asyncSend(conn.storage(), info[1], p, + comm.asyncSend(conn, p, Tag::genTag(my_rank, count, DATA_TAG))); ++count; } - UInt info[2]; + Vector info(space + offset, 2); + offset += 2; info[0] = (UInt)_not_defined; info[1] = 0; isend_requests.push_back( - comm.asyncSend(info, 2, p, Tag::genTag(my_rank, count, SIZE_TAG))); + comm.asyncSend(info, p, Tag::genTag(my_rank, count, SIZE_TAG))); } } /** * Receives the connectivity and store them in the ghosts elements */ Array & global_nodes_ids = const_cast &>(mesh.getGlobalNodesIds()); - Array & nodes_type = - const_cast &>(const_cast(mesh).getNodesType()); + Array & nodes_type = + const_cast &>(const_cast(mesh).getNodesType()); std::vector isend_nodes_requests; Vector nb_nodes_to_recv(nb_proc); UInt nb_total_nodes_to_recv = 0; UInt nb_current_nodes = global_nodes_ids.getSize(); NewNodesEvent new_nodes; NewElementsEvent new_elements; Array * ask_nodes_per_proc = new Array[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { nb_nodes_to_recv(p) = 0; if (p == my_rank) continue; Array & ask_nodes = ask_nodes_per_proc[p]; UInt count = 0; if (intersects_proc[p]) { ElementType type = _not_defined; do { - UInt info[2] = {0}; - comm.receive(info, 2, p, Tag::genTag(p, count, SIZE_TAG)); + Vector info(2); + comm.receive(info, p, Tag::genTag(p, count, SIZE_TAG)); type = (ElementType)info[0]; if (type != _not_defined) { UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); ; UInt nb_element = info[1] / nb_nodes_per_element; Array tmp_conn(nb_element, nb_nodes_per_element); tmp_conn.clear(); if (info[1] != 0) - comm.receive(tmp_conn.storage(), info[1], p, + comm.receive(tmp_conn, p, Tag::genTag(p, count, DATA_TAG)); AKANTU_DEBUG_INFO("I will receive " << nb_element << " elements of type " << ElementType(info[0]) << " from processor " << p << " (communication tag : " << Tag::genTag(p, count, DATA_TAG) << ")"); Array & ghost_connectivity = const_cast &>(mesh.getConnectivity(type, _ghost)); UInt nb_ghost_element = ghost_connectivity.getSize(); Element element(type, 0, _ghost); Vector conn(nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el) { UInt nb_node_to_ask_for_elem = 0; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt gn = tmp_conn(el, n); UInt ln = global_nodes_ids.find(gn); AKANTU_DEBUG_ASSERT(gn < mesh.getNbGlobalNodes(), "This global node seems not correct " << gn << " from element " << el << " node " << n); if (ln == UInt(-1)) { global_nodes_ids.push_back(gn); - nodes_type.push_back(-3); // pure ghost node + nodes_type.push_back(_nt_pure_gost); // pure ghost node ln = nb_current_nodes; new_nodes.getList().push_back(ln); ++nb_current_nodes; ask_nodes.push_back(gn); ++nb_node_to_ask_for_elem; } conn[n] = ln; } // all the nodes are already known locally, the element should // already exists UInt c = UInt(-1); if (nb_node_to_ask_for_elem == 0) { c = ghost_connectivity.find(conn); element.element = c; } if (c == UInt(-1)) { element.element = nb_ghost_element; ++nb_ghost_element; ghost_connectivity.push_back(conn); new_elements.getList().push_back(element); } communicator.recv_element[p].push_back(element); } } count++; } while (type != _not_defined); AKANTU_DEBUG_INFO("I have " << ask_nodes.getSize() << " missing nodes for elements coming from processor " << p << " (communication tag : " << Tag::genTag(my_rank, 0, ASK_NODES_TAG) << ")"); ask_nodes.push_back(UInt(-1)); isend_nodes_requests.push_back( - comm.asyncSend(ask_nodes.storage(), ask_nodes.getSize(), p, + comm.asyncSend(ask_nodes, p, Tag::genTag(my_rank, 0, ASK_NODES_TAG))); nb_nodes_to_recv(p) = ask_nodes.getSize() - 1; nb_total_nodes_to_recv += nb_nodes_to_recv(p); } } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); + delete [] space; for (UInt p = 0; p < nb_proc; ++p) { if (element_per_proc[p]) delete element_per_proc[p]; } delete[] element_per_proc; /** * Sends requested nodes to proc */ Array & nodes = const_cast &>(mesh.getNodes()); UInt nb_nodes = nodes.getSize(); std::vector isend_coordinates_requests; Array * nodes_to_send_per_proc = new Array[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank || !intersects_proc[p]) continue; Array asked_nodes; CommunicationStatus status; AKANTU_DEBUG_INFO("Waiting list of nodes to send to processor " << p << "(communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.probe(p, Tag::genTag(p, 0, ASK_NODES_TAG), status); UInt nb_nodes_to_send = status.getSize(); asked_nodes.resize(nb_nodes_to_send); AKANTU_DEBUG_INFO("I have " << nb_nodes_to_send - 1 << " nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); AKANTU_DEBUG_INFO("Getting list of nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); - comm.receive(asked_nodes.storage(), nb_nodes_to_send, p, + comm.receive(asked_nodes, p, Tag::genTag(p, 0, ASK_NODES_TAG)); nb_nodes_to_send--; asked_nodes.resize(nb_nodes_to_send); Array & nodes_to_send = nodes_to_send_per_proc[p]; nodes_to_send.extendComponentsInterlaced(spatial_dimension, 1); for (UInt n = 0; n < nb_nodes_to_send; ++n) { UInt ln = global_nodes_ids.find(asked_nodes(n)); AKANTU_DEBUG_ASSERT(ln != UInt(-1), "The node [" << asked_nodes(n) << "] requested by proc " << p << " was not found locally!"); nodes_to_send.push_back(nodes.storage() + ln * spatial_dimension); } if (nb_nodes_to_send != 0) { AKANTU_DEBUG_INFO("Sending the " << nb_nodes_to_send << " nodes to processor " << p << " (communication tag : " << Tag::genTag(p, 0, SEND_NODES_TAG) << ")"); isend_coordinates_requests.push_back(comm.asyncSend( - nodes_to_send.storage(), nb_nodes_to_send * spatial_dimension, p, + nodes_to_send, p, Tag::genTag(my_rank, 0, SEND_NODES_TAG))); } #if not defined(AKANTU_NDEBUG) else { AKANTU_DEBUG_INFO("No nodes to send to processor " << p); } #endif } comm.waitAll(isend_nodes_requests); comm.freeCommunicationRequest(isend_nodes_requests); delete[] ask_nodes_per_proc; nodes.resize(nb_total_nodes_to_recv + nb_nodes); for (UInt p = 0; p < nb_proc; ++p) { if ((p != my_rank) && (nb_nodes_to_recv(p) > 0)) { AKANTU_DEBUG_INFO("Receiving the " << nb_nodes_to_recv(p) << " nodes from processor " << p << " (communication tag : " << Tag::genTag(p, 0, SEND_NODES_TAG) << ")"); - comm.receive(nodes.storage() + nb_nodes * spatial_dimension, - nb_nodes_to_recv(p) * spatial_dimension, p, + Vector nodes_to_recv(nodes.storage() + nb_nodes * spatial_dimension, + nb_nodes_to_recv(p) * spatial_dimension); + comm.receive(nodes_to_recv, p, Tag::genTag(p, 0, SEND_NODES_TAG)); nb_nodes += nb_nodes_to_recv(p); } #if not defined(AKANTU_NDEBUG) else { if (p != my_rank) { AKANTU_DEBUG_INFO("No nodes to receive from processor " << p); } } #endif } comm.waitAll(isend_coordinates_requests); comm.freeCommunicationRequest(isend_coordinates_requests); delete[] nodes_to_send_per_proc; // Register the tags if any if (synchronizer_registry) { std::set::const_iterator it = tags_to_register.begin(); std::set::const_iterator end = tags_to_register.end(); for (; it != end; ++it) { synchronizer_registry->registerSynchronizer(communicator, *it); } } mesh.sendEvent(new_nodes); mesh.sendEvent(new_elements); delete[] intersects_proc; AKANTU_DEBUG_OUT(); return &communicator; } /* -------------------------------------------------------------------------- */ template GridSynchronizer * GridSynchronizer::createGridSynchronizer( Mesh & mesh, const SpatialGrid & grid, SynchronizerID id, SynchronizerRegistry * synchronizer_registry, const std::set & tags_to_register, MemoryID memory_id, const bool register_to_event_manager); template GridSynchronizer * GridSynchronizer::createGridSynchronizer( Mesh & mesh, const SpatialGrid & grid, SynchronizerID id, SynchronizerRegistry * synchronizer_registry, const std::set & tags_to_register, MemoryID memory_id, const bool register_to_event_manager); __END_AKANTU__ diff --git a/src/synchronizer/master_element_info_per_processor.cc b/src/synchronizer/master_element_info_per_processor.cc new file mode 100644 index 000000000..e27bda203 --- /dev/null +++ b/src/synchronizer/master_element_info_per_processor.cc @@ -0,0 +1,482 @@ +/** + * @file master_element_info_per_processor.cc + * + * @author Nicolas Richart + * + * @date Fri Mar 11 14:57:13 2016 + * + * @brief + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "element_info_per_processor.hh" +#include "distributed_synchronizer.hh" +#include "static_communicator.hh" +#include "element_group.hh" +#include "mesh_utils.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +#include +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +/* -------------------------------------------------------------------------- */ +MasterElementInfoPerProc::MasterElementInfoPerProc( + DistributedSynchronizer & synchronizer, StaticCommunicator & communicator, + UInt message_cnt, UInt root, Mesh & mesh, ElementType type, + const MeshPartition & partition) + : ElementInfoPerProc(synchronizer, communicator, message_cnt, root, mesh, + type), + partition(partition), all_nb_local_element(nb_proc, 0), + all_nb_ghost_element(nb_proc, 0), all_nb_element_to_send(nb_proc, 0) { + Vector size(5); + size(0) = (UInt)type; + + if (type != _not_defined) { + nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + nb_element = mesh.getNbElement(type); + const Array & partition_num = + this->partition.getPartition(this->type, _not_ghost); + const CSR & ghost_partition = + this->partition.getGhostPartitionCSR()(this->type, _not_ghost); + + for (UInt el = 0; el < nb_element; ++el) { + this->all_nb_local_element[partition_num(el)]++; + for (CSR::const_iterator part = ghost_partition.begin(el); + part != ghost_partition.end(el); ++part) { + this->all_nb_ghost_element[*part]++; + } + this->all_nb_element_to_send[partition_num(el)] += + ghost_partition.getNbCols(el) + 1; + } + + /// tag info + std::vector tag_names; + this->getMeshData().getTagNames(tag_names, type); + this->nb_tags = tag_names.size(); + + size(4) = nb_tags; + + for (UInt p = 0; p < nb_proc; ++p) { + if (p != root) { + size(1) = this->all_nb_local_element[p]; + size(2) = this->all_nb_ghost_element[p]; + size(3) = this->all_nb_element_to_send[p]; + AKANTU_DEBUG_INFO("Sending connectivities informations to proc " + << p << " TAG(" + << Tag::genTag(this->rank, this->message_count, + Tag::_SIZES) << ")"); + comm.send(size, p, + Tag::genTag(this->rank, this->message_count, Tag::_SIZES)); + } else { + this->nb_local_element = this->all_nb_local_element[p]; + this->nb_ghost_element = this->all_nb_ghost_element[p]; + } + } + } else { + for (UInt p = 0; p < this->nb_proc; ++p) { + if (p != this->root) { + AKANTU_DEBUG_INFO("Sending empty connectivities informations to proc " + << p << " TAG(" + << Tag::genTag(this->rank, this->message_count, + Tag::_SIZES) << ")"); + comm.send(size, p, + Tag::genTag(this->rank, this->message_count, Tag::_SIZES)); + } + } + } +} + +/* ------------------------------------------------------------------------ */ +void MasterElementInfoPerProc::synchronizeConnectivities() { + const Array & partition_num = + this->partition.getPartition(this->type, _not_ghost); + const CSR & ghost_partition = + this->partition.getGhostPartitionCSR()(this->type, _not_ghost); + + std::vector > buffers(this->nb_proc); + + /// copying the local connectivity + Array::const_vector_iterator conn_it = + this->mesh.getConnectivity(this->type, _not_ghost) + .begin(this->nb_nodes_per_element); + Array::const_vector_iterator conn_end = + this->mesh.getConnectivity(this->type, _not_ghost) + .end(this->nb_nodes_per_element); + + for (UInt el = 0; conn_it != conn_end; ++conn_it, ++el) { + buffers[partition_num(el)].push_back(*conn_it); + } + + /// copying the connectivity of ghost element + conn_it = this->mesh.getConnectivity(this->type, _not_ghost) + .begin(this->nb_nodes_per_element); + for (UInt el = 0; conn_it != conn_end; ++el, ++conn_it) { + for (CSR::const_iterator part = ghost_partition.begin(el); + part != ghost_partition.end(el); ++part) { + UInt proc = *part; + buffers[proc].push_back(*conn_it); + } + } + +#ifndef AKANTU_NDEBUG + for (UInt p = 0; p < this->nb_proc; ++p) { + UInt size = this->nb_nodes_per_element * + (this->all_nb_local_element[p] + this->all_nb_ghost_element[p]); + AKANTU_DEBUG_ASSERT( + buffers[p].getSize() == size, + "The connectivity data packed in the buffer are not correct"); + } +#endif + + /// send all connectivity and ghost information to all processors + std::vector requests; + for (UInt p = 0; p < this->nb_proc; ++p) { + if (p != this->root) { + AKANTU_DEBUG_INFO("Sending connectivities to proc " + << p << " TAG(" + << Tag::genTag(this->rank, this->message_count, + Tag::_CONNECTIVITY) << ")"); + requests.push_back(comm.asyncSend( + buffers[p], p, + Tag::genTag(this->rank, this->message_count, Tag::_CONNECTIVITY))); + } + } + + Array & old_nodes = this->getNodesGlobalIds(); + + /// create the renumbered connectivity + AKANTU_DEBUG_INFO("Renumbering local connectivities"); + MeshUtils::renumberMeshNodes(mesh, buffers[root], all_nb_local_element[root], + all_nb_ghost_element[root], type, old_nodes); + + comm.waitAll(requests); + comm.freeCommunicationRequest(requests); +} + +/* ------------------------------------------------------------------------ */ +void MasterElementInfoPerProc::synchronizePartitions() { + const Array & partition_num = + this->partition.getPartition(this->type, _not_ghost); + const CSR & ghost_partition = + this->partition.getGhostPartitionCSR()(this->type, _not_ghost); + + std::vector > buffers; + + /// splitting the partition information to send them to processors + Vector count_by_proc(nb_proc, 0); + for (UInt el = 0; el < nb_element; ++el) { + UInt proc = partition_num(el); + buffers[proc].push_back(ghost_partition.getNbCols(el)); + + UInt i(0); + for (CSR::const_iterator part = ghost_partition.begin(el); + part != ghost_partition.end(el); ++part, ++i) { + buffers[proc].push_back(*part); + } + } + + for (UInt el = 0; el < nb_element; ++el) { + UInt i(0); + for (CSR::const_iterator part = ghost_partition.begin(el); + part != ghost_partition.end(el); ++part, ++i) { + buffers[*part].push_back(partition_num(el)); + } + } + +#ifndef AKANTU_NDEBUG + for (UInt p = 0; p < this->nb_proc; ++p) { + AKANTU_DEBUG_ASSERT( + buffers[p].getSize() == + (this->all_nb_ghost_element[p] + this->all_nb_element_to_send[p]), + "Data stored in the buffer are most probably wrong"); + } +#endif + + std::vector requests; + /// last data to compute the communication scheme + for (UInt p = 0; p < this->nb_proc; ++p) { + if (p != this->root) { + AKANTU_DEBUG_INFO("Sending partition informations to proc " + << p << " TAG(" + << Tag::genTag(this->rank, this->message_count, + Tag::_PARTITIONS) << ")"); + requests.push_back(comm.asyncSend( + buffers[p], p, + Tag::genTag(this->rank, this->message_count, Tag::_PARTITIONS))); + } + } + + if (Mesh::getSpatialDimension(this->type) == + this->mesh.getSpatialDimension()) { + AKANTU_DEBUG_INFO("Creating communications scheme"); + this->fillCommunicationScheme(buffers[this->rank]); + } + + comm.waitAll(requests); + comm.freeCommunicationRequest(requests); +} + +/* -------------------------------------------------------------------------- */ +void MasterElementInfoPerProc::synchronizeTags() { + AKANTU_DEBUG_IN(); + + if (this->nb_tags == 0) { + AKANTU_DEBUG_OUT(); + return; + } + + UInt mesh_data_sizes_buffer_length; + MeshData & mesh_data = this->getMeshData(); + + /// tag info + std::vector tag_names; + mesh_data.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::const_iterator names_it = tag_names.begin(); + std::vector::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, 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, root); + + if (mesh_data_sizes_buffer_length != 0) { + // Sending the actual data to each processor + DynamicCommunicationBuffer * buffers = + new DynamicCommunicationBuffer[nb_proc]; + std::vector::const_iterator names_it = tag_names.begin(); + std::vector::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) + this->fillTagBuffer(buffers, *names_it); + } + + std::vector 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(this->rank, this->message_count, + Tag::_MESH_DATA) << ")"); + + requests.push_back(comm.asyncSend( + buffers[p], p, + Tag::genTag(this->rank, this->message_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 + this->fillMeshData(buffers[root], *names_it); + } + + comm.waitAll(requests); + comm.freeCommunicationRequest(requests); + requests.clear(); + delete[] buffers; + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template +void MasterElementInfoPerProc::fillTagBufferTemplated( + DynamicCommunicationBuffer * buffers, const std::string & tag_name) { + MeshData & mesh_data = this->getMeshData(); + + const Array & data = mesh_data.getElementalDataArray(tag_name, type); + const Array & partition_num = + this->partition.getPartition(this->type, _not_ghost); + const CSR & ghost_partition = + this->partition.getGhostPartitionCSR()(this->type, _not_ghost); + + // Not possible to use the iterator because it potentially triggers the + // creation of complex + // type templates (such as akantu::Vector< std::vector > which don't + // implement the right interface + // (e.g. operator<< in that case). + // typename Array::template const_iterator< Vector > data_it = + // data.begin(data.getNbComponent()); + // typename Array::template const_iterator< Vector > data_end = + // data.end(data.getNbComponent()); + + const T * data_it = data.storage(); + const T * data_end = data.storage() + data.getSize() * data.getNbComponent(); + const UInt * part = partition_num.storage(); + + /// copying the data, element by element + for (; data_it != data_end; ++part) { + for (UInt j(0); j < data.getNbComponent(); ++j, ++data_it) { + buffers[*part] << *data_it; + } + } + + data_it = data.storage(); + /// copying the data for the ghost element + for (UInt el(0); data_it != data_end; + data_it += data.getNbComponent(), ++el) { + CSR::const_iterator it = ghost_partition.begin(el); + CSR::const_iterator end = ghost_partition.end(el); + for (; it != end; ++it) { + UInt proc = *it; + for (UInt j(0); j < data.getNbComponent(); ++j) { + buffers[proc] << data_it[j]; + } + } + } +} + +/* -------------------------------------------------------------------------- */ +void MasterElementInfoPerProc::fillTagBuffer( + DynamicCommunicationBuffer * buffers, const std::string & tag_name) { + MeshData & mesh_data = this->getMeshData(); + +#define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ + case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ + this->fillTagBufferTemplated(buffers, \ + tag_name); \ + 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 MasterElementInfoPerProc::synchronizeGroups() { + AKANTU_DEBUG_IN(); + + DynamicCommunicationBuffer * buffers = + new DynamicCommunicationBuffer[nb_proc]; + + typedef std::vector > 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 &>(eg.getElements(type)).empty(); + } + + + const Array & partition_num = + this->partition.getPartition(this->type, _not_ghost); + const CSR & ghost_partition = + this->partition.getGhostPartitionCSR()(this->type, _not_ghost); + + + /// 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::const_iterator it = ghost_partition.begin(el); + CSR::const_iterator end = ghost_partition.end(el); + for (; it != end; ++it) { + UInt proc = *it; + buffers[proc] << *data_it; + } + } + + std::vector requests; + for (UInt p = 0; p < this->nb_proc; ++p) { + if (p == this->rank) + continue; + AKANTU_DEBUG_INFO("Sending element groups to proc " + << p << " TAG(" + << Tag::genTag(this->rank, p, Tag::_ELEMENT_GROUP) + << ")"); + requests.push_back(comm.asyncSend( + buffers[p], p, Tag::genTag(this->rank, p, Tag::_ELEMENT_GROUP))); + } + + this->fillElementGroupsFromBuffer(buffers[this->rank]); + + comm.waitAll(requests); + comm.freeCommunicationRequest(requests); + requests.clear(); + delete[] buffers; + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +__END_AKANTU__ diff --git a/src/synchronizer/node_info_per_processor.cc b/src/synchronizer/node_info_per_processor.cc new file mode 100644 index 000000000..322855007 --- /dev/null +++ b/src/synchronizer/node_info_per_processor.cc @@ -0,0 +1,406 @@ +/** + * @file node_info_per_processor.cc + * + * @author Nicolas Richart + * + * @date Fri Mar 11 15:49:43 2016 + * + * @brief + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "node_info_per_processor.hh" +#include "distributed_synchronizer.hh" +#include "static_communicator.hh" +#include "node_group.hh" +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +/* -------------------------------------------------------------------------- */ +NodeInfoPerProc::NodeInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, + UInt message_cnt, UInt root, Mesh & mesh) + : MeshAccessor(mesh), synchronizer(synchronizer), comm(communicator), + rank(comm.whoAmI()), nb_proc(comm.getNbProc()), root(root), mesh(mesh), + spatial_dimension(mesh.getSpatialDimension()), + message_count(message_cnt) {} + +/* -------------------------------------------------------------------------- */ +template +void NodeInfoPerProc::fillNodeGroupsFromBuffer(CommunicationBuffer & buffer) { + AKANTU_DEBUG_IN(); + + std::vector > 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 & global_nodes = mesh.getGlobalNodesIds(); + + Array::const_scalar_iterator nbegin = global_nodes.begin(); + Array::const_scalar_iterator nit = global_nodes.begin(); + Array::const_scalar_iterator nend = global_nodes.end(); + for (; nit != nend; ++nit) { + std::vector::iterator it = node_to_group[*nit].begin(); + std::vector::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 NodeInfoPerProc::fillNodesType() { + AKANTU_DEBUG_IN(); + + UInt nb_nodes = mesh.getNbNodes(); + Array & nodes_type = this->getNodesType(); + + Array nodes_set(nb_nodes); + nodes_set.set(0); + + enum NodeSet { + NORMAL_SET = 1, + GHOST_SET = 2, + }; + + Array already_seen(nb_nodes, 1, false); + + for (UInt g = _not_ghost; g <= _ghost; ++g) { + GhostType gt = (GhostType)g; + UInt set = NORMAL_SET; + if (gt == _ghost) + set = GHOST_SET; + + already_seen.set(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::const_vector_iterator conn_it = + mesh.getConnectivity(type, gt).begin(nb_nodes_per_element); + + for (UInt e = 0; e < nb_element; ++e, ++conn_it) { + const Vector & 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; + } + } + } + } + } + + for (UInt i = 0; i < nb_nodes; ++i) { + if (nodes_set(i) == NORMAL_SET) + nodes_type(i) = _nt_normal; + else if (nodes_set(i) == GHOST_SET) + nodes_type(i) = _nt_pure_gost; + else if (nodes_set(i) == (GHOST_SET + NORMAL_SET)) + nodes_type(i) = _nt_master; + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +MasterNodeInfoPerProc::MasterNodeInfoPerProc( + DistributedSynchronizer & synchronizer, StaticCommunicator & communicator, + UInt message_cnt, UInt root, Mesh & mesh) + : NodeInfoPerProc(synchronizer, communicator, message_cnt, root, mesh) { + UInt nb_global_nodes = this->mesh.getNbGlobalNodes(); + this->comm.broadcast(nb_global_nodes, this->root); +} + +/* -------------------------------------------------------------------------- */ +void MasterNodeInfoPerProc::synchronizeNodes() { + this->nodes_per_proc.resize(nb_proc); + this->nb_nodes_per_proc.resize(nb_proc); + + Array local_nodes(0, spatial_dimension); + Array & nodes = this->getNodes(); + + for (UInt p = 0; p < nb_proc; ++p) { + UInt nb_nodes = 0; + // UInt * buffer; + Array::const_scalar_iterator it; + Array::const_scalar_iterator end; + Array * nodes_to_send; + + if (p != root) { + nodes_to_send = new Array(0, spatial_dimension); + AKANTU_DEBUG_INFO("Receiving number of nodes from proc " + << p << " TAG(" << Tag::genTag(p, 0, Tag::_NB_NODES) + << ")"); + comm.receive(nb_nodes, p, Tag::genTag(p, 0, Tag::_NB_NODES)); + nodes_per_proc[p].resize(nb_nodes); + this->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], p, Tag::genTag(p, 0, Tag::_NODES)); + + it = nodes_per_proc[p].begin(); + end = nodes_per_proc[p].end(); + } else { + Array & local_ids = this->getNodesGlobalIds(); + this->nb_nodes_per_proc(p) = local_ids.getSize(); + + it = local_ids.begin(); + end = local_ids.end(); + + nodes_to_send = &local_nodes; + } + + /// get the coordinates for the selected nodes + for (; it != end; ++it) { + Vector coord(nodes.storage() + spatial_dimension * *it, + spatial_dimension); + nodes_to_send->push_back(coord); + } + + if (p != root) { /// send them for distant processors + AKANTU_DEBUG_INFO("Sending coordinates to proc " + << p << " TAG(" + << Tag::genTag(this->rank, 0, Tag::_COORDINATES) + << ")"); + comm.send(*nodes_to_send, p, + Tag::genTag(this->rank, 0, Tag::_COORDINATES)); + delete nodes_to_send; + } + } + + /// construct the local nodes coordinates + nodes.copy(local_nodes); +} + +/* -------------------------------------------------------------------------- */ +void MasterNodeInfoPerProc::synchronizeTypes() { + std::multimap > nodes_to_proc; + + std::vector > nodes_type_per_proc(nb_proc); + for (UInt p = 0; p < nb_proc; ++p) { + nodes_type_per_proc[p].resize(nb_nodes_per_proc(p)); + } + + this->fillNodesType(); + + for (UInt p = 0; p < nb_proc; ++p) { + if (p != root) { + AKANTU_DEBUG_INFO("Receiving first nodes types from proc " + << p << " TAG(" + << Tag::genTag(this->rank, this->message_count, + Tag::_NODES_TYPE) << ")"); + comm.receive(nodes_type_per_proc[p], p, + Tag::genTag(p, 0, Tag::_NODES_TYPE)); + } else { + nodes_type_per_proc[p].copy(this->getNodesType()); + } + + for (UInt n = 0; n < nb_nodes_per_proc[p]; ++n) { + if (nodes_type_per_proc[p](n) == _nt_master) + nodes_to_proc.insert( + std::make_pair(nodes_per_proc[p](n), std::make_pair(p, n))); + } + } + + typedef std::multimap >::iterator + node_to_proc_iterator; + + node_to_proc_iterator it_node; + std::pair it_range; + + for (UInt i = 0; i < mesh.getNbGlobalNodes(); ++i) { + it_range = nodes_to_proc.equal_range(i); + if (it_range.first == nodes_to_proc.end() || it_range.first->first != i) + continue; + + UInt master_proc = (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 != master_proc) + nodes_type_per_proc[proc](node) = NodeType(master_proc); + } + } + + std::vector requests; + for (UInt p = 0; p < nb_proc; ++p) { + if (p != root) { + AKANTU_DEBUG_INFO("Sending nodes types to proc " + << p << " TAG(" + << Tag::genTag(this->rank, 0, Tag::_NODES_TYPE) << ")"); + requests.push_back( + comm.asyncSend(nodes_type_per_proc[p], p, + Tag::genTag(this->rank, 0, Tag::_NODES_TYPE))); + } else { + this->getNodesType().copy(nodes_type_per_proc[p]); + } + } + + comm.waitAll(requests); + comm.freeCommunicationRequest(requests); + requests.clear(); +} + +/* -------------------------------------------------------------------------- */ +void MasterNodeInfoPerProc::synchronizeGroups() { + AKANTU_DEBUG_IN(); + + UInt nb_total_nodes = mesh.getNbGlobalNodes(); + + DynamicCommunicationBuffer buffer; + + typedef std::vector > 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 requests; + for (UInt p = 0; p < nb_proc; ++p) { + if (p == this->rank) + continue; + AKANTU_DEBUG_INFO("Sending node groups to proc " + << p << " TAG(" + << Tag::genTag(this->rank, p, Tag::_NODE_GROUP) << ")"); + requests.push_back(comm.asyncSend( + buffer, p, Tag::genTag(this->rank, p, Tag::_NODE_GROUP))); + } + + this->fillNodeGroupsFromBuffer(buffer); + + comm.waitAll(requests); + comm.freeCommunicationRequest(requests); + requests.clear(); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +SlaveNodeInfoPerProc::SlaveNodeInfoPerProc( + DistributedSynchronizer & synchronizer, StaticCommunicator & communicator, + UInt message_cnt, UInt root, Mesh & mesh) + : NodeInfoPerProc(synchronizer, communicator, message_cnt, root, mesh) { + UInt nb_global_nodes = 0; + comm.broadcast(nb_global_nodes, root); + this->setNbGlobalNodes(nb_global_nodes); +} + +/* -------------------------------------------------------------------------- */ +void SlaveNodeInfoPerProc::synchronizeNodes() { + AKANTU_DEBUG_INFO("Sending list of nodes to proc " << root); + Array & local_ids = this->getNodesGlobalIds(); + Array & nodes = this->getNodes(); + + UInt nb_nodes = local_ids.getSize(); + comm.send(nb_nodes, root, Tag::genTag(this->rank, 0, Tag::_NB_NODES)); + comm.send(local_ids, root, Tag::genTag(this->rank, 0, Tag::_NODES)); + + /* --------<<<<-COORDINATES---------------------------------------------- */ + nodes.resize(nb_nodes); + AKANTU_DEBUG_INFO("Receiving coordinates from proc " << root); + comm.receive(nodes, root, Tag::genTag(root, 0, Tag::_COORDINATES)); +} + +/* -------------------------------------------------------------------------- */ +void SlaveNodeInfoPerProc::synchronizeTypes() { + this->fillNodesType(); + + Array & nodes_types = this->getNodesType(); + + AKANTU_DEBUG_INFO("Sending first nodes types to proc " << root); + comm.send(nodes_types, root, Tag::genTag(this->rank, 0, Tag::_NODES_TYPE)); + + AKANTU_DEBUG_INFO("Receiving nodes types from proc " << root); + comm.receive(nodes_types, root, Tag::genTag(root, 0, Tag::_NODES_TYPE)); +} + +/* -------------------------------------------------------------------------- */ +void SlaveNodeInfoPerProc::synchronizeGroups() { + AKANTU_DEBUG_IN(); + + AKANTU_DEBUG_INFO("Receiving node groups from proc " + << root << " TAG(" + << Tag::genTag(root, this->rank, Tag::_NODE_GROUP) << ")"); + + CommunicationStatus status; + comm.probe(root, Tag::genTag(root, this->rank, Tag::_NODE_GROUP), + status); + + CommunicationBuffer buffer(status.getSize()); + comm.receive(buffer, root, Tag::genTag(root, this->rank, Tag::_NODE_GROUP)); + + this->fillNodeGroupsFromBuffer(buffer); + + AKANTU_DEBUG_OUT(); +} + +__END_AKANTU__ diff --git a/src/synchronizer/node_info_per_processor.hh b/src/synchronizer/node_info_per_processor.hh new file mode 100644 index 000000000..9cdb72f5a --- /dev/null +++ b/src/synchronizer/node_info_per_processor.hh @@ -0,0 +1,110 @@ +/** + * @file node_info_per_processor.hh + * + * @author Nicolas Richart + * + * @date Fri Mar 11 14:45:15 2016 + * + * @brief Helper classes to create the distributed synchronizer and distribute + * a mesh + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "mesh_accessor.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_NODE_INFO_PER_PROCESSOR_HH__ +#define __AKANTU_NODE_INFO_PER_PROCESSOR_HH__ + +namespace akantu { +class DistributedSynchronizer; +class StaticCommunicator; +} + +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +class NodeInfoPerProc : protected MeshAccessor { +public: + NodeInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, UInt message_cnt, + UInt root, Mesh & mesh); + + virtual void synchronizeNodes() = 0; + virtual void synchronizeTypes() = 0; + virtual void synchronizeGroups() = 0; + +protected: +template + void fillNodeGroupsFromBuffer(CommunicationBuffer & buffer); + void fillNodesType(); +protected: + DistributedSynchronizer & synchronizer; + StaticCommunicator & comm; + UInt rank; + UInt nb_proc; + UInt root; + + Mesh & mesh; + + UInt spatial_dimension; + + UInt message_count; +}; + +/* -------------------------------------------------------------------------- */ +class MasterNodeInfoPerProc : protected NodeInfoPerProc { +public: + MasterNodeInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, UInt message_cnt, + UInt root, Mesh & mesh); + + void synchronizeNodes(); + void synchronizeTypes(); + void synchronizeGroups(); + +private: + /// get the list of nodes to send and send them + std::vector > nodes_per_proc; + Array nb_nodes_per_proc; +}; + +/* -------------------------------------------------------------------------- */ +class SlaveNodeInfoPerProc : protected NodeInfoPerProc { +public: + SlaveNodeInfoPerProc(DistributedSynchronizer & synchronizer, + StaticCommunicator & communicator, UInt message_cnt, + UInt root, Mesh & mesh); + + void synchronizeNodes(); + void synchronizeTypes(); + void synchronizeGroups(); + +private: +}; + +__END_AKANTU__ + +#include "node_info_per_processor.hh" + +#endif /* __AKANTU_NODE_INFO_PER_PROCESSOR_HH__ */ diff --git a/src/synchronizer/real_static_communicator.hh b/src/synchronizer/real_static_communicator.hh index d703386e4..48e1ba574 100644 --- a/src/synchronizer/real_static_communicator.hh +++ b/src/synchronizer/real_static_communicator.hh @@ -1,109 +1,112 @@ /** * @file real_static_communicator.hh * * @author Nicolas Richart * * @date creation: Mon Jun 14 2010 * @date last modification: Wed Jan 13 2016 * * @brief empty class just for inheritance * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ - #ifndef __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ #define __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ class CommunicationRequest { public: CommunicationRequest(UInt source, UInt dest); virtual ~CommunicationRequest(); virtual void printself(std::ostream & stream, int indent = 0) const; AKANTU_GET_MACRO(Source, source, UInt); AKANTU_GET_MACRO(Destination, destination, UInt); + private: UInt source; UInt destination; UInt id; static UInt counter; }; /* -------------------------------------------------------------------------- */ class CommunicationStatus { public: - CommunicationStatus() : source(0), size(0), tag(0) {}; + CommunicationStatus() : source(0), size(0), tag(0){}; AKANTU_GET_MACRO(Source, source, Int); - AKANTU_GET_MACRO(Size, size, UInt); - AKANTU_GET_MACRO(Tag, tag, Int); + AKANTU_GET_MACRO(Size, size, UInt); + AKANTU_GET_MACRO(Tag, tag, Int); AKANTU_SET_MACRO(Source, source, Int); - AKANTU_SET_MACRO(Size, size, UInt); - AKANTU_SET_MACRO(Tag, tag, Int); + AKANTU_SET_MACRO(Size, size, UInt); + AKANTU_SET_MACRO(Tag, tag, Int); + private: Int source; UInt size; Int tag; }; /* -------------------------------------------------------------------------- */ /// Datatype to pack pairs for MPI_{MIN,MAX}LOC -template -struct SCMinMaxLoc { +template struct SCMinMaxLoc { T1 min_max; T2 loc; }; /* -------------------------------------------------------------------------- */ class StaticCommunicator; /* -------------------------------------------------------------------------- */ class RealStaticCommunicator { public: - RealStaticCommunicator(__attribute__ ((unused)) int & argc, - __attribute__ ((unused)) char ** & argv) { + RealStaticCommunicator(__attribute__((unused)) int & argc, + __attribute__((unused)) char **& argv) { prank = -1; psize = -1; }; - virtual ~RealStaticCommunicator() { }; + virtual ~RealStaticCommunicator(){}; friend class StaticCommunicator; + + Int getNbProc() { return this->psize; } + Int whoAmI() { return this->prank; } + protected: Int prank; - Int psize; }; __END_AKANTU__ #endif /* __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ */ diff --git a/src/synchronizer/slave_element_info_per_processor.cc b/src/synchronizer/slave_element_info_per_processor.cc new file mode 100644 index 000000000..4b2d18d30 --- /dev/null +++ b/src/synchronizer/slave_element_info_per_processor.cc @@ -0,0 +1,190 @@ +/** + * @file slave_element_info_per_processor.cc + * + * @author Nicolas Richart + * + * @date Fri Mar 11 14:59:21 2016 + * + * @brief + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "element_info_per_processor.hh" +#include "distributed_synchronizer.hh" +#include "static_communicator.hh" +#include "mesh_utils.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +#include +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +/* -------------------------------------------------------------------------- */ +SlaveElementInfoPerProc::SlaveElementInfoPerProc( + DistributedSynchronizer & synchronizer, StaticCommunicator & communicator, + UInt message_cnt, UInt root, Mesh & mesh) + : ElementInfoPerProc(synchronizer, communicator, message_cnt, root, mesh, _not_defined) { + + Vector size(5); + comm.receive(size, this->root, Tag::genTag(this->root, this->message_count, Tag::_SIZES)); + + this->type = (ElementType)size[0]; + this->nb_local_element = size[1]; + this->nb_ghost_element = size[2]; + this->nb_element_to_receive = size[3]; + this->nb_tags = size[4]; + + this->nb_nodes_per_element = Mesh::getNbNodesPerElement(type); +} + +/* -------------------------------------------------------------------------- */ + +bool SlaveElementInfoPerProc::needSynchronize() { + return this->type != _not_defined; +} + +/* -------------------------------------------------------------------------- */ +void SlaveElementInfoPerProc::synchronizeConnectivities() { + Array local_connectivity( + (this->nb_local_element + this->nb_ghost_element) * + this->nb_nodes_per_element); + + AKANTU_DEBUG_INFO("Receiving connectivities from proc " << root); + comm.receive(local_connectivity, this->root, + Tag::genTag(this->root, this->message_count, Tag::_CONNECTIVITY)); + + Array & old_nodes = this->getNodesGlobalIds(); + AKANTU_DEBUG_INFO("Renumbering local connectivities"); + MeshUtils::renumberMeshNodes(this->mesh, local_connectivity, + this->nb_local_element, this->nb_ghost_element, + this->type, old_nodes); +} + +/* -------------------------------------------------------------------------- */ +void SlaveElementInfoPerProc::synchronizePartitions() { + Array local_partitions(this->nb_element_to_receive + + this->nb_ghost_element * 2); + AKANTU_DEBUG_INFO("Receiving partition informations from proc " << root); + this->comm.receive(local_partitions, this->root, + Tag::genTag(root, this->message_count, Tag::_PARTITIONS)); + + if (Mesh::getSpatialDimension(this->type) == + this->mesh.getSpatialDimension()) { + AKANTU_DEBUG_INFO("Creating communications scheme"); + this->fillCommunicationScheme(local_partitions); + } +} + +/* -------------------------------------------------------------------------- */ +void SlaveElementInfoPerProc::synchronizeTags() { + AKANTU_DEBUG_IN(); + + if (this->nb_tags == 0) { + AKANTU_DEBUG_OUT(); + return; + } + + /* --------<<<<-TAGS------------------------------------------------- */ + UInt mesh_data_sizes_buffer_length = 0; + CommunicationBuffer mesh_data_sizes_buffer; + + AKANTU_DEBUG_INFO( + "Receiving the size of the information about the mesh data tags."); + comm.broadcast(mesh_data_sizes_buffer_length, 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, root); + AKANTU_DEBUG_INFO("Size of the information about the mesh data: " + << mesh_data_sizes_buffer_length); + + std::vector tag_names; + std::vector tag_type_codes; + std::vector 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(type_code_int); + mesh_data_sizes_buffer >> tag_nb_component[i]; + } + + std::vector::const_iterator names_it = tag_names.begin(); + std::vector::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, this->message_count, Tag::_MESH_DATA) << ")"); + comm.probe(root, Tag::genTag(root, this->message_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, this->message_count, Tag::_MESH_DATA) << ")"); + mesh_data_buffer.resize(mesh_data_buffer_size); + comm.receive(mesh_data_buffer, root, + Tag::genTag(root, this->message_count, Tag::_MESH_DATA)); + + // Loop over each tag for the current type + UInt k(0); + for (; names_it != names_end; ++names_it, ++k) { + this->fillMeshData(mesh_data_buffer, *names_it); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void SlaveElementInfoPerProc::synchronizeGroups() { + 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(root, Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP), status); + + CommunicationBuffer buffer(status.getSize()); + comm.receive(buffer, root, Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP)); + + this->fillElementGroupsFromBuffer(buffer); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ + +__END_AKANTU__ diff --git a/src/synchronizer/static_communicator.hh b/src/synchronizer/static_communicator.hh index b27f3b886..ee54f828c 100644 --- a/src/synchronizer/static_communicator.hh +++ b/src/synchronizer/static_communicator.hh @@ -1,277 +1,378 @@ /** * @file static_communicator.hh * * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Jan 19 2016 * * @brief Class handling the parallel communications * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STATIC_COMMUNICATOR_HH__ #define __AKANTU_STATIC_COMMUNICATOR_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_array.hh" #include "aka_event_handler_manager.hh" - +#include "communication_buffer.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #define AKANTU_COMMUNICATOR_LIST_0 BOOST_PP_SEQ_NIL #include "static_communicator_dummy.hh" #define AKANTU_COMMUNICATOR_LIST_1 \ BOOST_PP_SEQ_PUSH_BACK( \ AKANTU_COMMUNICATOR_LIST_0, \ (_communicator_dummy, (StaticCommunicatorDummy, BOOST_PP_NIL))) #if defined(AKANTU_USE_MPI) #include "static_communicator_mpi.hh" #define AKANTU_COMMUNICATOR_LIST_ALL \ BOOST_PP_SEQ_PUSH_BACK( \ AKANTU_COMMUNICATOR_LIST_1, \ (_communicator_mpi, (StaticCommunicatorMPI, BOOST_PP_NIL))) #else #define AKANTU_COMMUNICATOR_LIST_ALL AKANTU_COMMUNICATOR_LIST_1 #endif // AKANTU_COMMUNICATOR_LIST #include "real_static_communicator.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class RealStaticCommunicator; struct FinalizeCommunicatorEvent { FinalizeCommunicatorEvent(const StaticCommunicator & comm) : communicator(comm) {} const StaticCommunicator & communicator; }; class CommunicatorEventHandler { public: virtual ~CommunicatorEventHandler() {} virtual void onCommunicatorFinalize(__attribute__((unused)) const StaticCommunicator & communicator) { } private: inline void sendEvent(const FinalizeCommunicatorEvent & event) { onCommunicatorFinalize(event.communicator); } template friend class EventHandlerManager; }; class StaticCommunicator : public EventHandlerManager { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ protected: StaticCommunicator(int & argc, char **& argv, CommunicatorType type = _communicator_mpi); public: virtual ~StaticCommunicator(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Point to Point */ - /* ------------------------------------------------------------------------ */ - template - inline void send(Array & values, Int receiver, Int tag) { - return this->send(values.storage(), values.getSize(), receiver, tag); - } - template - inline void send(T * buffer, Int size, Int receiver, Int tag); - /* ------------------------------------------------------------------------ */ template inline void receive(Array & values, Int sender, Int tag) { + return this->receive(values.storage(), + values.getSize() * values.getNbComponent(), sender, + tag); + } + template + inline void receive(TensorStorage & values, Int sender, + Int tag) { + return this->receive(values.storage(), values.size(), sender, tag); + } + template + inline void receive(CommunicationBufferTemplated & values, + Int sender, Int tag) { return this->receive(values.storage(), values.getSize(), sender, tag); } + template inline void receive(T & values, Int sender, Int tag) { + return this->receive(&values, 1, sender, tag); + } + /* ------------------------------------------------------------------------ */ template - inline void receive(T * buffer, Int size, Int sender, Int tag); + inline void send(Array & values, Int receiver, Int tag) { + return this->send(values.storage(), + values.getSize() * values.getNbComponent(), receiver, + tag); + } + template + inline void send(TensorStorage & values, Int receiver, + Int tag) { + return this->send(values.storage(), values.size(), receiver, tag); + } + template + inline void send(CommunicationBufferTemplated & values, + Int receiver, Int tag) { + return this->send(values.storage(), values.getSize(), receiver, tag); + } + template inline void send(T & values, Int receiver, Int tag) { + return this->send(&values, 1, receiver, tag); + } /* ------------------------------------------------------------------------ */ template inline CommunicationRequest * asyncSend(Array & values, Int receiver, Int tag) { + return this->asyncSend(values.storage(), + values.getSize() * values.getNbComponent(), receiver, + tag); + } + template + inline CommunicationRequest * + asyncSend(TensorStorage & values, Int receiver, Int tag) { + return this->asyncSend(values.storage(), values.size(), receiver, tag); + } + template + inline CommunicationRequest * + asyncSend(CommunicationBufferTemplated & values, Int receiver, + Int tag) { return this->asyncSend(values.storage(), values.getSize(), receiver, tag); } template - inline CommunicationRequest * asyncSend(T * buffer, Int size, Int receiver, - Int tag); + inline CommunicationRequest * asyncSend(T & values, Int receiver, Int tag) { + return this->asyncSend(&values, 1, receiver, tag); + } /* ------------------------------------------------------------------------ */ template inline CommunicationRequest * asyncReceive(Array & values, Int sender, Int tag) { + return this->asyncReceive(values.storage(), + values.getSize() * values.getNbComponent(), + sender, tag); + } + template + inline CommunicationRequest * + asyncReceive(TensorStorage & values, Int sender, Int tag) { + return this->asyncReceive(values.storage(), values.size(), sender, tag); + } + template + inline CommunicationRequest * + asyncReceive(CommunicationBufferTemplated & values, Int sender, + Int tag) { return this->asyncReceive(values.storage(), values.getSize(), sender, tag); } - template - inline CommunicationRequest * asyncReceive(T * buffer, Int size, Int sender, - Int tag); /* ------------------------------------------------------------------------ */ template inline void probe(Int sender, Int tag, CommunicationStatus & status); /* ------------------------------------------------------------------------ */ /* Collectives */ /* ------------------------------------------------------------------------ */ template inline void allReduce(Array & values, const SynchronizerOperation & op) { - this->allReduce(values.storage(), values.getSize(), op); + this->allReduce(values.storage(), + values.getSize() * values.getNbComponent(), op); + } + template + inline void allReduce(TensorStorage & values, + const SynchronizerOperation & op) { + this->allReduce(values.storage(), values.size(), op); } template - inline void allReduce(T * values, int nb_values, - const SynchronizerOperation & op); + inline void allReduce(T & values, const SynchronizerOperation & op) { + this->allReduce(&values, 1, op); + } /* ------------------------------------------------------------------------ */ template inline void allGather(Array & values) { - this->allGather(values.storage(), values.getSize()); + AKANTU_DEBUG_ASSERT(UInt(this->real_static_communicator->getNbProc()) == + values.getSize(), + "The array size is not correct"); + this->allGather(values.storage(), values.getNbComponent()); + } + + template inline void allGather(Vector & values) { + AKANTU_DEBUG_ASSERT(UInt(this->real_static_communicator->getNbProc()) == + values.size(), + "The array size is not correct"); + this->allGather(values.storage(), 1); } - template inline void allGather(T * values, int nb_values); /* ------------------------------------------------------------------------ */ - template inline void allGatherV(Array & values) { - this->allGatherV(values.storage(), values.getSize()); + template + inline void allGatherV(Array & values, Array sizes) { + this->allGatherV(values.storage(), sizes.storage()); } - template inline void allGatherV(T * values, int * nb_values); /* ------------------------------------------------------------------------ */ template inline void reduce(Array & values, const SynchronizerOperation & op, int root = 0) { - this->reduce(values.storage(), values.getSize(), op, root); + this->reduce(values.storage(), values.getSize() * values.getNbComponent(), + op, root); } - template - inline void reduce(T * values, int nb_values, - const SynchronizerOperation & op, int root = 0); - /* ------------------------------------------------------------------------ */ template inline void gather(Array & values, int root = 0) { - this->gather(values.storage(), values.getSize(), root); + AKANTU_DEBUG_ASSERT(this->real_static_communicator->getNbProc() == + values.getSize(), + "The array size is not correct"); + this->gather(values.storage(), values.getNbComponent(), root); } - template - inline void gather(T * values, int nb_values, int root = 0); - /* ------------------------------------------------------------------------ */ - template inline void gatherV(Array & values, int root = 0) { - this->gatherV(values.storage(), values.getSize(), root); - } template - inline void gatherV(T * values, int * nb_values, int root = 0); + inline void gatherV(Array & values, Array sizes, int root = 0) { + this->gatherV(values.storage(), sizes.storage(), root); + } /* ------------------------------------------------------------------------ */ template inline void broadcast(Array & values, int root = 0) { + this->broadcast(values.storage(), + values.getSize() * values.getNbComponent(), root); + } + template + inline void broadcast(CommunicationBufferTemplated & values, + int root = 0) { this->broadcast(values.storage(), values.getSize(), root); } - template - inline void broadcast(T * values, int nb_values, int root = 0); + template inline void broadcast(T & values, int root = 0) { + this->broadcast(&values, 1, root); + } + /* ------------------------------------------------------------------------ */ inline void barrier(); /* ------------------------------------------------------------------------ */ /* Request handling */ /* ------------------------------------------------------------------------ */ inline bool testRequest(CommunicationRequest * request); inline void wait(CommunicationRequest * request); inline void waitAll(std::vector & requests); inline void freeCommunicationRequest(CommunicationRequest * request); inline void freeCommunicationRequest(std::vector & requests); +protected: + template + inline void send(T * buffer, Int size, Int receiver, Int tag); + template + inline void receive(T * buffer, Int size, Int sender, Int tag); + + template + inline CommunicationRequest * asyncSend(T * buffer, Int size, Int receiver, + Int tag); + template + inline CommunicationRequest * asyncReceive(T * buffer, Int size, Int sender, + Int tag); + + template + inline void allReduce(T * values, int nb_values, + const SynchronizerOperation & op); + + template inline void allGather(T * values, int nb_values); + template inline void allGatherV(T * values, int * nb_values); + + template + inline void reduce(T * values, int nb_values, + const SynchronizerOperation & op, int root = 0); + template + inline void gather(T * values, int nb_values, int root = 0); + + template + inline void gatherV(T * values, int * nb_values, int root = 0); + + template + inline void broadcast(T * values, int nb_values, int root = 0); + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: virtual Int getNbProc() const { return real_static_communicator->psize; }; virtual Int whoAmI() const { return real_static_communicator->prank; }; AKANTU_GET_MACRO(RealStaticCommunicator, *real_static_communicator, const RealStaticCommunicator &); AKANTU_GET_MACRO_NOT_CONST(RealStaticCommunicator, *real_static_communicator, RealStaticCommunicator &); template Comm & getRealStaticCommunicator() { return dynamic_cast(*real_static_communicator); } static StaticCommunicator & getStaticCommunicator(CommunicatorType type = _communicator_mpi); static StaticCommunicator & getStaticCommunicator(int & argc, char **& argv, CommunicatorType type = _communicator_mpi); static bool isInstantiated() { return is_instantiated; }; int getMaxTag(); int getMinTag(); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: static bool is_instantiated; static StaticCommunicator * static_communicator; RealStaticCommunicator * real_static_communicator; CommunicatorType real_type; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "static_communicator_inline_impl.hh" /* -------------------------------------------------------------------------- */ /* Inline Functions ArrayBase */ /* -------------------------------------------------------------------------- */ inline std::ostream & operator<<(std::ostream & stream, const CommunicationRequest & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_STATIC_COMMUNICATOR_HH__ */ diff --git a/src/synchronizer/static_communicator_dummy.hh b/src/synchronizer/static_communicator_dummy.hh index 7820e74ca..dd8e2e990 100644 --- a/src/synchronizer/static_communicator_dummy.hh +++ b/src/synchronizer/static_communicator_dummy.hh @@ -1,160 +1,159 @@ /** * @file static_communicator_dummy.hh * * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Wed Jan 13 2016 * * @brief Dummy communicator to make everything work im sequential * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_STATIC_COMMUNICATOR_DUMMY_HH__ #define __AKANTU_STATIC_COMMUNICATOR_DUMMY_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "real_static_communicator.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class StaticCommunicatorDummy : public RealStaticCommunicator { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: StaticCommunicatorDummy(__attribute__((unused)) int & argc, __attribute__((unused)) char **& argv) : RealStaticCommunicator(argc, argv) { - prank = 0; - psize = 1; - }; - virtual ~StaticCommunicatorDummy(){}; + this->prank = 0; + this->psize = 1; + } + + virtual ~StaticCommunicatorDummy() {} /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template void send(__attribute__((unused)) T * buffer, __attribute__((unused)) Int size, __attribute__((unused)) Int receiver, __attribute__((unused)) Int tag) {} template void receive(__attribute__((unused)) T * buffer, __attribute__((unused)) Int size, __attribute__((unused)) Int sender, __attribute__((unused)) Int tag) {} template CommunicationRequest * asyncSend(__attribute__((unused)) T * buffer, __attribute__((unused)) Int size, __attribute__((unused)) Int receiver, __attribute__((unused)) Int tag) { return new CommunicationRequest(0, 0); } template CommunicationRequest * asyncReceive(__attribute__((unused)) T * buffer, __attribute__((unused)) Int size, __attribute__((unused)) Int sender, __attribute__((unused)) Int tag) { return new CommunicationRequest(0, 0); } template inline void probe(__attribute__((unused)) Int sender, __attribute__((unused)) Int tag, __attribute__((unused)) CommunicationStatus & status) {} bool testRequest(__attribute__((unused)) CommunicationRequest * request) { return true; - }; - - void wait(__attribute__((unused)) CommunicationRequest * request){}; + } + void wait(__attribute__((unused)) CommunicationRequest * request) {} void waitAll(__attribute__((unused)) - std::vector & requests){}; + std::vector & requests) {} - void barrier(){}; + void barrier() {} template - void reduce(__attribute__ ((unused)) T * values, - __attribute__ ((unused)) int nb_values, - __attribute__ ((unused)) const SynchronizerOperation & op, - __attribute__ ((unused)) int root) {} - + void reduce(__attribute__((unused)) T * values, + __attribute__((unused)) int nb_values, + __attribute__((unused)) const SynchronizerOperation & op, + __attribute__((unused)) int root) {} template void allReduce(__attribute__((unused)) T * values, __attribute__((unused)) int nb_values, __attribute__((unused)) const SynchronizerOperation & op) {} template inline void allGather(__attribute__((unused)) T * values, __attribute__((unused)) int nb_values) {} template inline void allGatherV(__attribute__((unused)) T * values, __attribute__((unused)) int * nb_values) {} template inline void gather(__attribute__((unused)) T * values, __attribute__((unused)) int nb_values, __attribute__((unused)) int root = 0) {} template inline void gatherV(__attribute__((unused)) T * values, __attribute__((unused)) int * nb_values, __attribute__((unused)) int root = 0) {} template inline void broadcast(__attribute__((unused)) T * values, __attribute__((unused)) int nb_values, __attribute__((unused)) int root = 0) {} /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ int getMaxTag() { return std::numeric_limits::max(); } int getMinTag() { return 0; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ }; __END_AKANTU__ #endif /* __AKANTU_STATIC_COMMUNICATOR_DUMMY_HH__ */ diff --git a/src/synchronizer/static_communicator_inline_impl.hh b/src/synchronizer/static_communicator_inline_impl.hh index 44af178db..3ed406dca 100644 --- a/src/synchronizer/static_communicator_inline_impl.hh +++ b/src/synchronizer/static_communicator_inline_impl.hh @@ -1,178 +1,201 @@ /** * @file static_communicator_inline_impl.hh * * @author Nicolas Richart * * @date creation: Mon Sep 06 2010 * @date last modification: Thu Dec 10 2015 * * @brief implementation of inline functions * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ -inline void StaticCommunicator::freeCommunicationRequest(CommunicationRequest * request) { - if(request) delete request; +inline void +StaticCommunicator::freeCommunicationRequest(CommunicationRequest * request) { + if (request) + delete request; } /* -------------------------------------------------------------------------- */ -inline void StaticCommunicator::freeCommunicationRequest(std::vector & requests) { +inline void StaticCommunicator::freeCommunicationRequest( + std::vector & requests) { std::vector::iterator it; - for(it = requests.begin(); it != requests.end(); ++it) { + for (it = requests.begin(); it != requests.end(); ++it) { delete (*it); } } #if defined(__INTEL_COMPILER) -#pragma warning ( push ) -#pragma warning ( disable : 111 ) -#endif //defined(__INTEL_COMPILER) - -/* -------------------------------------------------------------------------- */ -#define AKANTU_BOOST_REAL_COMMUNICATOR_CALL(r, call, comm_type) \ - case BOOST_PP_LIST_AT(comm_type, 0): { \ - BOOST_PP_LIST_AT(comm_type, 1) * comm = \ - static_cast(real_static_communicator); \ - BOOST_PP_IF(BOOST_PP_LIST_AT(call, 0), \ - return comm->BOOST_PP_LIST_AT(call, 1), \ - comm->BOOST_PP_LIST_AT(call, 1); break;); \ +#pragma warning(push) +#pragma warning(disable : 111) +#endif // defined(__INTEL_COMPILER) + +/* -------------------------------------------------------------------------- */ +#define AKANTU_BOOST_REAL_COMMUNICATOR_CALL(r, call, comm_type) \ + case BOOST_PP_LIST_AT(comm_type, 0): { \ + BOOST_PP_LIST_AT(comm_type, 1) * comm = \ + static_cast( \ + real_static_communicator); \ + BOOST_PP_IF(BOOST_PP_LIST_AT(call, 0), \ + return comm->BOOST_PP_LIST_AT(call, 1), \ + comm->BOOST_PP_LIST_AT(call, 1); \ + break;); \ } -#define AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(call, ret) \ - do { \ - switch(real_type) \ - { \ - BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_REAL_COMMUNICATOR_CALL, \ - (ret, (call, BOST_PP_NIL)), \ - AKANTU_COMMUNICATOR_LIST_ALL) \ - default: \ - StaticCommunicatorDummy * comm = \ - static_cast(real_static_communicator); \ - BOOST_PP_IF(ret, return comm->call, comm->call); \ - } \ - } while(0) - +#define AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(call, ret) \ + do { \ + switch (real_type) { \ + BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_REAL_COMMUNICATOR_CALL, \ + (ret, (call, BOST_PP_NIL)), \ + AKANTU_COMMUNICATOR_LIST_ALL) \ + default: \ + StaticCommunicatorDummy * comm = \ + static_cast(real_static_communicator); \ + BOOST_PP_IF(ret, return comm->call, comm->call); \ + } \ + } while (0) /* -------------------------------------------------------------------------- */ -template -inline void StaticCommunicator::send(T * buffer, Int size, Int receiver, Int tag) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(send(buffer, size, receiver, tag), 0); +template +inline void StaticCommunicator::send(T * buffer, Int size, Int receiver, + Int tag) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(send(buffer, size, receiver, tag), + 0); } /* -------------------------------------------------------------------------- */ -template -inline void StaticCommunicator::receive(T * buffer, Int size, Int sender, Int tag) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(receive(buffer, size, sender, tag), 0); +template +inline void StaticCommunicator::receive(T * buffer, Int size, Int sender, + Int tag) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(receive(buffer, size, sender, tag), + 0); } /* -------------------------------------------------------------------------- */ -template -inline CommunicationRequest * StaticCommunicator::asyncSend(T * buffer, Int size, - Int receiver, Int tag) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(asyncSend(buffer, size, receiver, tag), 1); +template +inline CommunicationRequest * +StaticCommunicator::asyncSend(T * buffer, Int size, Int receiver, Int tag) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL( + asyncSend(buffer, size, receiver, tag), 1); } /* -------------------------------------------------------------------------- */ -template -inline CommunicationRequest * StaticCommunicator::asyncReceive(T * buffer, Int size, - Int sender, Int tag) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(asyncReceive(buffer, size, sender, tag), 1); +template +inline CommunicationRequest * +StaticCommunicator::asyncReceive(T * buffer, Int size, Int sender, Int tag) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL( + asyncReceive(buffer, size, sender, tag), 1); } /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::probe(Int sender, Int tag, - CommunicationStatus & status) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(template probe(sender, tag, status), 0); +template +inline void StaticCommunicator::probe(Int sender, Int tag, + CommunicationStatus & status) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL( + template probe(sender, tag, status), 0); } - /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::reduce(T * values, int nb_values, - const SynchronizerOperation & op, - int root) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(reduce(values, nb_values, op, root), 0); +template +inline void StaticCommunicator::reduce(T * values, int nb_values, + const SynchronizerOperation & op, + int root) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL( + reduce(values, nb_values, op, root), 0); } /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::allReduce(T * values, int nb_values, - const SynchronizerOperation & op) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(allReduce(values, nb_values, op), 0); +template +inline void StaticCommunicator::allReduce(T * values, int nb_values, + const SynchronizerOperation & op) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(allReduce(values, nb_values, op), + 0); } /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::allGather(T * values, int nb_values) { +template +inline void StaticCommunicator::allGather(T * values, int nb_values) { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(allGather(values, nb_values), 0); } /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::allGatherV(T * values, int * nb_values) { +template +inline void StaticCommunicator::allGatherV(T * values, int * nb_values) { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(allGatherV(values, nb_values), 0); } /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::gather(T * values, int nb_values, int root) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(gather(values, nb_values, root), 0); +template +inline void StaticCommunicator::gather(T * values, int nb_values, int root) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(gather(values, nb_values, root), + 0); } /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::gatherV(T * values, int * nb_values, int root) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(gatherV(values, nb_values, root), 0); +template +inline void StaticCommunicator::gatherV(T * values, int * nb_values, int root) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(gatherV(values, nb_values, root), + 0); } /* -------------------------------------------------------------------------- */ -template inline void StaticCommunicator::broadcast(T * values, int nb_values, int root) { - AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(broadcast(values, nb_values, root), 0); +template +inline void StaticCommunicator::broadcast(T * values, int nb_values, int root) { + AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(broadcast(values, nb_values, root), + 0); } /* -------------------------------------------------------------------------- */ inline void StaticCommunicator::barrier() { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(barrier(), 0); } /* -------------------------------------------------------------------------- */ inline bool StaticCommunicator::testRequest(CommunicationRequest * request) { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(testRequest(request), 1); } /* -------------------------------------------------------------------------- */ inline void StaticCommunicator::wait(CommunicationRequest * request) { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(wait(request), 0); } /* -------------------------------------------------------------------------- */ -inline void StaticCommunicator::waitAll(std::vector & requests) { +inline void +StaticCommunicator::waitAll(std::vector & requests) { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(waitAll(requests), 0); } /* -------------------------------------------------------------------------- */ inline int StaticCommunicator::getMaxTag() { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(getMaxTag(), 1); } /* -------------------------------------------------------------------------- */ inline int StaticCommunicator::getMinTag() { AKANTU_BOOST_REAL_COMMUNICATOR_SELECT_CALL(getMinTag(), 1); } #if defined(__INTEL_COMPILER) -#pragma warning ( pop ) -#endif //defined(__INTEL_COMPILER) +#pragma warning(pop) +#endif // defined(__INTEL_COMPILER) diff --git a/src/synchronizer/synchronizer.hh b/src/synchronizer/synchronizer.hh index 769105630..df5866ef2 100644 --- a/src/synchronizer/synchronizer.hh +++ b/src/synchronizer/synchronizer.hh @@ -1,174 +1,190 @@ /** * @file synchronizer.hh * * @author Guillaume Anciaux * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Dec 10 2015 * * @brief Common interface for synchronizers * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #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 /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ +/* -------------------------------------------------------------------------- */ +/** + * tag = |__________20_________|___8____|_4_| + * | proc | num mes| ct| + */ +class Tag { +public: + Tag() : tag(0) {} + Tag(int val) : tag(val) {} + + operator int() { return int(tag); } // remove the sign bit + + template + static inline Tag genTag(int proc, UInt msg_count, CommTag tag) { + int max_tag = StaticCommunicator::getStaticCommunicator().getMaxTag(); + int _tag = ((((proc & 0xFFFFF) << 12) + ((msg_count & 0xFF) << 4) + + ((Int)tag & 0xF))); + Tag t(max_tag == 0 ? _tag : (_tag % max_tag)); + return t; + } + + virtual void printself(std::ostream & stream, + __attribute__((unused)) int indent = 0) const { + stream << (tag >> 12) << ":" << (tag >> 4 & 0xFF) << ":" << (tag & 0xF); + } + + + enum CommTags { + _SIZES = 0, + _CONNECTIVITY = 1, + _DATA = 2, + _PARTITIONS = 3, + _NB_NODES = 4, + _NODES = 5, + _COORDINATES = 6, + _NODES_TYPE = 7, + _MESH_DATA = 8, + _ELEMENT_GROUP = 9, + _NODE_GROUP = 10, + }; +private: + int tag; +}; +/* -------------------------------------------------------------------------- */ + 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: - Tag() : tag(0) {} - Tag(int val) : tag(val) {} - - operator int() { return int(tag); } // remove the sign bit - - template - static inline Tag genTag(int proc, UInt msg_count, CommTag tag) { - int max_tag = StaticCommunicator::getStaticCommunicator().getMaxTag(); - int _tag = ((((proc & 0xFFFFF) << 12) + ((msg_count & 0xFF) << 4) + - ((Int)tag & 0xF))); - Tag t(max_tag == 0 ? _tag : (_tag % max_tag)); - return t; - } - - virtual void printself(std::ostream & stream, - __attribute__((unused)) int indent = 0) const { - stream << (tag >> 12) << ":" << (tag >> 4 & 0xFF) << ":" << (tag & 0xF); - } - - private: - int tag; - }; - - /// generate the tag from the ID template inline Tag genTagFromID(CommTag tag) { int max_tag = StaticCommunicator::getStaticCommunicator().getMaxTag(); - int _tag = std::abs((int(hash(this->getID())) << 4) + (tag & 0xF)); + int _tag = + std::abs((int(hash(this->getID())) << 4) + (tag & 0xF)); Tag t(max_tag == 0 ? _tag : (_tag % max_tag)); return t; } 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 size_to_send; /// size of data to recv to each processor std::vector size_to_receive; std::vector send_buffer; std::vector recv_buffer; std::vector send_requests; std::vector recv_requests; }; /// id of the synchronizer SynchronizerID id; /// message counter per tag std::map 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) { + const Tag & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_SYNCHRONIZER_HH__ */