diff --git a/packages/mpi.cmake b/packages/mpi.cmake index 145addc2b..9099da24d 100644 --- a/packages/mpi.cmake +++ b/packages/mpi.cmake @@ -1,169 +1,167 @@ #=============================================================================== # @file mpi.cmake # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Mon Nov 21 2011 # @date last modification: Wed Jan 20 2016 # # @brief package description for mpi # # @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(MPI EXTERNAL DESCRIPTION "Add MPI support in akantu" EXTRA_PACKAGE_OPTIONS PREFIX MPI_C MPI DEPENDS scotch) package_declare_sources(MPI - synchronizer/mpi_type_wrapper.hh - synchronizer/static_communicator_mpi.cc - synchronizer/static_communicator_mpi_inline_impl.hh - synchronizer/static_communicator_mpi.hh + synchronizer/mpi_communicator_data.hh + synchronizer/communicator_mpi_inline_impl.cc ) function(add_extra_mpi_options) unset(MPI_ID CACHE) package_get_include_dir(MPI _include_dir) foreach(_inc_dir ${_include_dir}) if(EXISTS "${_inc_dir}/mpi.h") if(NOT MPI_ID) file(STRINGS "${_inc_dir}/mpi.h" _mpi_version REGEX "#define MPI_(SUB)?VERSION .*") foreach(_ver ${_mpi_version}) string(REGEX MATCH "MPI_(VERSION|SUBVERSION) *([0-9]+)" _tmp "${_ver}") set(_mpi_${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) endforeach() set(MPI_STD_VERSION "${_mpi_VERSION}.${_mpi_SUBVERSION}" CACHE INTERNAL "") endif() if(NOT MPI_ID) # check if openmpi file(STRINGS "${_inc_dir}/mpi.h" _ompi_version REGEX "#define OMPI_.*_VERSION .*") if(_ompi_version) set(MPI_ID "OpenMPI" CACHE INTERNAL "") foreach(_version ${_ompi_version}) string(REGEX MATCH "OMPI_(.*)_VERSION (.*)" _tmp "${_version}") if(_tmp) set(MPI_VERSION_${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) endif() endforeach() set(MPI_ID_VERSION "${MPI_VERSION_MAJOR}.${MPI_VERSION_MINOR}.${MPI_VERSION_RELEASE}" CACHE INTERNAL "") endif() endif() if(NOT MPI_ID) # check if intelmpi file(STRINGS "${_inc_dir}/mpi.h" _impi_version REGEX "#define I_MPI_VERSION .*") if(_impi_version) set(MPI_ID "IntelMPI" CACHE INTERNAL "") string(REGEX MATCH "I_MPI_VERSION \"(.*)\"" _tmp "${_impi_version}") if(_tmp) set(MPI_ID_VERSION "${CMAKE_MATCH_1}" CACHE INTERNAL "") endif() endif() endif() if(NOT MPI_ID) # check if mvapich2 file(STRINGS "${_inc_dir}/mpi.h" _mvapich2_version REGEX "#define MVAPICH2_VERSION .*") if(_mvapich2_version) set(MPI_ID "MPVAPICH2" CACHE INTERNAL "") string(REGEX MATCH "MVAPICH2_VERSION \"(.*)\"" _tmp "${_mvapich2_version}") if(_tmp) set(MPI_ID_VERSION "${CMAKE_MATCH_1}" CACHE INTERNAL "") endif() endif() endif() if(NOT MPI_ID) # check if mpich (mpich as to be checked after all the mpi that derives from it) file(STRINGS "${_inc_dir}/mpi.h" _mpich_version REGEX "#define MPICH_VERSION .*") if(_mpich_version) set(MPI_ID "MPICH" CACHE INTERNAL "") string(REGEX MATCH "I_MPI_VERSION \"(.*)\"" _tmp "${_mpich_version}") if(_tmp) set(MPI_ID_VERSION "${CMAKE_MATCH_1}" CACHE INTERNAL "") endif() endif() endif() endif() endforeach() if(MPI_ID STREQUAL "IntelMPI" OR MPI_ID STREQUAL "MPICH" OR MPI_ID STREQUAL "MVAPICH2") set(_flags "-DMPICH_IGNORE_CXX_SEEK") elseif(MPI_ID STREQUAL "OpenMPI") set(_flags "-DOMPI_SKIP_MPICXX") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set( _flags "${_flags} -Wno-literal-suffix") endif() endif() include(FindPackageMessage) if(MPI_FOUND) find_package_message(MPI "MPI ID: ${MPI_ID} ${MPI_ID_VERSION} (MPI standard ${MPI_STD_VERSION})" "${MPI_STD_VERSION}") endif() set(MPI_EXTRA_COMPILE_FLAGS "${_flags}" CACHE STRING "Extra flags for MPI" FORCE) mark_as_advanced(MPI_EXTRA_COMPILE_FLAGS) #package_get_source_files(MPI _srcs _pub _priv) #list(APPEND _srcs "common/aka_error.cc") #set_property(SOURCE ${_srcs} PROPERTY COMPILE_FLAGS "${_flags}") package_set_compile_flags(MPI CXX ${_flags}) endfunction() package_on_enabled_script(MPI " add_extra_mpi_options() get_cmake_property(_all_vars VARIABLES) foreach(_var \${_all_vars}) if(_var MATCHES \"^MPI_.*\") mark_as_advanced(\${_var}) endif() endforeach() " ) package_declare_documentation(MPI "This is a meta package providing access to MPI." "" "Under Ubuntu (14.04 LTS) the installation can be performed using the commands:" "\\begin{command}" " > sudo apt-get install libopenmpi-dev" "\\end{command}" "" "Under Mac OS X the installation requires the following steps:" "\\begin{command}" " > sudo port install mpich-devel" "\\end{command}" ) package_set_package_system_dependency(MPI deb mpi-default-bin) package_set_package_system_dependency(MPI deb-src mpi-default-dev) diff --git a/src/common/aka_common.cc b/src/common/aka_common.cc index 7f6b343be..7e61edc3b 100644 --- a/src/common/aka_common.cc +++ b/src/common/aka_common.cc @@ -1,153 +1,155 @@ /** * @file aka_common.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Mon Jun 14 2010 * @date last modification: Tue Jan 19 2016 * * @brief Initialization of global variables * * @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 "aka_static_memory.hh" -#include "static_communicator.hh" +#include "communicator.hh" #include "aka_random_generator.hh" #include "parser.hh" #include "cppargparse.hh" #include "communication_tag.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void initialize(int & argc, char **& argv) { AKANTU_DEBUG_IN(); initialize("", argc, argv); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void initialize(const std::string & input_file, int & argc, char **& argv) { AKANTU_DEBUG_IN(); StaticMemory::getStaticMemory(); - StaticCommunicator & comm = - StaticCommunicator::getStaticCommunicator(argc, argv); + Communicator & comm = + Communicator::getStaticCommunicator(argc, argv); Tag::setMaxTag(comm.getMaxTag()); debug::debugger.setParallelContext(comm.whoAmI(), comm.getNbProc()); debug::setDebugLevel(dblError); static_argparser.setParallelContext(comm.whoAmI(), comm.getNbProc()); static_argparser.setExternalExitFunction(debug::exit); static_argparser.addArgument("--aka_input_file", "Akantu's input file", 1, cppargparse::_string, std::string()); static_argparser.addArgument( "--aka_debug_level", std::string("Akantu's overall debug level") + std::string(" (0: error, 1: exceptions, 4: warnings, 5: info, ..., " "100: dump") + std::string(" more info on levels can be foind in aka_error.hh)"), 1, cppargparse::_integer, int(dblWarning)); static_argparser.addArgument( "--aka_print_backtrace", "Should Akantu print a backtrace in case of error", 0, cppargparse::_boolean, false, true); static_argparser.parse(argc, argv, cppargparse::_remove_parsed); std::string infile = static_argparser["aka_input_file"]; if (infile == "") infile = input_file; debug::debugger.printBacktrace(static_argparser["aka_print_backtrace"]); if ("" != infile) { readInputFile(infile); } long int seed; try { seed = static_parser.getParameter("seed", _ppsc_current_scope); } catch (debug::Exception &) { seed = time(NULL); } seed *= (comm.whoAmI() + 1); RandomGenerator::seed(seed); int dbl_level = static_argparser["aka_debug_level"]; debug::setDebugLevel(DebugLevel(dbl_level)); AKANTU_DEBUG_INFO("Random seed set to " << seed); std::atexit(finalize); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void finalize() { AKANTU_DEBUG_IN(); - if (StaticCommunicator::isInstantiated()) { - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - delete &comm; - } + // if (StaticCommunicator::isInstantiated()) { + // StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + // delete &comm; + // } if (StaticMemory::isInstantiated()) { delete &(StaticMemory::getStaticMemory()); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void readInputFile(const std::string & input_file) { static_parser.parse(input_file); } /* -------------------------------------------------------------------------- */ cppargparse::ArgumentParser & getStaticArgumentParser() { return static_argparser; } /* -------------------------------------------------------------------------- */ Parser & getStaticParser() { return static_parser; } /* -------------------------------------------------------------------------- */ const ParserSection & getUserParser() { return *(static_parser.getSubSections(_st_user).first); } +std::unique_ptr Communicator::static_communicator; + } // akantu diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh index 437f748d0..b21921277 100644 --- a/src/common/aka_common.hh +++ b/src/common/aka_common.hh @@ -1,436 +1,415 @@ /** * @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 #include /* -------------------------------------------------------------------------- */ #include "aka_compatibilty_with_cpp_standard.hh" /* -------------------------------------------------------------------------- */ #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" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* Common types */ /* -------------------------------------------------------------------------- */ using ID = std::string; #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 */ /* -------------------------------------------------------------------------- */ using MemoryID = UInt; using Surface = std::string; typedef std::pair SurfacePair; using SurfacePairList = std::list; /* -------------------------------------------------------------------------- */ extern const UInt _all_dimensions; /* -------------------------------------------------------------------------- */ /* Mesh/FEM/Model types */ /* -------------------------------------------------------------------------- */ } // akantu #include "aka_element_classes_info.hh" namespace 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 MeshEventHandlerPriority defines relative order of execution of events enum EventHandlerPriority { _ehp_highest = 0, _ehp_mesh = 5, _ehp_fe_engine = 9, _ehp_synchronizer = 10, _ehp_dof_manager = 20, _ehp_model = 94, _ehp_non_local_manager = 100, _ehp_lowest = 100 }; /// 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 : Int { _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 _tsst_not_defined, ///< For not defined cases }; /// 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, _mt_not_defined }; /* -------------------------------------------------------------------------- */ /* Ghosts handling */ /* -------------------------------------------------------------------------- */ - -using SynchronizerID = ID; - /// @enum CommunicatorType type of communication method to use enum CommunicatorType { _communicator_mpi, _communicator_dummy }; /// @enum SynchronizationTag type of synchronizations enum SynchronizationTag { //--- Generic tags --- _gst_whatever, _gst_update, _gst_size, //--- 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 { using type = GhostType; static const type _begin_ = _not_ghost; static const type _end_ = _casper; }; using ghost_type_t = safe_enum; extern ghost_type_t ghost_types; /// 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 using is_scalar = std::is_arithmetic; /* -------------------------------------------------------------------------- */ #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); /* -------------------------------------------------------------------------- */ } // akantu #include "aka_fwd.hh" namespace 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(); } // akantu #include "aka_common_inline_impl.cc" /* -------------------------------------------------------------------------- */ #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 namespace std { /** * 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; }; } //std #endif /* __AKANTU_COMMON_HH__ */ diff --git a/src/io/dumper/dumper_element_partition.hh b/src/io/dumper/dumper_element_partition.hh index 21296b317..ff8aa2654 100644 --- a/src/io/dumper/dumper_element_partition.hh +++ b/src/io/dumper/dumper_element_partition.hh @@ -1,124 +1,124 @@ /** * @file dumper_element_partition.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Tue Sep 02 2014 * @date last modification: Tue Jul 14 2015 * * @brief ElementPartition field * * @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 . * */ /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ #ifdef AKANTU_IGFEM # include "dumper_igfem_element_partition.hh" #endif /* -------------------------------------------------------------------------- */ template class element_partition_field_iterator : public element_iterator { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: typedef element_iterator parent; typedef typename types::return_type return_type; typedef typename types::array_iterator array_iterator; typedef typename types::field_type field_type; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: element_partition_field_iterator(const field_type & field, const typename field_type::type_iterator & t_it, const typename field_type::type_iterator & t_it_end, const array_iterator & array_it, const array_iterator & array_it_end, const GhostType ghost_type = _not_ghost) : parent(field, t_it, t_it_end, array_it, array_it_end, ghost_type) { - prank = StaticCommunicator::getStaticCommunicator().whoAmI(); + prank = Communicator::getStaticCommunicator().whoAmI(); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: return_type operator*() { return return_type(1, prank); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: UInt prank; }; /* -------------------------------------------------------------------------- */ template class ElementPartitionField : public GenericElementalField, element_partition_field_iterator> { public: /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ typedef SingleType types; typedef element_partition_field_iterator iterator; typedef GenericElementalField parent; typedef typename types::field_type field_type; public: /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ ElementPartitionField(const field_type & field, UInt spatial_dimension = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) : parent(field, spatial_dimension, ghost_type, element_kind) { this->homogeneous = true; } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ UInt getDim() { return 1; } }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu diff --git a/src/io/dumper/dumper_elemental_field.hh b/src/io/dumper/dumper_elemental_field.hh index 452c277d3..231e5cdeb 100644 --- a/src/io/dumper/dumper_elemental_field.hh +++ b/src/io/dumper/dumper_elemental_field.hh @@ -1,80 +1,80 @@ /** * @file dumper_elemental_field.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Mon Aug 17 2015 * * @brief description of elemental fields * * @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_DUMPER_ELEMENTAL_FIELD_HH__ #define __AKANTU_DUMPER_ELEMENTAL_FIELD_HH__ /* -------------------------------------------------------------------------- */ -#include "static_communicator.hh" +#include "communicator.hh" #include "dumper_field.hh" #include "dumper_generic_elemental_field.hh" #ifdef AKANTU_IGFEM # include "dumper_igfem_elemental_field.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { __BEGIN_AKANTU_DUMPER__ /* -------------------------------------------------------------------------- */ template class ret = Vector,bool filtered = false> class ElementalField : public GenericElementalField, elemental_field_iterator> { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ public: typedef SingleType types; typedef typename types::field_type field_type; typedef elemental_field_iterator iterator; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: ElementalField(const field_type & field, UInt spatial_dimension = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) : GenericElementalField(field, spatial_dimension, ghost_type, element_kind) { } }; /* -------------------------------------------------------------------------- */ __END_AKANTU_DUMPER__ } // akantu #endif /* __AKANTU_DUMPER_ELEMENTAL_FIELD_HH__ */ diff --git a/src/io/dumper/dumper_iohelper.cc b/src/io/dumper/dumper_iohelper.cc index 124f17255..863cb4f73 100644 --- a/src/io/dumper/dumper_iohelper.cc +++ b/src/io/dumper/dumper_iohelper.cc @@ -1,302 +1,302 @@ /** * @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 /* -------------------------------------------------------------------------- */ namespace 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(); + UInt whoami = Communicator::getStaticCommunicator().whoAmI(); + UInt nb_proc = Communicator::getStaticCommunicator().getNbProc(); if(is_parallel) dumper->setParallelContext(whoami, nb_proc); else dumper->setParallelContext(0, 1); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setDirectory(const std::string & directory) { this->directory = directory; dumper->setPrefix(directory); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setBaseName(const std::string & basename) { filename = basename; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::setTimeStep(Real time_step) { if(!time_activated) this->dumper->activateTimeDescFiles(time_step); else this->dumper->setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump() { try { dumper->dump(filename, count); } catch (iohelper::IOHelperException & e) { AKANTU_DEBUG_ERROR("I was not able to dump your data with a Dumper: " << e.what()); } ++count; } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(UInt step) { this->count = step; this->dump(); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::dump(Real current_time, UInt step) { this->dumper->setCurrentTime(current_time); this->dump(step); } /* -------------------------------------------------------------------------- */ void DumperIOHelper::registerMesh(const Mesh & mesh, UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & element_kind) { #if defined(AKANTU_IGFEM) if (element_kind == _ek_igfem) { registerField("connectivities", new dumper::IGFEMConnectivityField(mesh.getConnectivities(), spatial_dimension, ghost_type)); } else #endif registerField("connectivities", new dumper::ElementalField(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<_point_1>() { return iohelper::POINT_SET; } template <> iohelper::ElemType getIOHelperType<_segment_2>() { return iohelper::LINE1; } template <> iohelper::ElemType getIOHelperType<_segment_3>() { return iohelper::LINE2; } template <> iohelper::ElemType getIOHelperType<_triangle_3>() { return iohelper::TRIANGLE1; } template <> iohelper::ElemType getIOHelperType<_triangle_6>() { return iohelper::TRIANGLE2; } template <> iohelper::ElemType getIOHelperType<_quadrangle_4>() { return iohelper::QUAD1; } template <> iohelper::ElemType getIOHelperType<_quadrangle_8>() { return iohelper::QUAD2; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_4>() { return iohelper::TETRA1; } template <> iohelper::ElemType getIOHelperType<_tetrahedron_10>() { return iohelper::TETRA2; } template <> iohelper::ElemType getIOHelperType<_hexahedron_8>() { return iohelper::HEX1; } template <> iohelper::ElemType getIOHelperType<_hexahedron_20>() { return iohelper::HEX2; } template <> iohelper::ElemType getIOHelperType<_pentahedron_6>() { return iohelper::PRISM1; } template <> iohelper::ElemType getIOHelperType<_pentahedron_15>() { return iohelper::PRISM2; } #if defined(AKANTU_COHESIVE_ELEMENT) template <> iohelper::ElemType getIOHelperType<_cohesive_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; } /* -------------------------------------------------------------------------- */ } // akantu namespace iohelper { template<> DataType getDataType() { return _int; } } diff --git a/src/io/dumper/dumper_paraview.cc b/src/io/dumper/dumper_paraview.cc index 51bb948ef..dd39653fa 100644 --- a/src/io/dumper/dumper_paraview.cc +++ b/src/io/dumper/dumper_paraview.cc @@ -1,67 +1,66 @@ /** * @file dumper_paraview.cc * * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Sun Sep 26 2010 * @date last modification: Sun Oct 19 2014 * * @brief implementations of DumperParaview * * @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 "communicator.hh" #include "dumper_paraview.hh" -#include "static_communicator.hh" #include namespace akantu { DumperParaview::DumperParaview(const std::string & filename, - const std::string & directory, - bool parallel) : DumperIOHelper() { + const std::string & directory, bool parallel) + : DumperIOHelper() { iohelper::DumperParaview * dumper_para = new iohelper::DumperParaview(); dumper = dumper_para; setBaseName(filename); this->setParallelContext(parallel); dumper_para->setMode(iohelper::BASE64); dumper_para->setPrefix(directory); dumper_para->init(); } /* -------------------------------------------------------------------------- */ -DumperParaview::~DumperParaview() { -} - +DumperParaview::~DumperParaview() {} /* -------------------------------------------------------------------------- */ void DumperParaview::setBaseName(const std::string & basename) { DumperIOHelper::setBaseName(basename); - static_cast(dumper)->setVTUSubDirectory(filename + "-VTU"); + static_cast(dumper)->setVTUSubDirectory(filename + + "-VTU"); } -} // akantu +} // namespace akantu diff --git a/src/mesh/group_manager.cc b/src/mesh/group_manager.cc index b0164f0a8..4c7c460d8 100644 --- a/src/mesh/group_manager.cc +++ b/src/mesh/group_manager.cc @@ -1,1041 +1,1041 @@ /** * @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 "aka_csr.hh" #include "data_accessor.hh" #include "element_group.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_accessor.hh" #include "mesh_utils.hh" #include "node_group.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include #include #include /* -------------------------------------------------------------------------- */ namespace 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() { auto eit = element_groups.begin(); auto eend = element_groups.end(); for (; eit != eend; ++eit) delete (eit->second); auto nit = node_groups.begin(); auto 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(); auto 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); auto 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(); auto eit = element_groups.find(group_name); auto 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(); auto eit = element_groups.begin(); auto 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 { using DistantIDs = std::set>; public: ClusterSynchronizer(GroupManager & group_manager, UInt element_dimension, std::string cluster_name_prefix, ElementTypeMapArray & element_to_fragment, const ElementSynchronizer & element_synchronizer, UInt nb_cluster) : group_manager(group_manager), element_dimension(element_dimension), cluster_name_prefix(cluster_name_prefix), element_to_fragment(element_to_fragment), element_synchronizer(element_synchronizer), nb_cluster(nb_cluster) {} UInt synchronize() { - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + Communicator & comm = Communicator::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); 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 element_synchronizer.synchronizeOnce(*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); 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); for (auto & ids : distant_ids) { total_pairs(local_pair_index, 0) = ids.first; total_pairs(local_pair_index, 1) = ids.second; ++local_pair_index; } /// communicate pairs to all processors nb_pairs *= 2; comm.allGatherV(total_pairs, nb_pairs); /// renumber clusters /// generate fragment list std::vector> 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.size() != 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.size() * 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; auto 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 getNbData(const Array & elements, const SynchronizationTag & tag) const { if (tag == _gst_gm_clusters) return elements.size() * sizeof(UInt); return 0; } inline void packData(CommunicationBuffer & buffer, const Array & elements, const 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 unpackData(CommunicationBuffer & buffer, const Array & elements, const 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; const ElementSynchronizer & element_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"); } /* -------------------------------------------------------------------------- */ UInt GroupManager::createClusters( UInt element_dimension, Mesh & mesh_facets, std::string cluster_name_prefix, const GroupManager::ClusteringFilter & filter) { return createClusters(element_dimension, cluster_name_prefix, filter, mesh_facets); } /* -------------------------------------------------------------------------- */ UInt GroupManager::createClusters( UInt element_dimension, std::string cluster_name_prefix, const GroupManager::ClusteringFilter & filter) { std::unique_ptr mesh_facets; if (!mesh_facets && element_dimension > 0) { MeshAccessor mesh_accessor(const_cast(mesh)); mesh_facets = std::make_unique(mesh.getSpatialDimension(), mesh_accessor.getNodesSharedPtr(), "mesh_facets_for_clusters"); mesh_facets->defineMeshParent(mesh); MeshUtils::buildAllFacets(mesh, *mesh_facets, element_dimension, element_dimension - 1); } return createClusters(element_dimension, cluster_name_prefix, filter, *mesh_facets); } /* -------------------------------------------------------------------------- */ //// \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, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); - UInt nb_proc = StaticCommunicator::getStaticCommunicator().getNbProc(); + UInt nb_proc = mesh.getCommunicator().getNbProc(); std::string tmp_cluster_name_prefix = cluster_name_prefix; ElementTypeMapArray * element_to_fragment = nullptr; if (nb_proc > 1 && mesh.isDistributed()) { element_to_fragment = new ElementTypeMapArray("element_to_fragment", id, memory_id); element_to_fragment->initialize( mesh, _nb_component = 1, _spatial_dimension = element_dimension, _element_kind = _ek_not_defined, _with_nb_element = true); // mesh.initElementTypeMapArray(*element_to_fragment, 1, element_dimension, // false, _ek_not_defined, true); tmp_cluster_name_prefix = "tmp_" + tmp_cluster_name_prefix; } ElementTypeMapArray seen_elements("seen_elements", id, memory_id); seen_elements.initialize(mesh, _spatial_dimension = element_dimension, _element_kind = _ek_not_defined, _with_nb_element = true); // 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.size(); ++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 && mesh.isDistributed()) (*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 && mesh.isDistributed()) { ClusterSynchronizer cluster_synchronizer( *this, element_dimension, cluster_name_prefix, *element_to_fragment, this->mesh.getElementSynchronizer(), nb_cluster); nb_cluster = cluster_synchronizer.synchronize(); delete element_to_fragment; } 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.size() == nb_element, "Not the same number of elements (" << *type_it << ":" << *gt << ") in the map from MeshData (" << dataset.size() << ") " << 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.size() == 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> 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(); + const Communicator & comm = mesh.getCommunicator(); Int nb_proc = comm.getNbProc(); Int my_rank = comm.whoAmI(); if (nb_proc == 1) return; if (my_rank == 0) { for (Int p = 1; p < nb_proc; ++p) { CommunicationStatus status; comm.probe(p, p, status); AKANTU_DEBUG_INFO("Got " << printMemorySize(status.size()) << " from proc " << p); CommunicationBuffer recv_buffer(status.size()); comm.receive(recv_buffer, p, p); this->checkAndAddGroups(recv_buffer); } DynamicCommunicationBuffer comm_buffer; this->fillBufferWithGroupNames(comm_buffer); UInt buffer_size = comm_buffer.size(); comm.broadcast(buffer_size, 0); AKANTU_DEBUG_INFO("Initiating broadcast with " << printMemorySize(comm_buffer.size())); comm.broadcast(comm_buffer, 0); } else { DynamicCommunicationBuffer comm_buffer; this->fillBufferWithGroupNames(comm_buffer); AKANTU_DEBUG_INFO("Sending " << printMemorySize(comm_buffer.size()) << " to proc " << 0); comm.send(comm_buffer, 0, my_rank); UInt buffer_size = 0; comm.broadcast(buffer_size, 0); AKANTU_DEBUG_INFO("Receiving broadcast with " << printMemorySize(comm_buffer.size())); CommunicationBuffer recv_buffer(buffer_size); 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); } } // namespace akantu diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc index 4ecde762f..fbb270d88 100644 --- a/src/mesh/mesh.cc +++ b/src/mesh/mesh.cc @@ -1,476 +1,474 @@ /** * @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 "element_class.hh" #include "group_manager_inline_impl.cc" #include "mesh.hh" #include "mesh_io.hh" /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "mesh_utils_distribution.hh" #include "node_synchronizer.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumper_field.hh" #include "dumper_internal_material_field.hh" #endif /* -------------------------------------------------------------------------- */ namespace 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, StaticCommunicator & communicator) : Memory(id, memory_id), GroupManager(*this, id + ":group_manager", memory_id), nodes_type(0, 1, id + ":nodes_type"), connectivities("connectivities", id, memory_id), ghosts_counters("ghosts_counters", id, memory_id), normals("normals", id, memory_id), spatial_dimension(spatial_dimension), lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.), size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.), local_upper_bounds(spatial_dimension, 0.), mesh_data("mesh_data", id, memory_id), communicator(&communicator) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -Mesh::Mesh(UInt spatial_dimension, StaticCommunicator & communicator, +Mesh::Mesh(UInt spatial_dimension, Communicator & communicator, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, communicator) { AKANTU_DEBUG_IN(); this->nodes = std::make_shared>(0, spatial_dimension, id + ":coordinates"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id) - : Mesh(spatial_dimension, StaticCommunicator::getStaticCommunicator(), id, + : Mesh(spatial_dimension, Communicator::getStaticCommunicator(), id, memory_id) {} /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, std::shared_ptr> nodes, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, - StaticCommunicator::getStaticCommunicator()) { + Communicator::getStaticCommunicator()) { this->nodes = nodes; this->nb_global_nodes = this->nodes->size(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique>(); } this->computeBoundingBox(); } /* -------------------------------------------------------------------------- */ Mesh & Mesh::initMeshFacets(const ID & id) { AKANTU_DEBUG_IN(); if (!mesh_facets) { mesh_facets = std::make_unique(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(); } /* -------------------------------------------------------------------------- */ Mesh::~Mesh() = default; /* -------------------------------------------------------------------------- */ void Mesh::read(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.read(filename, *this, mesh_io_type); type_iterator it = this->firstType(spatial_dimension, _not_ghost, _ek_not_defined); type_iterator last = this->lastType(spatial_dimension, _not_ghost, _ek_not_defined); if (it == last) AKANTU_EXCEPTION( "The mesh contained in the file " << filename << " does not seem to be of the good dimension." << " No element of dimension " << spatial_dimension << " where read."); this->nb_global_nodes = this->nodes->size(); this->computeBoundingBox(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique>(); } } /* -------------------------------------------------------------------------- */ 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->size(); ++i) { // if(!isPureGhostNode(i)) for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::min(local_lower_bounds[k], (*nodes)(i, k)); local_upper_bounds(k) = std::max(local_upper_bounds[k], (*nodes)(i, k)); } } if (this->is_distributed) { - 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, _so_min); + communicator->allReduce(reduce_bounds, SynchronizerOperation::_min); for (UInt k = 0; k < spatial_dimension; ++k) { lower_bounds(k) = reduce_bounds(k, 0); upper_bounds(k) = -reduce_bounds(k, 1); } } else { this->lower_bounds = this->local_lower_bounds; this->upper_bounds = this->local_upper_bounds; } size = upper_bounds - lower_bounds; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::initNormals() { normals.initialize(*this, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined); } /* -------------------------------------------------------------------------- */ void Mesh::getGlobalConnectivity( ElementTypeMapArray & global_connectivity, UInt dimension, GhostType ghost_type) { AKANTU_DEBUG_IN(); for (auto type : elementTypes(dimension, ghost_type)) { auto & local_conn = connectivities(type, ghost_type); auto & g_connectivity = global_connectivity(type, ghost_type); UInt nb_nodes = local_conn.size() * local_conn.getNbComponent(); if (!nodes_global_ids && is_mesh_facets) { std::transform( local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *mesh_parent->nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } else { std::transform(local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Mesh::getGroupDumper(const std::string & dumper_name, const std::string & group_name) { if (group_name == "all") return this->getDumper(dumper_name); else return element_groups[group_name]->getDumper(dumper_name); } /* -------------------------------------------------------------------------- */ template ElementTypeMap Mesh::getNbDataPerElem(ElementTypeMapArray & arrays, const ElementKind & element_kind) { ElementTypeMap nb_data_per_elem; for (auto type : elementTypes(spatial_dimension, _not_ghost, element_kind)) { UInt nb_elements = this->getNbElement(type); auto & array = arrays(type); nb_data_per_elem(type) = array.getNbComponent() * array.size(); nb_data_per_elem(type) /= nb_elements; } return nb_data_per_elem; } /* -------------------------------------------------------------------------- */ template ElementTypeMap 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 = nullptr; ElementTypeMapArray * internal = nullptr; try { internal = &(this->getData(field_id)); } catch (...) { return nullptr; } 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 /* -------------------------------------------------------------------------- */ void Mesh::distribute() { - this->distribute(StaticCommunicator::getStaticCommunicator()); + this->distribute(Communicator::getStaticCommunicator()); } /* -------------------------------------------------------------------------- */ -void Mesh::distribute(StaticCommunicator & communicator) { +void Mesh::distribute(Communicator & communicator) { AKANTU_DEBUG_ASSERT(is_distributed == false, "This mesh is already distribute"); this->communicator = &communicator; this->element_synchronizer = std::make_unique( *this, this->getID() + ":element_synchronizer", this->getMemoryID(), true); this->node_synchronizer = std::make_unique( *this, this->getID() + ":node_synchronizer", this->getMemoryID(), true); Int psize = this->communicator->getNbProc(); #ifdef AKANTU_USE_SCOTCH Int prank = this->communicator->whoAmI(); if (prank == 0) { MeshPartitionScotch partition(*this, spatial_dimension); partition.partitionate(psize); MeshUtilsDistribution::distributeMeshCentralized(*this, 0, partition); } else { MeshUtilsDistribution::distributeMeshCentralized(*this, 0); } #else if (!(psize == 1)) { AKANTU_DEBUG_ERROR("Cannot distribute a mesh without a partitioning tool"); } #endif this->is_distributed = true; this->element_synchronizer->buildPrankToElement(); this->computeBoundingBox(); } /* -------------------------------------------------------------------------- */ void Mesh::getAssociatedElements(const Array & node_list, Array & elements) { for (const auto & node : node_list) for (const auto & element : *nodes_to_elements[node]) elements.push_back(element); } /* -------------------------------------------------------------------------- */ void Mesh::fillNodesToElements() { Element e; UInt nb_nodes = nodes->size(); for (UInt n = 0; n < nb_nodes; ++n) { if(this->nodes_to_elements[n]) this->nodes_to_elements[n]->clear(); else this->nodes_to_elements[n] = std::make_unique>(); } for (auto ghost_type : ghost_types) { e.ghost_type = ghost_type; for (const auto & type : elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { e.type = type; e.kind = getKind(type); UInt nb_element = this->getNbElement(type, ghost_type); Array::const_iterator> conn_it = connectivities(type, ghost_type) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; const Vector & conn = *conn_it; for (UInt n = 0; n < conn.size(); ++n) nodes_to_elements[conn(n)]->insert(e); } } } } /* -------------------------------------------------------------------------- */ void Mesh::eraseElements(const Array & elements) { ElementTypeMap last_element; RemovedElementsEvent event(*this); auto & remove_list = event.getList(); auto & new_numbering = event.getNewNumbering(); for(auto && el : elements) { if(el.ghost_type != _not_ghost) { auto & count = ghosts_counters(el); --count; if (count > 0) continue; } remove_list.push_back(el); if (not last_element.exists(el.type, el.ghost_type)) { UInt nb_element = mesh.getNbElement(el.type, el.ghost_type); last_element(nb_element - 1, el.type, el.ghost_type); auto & numbering = new_numbering.alloc(nb_element, 1, el.type, el.ghost_type); for (auto && pair : enumerate(numbering)) { std::get<1>(pair) = std::get<0>(pair); } } UInt & pos = last_element(el.type, el.ghost_type); auto & numbering = new_numbering(el.type, el.ghost_type); numbering(el.element) = UInt(-1); numbering(pos) = el.element; --pos; } this->sendEvent(event); } } // namespace akantu diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh index 04f5c903c..439e9584d 100644 --- a/src/mesh/mesh.hh +++ b/src/mesh/mesh.hh @@ -1,609 +1,609 @@ /** * @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_array.hh" #include "aka_event_handler_manager.hh" #include "aka_memory.hh" #include "dumpable.hh" #include "element.hh" #include "element_class.hh" #include "element_type_map.hh" #include "group_manager.hh" #include "mesh_data.hh" #include "mesh_events.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { -class StaticCommunicator; +class Communicator; class ElementSynchronizer; class NodeSynchronizer; } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ /* Mesh */ /* -------------------------------------------------------------------------- */ /** * @class Mesh this contain the coordinates of the nodes in the Mesh.nodes * Array, and the connectivity. The connectivity are stored in by element * types. * * In order to loop on all element you have to loop on all types like this : * @code{.cpp} 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 */ /* ------------------------------------------------------------------------ */ private: /// default constructor used for chaining, the last parameter is just to /// differentiate constructors Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id, - StaticCommunicator & communicator); + Communicator & communicator); public: /// constructor that create nodes coordinates array Mesh(UInt spatial_dimension, const ID & id = "mesh", const MemoryID & memory_id = 0); /// mesh not distributed and not using the default communicator - Mesh(UInt spatial_dimension, StaticCommunicator & communicator, + Mesh(UInt spatial_dimension, Communicator & communicator, const ID & id = "mesh", const MemoryID & memory_id = 0); /// constructor that use an existing nodes coordinates array, by knowing its /// ID // Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, // const MemoryID & memory_id = 0); /** * constructor that use an existing nodes coordinates * array, by getting the vector of coordinates */ Mesh(UInt spatial_dimension, std::shared_ptr> 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(); /// function that computes the bounding box (fills xmin, xmax) void computeBoundingBox(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// patitionate the mesh among the processors involved in their computation - virtual void distribute(StaticCommunicator & communicator); + virtual void distribute(Communicator & communicator); virtual void distribute(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// 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().size() != 0) EventHandlerManager::sendEvent(event); } /// prepare the event to remove the elements listed void eraseElements(const Array & elements); /* ------------------------------------------------------------------------ */ 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); public: void getAssociatedElements(const Array & node_list, Array & elements); private: /// fills the nodes_to_elements structure void fillNodesToElements(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the id of the mesh AKANTU_GET_MACRO(ID, Memory::id, const ID &); /// get the id of the mesh AKANTU_GET_MACRO(MemoryID, Memory::memory_id, const MemoryID &); /// get the spatial dimension of the mesh = number of component of the /// coordinates AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the nodes Array aka coordinates AKANTU_GET_MACRO(Nodes, *nodes, const Array &); 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->size(), 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 id of a node inline UInt getNodeLocalId(UInt global_id) const; /// get the global number of nodes inline UInt getNbGlobalNodes() const; /// get the nodes type Array AKANTU_GET_MACRO(NodesType, nodes_type, const Array &); protected: AKANTU_GET_MACRO_NOT_CONST(NodesType, nodes_type, Array &); public: inline NodeType getNodeType(UInt local_id) const; /// say if a node is a pure ghost node inline bool isPureGhostNode(UInt n) const; /// say if a node is pur local or master node inline bool isLocalOrMasterNode(UInt n) const; inline bool isLocalNode(UInt n) const; inline bool isMasterNode(UInt n) const; inline bool isSlaveNode(UInt n) const; AKANTU_GET_MACRO(LowerBounds, lower_bounds, const Vector &); 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> & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the element connected to a subelement Array> & 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); /// register a new ElementalTypeMap in the MeshData template inline ElementTypeMapArray & registerData(const std::string & data_name); template inline bool hasData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template inline const Array & getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template inline Array & getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get a name field associated to the mesh template inline const ElementTypeMapArray & getData(const ID & data_name) const; /// get a name field associated to the mesh template inline ElementTypeMapArray & getData(const ID & 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 inline const Mesh & getMeshFacets() const; inline Mesh & getMeshFacets(); /// Parent mesh accessor inline const Mesh & getMeshParent() const; inline bool isMeshFacets() const { return this->is_mesh_facets; } /// defines is the mesh is distributed or not inline bool isDistributed() const { return this->is_distributed; } #ifndef SWIG /// return the dumper from a group and and a dumper name DumperIOHelper & getGroupDumper(const std::string & dumper_name, const std::string & group_name); #endif /* ------------------------------------------------------------------------ */ /* Wrappers on ElementClass functions */ /* ------------------------------------------------------------------------ */ public: /// get the number of nodes per element for a given element type static inline UInt getNbNodesPerElement(const ElementType & type); /// get the number of nodes per element for a given element type considered as /// a first order element static inline ElementType getP1ElementType(const ElementType & type); /// get the kind of the element type static inline ElementKind getKind(const ElementType & type); /// get spatial dimension of a type of element static inline UInt getSpatialDimension(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type, UInt t); /// 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 */ /* ------------------------------------------------------------------------ */ using type_iterator = ElementTypeMapArray::type_iterator; using ElementTypesIteratorHelper = ElementTypeMapArray::ElementTypesIteratorHelper; template ElementTypesIteratorHelper elementTypes(pack &&... _pack) const; inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.firstType(dim, ghost_type, kind); } inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.lastType(dim, ghost_type, kind); } AKANTU_GET_MACRO(ElementSynchronizer, *element_synchronizer, const ElementSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(ElementSynchronizer, *element_synchronizer, ElementSynchronizer &); AKANTU_GET_MACRO(NodeSynchronizer, *node_synchronizer, const NodeSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(NodeSynchronizer, *node_synchronizer, NodeSynchronizer &); // AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, StaticCommunicator // &); - AKANTU_GET_MACRO(Communicator, *communicator, const StaticCommunicator &); + AKANTU_GET_MACRO(Communicator, *communicator, const auto &); /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshAccessor; //#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(); /// 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 the ghost element counter inline Array & getGhostsCounters(const ElementType & type, const GhostType & ghost_type = _ghost) { AKANTU_DEBUG_ASSERT(ghost_type != _not_ghost, "No ghost counter for _not_ghost elements"); return ghosts_counters(type, ghost_type); } /// get a pointer to the element_to_subelement Array for the given type and /// create it if necessary inline Array> & 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 std::shared_ptr> nodes; /// global node ids std::unique_ptr> 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; /// global number of nodes; UInt nb_global_nodes{0}; /// all class of elements present in this mesh (for heterogenous meshes) ElementTypeMapArray connectivities; /// count the references on ghost elements ElementTypeMapArray ghosts_counters; /// 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{0}; /// 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 std::unique_ptr mesh_facets; /// parent mesh (this is set for mesh_facets meshes) const Mesh * mesh_parent{nullptr}; /// defines if current mesh is mesh_facets or not bool is_mesh_facets{false}; /// defines if the mesh is centralized or distributed bool is_distributed{false}; /// Communicator on which mesh is distributed - const StaticCommunicator * communicator; + const Communicator * communicator; /// Element synchronizer std::unique_ptr element_synchronizer; /// Node synchronizer std::unique_ptr node_synchronizer; using NodesToElements = std::vector>>; /// This info is stored to simplify the dynamic changes NodesToElements nodes_to_elements; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const 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; } } // namespace akantu /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ #include "element_type_map_tmpl.hh" #include "mesh_inline_impl.cc" #endif /* __AKANTU_MESH_HH__ */ diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc index d22c3f001..91857c866 100644 --- a/src/mesh_utils/cohesive_element_inserter.cc +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -1,448 +1,448 @@ /** * @file cohesive_element_inserter.cc * * @author Marco Vocialta * * @date creation: Wed Dec 04 2013 * @date last modification: Sun Oct 04 2015 * * @brief Cohesive element inserter functions * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "element_group.hh" #include #include /* -------------------------------------------------------------------------- */ namespace akantu { CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, bool is_extrinsic, const ID & id) : id(id), mesh(mesh), mesh_facets(mesh.initMeshFacets()), insertion_facets("insertion_facets", id), insertion_limits(mesh.getSpatialDimension(), 2), check_facets("check_facets", id) { MeshUtils::buildAllFacets(mesh, mesh_facets, 0); init(is_extrinsic); } /* -------------------------------------------------------------------------- */ CohesiveElementInserter::~CohesiveElementInserter() { #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) delete global_ids_updater; #endif } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::init(bool is_extrinsic) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); MeshUtils::resetFacetToDouble(mesh_facets); /// initialize facet insertion array insertion_facets.initialize(mesh_facets, _spatial_dimension = (spatial_dimension - 1), _with_nb_element = true); // mesh_facets.initElementTypeMapArray( // insertion_facets, 1, spatial_dimension - 1, false, _ek_regular, true); /// init insertion limits for (UInt dim = 0; dim < spatial_dimension; ++dim) { insertion_limits(dim, 0) = std::numeric_limits::max() * (-1.); insertion_limits(dim, 1) = std::numeric_limits::max(); } if (is_extrinsic) { check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(check_facets, 1, spatial_dimension - // 1); initFacetsCheck(); } #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) facet_synchronizer = NULL; global_ids_updater = NULL; #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::initFacetsCheck() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType facet_gt = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); for (; it != last; ++it) { ElementType facet_type = *it; Array & f_check = check_facets(facet_type, facet_gt); const Array> & element_to_facet = mesh_facets.getElementToSubelement(facet_type, facet_gt); UInt nb_facet = element_to_facet.size(); f_check.resize(nb_facet); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull || (element_to_facet(f)[0].ghost_type == _ghost && element_to_facet(f)[1].ghost_type == _ghost)) { f_check(f) = false; } else f_check(f) = true; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector bary_facet(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for (; it != end; ++it) { ElementType type = *it; Array & f_check = check_facets(type, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (f_check(f)) { mesh_facets.getBarycenter(f, type, bary_facet.storage(), ghost_type); UInt coord_in_limit = 0; while (coord_in_limit < spatial_dimension && bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) ++coord_in_limit; if (coord_in_limit != spatial_dimension) f_check(f) = false; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::setLimit(SpacialDirection axis, Real first_limit, Real second_limit) { AKANTU_DEBUG_ASSERT( axis < mesh.getSpatialDimension(), "You are trying to limit insertion in a direction that doesn't exist"); insertion_limits(axis, 0) = std::min(first_limit, second_limit); insertion_limits(axis, 1) = std::max(first_limit, second_limit); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertIntrinsicElements() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); Vector bary_facet(spatial_dimension); for (auto && ghost_type : ghost_types) { for (const auto & type_facet : mesh_facets.elementTypes(spatial_dimension - 1, ghost_type)) { auto & f_insertion = insertion_facets(type_facet, ghost_type); auto & element_to_facet = mesh_facets.getElementToSubelement(type_facet, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type_facet, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull) continue; mesh_facets.getBarycenter(f, type_facet, bary_facet.storage(), ghost_type); UInt coord_in_limit = 0; while (coord_in_limit < spatial_dimension && bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) ++coord_in_limit; if (coord_in_limit == spatial_dimension) f_insertion(f) = true; } } } AKANTU_DEBUG_OUT(); return insertElements(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::insertIntrinsicElements(std::string physname, UInt material_index) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray * phys_data; try { phys_data = &(mesh_facets.getData("physical_names")); } catch (...) { phys_data = &(mesh_facets.registerData("physical_names")); phys_data->initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true); // mesh_facets.initElementTypeMapArray(*phys_data, 1, spatial_dimension - 1, // false, _ek_regular, true); } Vector bary_facet(spatial_dimension); mesh_facets.createElementGroup(physname); GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for (; it != end; ++it) { const ElementType type_facet = *it; Array & f_insertion = insertion_facets(type_facet, ghost_type); Array> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, ghost_type); UInt nb_facet = mesh_facets.getNbElement(type_facet, ghost_type); UInt coord_in_limit = 0; ElementGroup & group = mesh.getElementGroup(physname); ElementGroup & group_facet = mesh_facets.getElementGroup(physname); Vector bary_physgroup(spatial_dimension); Real norm_bary; for (ElementGroup::const_element_iterator el_it( group.begin(type_facet, ghost_type)); el_it != group.end(type_facet, ghost_type); ++el_it) { UInt e = *el_it; mesh.getBarycenter(e, type_facet, bary_physgroup.storage(), ghost_type); #ifndef AKANTU_NDEBUG bool find_a_partner = false; #endif norm_bary = bary_physgroup.norm(); Array & material_id = (*phys_data)(type_facet, ghost_type); for (UInt f = 0; f < nb_facet; ++f) { if (element_to_facet(f)[1] == ElementNull) continue; mesh_facets.getBarycenter(f, type_facet, bary_facet.storage(), ghost_type); coord_in_limit = 0; while (coord_in_limit < spatial_dimension && (std::abs(bary_facet(coord_in_limit) - bary_physgroup(coord_in_limit)) / norm_bary < Math::getTolerance())) ++coord_in_limit; if (coord_in_limit == spatial_dimension) { f_insertion(f) = true; #ifndef AKANTU_NDEBUG find_a_partner = true; #endif group_facet.add(type_facet, f, ghost_type, false); material_id(f) = material_index; break; } } AKANTU_DEBUG_ASSERT(find_a_partner, "The element nO " << e << " of physical group " << physname << " did not find its associated facet!" << " Try to decrease math tolerance. " << std::endl); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertElements(bool only_double_facets) { CohesiveNewNodesEvent node_event; NewElementsEvent element_event; Array new_pairs(0, 2); UInt nb_new_elements = MeshUtils::insertCohesiveElements( mesh, mesh_facets, insertion_facets, new_pairs, element_event.getList(), only_double_facets); UInt nb_new_nodes = new_pairs.size(); node_event.getList().reserve(nb_new_nodes); node_event.getOldNodesList().reserve(nb_new_nodes); for (UInt n = 0; n < nb_new_nodes; ++n) { node_event.getList().push_back(new_pairs(n, 1)); node_event.getOldNodesList().push_back(new_pairs(n, 0)); } #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - if (mesh.getNodesType().size()) { + if (mesh.isDistributed()) { /// update nodes type updateNodesType(mesh, node_event); updateNodesType(mesh_facets, node_event); /// update global ids nb_new_nodes = this->updateGlobalIDs(node_event); /// compute total number of new elements - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - comm.allReduce(&nb_new_elements, 1, _so_sum); + const auto & comm = mesh.getCommunicator(); + comm.allReduce(nb_new_elements, _so_sum); } #endif if (nb_new_nodes > 0) mesh.sendEvent(node_event); if (nb_new_elements > 0) { updateInsertionFacets(); // mesh.updateTypesOffsets(_not_ghost); mesh.sendEvent(element_event); MeshUtils::resetFacetToDouble(mesh_facets); } #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - if (mesh.getNodesType().size()) { + if (mesh.isDistributed()) { /// update global ids this->synchronizeGlobalIDs(node_event); } #endif return nb_new_elements; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::updateInsertionFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType facet_gt = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); for (; it != last; ++it) { ElementType facet_type = *it; Array & ins_facets = insertion_facets(facet_type, facet_gt); // this is the extrinsic case if (check_facets.exists(facet_type, facet_gt)) { Array & f_check = check_facets(facet_type, facet_gt); UInt nb_facets = f_check.size(); for (UInt f = 0; f < ins_facets.size(); ++f) { if (ins_facets(f)) { ++nb_facets; ins_facets(f) = false; f_check(f) = false; } } f_check.resize(nb_facets); } // and this the intrinsic one else { ins_facets.resize(mesh_facets.getNbElement(facet_type, facet_gt)); ins_facets.set(false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "CohesiveElementInserter [" << std::endl; stream << space << " + mesh [" << std::endl; mesh.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + mesh_facets [" << std::endl; mesh_facets.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } } // namespace akantu diff --git a/src/model/common/neighborhood_base.cc b/src/model/common/neighborhood_base.cc index 10d411b46..1fbf3f5a4 100644 --- a/src/model/common/neighborhood_base.cc +++ b/src/model/common/neighborhood_base.cc @@ -1,295 +1,295 @@ /** * @file neighborhood_base.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of generic neighborhood base * * @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 "neighborhood_base.hh" #include "grid_synchronizer.hh" #include "mesh_accessor.hh" #include "model.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NeighborhoodBase::NeighborhoodBase(Model & model, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), model(model), neighborhood_radius(0.), spatial_grid(nullptr), is_creating_grid(false), grid_synchronizer(nullptr), quad_coordinates(quad_coordinates), spatial_dimension(this->model.getMesh().getSpatialDimension()) { AKANTU_DEBUG_IN(); this->registerDataAccessor(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ NeighborhoodBase::~NeighborhoodBase() = default; /* -------------------------------------------------------------------------- */ // void NeighborhoodBase::createSynchronizerRegistry( // DataAccessor * data_accessor) { // this->synch_registry = new SynchronizerRegistry(*data_accessor); // } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::initNeighborhood() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Creating the grid"); this->createGrid(); AKANTU_DEBUG_OUT(); } /* ------------------------------------------------------------------------- */ void NeighborhoodBase::createGrid() { AKANTU_DEBUG_IN(); const Real safety_factor = 1.2; // for the cell grid spacing Mesh & mesh = this->model.getMesh(); const auto & lower_bounds = mesh.getLocalLowerBounds(); const auto & upper_bounds = mesh.getLocalUpperBounds(); Vector center = 0.5 * (upper_bounds + lower_bounds); Vector spacing(spatial_dimension, this->neighborhood_radius * safety_factor); spatial_grid = std::make_unique>( spatial_dimension, spacing, center); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::updatePairList() { AKANTU_DEBUG_IN(); //// loop over all quads -> all cells for (auto && cell_id : *spatial_grid) { AKANTU_DEBUG_INFO("Looping on next cell"); for (auto && q1 : spatial_grid->getCell(cell_id)) { if (q1.ghost_type == _ghost) break; auto coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(spatial_dimension); auto q1_coords = Vector(coords_type_1_it[q1.global_num]); AKANTU_DEBUG_INFO("Current quadrature point in this cell: " << q1); auto cell_id = spatial_grid->getCellID(q1_coords); /// loop over all the neighboring cells of the current quad for (auto && neighbor_cell : cell_id.neighbors()) { // loop over the quadrature point in the current neighboring cell for (auto && q2 : spatial_grid->getCell(neighbor_cell)) { auto coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(spatial_dimension); auto q2_coords = Vector(coords_type_2_it[q2.global_num]); Real distance = q1_coords.distance(q2_coords); if (distance <= this->neighborhood_radius + Math::getTolerance() && (q2.ghost_type == _ghost || (q2.ghost_type == _not_ghost && q1.global_num <= q2.global_num))) { // storing only half lists pair_list[q2.ghost_type].push_back(std::make_pair(q1, q2)); } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::savePairs(const std::string & filename) const { std::stringstream sstr; - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const Communicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; std::ofstream pout; pout.open(sstr.str().c_str()); for (auto && ghost_type : ghost_types) { for (const auto & pair : pair_list[ghost_type]) { const auto & q1 = pair.first; const auto & q2 = pair.second; pout << q1 << " " << q2 << " " << std::endl; } } pout.close(); if (comm.getNbProc() != 1) return; Mesh mesh_out(spatial_dimension); MeshAccessor mesh_accessor(mesh_out); auto & connectivity = mesh_accessor.getConnectivity(_segment_2); auto & tag = mesh_accessor.getData("tag_1", _segment_2); auto & nodes = mesh_accessor.getNodes(); std::map quad_to_nodes; UInt node = 0; IntegrationPoint q1, q2; bool inserted; for (auto && ghost_type : ghost_types) { for (const auto & pair : pair_list[ghost_type]) { std::tie(q1, q2) = pair; auto add_node = [&](auto && q) { std::tie(std::ignore, inserted) = quad_to_nodes.insert(std::make_pair(q, node)); if (not inserted) return; auto coords_it = this->quad_coordinates(q.type, q.ghost_type) .begin(spatial_dimension); auto && coords = Vector(coords_it[q.global_num]); nodes.push_back(coords); ++node; }; add_node(q1); add_node(q2); } } for (auto && ghost_type : ghost_types) { for (const auto & pair : pair_list[ghost_type]) { std::tie(q1, q2) = pair; UInt node1 = quad_to_nodes[q1]; UInt node2 = quad_to_nodes[q2]; connectivity.push_back(Vector{node1, node2}); tag.push_back(node1 + 1); if (node1 != node2) { connectivity.push_back(Vector{node2, node1}); tag.push_back(node2 + 1); } } } mesh_out.write(filename + ".msh"); } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::saveNeighborCoords(const std::string & filename) const { // this function is not optimized and only used for tests on small meshes // @todo maybe optimize this function for better performance? IntegrationPoint q2; std::stringstream sstr; - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + const Communicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; std::ofstream pout; pout.open(sstr.str().c_str()); /// loop over all the quads and write the position of their neighbors for (auto && cell_id : *spatial_grid) { for (auto && q1 : spatial_grid->getCell(cell_id)) { auto coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(spatial_dimension); auto && q1_coords = Vector(coords_type_1_it[q1.global_num]); pout << "#neighbors for quad " << q1.global_num << std::endl; pout << q1_coords << std::endl; for (auto && ghost_type2 : ghost_types) { for (auto && pair : pair_list[ghost_type2]) { if (q1 == pair.first && pair.second != q1) { q2 = pair.second; } else if (q1 == pair.second && pair.first != q1) { q2 = pair.first; } else { continue; } auto coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(spatial_dimension); auto && q2_coords = Vector(coords_type_2_it[q2.global_num]); pout << q2_coords << std::endl; } } } } } /* -------------------------------------------------------------------------- */ void NeighborhoodBase::onElementsRemoved( const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = 0; // Change the pairs in new global numbering for (auto ghost_type2 : ghost_types) { for (auto && pair : pair_list[ghost_type2]) { auto cleanPoint = [&](auto && q) { if (new_numbering.exists(q.type, q.ghost_type)) { UInt q_new_el = new_numbering(q.type, q.ghost_type)(q.element); AKANTU_DEBUG_ASSERT(q_new_el != UInt(-1), "A local quadrature_point " "as been removed instead of " "just being renumbered"); q.element = q_new_el; nb_quad = fem.getNbIntegrationPoints(q.type, q.ghost_type); q.global_num = nb_quad * q.element + q.num_point; } }; cleanPoint(pair.first); cleanPoint(pair.second); } } this->grid_synchronizer->onElementsRemoved(element_list, new_numbering, event); AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/model/common/non_local_toolbox/non_local_manager.cc b/src/model/common/non_local_toolbox/non_local_manager.cc index 7c2487e5d..fe6e38c1a 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.cc +++ b/src/model/common/non_local_toolbox/non_local_manager.cc @@ -1,639 +1,639 @@ /** * @file non_local_manager.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Fri Apr 13 2012 * @date last modification: Wed Dec 16 2015 * * @brief Implementation of non-local manager * * @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 "non_local_manager.hh" #include "grid_synchronizer.hh" #include "model.hh" #include "non_local_neighborhood.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLocalManager::NonLocalManager(Model & model, NonLocalManagerCallback & callback, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), Parsable(_st_neighborhoods, id), spatial_dimension(model.getMesh().getSpatialDimension()), model(model), integration_points_positions("integration_points_positions", id, memory_id), volumes("volumes", id, memory_id), compute_stress_calls(0), dummy_registry(nullptr), dummy_grid(nullptr) { /// parse the neighborhood information from the input file const Parser & parser = getStaticParser(); /// iterate over all the non-local sections and store them in a map std::pair weight_sect = parser.getSubSections(_st_non_local); Parser::const_section_iterator it = weight_sect.first; for (; it != weight_sect.second; ++it) { const ParserSection & section = *it; ID name = section.getName(); this->weight_function_types[name] = section; } this->callback = &callback; } /* -------------------------------------------------------------------------- */ NonLocalManager::~NonLocalManager() = default; /* -------------------------------------------------------------------------- */ void NonLocalManager::initialize() { volumes.initialize(this->model.getFEEngine(), _spatial_dimension = spatial_dimension); AKANTU_DEBUG_ASSERT(this->callback, "A callback should be registered prior to this call"); this->callback->insertIntegrationPointsInNeighborhoods(_not_ghost); auto & mesh = this->model.getMesh(); mesh.registerEventHandler(*this, _ehp_non_local_manager); /// store the number of current ghost elements for each type in the mesh //ElementTypeMap nb_ghost_protected; // for (auto type : mesh.elementTypes(spatial_dimension, _ghost)) // nb_ghost_protected(mesh.getNbElement(type, _ghost), type, _ghost); /// exchange the missing ghosts for the non-local neighborhoods this->createNeighborhoodSynchronizers(); /// insert the ghost quadrature points of the non-local materials into the /// non-local neighborhoods this->callback->insertIntegrationPointsInNeighborhoods(_ghost); FEEngine & fee = this->model.getFEEngine(); this->updatePairLists(); /// cleanup the unneccessary ghost elements this->cleanupExtraGhostElements(); //nb_ghost_protected); this->callback->initializeNonLocal(); this->setJacobians(fee, _ek_regular); this->initNonLocalVariables(); this->computeWeights(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::setJacobians(const FEEngine & fe_engine, const ElementKind & kind) { Mesh & mesh = this->model.getMesh(); for (auto ghost_type : ghost_types) { for (auto type : mesh.elementTypes(spatial_dimension, ghost_type, kind)) { jacobians(type, ghost_type) = &fe_engine.getIntegratorInterface().getJacobians(type, ghost_type); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhood(const ID & weight_func, const ID & neighborhood_id) { AKANTU_DEBUG_IN(); auto weight_func_it = this->weight_function_types.find(weight_func); AKANTU_DEBUG_ASSERT(weight_func_it != weight_function_types.end(), "No info found in the input file for the weight_function " << weight_func << " in the neighborhood " << neighborhood_id); const ParserSection & section = weight_func_it->second; const ID weight_func_type = section.getOption(); /// create new neighborhood for given ID std::stringstream sstr; sstr << id << ":neighborhood:" << neighborhood_id; if (weight_func_type == "base_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); #if defined(AKANTU_DAMAGE_NON_LOCAL) else if (weight_func_type == "remove_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); else if (weight_func_type == "stress_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); else if (weight_func_type == "damage_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); #endif else AKANTU_EXCEPTION("error in weight function type provided in material file"); neighborhoods[neighborhood_id]->parseSection(section); neighborhoods[neighborhood_id]->initNeighborhood(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhoodSynchronizers() { /// exchange all the neighborhood IDs, so that every proc knows how many /// neighborhoods exist globally /// First: Compute locally the maximum ID size UInt max_id_size = 0; UInt current_size = 0; NeighborhoodMap::const_iterator it; for (it = neighborhoods.begin(); it != neighborhoods.end(); ++it) { current_size = it->first.size(); if (current_size > max_id_size) max_id_size = current_size; } /// get the global maximum ID size on each proc - StaticCommunicator & static_communicator = - akantu::StaticCommunicator::getStaticCommunicator(); - static_communicator.allReduce(max_id_size, _so_max); + const Communicator & static_communicator = + model.getMesh().getCommunicator(); + static_communicator.allReduce(max_id_size, SynchronizerOperation::_max); /// get the rank for this proc and the total nb proc UInt prank = static_communicator.whoAmI(); UInt psize = static_communicator.getNbProc(); /// exchange the number of neighborhoods on each proc Array nb_neighborhoods_per_proc(psize); nb_neighborhoods_per_proc(prank) = neighborhoods.size(); static_communicator.allGather(nb_neighborhoods_per_proc); /// compute the total number of neighborhoods UInt nb_neighborhoods_global = std::accumulate( nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.end(), 0); /// allocate an array of chars to store the names of all neighborhoods Array buffer(nb_neighborhoods_global, max_id_size); /// starting index on this proc UInt starting_index = std::accumulate(nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.begin() + prank, 0); it = neighborhoods.begin(); /// store the names of local neighborhoods in the buffer for (UInt i = 0; i < neighborhoods.size(); ++i, ++it) { UInt c = 0; for (; c < it->first.size(); ++c) buffer(i + starting_index, c) = it->first[c]; for (; c < max_id_size; ++c) buffer(i + starting_index, c) = char(0); } /// store the nb of data to send in the all gather Array buffer_size(nb_neighborhoods_per_proc); buffer_size *= max_id_size; /// exchange the names of all the neighborhoods with all procs static_communicator.allGatherV(buffer, buffer_size); for (UInt i = 0; i < nb_neighborhoods_global; ++i) { std::stringstream neighborhood_id; for (UInt c = 0; c < max_id_size; ++c) { if (buffer(i, c) == char(0)) break; neighborhood_id << buffer(i, c); } global_neighborhoods.insert(neighborhood_id.str()); } /// this proc does not know all the neighborhoods -> create dummy /// grid so that this proc can participate in the all gather for /// detecting the overlap of neighborhoods this proc doesn't know Vector grid_center(this->spatial_dimension, std::numeric_limits::max()); Vector spacing(this->spatial_dimension, 0.); dummy_grid = std::make_unique>( this->spatial_dimension, spacing, grid_center); for (auto & neighborhood_id : global_neighborhoods) { it = neighborhoods.find(neighborhood_id); if (it != neighborhoods.end()) { it->second->createGridSynchronizer(); } else { dummy_synchronizers[neighborhood_id] = std::make_unique( this->model.getMesh(), *dummy_grid, std::string(this->id + ":" + neighborhood_id + ":grid_synchronizer"), this->memory_id, false); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::synchronize(DataAccessor & data_accessor, const SynchronizationTag & tag) { for (auto & neighborhood_id : global_neighborhoods) { auto it = neighborhoods.find(neighborhood_id); if (it != neighborhoods.end()) { it->second->synchronize(data_accessor, tag); } else { auto synchronizer_it = dummy_synchronizers.find(neighborhood_id); if (synchronizer_it == dummy_synchronizers.end()) continue; synchronizer_it->second->synchronizeOnce(data_accessor, tag); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::averageInternals(const GhostType & ghost_type) { /// update the weights of the weight function if (ghost_type == _not_ghost) this->computeWeights(); /// loop over all neighborhoods and compute the non-local variables for (auto & neighborhood : neighborhoods) { /// loop over all the non-local variables of the given neighborhood for (auto & non_local_variable : non_local_variables) { NonLocalVariable & non_local_var = *non_local_variable.second; neighborhood.second->weightedAverageOnNeighbours( non_local_var.local, non_local_var.non_local, non_local_var.nb_component, ghost_type); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::computeWeights() { AKANTU_DEBUG_IN(); this->updateWeightFunctionInternals(); this->volumes.clear(); for (auto global_neighborhood : global_neighborhoods) { auto it = neighborhoods.find(global_neighborhood); if (it != neighborhoods.end()) it->second->updateWeights(); else { dummy_synchronizers[global_neighborhood]->synchronize(dummy_accessor, _gst_mnl_weight); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::updatePairLists() { AKANTU_DEBUG_IN(); integration_points_positions.initialize( this->model.getFEEngine(), _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension); /// compute the position of the quadrature points this->model.getFEEngine().computeIntegrationPointsCoordinates( integration_points_positions); for (auto & pair : neighborhoods) pair.second->updatePairList(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::registerNonLocalVariable(const ID & variable_name, const ID & nl_variable_name, UInt nb_component) { AKANTU_DEBUG_IN(); auto non_local_variable_it = non_local_variables.find(variable_name); if (non_local_variable_it == non_local_variables.end()) non_local_variables[nl_variable_name] = std::make_unique( variable_name, nl_variable_name, this->id, nb_component); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementTypeMapReal & NonLocalManager::registerWeightFunctionInternal(const ID & field_name) { AKANTU_DEBUG_IN(); auto it = this->weight_function_internals.find(field_name); if (it == weight_function_internals.end()) { weight_function_internals[field_name] = std::make_unique(field_name, this->id, this->memory_id); } return *(weight_function_internals[field_name]); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::updateWeightFunctionInternals() { for (auto & pair : this->weight_function_internals) { auto & internals = *pair.second; internals.clear(); for (auto ghost_type : ghost_types) this->callback->updateLocalInternal(internals, ghost_type, _ek_regular); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::initNonLocalVariables() { /// loop over all the non-local variables for (auto & pair : non_local_variables) { auto & variable = *pair.second; variable.non_local.initialize(this->model.getFEEngine(), _nb_component = variable.nb_component, _spatial_dimension = spatial_dimension); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::computeAllNonLocalStresses() { /// update the flattened version of the internals for (auto & pair : non_local_variables) { auto & variable = *pair.second; variable.local.clear(); variable.non_local.clear(); for (auto ghost_type : ghost_types) { this->callback->updateLocalInternal(variable.local, ghost_type, _ek_regular); } } this->volumes.clear(); for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; neighborhood.asynchronousSynchronize(_gst_mnl_for_average); } this->averageInternals(_not_ghost); AKANTU_DEBUG_INFO("Wait distant non local stresses"); for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; neighborhood.waitEndSynchronize(_gst_mnl_for_average); } this->averageInternals(_ghost); /// copy the results in the materials for (auto & pair : non_local_variables) { auto & variable = *pair.second; for (auto ghost_type : ghost_types) { this->callback->updateNonLocalInternal(variable.non_local, ghost_type, _ek_regular); } } this->callback->computeNonLocalStresses(_not_ghost); ++this->compute_stress_calls; } /* -------------------------------------------------------------------------- */ void NonLocalManager::cleanupExtraGhostElements() { //ElementTypeMap & nb_ghost_protected) { using ElementSet = std::set; ElementSet relevant_ghost_elements; /// loop over all the neighborhoods and get their protected ghosts for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; ElementSet to_keep_per_neighborhood; neighborhood.cleanupExtraGhostElements(to_keep_per_neighborhood); for (auto & element : to_keep_per_neighborhood) relevant_ghost_elements.insert(element); } // /// remove all unneccessary ghosts from the mesh // /// Create list of element to remove and new numbering for element to keep // Mesh & mesh = this->model.getMesh(); // ElementSet ghost_to_erase; // RemovedElementsEvent remove_elem(mesh); // auto & new_numberings = remove_elem.getNewNumbering(); // Element element; // element.ghost_type = _ghost; // for (auto & type : mesh.elementTypes(spatial_dimension, _ghost)) { // element.type = type; // UInt nb_ghost_elem = mesh.getNbElement(type, _ghost); // // UInt nb_ghost_elem_protected = 0; // // try { // // nb_ghost_elem_protected = nb_ghost_protected(type, _ghost); // // } catch (...) { // // } // if (!new_numberings.exists(type, _ghost)) // new_numberings.alloc(nb_ghost_elem, 1, type, _ghost); // else // new_numberings(type, _ghost).resize(nb_ghost_elem); // Array & new_numbering = new_numberings(type, _ghost); // for (UInt g = 0; g < nb_ghost_elem; ++g) { // element.element = g; // if (element.element >= nb_ghost_elem_protected && // relevant_ghost_elements.find(element) == // relevant_ghost_elements.end()) { // remove_elem.getList().push_back(element); // new_numbering(element.element) = UInt(-1); // } // } // /// renumber remaining ghosts // UInt ng = 0; // for (UInt g = 0; g < nb_ghost_elem; ++g) { // if (new_numbering(g) != UInt(-1)) { // new_numbering(g) = ng; // ++ng; // } // } // } // for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost)) { // UInt nb_elem = mesh.getNbElement(type, _not_ghost); // if (!new_numberings.exists(type, _not_ghost)) // new_numberings.alloc(nb_elem, 1, type, _not_ghost); // Array & new_numbering = new_numberings(type, _not_ghost); // for (UInt e = 0; e < nb_elem; ++e) { // new_numbering(e) = e; // } // } // mesh.sendEvent(remove_elem); } /* -------------------------------------------------------------------------- */ void NonLocalManager::onElementsRemoved( const Array & element_list, const ElementTypeMapArray & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { FEEngine & fee = this->model.getFEEngine(); this->removeIntegrationPointsFromMap( event.getNewNumbering(), spatial_dimension, integration_points_positions, fee, _ek_regular); this->removeIntegrationPointsFromMap(event.getNewNumbering(), 1, volumes, fee, _ek_regular); /// loop over all the neighborhoods and call onElementsRemoved std::set::const_iterator global_neighborhood_it = global_neighborhoods.begin(); NeighborhoodMap::iterator it; for (; global_neighborhood_it != global_neighborhoods.end(); ++global_neighborhood_it) { it = neighborhoods.find(*global_neighborhood_it); if (it != neighborhoods.end()) it->second->onElementsRemoved(element_list, new_numbering, event); else dummy_synchronizers[*global_neighborhood_it]->onElementsRemoved( element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::onElementsAdded(const Array &, const NewElementsEvent &) { this->resizeElementTypeMap(1, volumes, model.getFEEngine()); this->resizeElementTypeMap(spatial_dimension, integration_points_positions, model.getFEEngine()); } /* -------------------------------------------------------------------------- */ void NonLocalManager::resizeElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { Mesh & mesh = this->model.getMesh(); for (auto gt : ghost_types) { for (auto type : mesh.elementTypes(spatial_dimension, gt, el_kind)) { UInt nb_element = mesh.getNbElement(type, gt); UInt nb_quads = fee.getNbIntegrationPoints(type, gt); if (!element_map.exists(type, gt)) element_map.alloc(nb_element * nb_quads, nb_component, type, gt); else element_map(type, gt).resize(nb_element * nb_quads); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::removeIntegrationPointsFromMap( const ElementTypeMapArray & new_numbering, UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { for (auto gt : ghost_types) { for (auto type : new_numbering.elementTypes(_all_dimensions, gt, el_kind)) { if (element_map.exists(type, gt)) { const Array & renumbering = new_numbering(type, gt); Array & vect = element_map(type, gt); UInt nb_quad_per_elem = fee.getNbIntegrationPoints(type, gt); Array tmp(renumbering.size() * nb_quad_per_elem, nb_component); AKANTU_DEBUG_ASSERT( tmp.size() == vect.size(), "Something strange append some mater was created or disappeared in " << vect.getID() << "(" << vect.size() << "!=" << tmp.size() << ") " "!!"); UInt new_size = 0; for (UInt i = 0; i < renumbering.size(); ++i) { UInt new_i = renumbering(i); if (new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component * nb_quad_per_elem, vect.storage() + i * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem * sizeof(Real)); ++new_size; } } tmp.resize(new_size * nb_quad_per_elem); vect.copy(tmp); } } } } /* -------------------------------------------------------------------------- */ UInt NonLocalManager::getNbData(const Array & elements, const ID & id) const { UInt size = 0; UInt nb_quadrature_points = this->model.getNbIntegrationPoints(elements); auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); size += it->second->nb_component * sizeof(Real) * nb_quadrature_points; return size; } /* -------------------------------------------------------------------------- */ void NonLocalManager::packData(CommunicationBuffer & buffer, const Array & elements, const ID & id) const { auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor::packElementalDataHelper( it->second->local, buffer, elements, true, this->model.getFEEngine()); } /* -------------------------------------------------------------------------- */ void NonLocalManager::unpackData(CommunicationBuffer & buffer, const Array & elements, const ID & id) const { auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor::unpackElementalDataHelper( it->second->local, buffer, elements, true, this->model.getFEEngine()); } } // namespace akantu diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh index e201b6df9..780c3e002 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh @@ -1,280 +1,280 @@ /** * @file non_local_neighborhood_tmpl.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Mon Sep 28 2015 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of class non-local neighborhood * * @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 "non_local_manager.hh" #include "non_local_neighborhood.hh" -#include "static_communicator.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template template inline void NonLocalNeighborhood::foreach_weight( const GhostType & ghost_type, Func && func) { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template template inline void NonLocalNeighborhood::foreach_weight( const GhostType & ghost_type, Func && func) const { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template NonLocalNeighborhood::NonLocalNeighborhood( NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : NonLocalNeighborhoodBase(manager.getModel(), quad_coordinates, id, memory_id), non_local_manager(manager) { AKANTU_DEBUG_IN(); this->weight_function = std::make_unique(manager); this->registerSubSection(_st_weight_function, "weight_parameter", *weight_function); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template NonLocalNeighborhood::~NonLocalNeighborhood() = default; /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::computeWeights() { AKANTU_DEBUG_IN(); this->weight_function->setRadius(this->neighborhood_radius); Vector q1_coord(this->spatial_dimension); Vector q2_coord(this->spatial_dimension); UInt nb_weights_per_pair = 2; /// w1: q1->q2, w2: q2->q1 /// get the elementtypemap for the neighborhood volume for each quadrature /// point ElementTypeMapReal & quadrature_points_volumes = this->non_local_manager.getVolumes(); /// update the internals of the weight function if applicable (not /// all the weight functions have internals and do noting in that /// case) weight_function->updateInternals(); for (auto ghost_type : ghost_types) { /// allocate the array to store the weight, if it doesn't exist already if (!(pair_weight[ghost_type])) { pair_weight[ghost_type] = std::make_unique>(0, nb_weights_per_pair); } /// resize the array to the correct size pair_weight[ghost_type]->resize(pair_list[ghost_type].size()); /// set entries to zero pair_weight[ghost_type]->clear(); /// loop over all pairs in the current pair list array and their /// corresponding weights PairList::const_iterator first_pair = pair_list[ghost_type].begin(); PairList::const_iterator last_pair = pair_list[ghost_type].end(); Array::vector_iterator weight_it = pair_weight[ghost_type]->begin(nb_weights_per_pair); // Compute the weights for (; first_pair != last_pair; ++first_pair, ++weight_it) { Vector & weight = *weight_it; const IntegrationPoint & q1 = first_pair->first; const IntegrationPoint & q2 = first_pair->second; /// get the coordinates for the given pair of quads Array::const_vector_iterator coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(this->spatial_dimension); q1_coord = coords_type_1_it[q1.global_num]; Array::const_vector_iterator coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(this->spatial_dimension); q2_coord = coords_type_2_it[q2.global_num]; Array & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); const Array & jacobians_2 = this->non_local_manager.getJacobians(q2.type, q2.ghost_type); const Real & q2_wJ = jacobians_2(q2.global_num); /// compute distance between the two quadrature points Real r = q1_coord.distance(q2_coord); /// compute the weight for averaging on q1 based on the distance Real w1 = this->weight_function->operator()(r, q1, q2); weight(0) = q2_wJ * w1; quad_volumes_1(q1.global_num) += weight(0); if (q2.ghost_type != _ghost && q1.global_num != q2.global_num) { const Array & jacobians_1 = this->non_local_manager.getJacobians(q1.type, q1.ghost_type); Array & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); /// compute the weight for averaging on q2 const Real & q1_wJ = jacobians_1(q1.global_num); Real w2 = this->weight_function->operator()(r, q2, q1); weight(1) = q1_wJ * w2; quad_volumes_2(q2.global_num) += weight(1); } else weight(1) = 0.; } } /// normalize the weights for (auto ghost_type : ghost_types) { foreach_weight(ghost_type, [this, &quadrature_points_volumes]( const auto & q1, const auto & q2, auto & weight) { auto & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); auto & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); Real q1_volume = quad_volumes_1(q1.global_num); auto ghost_type2 = q2.ghost_type; weight(0) *= 1. / q1_volume; if (ghost_type2 != _ghost) { Real q2_volume = quad_volumes_2(q2.global_num); weight(1) *= 1. / q2_volume; } }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::saveWeights( const std::string & filename) const { std::ofstream pout; std::stringstream sstr; - const StaticCommunicator & comm = model.getMesh().getCommunicator(); + const Communicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType)gt; AKANTU_DEBUG_ASSERT((pair_weight[ghost_type]), "the weights have not been computed yet"); Array & weights = *(pair_weight[ghost_type]); Array::const_vector_iterator weights_it = weights.begin(2); for (UInt i = 0; i < weights.size(); ++i, ++weights_it) pout << "w1: " << (*weights_it)(0) << " w2: " << (*weights_it)(1) << std::endl; } } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::weightedAverageOnNeighbours( const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const { auto it = non_local_variables.find(accumulated.getName()); // do averaging only for variables registered in the neighborhood if (it == non_local_variables.end()) return; foreach_weight( ghost_type2, [ghost_type2, nb_degree_of_freedom, &to_accumulate, &accumulated](const auto & q1, const auto & q2, auto & weight) { const Vector to_acc_1 = to_accumulate(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; const Vector to_acc_2 = to_accumulate(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; Vector acc_1 = accumulated(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; Vector acc_2 = accumulated(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; acc_1 += weight(0) * to_acc_2; if (ghost_type2 != _ghost) { acc_2 += weight(1) * to_acc_1; } }); } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::updateWeights() { // Update the weights for the non local variable averaging if (this->weight_function->getUpdateRate() && (this->non_local_manager.getNbStressCalls() % this->weight_function->getUpdateRate() == 0)) { SynchronizerRegistry::synchronize(_gst_mnl_weight); this->computeWeights(); } } } // namespace akantu #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL__ */ diff --git a/src/model/dof_manager.cc b/src/model/dof_manager.cc index 0cd583dae..4a33ef9ea 100644 --- a/src/model/dof_manager.cc +++ b/src/model/dof_manager.cc @@ -1,597 +1,595 @@ /** * @file dof_manager.cc * * @author Nicolas Richart * * @date Wed Aug 12 09:52:30 2015 * * @brief Implementation of the common parts of the DOFManagers * * @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 "dof_manager.hh" #include "element_group.hh" #include "mesh.hh" #include "mesh_utils.hh" #include "node_group.hh" #include "non_linear_solver.hh" #include "sparse_matrix.hh" -#include "static_communicator.hh" +#include "communicator.hh" #include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ DOFManager::DOFManager(const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), mesh(nullptr), local_system_size(0), pure_local_system_size(0), system_size(0), - communicator(StaticCommunicator::getStaticCommunicator()) {} + communicator(Communicator::getStaticCommunicator()) {} /* -------------------------------------------------------------------------- */ DOFManager::DOFManager(Mesh & mesh, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), mesh(&mesh), local_system_size(0), pure_local_system_size(0), system_size(0), communicator(mesh.getCommunicator()) { this->mesh->registerEventHandler(*this, _ehp_dof_manager); } /* -------------------------------------------------------------------------- */ DOFManager::~DOFManager() = default; /* -------------------------------------------------------------------------- */ // void DOFManager::getEquationsNumbers(const ID &, Array &) { // AKANTU_DEBUG_TO_IMPLEMENT(); // } /* -------------------------------------------------------------------------- */ std::vector DOFManager::getDOFIDs() const { std::vector keys; for (const auto & dof_data : this->dofs) keys.push_back(dof_data.first); return keys; } /* -------------------------------------------------------------------------- */ void DOFManager::assembleElementalArrayLocalArray( const Array & elementary_vect, Array & array_assembeled, const ElementType & type, const GhostType & ghost_type, Real scale_factor, const Array & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_element; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; UInt * filter_it = NULL; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); filter_it = filter_elements.storage(); } else { nb_element = this->mesh->getNbElement(type, ghost_type); } AKANTU_DEBUG_ASSERT(elementary_vect.size() == nb_element, "The vector elementary_vect(" << elementary_vect.getID() << ") has not the good size."); const Array & connectivity = this->mesh->getConnectivity(type, ghost_type); // Array::const_vector_iterator conn_begin = // connectivity.begin(nb_nodes_per_element); // Array::const_vector_iterator conn_it = conn_begin; Array::const_matrix_iterator elem_it = elementary_vect.begin(nb_degree_of_freedom, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++elem_it) { UInt element = el; if (filter_it != NULL) { // conn_it = conn_begin + *filter_it; element = *filter_it; } // const Vector & conn = *conn_it; const Matrix & elemental_val = *elem_it; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt offset_node = connectivity(element, n) * nb_degree_of_freedom; Vector assemble(array_assembeled.storage() + offset_node, nb_degree_of_freedom); Vector elem_val = elemental_val(n); assemble.aXplusY(elem_val, scale_factor); } if (filter_it != NULL) ++filter_it; // else // ++conn_it; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManager::assembleElementalArrayToResidual( const ID & dof_id, const Array & elementary_vect, const ElementType & type, const GhostType & ghost_type, Real scale_factor, const Array & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; Array array_localy_assembeled(this->mesh->getNbNodes(), nb_degree_of_freedom); array_localy_assembeled.clear(); this->assembleElementalArrayLocalArray( elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor, filter_elements); this->assembleToResidual(dof_id, array_localy_assembeled, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManager::assembleElementalArrayToLumpedMatrix( const ID & dof_id, const Array & elementary_vect, const ID & lumped_mtx, const ElementType & type, const GhostType & ghost_type, Real scale_factor, const Array & filter_elements) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; Array array_localy_assembeled(this->mesh->getNbNodes(), nb_degree_of_freedom); array_localy_assembeled.clear(); this->assembleElementalArrayLocalArray( elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor, filter_elements); this->assembleToLumpedMatrix(dof_id, array_localy_assembeled, lumped_mtx, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DOFManager::DOFData::DOFData(const ID & dof_id) : support_type(_dst_generic), group_support("__mesh__"), dof(NULL), blocked_dofs(NULL), increment(NULL), previous(NULL), solution(0, 1, dof_id + ":solution"), local_equation_number(0, 1, dof_id + ":local_equation_number") {} /* -------------------------------------------------------------------------- */ DOFManager::DOFData::~DOFData() {} /* -------------------------------------------------------------------------- */ DOFManager::DOFData & DOFManager::getNewDOFData(const ID & dof_id) { DOFStorage::iterator it = this->dofs.find(dof_id); if (it != this->dofs.end()) { AKANTU_EXCEPTION("This dof array has already been registered"); } std::unique_ptr dofs_storage = std::make_unique(dof_id); this->dofs[dof_id] = std::move(dofs_storage); return *dofs_storage; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsInternal(const ID & dof_id, Array & dofs_array) { DOFData & dofs_storage = this->getDOFData(dof_id); dofs_storage.dof = &dofs_array; UInt nb_local_dofs = 0; UInt nb_pure_local = 0; const DOFSupportType & support_type = dofs_storage.support_type; switch (support_type) { case _dst_nodal: { UInt nb_nodes = 0; const ID & group = dofs_storage.group_support; NodeGroup * node_group = NULL; if (group == "__mesh__") { nb_nodes = this->mesh->getNbNodes(); } else { node_group = &this->mesh->getElementGroup(group).getNodeGroup(); nb_nodes = node_group->size(); } nb_local_dofs = nb_nodes; AKANTU_DEBUG_ASSERT( dofs_array.size() == nb_local_dofs, "The array of dof is too shot to be associated to nodes."); for (UInt n = 0; n < nb_nodes; ++n) { UInt node = n; if (node_group) node = node_group->getNodes()(n); nb_pure_local += this->mesh->isLocalOrMasterNode(node) ? 1 : 0; } nb_pure_local *= dofs_array.getNbComponent(); nb_local_dofs *= dofs_array.getNbComponent(); break; } case _dst_generic: { nb_local_dofs = nb_pure_local = dofs_array.size() * dofs_array.getNbComponent(); break; } default: { AKANTU_EXCEPTION("This type of dofs is not handled yet."); } } this->pure_local_system_size += nb_pure_local; this->local_system_size += nb_local_dofs; - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - comm.allReduce(nb_pure_local, _so_sum); + communicator.allReduce(nb_pure_local, SynchronizerOperation::_sum); this->system_size += nb_pure_local; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFs(const ID & dof_id, Array & dofs_array, const DOFSupportType & support_type) { DOFData & dofs_storage = this->getNewDOFData(dof_id); dofs_storage.support_type = support_type; this->registerDOFsInternal(dof_id, dofs_array); } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFs(const ID & dof_id, Array & dofs_array, const ID & support_group) { DOFData & dofs_storage = this->getNewDOFData(dof_id); dofs_storage.support_type = _dst_nodal; dofs_storage.group_support = support_group; this->registerDOFsInternal(dof_id, dofs_array); } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsPrevious(const ID & dof_id, Array & array) { DOFData & dof = this->getDOFData(dof_id); if (dof.previous != NULL) { AKANTU_EXCEPTION("The previous dofs array for " << dof_id << " has already been registered"); } dof.previous = &array; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsIncrement(const ID & dof_id, Array & array) { DOFData & dof = this->getDOFData(dof_id); if (dof.increment != NULL) { AKANTU_EXCEPTION("The dofs increment array for " << dof_id << " has already been registered"); } dof.increment = &array; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFsDerivative(const ID & dof_id, UInt order, Array & dofs_derivative) { DOFData & dof = this->getDOFData(dof_id); std::vector *> & derivatives = dof.dof_derivatives; if (derivatives.size() < order) { derivatives.resize(order, NULL); } else { if (derivatives[order - 1] != NULL) { AKANTU_EXCEPTION("The dof derivatives of order " << order << " already been registered for this dof (" << dof_id << ")"); } } derivatives[order - 1] = &dofs_derivative; } /* -------------------------------------------------------------------------- */ void DOFManager::registerBlockedDOFs(const ID & dof_id, Array & blocked_dofs) { DOFData & dof = this->getDOFData(dof_id); if (dof.blocked_dofs != NULL) { AKANTU_EXCEPTION("The blocked dofs array for " << dof_id << " has already been registered"); } dof.blocked_dofs = &blocked_dofs; } /* -------------------------------------------------------------------------- */ void DOFManager::splitSolutionPerDOFs() { DOFStorage::iterator it = this->dofs.begin(); DOFStorage::iterator end = this->dofs.end(); for (; it != end; ++it) { DOFData & dof_data = *it->second; dof_data.solution.resize(dof_data.dof->size() * dof_data.dof->getNbComponent()); this->getSolutionPerDOFs(it->first, dof_data.solution); } } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManager::registerSparseMatrix(const ID & matrix_id, std::unique_ptr & matrix) { SparseMatricesMap::const_iterator it = this->matrices.find(matrix_id); if (it != this->matrices.end()) { AKANTU_EXCEPTION("The matrix " << matrix_id << " already exists in " << this->id); } SparseMatrix & ret = *matrix; this->matrices[matrix_id] = std::move(matrix); return ret; } /* -------------------------------------------------------------------------- */ /// Get an instance of a new SparseMatrix Array & DOFManager::getNewLumpedMatrix(const ID & id) { ID matrix_id = this->id + ":lumped_mtx:" + id; LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(matrix_id); if (it != this->lumped_matrices.end()) { AKANTU_EXCEPTION("The lumped matrix " << matrix_id << " already exists in " << this->id); } auto mtx = std::make_unique>(this->local_system_size, 1, matrix_id); this->lumped_matrices[matrix_id] = std::move(mtx); return *this->lumped_matrices[matrix_id]; } /* -------------------------------------------------------------------------- */ NonLinearSolver & DOFManager::registerNonLinearSolver( const ID & non_linear_solver_id, std::unique_ptr & non_linear_solver) { NonLinearSolversMap::const_iterator it = this->non_linear_solvers.find(non_linear_solver_id); if (it != this->non_linear_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << non_linear_solver_id << " already exists in " << this->id); } NonLinearSolver & ret = *non_linear_solver; this->non_linear_solvers[non_linear_solver_id] = std::move(non_linear_solver); return ret; } /* -------------------------------------------------------------------------- */ TimeStepSolver & DOFManager::registerTimeStepSolver( const ID & time_step_solver_id, std::unique_ptr & time_step_solver) { TimeStepSolversMap::const_iterator it = this->time_step_solvers.find(time_step_solver_id); if (it != this->time_step_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << time_step_solver_id << " already exists in " << this->id); } TimeStepSolver & ret = *time_step_solver; this->time_step_solvers[time_step_solver_id] = std::move(time_step_solver); return ret; } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManager::getMatrix(const ID & id) { ID matrix_id = this->id + ":mtx:" + id; SparseMatricesMap::const_iterator it = this->matrices.find(matrix_id); if (it == this->matrices.end()) { AKANTU_SILENT_EXCEPTION("The matrix " << matrix_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasMatrix(const ID & id) const { ID mtx_id = this->id + ":mtx:" + id; SparseMatricesMap::const_iterator it = this->matrices.find(mtx_id); return it != this->matrices.end(); } /* -------------------------------------------------------------------------- */ Array & DOFManager::getLumpedMatrix(const ID & id) { ID matrix_id = this->id + ":lumped_mtx:" + id; LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(matrix_id); if (it == this->lumped_matrices.end()) { AKANTU_SILENT_EXCEPTION("The lumped matrix " << matrix_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ const Array & DOFManager::getLumpedMatrix(const ID & id) const { ID matrix_id = this->id + ":lumped_mtx:" + id; LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(matrix_id); if (it == this->lumped_matrices.end()) { AKANTU_SILENT_EXCEPTION("The lumped matrix " << matrix_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasLumpedMatrix(const ID & id) const { ID mtx_id = this->id + ":lumped_mtx:" + id; LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(mtx_id); return it != this->lumped_matrices.end(); } /* -------------------------------------------------------------------------- */ NonLinearSolver & DOFManager::getNonLinearSolver(const ID & id) { ID non_linear_solver_id = this->id + ":nls:" + id; NonLinearSolversMap::const_iterator it = this->non_linear_solvers.find(non_linear_solver_id); if (it == this->non_linear_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << non_linear_solver_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasNonLinearSolver(const ID & id) const { ID solver_id = this->id + ":nls:" + id; NonLinearSolversMap::const_iterator it = this->non_linear_solvers.find(solver_id); return it != this->non_linear_solvers.end(); } /* -------------------------------------------------------------------------- */ TimeStepSolver & DOFManager::getTimeStepSolver(const ID & id) { ID time_step_solver_id = this->id + ":tss:" + id; TimeStepSolversMap::const_iterator it = this->time_step_solvers.find(time_step_solver_id); if (it == this->time_step_solvers.end()) { AKANTU_EXCEPTION("The non linear solver " << time_step_solver_id << " does not exists in " << this->id); } return *(it->second); } /* -------------------------------------------------------------------------- */ bool DOFManager::hasTimeStepSolver(const ID & solver_id) const { ID time_step_solver_id = this->id + ":tss:" + solver_id; TimeStepSolversMap::const_iterator it = this->time_step_solvers.find(time_step_solver_id); return it != this->time_step_solvers.end(); } /* -------------------------------------------------------------------------- */ void DOFManager::savePreviousDOFs(const ID & dofs_id) { this->getPreviousDOFs(dofs_id).copy(this->getDOFs(dofs_id)); } /* -------------------------------------------------------------------------- */ /* Mesh Events */ /* -------------------------------------------------------------------------- */ std::pair DOFManager::updateNodalDOFs(const ID & dof_id, const Array & nodes_list) { auto & dof_data = this->getDOFData(dof_id); UInt nb_new_local_dofs = 0; UInt nb_new_pure_local = 0; nb_new_local_dofs = nodes_list.size(); for (const auto & node : nodes_list) { nb_new_pure_local += this->mesh->isLocalOrMasterNode(node) ? 1 : 0; } const auto & dof_array = *dof_data.dof; nb_new_pure_local *= dof_array.getNbComponent(); nb_new_local_dofs *= dof_array.getNbComponent(); this->pure_local_system_size += nb_new_pure_local; this->local_system_size += nb_new_local_dofs; UInt nb_new_global = nb_new_pure_local; - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - comm.allReduce(nb_new_global, _so_sum); + communicator.allReduce(nb_new_global, SynchronizerOperation::_sum); this->system_size += nb_new_global; return std::make_pair(nb_new_local_dofs, nb_new_pure_local); } /* -------------------------------------------------------------------------- */ void DOFManager::onNodesAdded(const Array & nodes_list, const NewNodesEvent &) { for (auto & pair : this->dofs) { const auto & dof_id = pair.first; auto & dof_data = this->getDOFData(dof_id); if (dof_data.support_type != _dst_nodal) continue; const auto & group = dof_data.group_support; if (group == "__mesh__") { this->updateNodalDOFs(dof_id, nodes_list); } else { const auto & node_group = this->mesh->getElementGroup(group).getNodeGroup(); Array new_nodes_list; for (const auto & node : nodes_list) { if (node_group.find(node) != UInt(-1)) new_nodes_list.push_back(node); } this->updateNodalDOFs(dof_id, new_nodes_list); } } } /* -------------------------------------------------------------------------- */ void DOFManager::onNodesRemoved(const Array &, const Array &, const RemovedNodesEvent &) {} /* -------------------------------------------------------------------------- */ void DOFManager::onElementsAdded(const Array &, const NewElementsEvent &) {} /* -------------------------------------------------------------------------- */ void DOFManager::onElementsRemoved(const Array &, const ElementTypeMapArray &, const RemovedElementsEvent &) {} /* -------------------------------------------------------------------------- */ void DOFManager::onElementsChanged(const Array &, const Array &, const ElementTypeMapArray &, const ChangedElementsEvent &) {} /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/dof_manager.hh b/src/model/dof_manager.hh index c8aa2f9e4..23b76fc4c 100644 --- a/src/model/dof_manager.hh +++ b/src/model/dof_manager.hh @@ -1,465 +1,465 @@ /** * @file dof_manager.hh * * @author Nicolas Richart * * @date Wed Jul 22 11:43:43 2015 * * @brief Class handling the different types of dofs * * @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_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DOF_MANAGER_HH__ #define __AKANTU_DOF_MANAGER_HH__ namespace akantu { class TermsToAssemble; class NonLinearSolver; class TimeStepSolver; class SparseMatrix; } // namespace akantu namespace akantu { class DOFManager : protected Memory, protected MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DOFManager(const ID & id = "dof_manager", const MemoryID & memory_id = 0); DOFManager(Mesh & mesh, const ID & id = "dof_manager", const MemoryID & memory_id = 0); virtual ~DOFManager(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ private: /// common function to help registering dofs void registerDOFsInternal(const ID & dof_id, Array & dofs_array); public: /// register an array of degree of freedom virtual void registerDOFs(const ID & dof_id, Array & dofs_array, const DOFSupportType & support_type); /// the dof as an implied type of _dst_nodal and is defined only on a subset /// of nodes virtual void registerDOFs(const ID & dof_id, Array & dofs_array, const ID & group_support); /// register an array of previous values of the degree of freedom virtual void registerDOFsPrevious(const ID & dof_id, Array & dofs_array); /// register an array of increment of degree of freedom virtual void registerDOFsIncrement(const ID & dof_id, Array & dofs_array); /// register an array of derivatives for a particular dof array virtual void registerDOFsDerivative(const ID & dof_id, UInt order, Array & dofs_derivative); /// register array representing the blocked degree of freedoms virtual void registerBlockedDOFs(const ID & dof_id, Array & blocked_dofs); /// Assemble an array to the global residual array virtual void assembleToResidual(const ID & dof_id, const Array & array_to_assemble, Real scale_factor = 1.) = 0; /// Assemble an array to the global lumped matrix array virtual void assembleToLumpedMatrix(const ID & dof_id, const Array & array_to_assemble, const ID & lumped_mtx, Real scale_factor = 1.) = 0; /** * Assemble elementary values to a local array of the size nb_nodes * * nb_dof_per_node. The dof number is implicitly considered as * conn(el, n) * nb_nodes_per_element + d. * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalArrayLocalArray( const Array & elementary_vect, Array & array_assembeled, const ElementType & type, const GhostType & ghost_type, Real scale_factor = 1., const Array & filter_elements = empty_filter); /** * Assemble elementary values to the global residual array. The dof number is * implicitly considered as conn(el, n) * nb_nodes_per_element + d. * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalArrayToResidual( const ID & dof_id, const Array & elementary_vect, const ElementType & type, const GhostType & ghost_type, Real scale_factor = 1., const Array & filter_elements = empty_filter); /** * Assemble elementary values to a global array corresponding to a lumped * matrix */ virtual void assembleElementalArrayToLumpedMatrix( const ID & dof_id, const Array & elementary_vect, const ID & lumped_mtx, const ElementType & type, const GhostType & ghost_type, Real scale_factor = 1., const Array & filter_elements = empty_filter); /** * Assemble elementary values to the global residual array. The dof number is * implicitly considered as conn(el, n) * nb_nodes_per_element + d. With 0 < * n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array & elementary_mat, const ElementType & type, const GhostType & ghost_type = _not_ghost, const MatrixType & elemental_matrix_type = _symmetric, const Array & filter_elements = empty_filter) = 0; /// multiply a vector by a matrix and assemble the result to the residual virtual void assembleMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array & x, Real scale_factor = 1) = 0; /// multiply a vector by a lumped matrix and assemble the result to the /// residual virtual void assembleLumpedMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array & x, Real scale_factor = 1) = 0; /// assemble coupling terms between to dofs virtual void assemblePreassembledMatrix(const ID & dof_id_m, const ID & dof_id_n, const ID & matrix_id, const TermsToAssemble & terms) = 0; /// sets the residual to 0 virtual void clearResidual() = 0; /// sets the matrix to 0 virtual void clearMatrix(const ID & mtx) = 0; /// sets the lumped matrix to 0 virtual void clearLumpedMatrix(const ID & mtx) = 0; /// splits the solution storage from a global view to the per dof storages void splitSolutionPerDOFs(); /// extract a lumped matrix part corresponding to a given dof virtual void getLumpedMatrixPerDOFs(const ID & dof_id, const ID & lumped_mtx, Array & lumped) = 0; protected: /// minimum functionality to implement per derived version of the DOFManager /// to allow the splitSolutionPerDOFs function to work virtual void getSolutionPerDOFs(const ID & dof_id, Array & solution_array) = 0; protected: /* ------------------------------------------------------------------------ */ /// register a matrix SparseMatrix & registerSparseMatrix(const ID & matrix_id, std::unique_ptr & matrix); /// register a non linear solver instantiated by a derived class NonLinearSolver & registerNonLinearSolver(const ID & non_linear_solver_id, std::unique_ptr & non_linear_solver); /// register a time step solver instantiated by a derived class TimeStepSolver & registerTimeStepSolver(const ID & time_step_solver_id, std::unique_ptr & time_step_solver); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get the equation numbers corresponding to a dof_id. This might be used to /// access the matrix. inline const Array & getEquationsNumbers(const ID & dof_id) const; /// Global number of dofs AKANTU_GET_MACRO(SystemSize, this->system_size, UInt); /// Local number of dofs AKANTU_GET_MACRO(LocalSystemSize, this->local_system_size, UInt); /// Retrieve all the registered DOFs std::vector getDOFIDs() const; /* ------------------------------------------------------------------------ */ /* DOFs and derivatives accessors */ /* ------------------------------------------------------------------------ */ /// Get a reference to the registered dof array for a given id inline Array & getDOFs(const ID & dofs_id); /// Get the support type of a given dof inline DOFSupportType getSupportType(const ID & dofs_id) const; /// are the dofs registered inline bool hasDOFs(const ID & dofs_id) const; /// Get a reference to the registered dof derivatives array for a given id inline Array & getDOFsDerivatives(const ID & dofs_id, UInt order); /// Does the dof has derivatives inline bool hasDOFsDerivatives(const ID & dofs_id, UInt order) const; /// Get a reference to the blocked dofs array registered for the given id inline const Array & getBlockedDOFs(const ID & dofs_id) const; /// Does the dof has a blocked array inline bool hasBlockedDOFs(const ID & dofs_id) const; /// Get a reference to the registered dof increment array for a given id inline Array & getDOFsIncrement(const ID & dofs_id); /// Does the dof has a increment array inline bool hasDOFsIncrement(const ID & dofs_id) const; /// Does the dof has a previous array inline Array & getPreviousDOFs(const ID & dofs_id); /// Get a reference to the registered dof array for previous step values a /// given id inline bool hasPreviousDOFs(const ID & dofs_id) const; /// saves the values from dofs to previous dofs virtual void savePreviousDOFs(const ID & dofs_id); /// Get a reference to the solution array registered for the given id inline const Array & getSolution(const ID & dofs_id) const; /* ------------------------------------------------------------------------ */ /* Matrices accessors */ /* ------------------------------------------------------------------------ */ /// Get an instance of a new SparseMatrix virtual SparseMatrix & getNewMatrix(const ID & matrix_id, const MatrixType & matrix_type) = 0; /// Get an instance of a new SparseMatrix as a copy of the SparseMatrix /// matrix_to_copy_id virtual SparseMatrix & getNewMatrix(const ID & matrix_id, const ID & matrix_to_copy_id) = 0; /// Get the reference of an existing matrix SparseMatrix & getMatrix(const ID & matrix_id); /// check if the given matrix exists bool hasMatrix(const ID & matrix_id) const; /// Get an instance of a new lumped matrix virtual Array & getNewLumpedMatrix(const ID & matrix_id); /// Get the lumped version of a given matrix const Array & getLumpedMatrix(const ID & matrix_id) const; /// Get the lumped version of a given matrix Array & getLumpedMatrix(const ID & matrix_id); /// check if the given matrix exists bool hasLumpedMatrix(const ID & matrix_id) const; /* ------------------------------------------------------------------------ */ /* Non linear system solver */ /* ------------------------------------------------------------------------ */ /// Get instance of a non linear solver virtual NonLinearSolver & getNewNonLinearSolver( const ID & nls_solver_id, const NonLinearSolverType & _non_linear_solver_type) = 0; /// get instance of a non linear solver virtual NonLinearSolver & getNonLinearSolver(const ID & nls_solver_id); /// check if the given solver exists bool hasNonLinearSolver(const ID & solver_id) const; /* ------------------------------------------------------------------------ */ /* Time-Step Solver */ /* ------------------------------------------------------------------------ */ /// Get instance of a time step solver virtual TimeStepSolver & getNewTimeStepSolver(const ID & time_step_solver_id, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver) = 0; /// get instance of a time step solver virtual TimeStepSolver & getTimeStepSolver(const ID & time_step_solver_id); /// check if the given solver exists bool hasTimeStepSolver(const ID & solver_id) const; /* ------------------------------------------------------------------------ */ const Mesh & getMesh() { if (mesh) { return *mesh; } else { AKANTU_EXCEPTION("No mesh registered in this dof manager"); } } /* ------------------------------------------------------------------------ */ - AKANTU_GET_MACRO(Communicator, communicator, const StaticCommunicator &); + AKANTU_GET_MACRO(Communicator, communicator, const auto &); /* ------------------------------------------------------------------------ */ /* MeshEventHandler interface */ /* ------------------------------------------------------------------------ */ protected: /// helper function for the DOFManager::onNodesAdded method virtual std::pair updateNodalDOFs(const ID & dof_id, const Array & nodes_list); public: /// function to implement to react on akantu::NewNodesEvent virtual void onNodesAdded(const Array & nodes_list, const NewNodesEvent & event); /// function to implement to react on akantu::RemovedNodesEvent virtual void onNodesRemoved(const Array & nodes_list, const Array & new_numbering, const RemovedNodesEvent & event); /// function to implement to react on akantu::NewElementsEvent virtual void onElementsAdded(const Array & elements_list, const NewElementsEvent & event); /// function to implement to react on akantu::RemovedElementsEvent virtual void onElementsRemoved(const Array & elements_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event); /// function to implement to react on akantu::ChangedElementsEvent virtual void onElementsChanged(const Array & old_elements_list, const Array & new_elements_list, const ElementTypeMapArray & new_numbering, const ChangedElementsEvent & event); protected: struct DOFData; inline DOFData & getDOFData(const ID & dof_id); inline const DOFData & getDOFData(const ID & dof_id) const; template inline _DOFData & getDOFDataTyped(const ID & dof_id); template inline const _DOFData & getDOFDataTyped(const ID & dof_id) const; virtual DOFData & getNewDOFData(const ID & dof_id); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// dof representations in the dof manager struct DOFData { DOFData() = delete; explicit DOFData(const ID & dof_id); virtual ~DOFData(); /// DOF support type (nodal, general) this is needed to determine how the /// dof are shared among processors DOFSupportType support_type; ID group_support; /// Degree of freedom array Array * dof; /// Blocked degree of freedoms array Array * blocked_dofs; /// Degree of freedoms increment Array * increment; /// Degree of freedoms at previous step Array * previous; /// Solution associated to the dof Array solution; /// local numbering equation numbers Array local_equation_number; /* ---------------------------------------------------------------------- */ /* data for dynamic simulations */ /* ---------------------------------------------------------------------- */ /// Degree of freedom derivatives arrays std::vector *> dof_derivatives; }; /// type to store dofs information using DOFStorage = std::map>; /// type to store all the matrices using SparseMatricesMap = std::map>; /// type to store all the lumped matrices using LumpedMatricesMap = std::map>>; /// type to store all the non linear solver using NonLinearSolversMap = std::map>; /// type to store all the time step solver using TimeStepSolversMap = std::map>; /// store a reference to the dof arrays DOFStorage dofs; /// list of sparse matrices that where created SparseMatricesMap matrices; /// list of lumped matrices LumpedMatricesMap lumped_matrices; /// non linear solvers storage NonLinearSolversMap non_linear_solvers; /// time step solvers storage TimeStepSolversMap time_step_solvers; /// reference to the underlying mesh Mesh * mesh; /// Total number of degrees of freedom (size with the ghosts) UInt local_system_size; /// Number of purely local dofs (size without the ghosts) UInt pure_local_system_size; /// Total number of degrees of freedom UInt system_size; /// Communicator used for this manager, should be the same as in the mesh if a /// mesh is registered - const StaticCommunicator & communicator; + const Communicator & communicator; }; } // namespace akantu #include "dof_manager_inline_impl.cc" #endif /* __AKANTU_DOF_MANAGER_HH__ */ diff --git a/src/model/dof_manager_default.cc b/src/model/dof_manager_default.cc index bef2418bf..6944e7da6 100644 --- a/src/model/dof_manager_default.cc +++ b/src/model/dof_manager_default.cc @@ -1,913 +1,913 @@ /** * @file dof_manager_default.cc * * @author Nicolas Richart * * @date Tue Aug 11 16:21:01 2015 * * @brief Implementation of the default DOFManager * * @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 "dof_manager_default.hh" #include "dof_synchronizer.hh" #include "element_group.hh" #include "node_synchronizer.hh" #include "non_linear_solver_default.hh" #include "sparse_matrix_aij.hh" -#include "static_communicator.hh" +#include "communicator.hh" #include "terms_to_assemble.hh" #include "time_step_solver_default.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ inline void DOFManagerDefault::addSymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix & elementary_mat, const Vector & equation_numbers, UInt max_size) { for (UInt i = 0; i < elementary_mat.rows(); ++i) { UInt c_irn = equation_numbers(i); if (c_irn < max_size) { for (UInt j = i; j < elementary_mat.cols(); ++j) { UInt c_jcn = equation_numbers(j); if (c_jcn < max_size) { matrix(c_irn, c_jcn) += elementary_mat(i, j); } } } } } /* -------------------------------------------------------------------------- */ inline void DOFManagerDefault::addUnsymmetricElementalMatrixToSymmetric( SparseMatrixAIJ & matrix, const Matrix & elementary_mat, const Vector & equation_numbers, UInt max_size) { for (UInt i = 0; i < elementary_mat.rows(); ++i) { UInt c_irn = equation_numbers(i); if (c_irn < max_size) { for (UInt j = 0; j < elementary_mat.cols(); ++j) { UInt c_jcn = equation_numbers(j); if (c_jcn < max_size) { if (c_jcn >= c_irn) { matrix(c_irn, c_jcn) += elementary_mat(i, j); } } } } } } /* -------------------------------------------------------------------------- */ inline void DOFManagerDefault::addElementalMatrixToUnsymmetric( SparseMatrixAIJ & matrix, const Matrix & elementary_mat, const Vector & equation_numbers, UInt max_size) { for (UInt i = 0; i < elementary_mat.rows(); ++i) { UInt c_irn = equation_numbers(i); if (c_irn < max_size) { for (UInt j = 0; j < elementary_mat.cols(); ++j) { UInt c_jcn = equation_numbers(j); if (c_jcn < max_size) { matrix(c_irn, c_jcn) += elementary_mat(i, j); } } } } } /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFManagerDefault(const ID & id, const MemoryID & memory_id) : DOFManager(id, memory_id), residual(0, 1, std::string(id + ":residual")), global_residual(nullptr), global_solution(0, 1, std::string(id + ":global_solution")), global_blocked_dofs(0, 1, std::string(id + ":global_blocked_dofs")), previous_global_blocked_dofs( 0, 1, std::string(id + ":previous_global_blocked_dofs")), dofs_type(0, 1, std::string(id + ":dofs_type")), data_cache(0, 1, std::string(id + ":data_cache_array")), jacobian_release(0), global_equation_number(0, 1, "global_equation_number"), first_global_dof_id(0), synchronizer(nullptr) {} /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFManagerDefault(Mesh & mesh, const ID & id, const MemoryID & memory_id) : DOFManager(mesh, id, memory_id), residual(0, 1, std::string(id + ":residual")), global_residual(nullptr), global_solution(0, 1, std::string(id + ":global_solution")), global_blocked_dofs(0, 1, std::string(id + ":global_blocked_dofs")), previous_global_blocked_dofs( 0, 1, std::string(id + ":previous_global_blocked_dofs")), dofs_type(0, 1, std::string(id + ":dofs_type")), data_cache(0, 1, std::string(id + ":data_cache_array")), jacobian_release(0), global_equation_number(0, 1, "global_equation_number"), first_global_dof_id(0), synchronizer(nullptr) { if (this->mesh->isDistributed()) this->synchronizer = std::make_unique( *this, this->id + ":dof_synchronizer", this->memory_id, communicator); } /* -------------------------------------------------------------------------- */ DOFManagerDefault::~DOFManagerDefault() = default; /* -------------------------------------------------------------------------- */ template void DOFManagerDefault::assembleToGlobalArray( const ID & dof_id, const Array & array_to_assemble, Array & global_array, T scale_factor) { AKANTU_DEBUG_IN(); const Array & equation_number = this->getLocalEquationNumbers(dof_id); UInt nb_degree_of_freedoms = array_to_assemble.size() * array_to_assemble.getNbComponent(); AKANTU_DEBUG_ASSERT(equation_number.size() == nb_degree_of_freedoms, "The array to assemble does not have a correct size." << " (" << array_to_assemble.getID() << ")"); typename Array::const_scalar_iterator arr_it = array_to_assemble.begin_reinterpret(nb_degree_of_freedoms); Array::const_scalar_iterator equ_it = equation_number.begin(); for (UInt d = 0; d < nb_degree_of_freedoms; ++d, ++arr_it, ++equ_it) { global_array(*equ_it) += scale_factor * (*arr_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFDataDefault::DOFDataDefault(const ID & dof_id) : DOFData(dof_id), associated_nodes(0, 1, dof_id + "associated_nodes") {} /* -------------------------------------------------------------------------- */ DOFManager::DOFData & DOFManagerDefault::getNewDOFData(const ID & dof_id) { this->dofs[dof_id] = std::make_unique(dof_id); return *this->dofs[dof_id]; } /* -------------------------------------------------------------------------- */ class GlobalDOFInfoDataAccessor : public DataAccessor { public: typedef typename std::unordered_map>::size_type size_type; GlobalDOFInfoDataAccessor() = default; void addDOFToNode(UInt node, UInt dof) { dofs_per_node[node].push_back(dof); } UInt getNthDOFForNode(UInt nth_dof, UInt node) const { return dofs_per_node.find(node)->second[nth_dof]; } virtual UInt getNbData(const Array & nodes, const SynchronizationTag & tag) const { if (tag == _gst_size) { return nodes.size() * sizeof(size_type); } if (tag == _gst_update) { UInt total_size = 0; for (auto node : nodes) { auto it = dofs_per_node.find(node); if (it != dofs_per_node.end()) total_size += CommunicationBuffer::sizeInBuffer(it->second); } return total_size; } return 0; } virtual void packData(CommunicationBuffer & buffer, const Array & nodes, const SynchronizationTag & tag) const { for (auto node : nodes) { auto it = dofs_per_node.find(node); if (tag == _gst_size) { if (it != dofs_per_node.end()) { buffer << it->second.size(); } else { buffer << 0; } } else if (tag == _gst_update) { if (it != dofs_per_node.end()) buffer << it->second; } } } virtual void unpackData(CommunicationBuffer & buffer, const Array & nodes, const SynchronizationTag & tag) { for (auto node : nodes) { auto it = dofs_per_node.find(node); if (tag == _gst_size) { size_type size; buffer >> size; if (size != 0) dofs_per_node[node].resize(size); } else if (tag == _gst_update) { if (it != dofs_per_node.end()) buffer >> it->second; } } } protected: std::unordered_map> dofs_per_node; }; /* -------------------------------------------------------------------------- */ void DOFManagerDefault::registerDOFsInternal(const ID & dof_id, UInt nb_dofs, UInt nb_pure_local_dofs) { // auto prank = this->communicator.whoAmI(); // auto psize = this->communicator.getNbProc(); // access the relevant data to update auto & dof_data = this->getDOFDataTyped(dof_id); const auto & support_type = dof_data.support_type; const auto & group = dof_data.group_support; if (support_type == _dst_nodal and group != "__mesh__") { auto & support_nodes = this->mesh->getElementGroup(group).getNodeGroup().getNodes(); this->updateDOFsData( dof_data, nb_dofs, nb_pure_local_dofs, [&support_nodes](UInt node) -> UInt { return support_nodes[node]; }); } else { this->updateDOFsData(dof_data, nb_dofs, nb_pure_local_dofs, [](UInt node) -> UInt { return node; }); } // update the synchronizer if needed if (this->synchronizer) this->synchronizer->registerDOFs(dof_id); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::registerDOFs(const ID & dof_id, Array & dofs_array, const DOFSupportType & support_type) { // stores the current numbers of dofs UInt nb_dofs_old = this->local_system_size; UInt nb_pure_local_dofs_old = this->pure_local_system_size; // update or create the dof_data DOFManager::registerDOFs(dof_id, dofs_array, support_type); UInt nb_dofs = this->local_system_size - nb_dofs_old; UInt nb_pure_local_dofs = this->pure_local_system_size - nb_pure_local_dofs_old; this->registerDOFsInternal(dof_id, nb_dofs, nb_pure_local_dofs); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::registerDOFs(const ID & dof_id, Array & dofs_array, const ID & group_support) { // stores the current numbers of dofs UInt nb_dofs_old = this->local_system_size; UInt nb_pure_local_dofs_old = this->pure_local_system_size; // update or create the dof_data DOFManager::registerDOFs(dof_id, dofs_array, group_support); UInt nb_dofs = this->local_system_size - nb_dofs_old; UInt nb_pure_local_dofs = this->pure_local_system_size - nb_pure_local_dofs_old; this->registerDOFsInternal(dof_id, nb_dofs, nb_pure_local_dofs); } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManagerDefault::getNewMatrix(const ID & id, const MatrixType & matrix_type) { ID matrix_id = this->id + ":mtx:" + id; std::unique_ptr sm = std::make_unique(*this, matrix_type, matrix_id); return this->registerSparseMatrix(matrix_id, sm); } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManagerDefault::getNewMatrix(const ID & id, const ID & matrix_to_copy_id) { ID matrix_id = this->id + ":mtx:" + id; SparseMatrixAIJ & sm_to_copy = this->getMatrix(matrix_to_copy_id); std::unique_ptr sm = std::make_unique(sm_to_copy, matrix_id); return this->registerSparseMatrix(matrix_id, sm); } /* -------------------------------------------------------------------------- */ SparseMatrixAIJ & DOFManagerDefault::getMatrix(const ID & id) { SparseMatrix & matrix = DOFManager::getMatrix(id); return dynamic_cast(matrix); } /* -------------------------------------------------------------------------- */ NonLinearSolver & DOFManagerDefault::getNewNonLinearSolver(const ID & id, const NonLinearSolverType & type) { ID non_linear_solver_id = this->id + ":nls:" + id; std::unique_ptr nls; switch (type) { #if defined(AKANTU_IMPLICIT) case _nls_newton_raphson: case _nls_newton_raphson_modified: { nls = std::make_unique( *this, type, non_linear_solver_id, this->memory_id); break; } case _nls_linear: { nls = std::make_unique( *this, type, non_linear_solver_id, this->memory_id); break; } #endif case _nls_lumped: { nls = std::make_unique( *this, type, non_linear_solver_id, this->memory_id); break; } default: AKANTU_EXCEPTION("The asked type of non linear solver is not supported by " "this dof manager"); } return this->registerNonLinearSolver(non_linear_solver_id, nls); } /* -------------------------------------------------------------------------- */ TimeStepSolver & DOFManagerDefault::getNewTimeStepSolver(const ID & id, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver) { ID time_step_solver_id = this->id + ":tss:" + id; std::unique_ptr tss = std::make_unique( *this, type, non_linear_solver, time_step_solver_id, this->memory_id); return this->registerTimeStepSolver(time_step_solver_id, tss); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::clearResidual() { this->residual.resize(this->local_system_size); this->residual.clear(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::clearMatrix(const ID & mtx) { this->getMatrix(mtx).clear(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::clearLumpedMatrix(const ID & mtx) { this->getLumpedMatrix(mtx).clear(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::updateGlobalBlockedDofs() { DOFStorage::iterator it = this->dofs.begin(); DOFStorage::iterator end = this->dofs.end(); this->previous_global_blocked_dofs.copy(this->global_blocked_dofs); this->global_blocked_dofs.resize(this->local_system_size); this->global_blocked_dofs.clear(); for (; it != end; ++it) { if (!this->hasBlockedDOFs(it->first)) continue; DOFData & dof_data = *it->second; this->assembleToGlobalArray(it->first, *dof_data.blocked_dofs, this->global_blocked_dofs, true); } } /* -------------------------------------------------------------------------- */ template void DOFManagerDefault::getArrayPerDOFs(const ID & dof_id, const Array & global_array, Array & local_array) const { AKANTU_DEBUG_IN(); const Array & equation_number = this->getLocalEquationNumbers(dof_id); UInt nb_degree_of_freedoms = equation_number.size(); local_array.resize(nb_degree_of_freedoms / local_array.getNbComponent()); auto loc_it = local_array.begin_reinterpret(nb_degree_of_freedoms); auto equ_it = equation_number.begin(); for (UInt d = 0; d < nb_degree_of_freedoms; ++d, ++loc_it, ++equ_it) { (*loc_it) = global_array(*equ_it); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ // void DOFManagerDefault::getEquationsNumbers(const ID & dof_id, // Array & equation_numbers) { // AKANTU_DEBUG_IN(); // this->getArrayPerDOFs(dof_id, this->global_equation_number, // equation_numbers); AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::getSolutionPerDOFs(const ID & dof_id, Array & solution_array) { AKANTU_DEBUG_IN(); this->getArrayPerDOFs(dof_id, this->global_solution, solution_array); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::getLumpedMatrixPerDOFs(const ID & dof_id, const ID & lumped_mtx, Array & lumped) { AKANTU_DEBUG_IN(); this->getArrayPerDOFs(dof_id, this->getLumpedMatrix(lumped_mtx), lumped); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleToResidual( const ID & dof_id, const Array & array_to_assemble, Real scale_factor) { AKANTU_DEBUG_IN(); this->assembleToGlobalArray(dof_id, array_to_assemble, this->residual, scale_factor); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleToLumpedMatrix( const ID & dof_id, const Array & array_to_assemble, const ID & lumped_mtx, Real scale_factor) { AKANTU_DEBUG_IN(); Array & lumped = this->getLumpedMatrix(lumped_mtx); this->assembleToGlobalArray(dof_id, array_to_assemble, lumped, scale_factor); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleMatMulVectToResidual(const ID & dof_id, const ID & A_id, const Array & x, Real scale_factor) { SparseMatrixAIJ & A = this->getMatrix(A_id); // Array data_cache(this->local_system_size, 1, 0.); this->data_cache.resize(this->local_system_size); this->data_cache.clear(); this->assembleToGlobalArray(dof_id, x, data_cache, 1.); A.matVecMul(data_cache, this->residual, scale_factor, 1.); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleLumpedMatMulVectToResidual( const ID & dof_id, const ID & A_id, const Array & x, Real scale_factor) { const Array & A = this->getLumpedMatrix(A_id); // Array data_cache(this->local_system_size, 1, 0.); this->data_cache.resize(this->local_system_size); this->data_cache.clear(); this->assembleToGlobalArray(dof_id, x, data_cache, scale_factor); Array::const_scalar_iterator A_it = A.begin(); Array::const_scalar_iterator A_end = A.end(); Array::const_scalar_iterator x_it = data_cache.begin(); Array::scalar_iterator r_it = this->residual.begin(); for (; A_it != A_end; ++A_it, ++x_it, ++r_it) { *r_it += *A_it * *x_it; } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array & elementary_mat, const ElementType & type, const GhostType & ghost_type, const MatrixType & elemental_matrix_type, const Array & filter_elements) { AKANTU_DEBUG_IN(); DOFData & dof_data = this->getDOFData(dof_id); AKANTU_DEBUG_ASSERT(dof_data.support_type == _dst_nodal, "This function applies only on Nodal dofs"); this->addToProfile(matrix_id, dof_id, type, ghost_type); const Array & equation_number = this->getLocalEquationNumbers(dof_id); SparseMatrixAIJ & A = this->getMatrix(matrix_id); UInt nb_element; if (ghost_type == _not_ghost) { nb_element = this->mesh->getNbElement(type); } else { AKANTU_DEBUG_TO_IMPLEMENT(); } UInt * filter_it = nullptr; if (filter_elements != empty_filter) { nb_element = filter_elements.size(); filter_it = filter_elements.storage(); } else { if (dof_data.group_support != "__mesh__") { const Array & group_elements = this->mesh->getElementGroup(dof_data.group_support) .getElements(type, ghost_type); nb_element = group_elements.size(); filter_it = group_elements.storage(); } else { nb_element = this->mesh->getNbElement(type, ghost_type); } } AKANTU_DEBUG_ASSERT(elementary_mat.size() == nb_element, "The vector elementary_mat(" << elementary_mat.getID() << ") has not the good size."); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_degree_of_freedom = dof_data.dof->getNbComponent(); const Array & connectivity = this->mesh->getConnectivity(type, ghost_type); auto conn_begin = connectivity.begin(nb_nodes_per_element); auto conn_it = conn_begin; UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom; Vector element_eq_nb(nb_degree_of_freedom * nb_nodes_per_element); Array::const_matrix_iterator el_mat_it = elementary_mat.begin(size_mat, size_mat); for (UInt e = 0; e < nb_element; ++e, ++el_mat_it) { if (filter_it) conn_it = conn_begin + *filter_it; this->extractElementEquationNumber(equation_number, *conn_it, nb_degree_of_freedom, element_eq_nb); std::transform(element_eq_nb.storage(), element_eq_nb.storage() + element_eq_nb.size(), element_eq_nb.storage(), [&](UInt & local) -> UInt { return this->localToGlobalEquationNumber(local); }); if (filter_it) ++filter_it; else ++conn_it; if (A.getMatrixType() == _symmetric) if (elemental_matrix_type == _symmetric) this->addSymmetricElementalMatrixToSymmetric( A, *el_mat_it, element_eq_nb, A.size()); else this->addUnsymmetricElementalMatrixToSymmetric( A, *el_mat_it, element_eq_nb, A.size()); else this->addElementalMatrixToUnsymmetric(A, *el_mat_it, element_eq_nb, A.size()); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assemblePreassembledMatrix( const ID & dof_id_m, const ID & dof_id_n, const ID & matrix_id, const TermsToAssemble & terms) { const Array & equation_number_m = this->getLocalEquationNumbers(dof_id_m); const Array & equation_number_n = this->getLocalEquationNumbers(dof_id_n); SparseMatrixAIJ & A = this->getMatrix(matrix_id); for (const auto & term : terms) { UInt gi = this->localToGlobalEquationNumber(equation_number_m(term.i())); UInt gj = this->localToGlobalEquationNumber(equation_number_n(term.j())); A.add(gi, gj, term); } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); const DOFData & dof_data = this->getDOFData(dof_id); if (dof_data.support_type != _dst_nodal) return; auto mat_dof = std::make_pair(matrix_id, dof_id); auto type_pair = std::make_pair(type, ghost_type); auto prof_it = this->matrix_profiled_dofs.find(mat_dof); if (prof_it != this->matrix_profiled_dofs.end() && std::find(prof_it->second.begin(), prof_it->second.end(), type_pair) != prof_it->second.end()) return; UInt nb_degree_of_freedom_per_node = dof_data.dof->getNbComponent(); const Array & equation_number = this->getLocalEquationNumbers(dof_id); SparseMatrixAIJ & A = this->getMatrix(matrix_id); UInt size = A.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto & connectivity = this->mesh->getConnectivity(type, ghost_type); auto cbegin = connectivity.begin(nb_nodes_per_element); auto cit = cbegin; UInt nb_elements = connectivity.size(); UInt * ge_it = nullptr; if (dof_data.group_support != "__mesh__") { const Array & group_elements = this->mesh->getElementGroup(dof_data.group_support) .getElements(type, ghost_type); ge_it = group_elements.storage(); nb_elements = group_elements.size(); } UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom_per_node; Vector element_eq_nb(size_mat); for (UInt e = 0; e < nb_elements; ++e) { if (ge_it) cit = cbegin + *ge_it; this->extractElementEquationNumber( equation_number, *cit, nb_degree_of_freedom_per_node, element_eq_nb); std::transform(element_eq_nb.storage(), element_eq_nb.storage() + element_eq_nb.size(), element_eq_nb.storage(), [&](UInt & local) -> UInt { return this->localToGlobalEquationNumber(local); }); if (ge_it) ++ge_it; else ++cit; for (UInt i = 0; i < size_mat; ++i) { UInt c_irn = element_eq_nb(i); if (c_irn < size) { for (UInt j = 0; j < size_mat; ++j) { UInt c_jcn = element_eq_nb(j); if (c_jcn < size) { A.add(c_irn, c_jcn); } } } } } this->matrix_profiled_dofs[mat_dof].push_back(type_pair); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::applyBoundary(const ID & matrix_id) { SparseMatrixAIJ & J = this->getMatrix(matrix_id); if (this->jacobian_release == J.getValueRelease()) { auto are_equal = std::equal(global_blocked_dofs.begin(), global_blocked_dofs.end(), previous_global_blocked_dofs.begin()); if (are_equal) J.applyBoundary(); previous_global_blocked_dofs.copy(global_blocked_dofs); } else { J.applyBoundary(); } this->jacobian_release = J.getValueRelease(); } /* -------------------------------------------------------------------------- */ const Array & DOFManagerDefault::getGlobalResidual() { if (this->synchronizer) { if (not this->global_residual) { this->global_residual = std::make_unique>(0, 1, "global_residual"); } if (this->synchronizer->getCommunicator().whoAmI() == 0) { this->global_residual->resize(this->system_size); this->synchronizer->gather(this->residual, *this->global_residual); } else { this->synchronizer->gather(this->residual); } return *this->global_residual; } else { return this->residual; } } /* -------------------------------------------------------------------------- */ const Array & DOFManagerDefault::getResidual() const { return this->residual; } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::setGlobalSolution(const Array & solution) { if (this->synchronizer) { if (this->synchronizer->getCommunicator().whoAmI() == 0) { this->synchronizer->scatter(this->global_solution, solution); } else { this->synchronizer->scatter(this->global_solution); } } else { AKANTU_DEBUG_ASSERT(solution.size() == this->global_solution.size(), "Sequential call to this function needs the solution " "to be the same size as the global_solution"); this->global_solution.copy(solution); } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::onNodesAdded(const Array & nodes_list, const NewNodesEvent & event) { DOFManager::onNodesAdded(nodes_list, event); if (this->synchronizer) this->synchronizer->onNodesAdded(nodes_list); } /* -------------------------------------------------------------------------- */ std::pair DOFManagerDefault::updateNodalDOFs(const ID & dof_id, const Array & nodes_list) { UInt nb_new_local_dofs, nb_new_pure_local; std::tie(nb_new_local_dofs, nb_new_pure_local) = DOFManager::updateNodalDOFs(dof_id, nodes_list); auto & dof_data = this->getDOFDataTyped(dof_id); updateDOFsData(dof_data, nb_new_local_dofs, nb_new_pure_local, [&nodes_list](UInt pos) -> UInt { return nodes_list[pos]; }); return std::make_pair(nb_new_local_dofs, nb_new_pure_local); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::updateDOFsData(DOFDataDefault & dof_data, UInt nb_new_local_dofs, UInt nb_new_pure_local, std::function getNode) { auto prank = this->communicator.whoAmI(); auto psize = this->communicator.getNbProc(); // access the relevant data to update const auto & support_type = dof_data.support_type; GlobalDOFInfoDataAccessor data_accessor; // resize all relevant arrays this->residual.resize(this->local_system_size); this->dofs_type.resize(this->local_system_size); this->global_solution.resize(this->local_system_size); this->global_blocked_dofs.resize(this->local_system_size); this->previous_global_blocked_dofs.resize(this->local_system_size); this->global_equation_number.resize(this->local_system_size); for (auto & lumped_matrix : lumped_matrices) lumped_matrix.second->resize(this->local_system_size); dof_data.local_equation_number.reserve( dof_data.local_equation_number.size() + nb_new_local_dofs); // determine the first local/global dof id to use Array nb_dofs_per_proc(psize); nb_dofs_per_proc(prank) = nb_new_pure_local; this->communicator.allGather(nb_dofs_per_proc); this->first_global_dof_id += std::accumulate( nb_dofs_per_proc.begin(), nb_dofs_per_proc.begin() + prank, 0); UInt first_dof_id = this->local_system_size - nb_new_local_dofs; if (support_type == _dst_nodal) { dof_data.associated_nodes.reserve(dof_data.associated_nodes.size() + nb_new_local_dofs); } // update per dof info for (UInt d = 0; d < nb_new_local_dofs; ++d) { UInt local_eq_num = first_dof_id + d; dof_data.local_equation_number.push_back(local_eq_num); bool is_local_dof = true; // determine the dof type switch (support_type) { case _dst_nodal: { UInt node = getNode(d / dof_data.dof->getNbComponent()); this->dofs_type(local_eq_num) = this->mesh->getNodeType(node); dof_data.associated_nodes.push_back(node); is_local_dof = this->mesh->isLocalOrMasterNode(node); if (is_local_dof) { data_accessor.addDOFToNode(node, first_global_dof_id); } break; } case _dst_generic: { this->dofs_type(local_eq_num) = _nt_normal; break; } default: { AKANTU_EXCEPTION("This type of dofs is not handled yet."); } } // update global id for local dofs if (is_local_dof) { this->global_equation_number(local_eq_num) = this->first_global_dof_id; this->global_to_local_mapping[this->first_global_dof_id] = local_eq_num; ++this->first_global_dof_id; } else { this->global_equation_number(local_eq_num) = 0; } } // synchronize the global numbering for slaves if (support_type == _dst_nodal && this->synchronizer) { auto nb_dofs_per_node = dof_data.dof->getNbComponent(); auto & node_synchronizer = this->mesh->getNodeSynchronizer(); node_synchronizer.synchronizeOnce(data_accessor, _gst_size); node_synchronizer.synchronizeOnce(data_accessor, _gst_update); std::vector counters(nb_new_local_dofs / nb_dofs_per_node); for (UInt d = 0; d < nb_new_local_dofs; ++d) { UInt local_eq_num = first_dof_id + d; if (not this->isSlaveDOF(local_eq_num)) continue; UInt node = d / nb_dofs_per_node; UInt dof_count = counters[node]++; node = getNode(node); UInt global_dof_id = data_accessor.getNthDOFForNode(dof_count, node); this->global_equation_number(local_eq_num) = global_dof_id; this->global_to_local_mapping[global_dof_id] = local_eq_num; } } } } // namespace akantu // LocalWords: dof dofs diff --git a/src/model/model.cc b/src/model/model.cc index 3cc0b81d7..1a17d7ed9 100644 --- a/src/model/model.cc +++ b/src/model/model.cc @@ -1,352 +1,350 @@ /** * @file model.cc * * @author Guillaume Anciaux * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Mon Oct 03 2011 * @date last modification: Thu Nov 19 2015 * * @brief implementation of model common parts * * @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 "model.hh" -#include "element_group.hh" -#include "synchronizer_registry.hh" +#include "communicator.hh" #include "data_accessor.hh" -#include "static_communicator.hh" +#include "element_group.hh" #include "element_synchronizer.hh" +#include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ -Model::Model(Mesh& mesh, UInt dim, const ID & id, - const MemoryID & memory_id) : - Memory(id, memory_id), ModelSolver(mesh, id, memory_id), - mesh(mesh), - spatial_dimension(dim == _all_dimensions ? mesh.getSpatialDimension() : dim), - is_pbc_slave_node(0,1,"is_pbc_slave_node") , - parser(getStaticParser()) { +Model::Model(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) + : Memory(id, memory_id), ModelSolver(mesh, id, memory_id), mesh(mesh), + spatial_dimension(dim == _all_dimensions ? mesh.getSpatialDimension() + : dim), + is_pbc_slave_node(0, 1, "is_pbc_slave_node"), parser(getStaticParser()) { AKANTU_DEBUG_IN(); this->mesh.registerEventHandler(*this, _ehp_model); - + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Model::~Model() = default; /* -------------------------------------------------------------------------- */ -//void Model::setParser(Parser & parser) { this->parser = &parser; } +// void Model::setParser(Parser & parser) { this->parser = &parser; } /* -------------------------------------------------------------------------- */ void Model::initFull(const ModelOptions & options) { AKANTU_DEBUG_IN(); method = options.analysis_method; if (!this->hasDefaultSolver()) { this->initNewSolver(this->method); } initModel(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Model::initNewSolver(const AnalysisMethod & method) { ID solver_name; TimeStepSolverType tss_type; std::tie(solver_name, tss_type) = this->getDefaultSolverID(method); if (!this->hasSolver(solver_name)) { ModelSolverOptions options = this->getDefaultSolverOptions(tss_type); this->getNewSolver(solver_name, tss_type, options.non_linear_solver_type); this->setIntegrationScheme(solver_name, "displacement", options.integration_scheme_type["displacement"], options.solution_type["displacement"]); } this->method = method; this->setDefaultSolver(solver_name); } /* -------------------------------------------------------------------------- */ void Model::initPBC() { std::map::iterator it = pbc_pair.begin(); std::map::iterator end = pbc_pair.end(); is_pbc_slave_node.resize(mesh.getNbNodes()); #ifndef AKANTU_NDEBUG Array::const_vector_iterator coord_it = mesh.getNodes().begin(this->spatial_dimension); #endif while (it != end) { UInt i1 = (*it).first; is_pbc_slave_node(i1) = true; #ifndef AKANTU_NDEBUG UInt i2 = (*it).second; UInt slave = mesh.isDistributed() ? mesh.getGlobalNodesIds()(i1) : i1; UInt master = mesh.isDistributed() ? mesh.getGlobalNodesIds()(i2) : i2; AKANTU_DEBUG_INFO("pairing " << slave << " (" << Vector(coord_it[i1]) << ") with " << master << " (" << Vector(coord_it[i2]) << ")"); #endif ++it; } } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup(const std::string & group_name, const std::string & dumper_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void Model::dumpGroup() { GroupManager::element_group_iterator bit = mesh.element_group_begin(); GroupManager::element_group_iterator bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->dump(); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory) { GroupManager::element_group_iterator bit = mesh.element_group_begin(); GroupManager::element_group_iterator bend = mesh.element_group_end(); for (; bit != bend; ++bit) { bit->second->setDirectory(directory); } } /* -------------------------------------------------------------------------- */ void Model::setGroupDirectory(const std::string & directory, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setGroupBaseName(const std::string & basename, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.setBaseName(basename); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Model::getGroupDumper(const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); return group.getDumper(); } /* -------------------------------------------------------------------------- */ // DUMPER stuff /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & field_id, dumper::Field * field, DumperIOHelper & dumper) { #ifdef AKANTU_USE_IOHELPER dumper.registerField(field_id, field); #endif } /* -------------------------------------------------------------------------- */ void Model::addDumpField(const std::string & field_id) { this->addDumpFieldToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVector(const std::string & field_id) { this->addDumpFieldVectorToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensor(const std::string & field_id) { this->addDumpFieldTensorToDumper(mesh.getDefaultDumperName(), field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseName(const std::string & field_id) { mesh.setBaseName(field_id); } /* -------------------------------------------------------------------------- */ void Model::setBaseNameToDumper(const std::string & dumper_name, const std::string & basename) { mesh.setBaseNameToDumper(dumper_name, basename); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, false); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldToDumper(group.getDefaultDumperName(), field_id, group_name, _ek_regular, false); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupField(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->removeDumpGroupFieldFromDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); group.removeDumpFieldFromDumper(dumper_name, field_id); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, 3); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name) { ElementGroup & group = mesh.getElementGroup(group_name); this->addDumpGroupFieldVectorToDumper(group.getDefaultDumperName(), field_id, group_name); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name) { this->addDumpGroupFieldToDumper(dumper_name, field_id, group_name, _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id) { this->addDumpGroupFieldToDumper(dumper_name, field_id, "all", _ek_regular, true); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { this->addDumpGroupFieldToDumper(dumper_name, field_id, group_name, this->spatial_dimension, element_kind, padding_flag); } /* -------------------------------------------------------------------------- */ void Model::addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, UInt spatial_dimension, const ElementKind & element_kind, bool padding_flag) { #ifdef AKANTU_USE_IOHELPER dumper::Field * field = NULL; if (!field) field = this->createNodalFieldReal(field_id, group_name, padding_flag); if (!field) field = this->createNodalFieldUInt(field_id, group_name, padding_flag); if (!field) field = this->createNodalFieldBool(field_id, group_name, padding_flag); if (!field) field = this->createElementalField(field_id, group_name, padding_flag, spatial_dimension, element_kind); if (!field) field = this->mesh.createFieldFromAttachedData(field_id, group_name, element_kind); if (!field) field = this->mesh.createFieldFromAttachedData(field_id, group_name, element_kind); if (!field) AKANTU_DEBUG_WARNING("No field could be found based on name: " << field_id); if (field) { DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name, group_name); this->addDumpGroupFieldToDumper(field_id, field, dumper); } #endif } /* -------------------------------------------------------------------------- */ void Model::dump() { mesh.dump(); } /* -------------------------------------------------------------------------- */ void Model::setDirectory(const std::string & directory) { mesh.setDirectory(directory); } /* -------------------------------------------------------------------------- */ void Model::setDirectoryToDumper(const std::string & dumper_name, const std::string & directory) { mesh.setDirectoryToDumper(dumper_name, directory); } /* -------------------------------------------------------------------------- */ void Model::setTextModeToDumper() { mesh.setTextModeToDumper(); } /* -------------------------------------------------------------------------- */ -} // akantu +} // namespace akantu diff --git a/src/model/model_solver.cc b/src/model/model_solver.cc index fb4231877..678ae42cb 100644 --- a/src/model/model_solver.cc +++ b/src/model/model_solver.cc @@ -1,365 +1,359 @@ /** * @file model_solver.cc * * @author Nicolas Richart * * @date Wed Aug 12 13:31:56 2015 * * @brief Implementation of ModelSolver * * @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 "model_solver.hh" #include "dof_manager.hh" +#include "dof_manager_default.hh" +#include "mesh.hh" #include "non_linear_solver.hh" #include "time_step_solver.hh" -#include "mesh.hh" - -#if defined(AKANTU_USE_MPI) -#include "mpi_type_wrapper.hh" -#endif - -#include "dof_manager_default.hh" - #if defined(AKANTU_USE_PETSC) #include "dof_manager_petsc.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ModelSolver::ModelSolver(Mesh & mesh, const ID & id, UInt memory_id) : Parsable(_st_model_solver, id), SolverCallback(), parent_id(id), parent_memory_id(memory_id), mesh(mesh), dof_manager(NULL), default_solver_id("") {} /* -------------------------------------------------------------------------- */ ModelSolver::~ModelSolver() { delete this->dof_manager; } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager() { std::pair sub_sect = getStaticParser().getSubSections(_st_model_solver); // default without external solver activated at compilation same as mumps that // is the historical solver but with only the lumped solver ID solver_type = "explicit"; #if defined(AKANTU_USE_MUMPS) solver_type = "mumps"; #elif defined(AKANTU_USE_PETSC) solver_type = "petsc"; #endif const ParserSection * section = NULL; Parser::const_section_iterator it; for (it = sub_sect.first; it != sub_sect.second && section == NULL; ++it) { if (it->getName() == this->parent_id) { section = &(*it); solver_type = section->getOption(solver_type); } } if (section) { this->initDOFManager(*section, solver_type); } else { this->initDOFManager(solver_type); } } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager(const ID & solver_type) { if (solver_type == "explicit") { ID id = this->parent_id + ":dof_manager_default"; this->dof_manager = new DOFManagerDefault(mesh, id, this->parent_memory_id); } else if (solver_type == "petsc") { #if defined(AKANTU_USE_PETSC) ID id = this->parent_id + ":dof_manager_petsc"; this->dof_manager = new DOFManagerPETSc(mesh, id, this->parent_memory_id); #else AKANTU_EXCEPTION( "To use PETSc you have to activate it in the compilations options"); #endif } else if (solver_type == "mumps") { #if defined(AKANTU_USE_MUMPS) ID id = this->parent_id + ":dof_manager_default"; this->dof_manager = new DOFManagerDefault(mesh, id, this->parent_memory_id); #else AKANTU_EXCEPTION( "To use MUMPS you have to activate it in the compilations options"); #endif } else { AKANTU_EXCEPTION( "To use the solver " << solver_type << " you will have to code it. This is an unknown solver type."); } this->setDOFManager(*this->dof_manager); } /* -------------------------------------------------------------------------- */ template static T getOptionToType(const std::string & opt_str) { std::stringstream sstr(opt_str); T opt; sstr >> opt; return opt; } /* -------------------------------------------------------------------------- */ void ModelSolver::initDOFManager(const ParserSection & section, const ID & solver_type) { this->initDOFManager(solver_type); std::pair sub_sect = section.getSubSections(_st_time_step_solver); Parser::const_section_iterator it; for (it = sub_sect.first; it != sub_sect.second; ++it) { ID solver_id = it->getName(); // std::string str = it->getOption(); TimeStepSolverType tss_type = it->getParameter("type", this->getDefaultSolverType()); ModelSolverOptions tss_options = this->getDefaultSolverOptions(tss_type); std::pair sub_solvers_sect = it->getSubSections(_st_non_linear_solver); Parser::const_section_iterator sub_it; UInt nb_non_linear_solver_section = it->getNbSubSections(_st_non_linear_solver); NonLinearSolverType nls_type = tss_options.non_linear_solver_type; if (nb_non_linear_solver_section == 1) { const ParserSection & nls_section = *(sub_solvers_sect.first); nls_type = getOptionToType(nls_section.getName()); } else if (nb_non_linear_solver_section > 0) { AKANTU_EXCEPTION("More than one non linear solver are provided for the " "time step solver " << solver_id); } this->getNewSolver(solver_id, tss_type, nls_type); if (nb_non_linear_solver_section == 1) { const ParserSection & nls_section = *(sub_solvers_sect.first); this->dof_manager->getNonLinearSolver(solver_id).parseSection( nls_section); } std::pair sub_integrator_sect = it->getSubSections(_st_integration_scheme); for (sub_it = sub_integrator_sect.first; sub_it != sub_integrator_sect.second; ++sub_it) { const ParserSection & is_section = *sub_it; const ID & dof_id = is_section.getName(); IntegrationSchemeType it_type = is_section.getParameter( "type", tss_options.integration_scheme_type[dof_id]); IntegrationScheme::SolutionType s_type = is_section.getParameter( "solution_type", tss_options.solution_type[dof_id]); this->setIntegrationScheme(solver_id, dof_id, it_type, s_type); } std::map::const_iterator it = tss_options.integration_scheme_type.begin(); std::map::const_iterator end = tss_options.integration_scheme_type.end(); for (; it != end; ++it) { if (!this->hasIntegrationScheme(solver_id, it->first)) { this->setIntegrationScheme(solver_id, it->first, it->second, tss_options.solution_type[it->first]); } } } if (section.hasParameter("default_solver")) { ID default_solver = section.getParameter("default_solver"); this->setDefaultSolver(default_solver); } } /* -------------------------------------------------------------------------- */ TimeStepSolver & ModelSolver::getSolver(const ID & solver_id) { ID tmp_solver_id = solver_id; if (tmp_solver_id == "") tmp_solver_id = this->default_solver_id; TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(tmp_solver_id); return tss; } /* -------------------------------------------------------------------------- */ const TimeStepSolver & ModelSolver::getSolver(const ID & solver_id) const { ID tmp_solver_id = solver_id; if (solver_id == "") tmp_solver_id = this->default_solver_id; const TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(tmp_solver_id); return tss; } /* -------------------------------------------------------------------------- */ TimeStepSolver & ModelSolver::getTimeStepSolver(const ID & solver_id) { return this->getSolver(solver_id); } /* -------------------------------------------------------------------------- */ const TimeStepSolver & ModelSolver::getTimeStepSolver(const ID & solver_id) const { return this->getSolver(solver_id); } /* -------------------------------------------------------------------------- */ NonLinearSolver & ModelSolver::getNonLinearSolver(const ID & solver_id) { return this->getSolver(solver_id).getNonLinearSolver(); } /* -------------------------------------------------------------------------- */ const NonLinearSolver & ModelSolver::getNonLinearSolver(const ID & solver_id) const { return this->getSolver(solver_id).getNonLinearSolver(); } /* -------------------------------------------------------------------------- */ bool ModelSolver::hasSolver(const ID & solver_id) const { ID tmp_solver_id = solver_id; if (solver_id == "") tmp_solver_id = this->default_solver_id; return this->dof_manager->hasTimeStepSolver(tmp_solver_id); } /* -------------------------------------------------------------------------- */ void ModelSolver::setDefaultSolver(const ID & solver_id) { AKANTU_DEBUG_ASSERT( this->hasSolver(solver_id), "Cannot set the default solver to a solver that does not exists"); this->default_solver_id = solver_id; } /* -------------------------------------------------------------------------- */ void ModelSolver::solveStep(const ID & solver_id) { AKANTU_DEBUG_IN(); TimeStepSolver & tss = this->getSolver(solver_id); // make one non linear solve tss.solveStep(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ModelSolver::getNewSolver(const ID & solver_id, TimeStepSolverType time_step_solver_type, NonLinearSolverType non_linear_solver_type) { if (this->default_solver_id == "") { this->default_solver_id = solver_id; } if (non_linear_solver_type == _nls_auto) { switch (time_step_solver_type) { case _tsst_dynamic: case _tsst_static: non_linear_solver_type = _nls_newton_raphson; break; case _tsst_dynamic_lumped: non_linear_solver_type = _nls_lumped; break; case _tsst_not_defined: AKANTU_EXCEPTION(time_step_solver_type << " is not a valid time step solver type"); break; } } this->initSolver(time_step_solver_type, non_linear_solver_type); NonLinearSolver & nls = this->dof_manager->getNewNonLinearSolver( solver_id, non_linear_solver_type); this->dof_manager->getNewTimeStepSolver(solver_id, time_step_solver_type, nls); } /* -------------------------------------------------------------------------- */ Real ModelSolver::getTimeStep(const ID & solver_id) const { const TimeStepSolver & tss = this->getSolver(solver_id); return tss.getTimeStep(); } /* -------------------------------------------------------------------------- */ void ModelSolver::setTimeStep(Real time_step, const ID & solver_id) { TimeStepSolver & tss = this->getSolver(solver_id); return tss.setTimeStep(time_step); } /* -------------------------------------------------------------------------- */ void ModelSolver::setIntegrationScheme( const ID & solver_id, const ID & dof_id, const IntegrationSchemeType & integration_scheme_type, IntegrationScheme::SolutionType solution_type) { TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(solver_id); tss.setIntegrationScheme(dof_id, integration_scheme_type, solution_type); } /* -------------------------------------------------------------------------- */ bool ModelSolver::hasDefaultSolver() const { return (this->default_solver_id != ""); } /* -------------------------------------------------------------------------- */ bool ModelSolver::hasIntegrationScheme(const ID & solver_id, const ID & dof_id) const { TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(solver_id); return tss.hasIntegrationScheme(dof_id); } /* -------------------------------------------------------------------------- */ void ModelSolver::predictor() {} /* -------------------------------------------------------------------------- */ void ModelSolver::corrector() {} /* -------------------------------------------------------------------------- */ TimeStepSolverType ModelSolver::getDefaultSolverType() const { return _tsst_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions ModelSolver::getDefaultSolverOptions(__attribute__((unused)) const TimeStepSolverType & type) const { ModelSolverOptions options; options.non_linear_solver_type = _nls_auto; return options; } } // namespace akantu diff --git a/src/model/non_linear_solver_linear.cc b/src/model/non_linear_solver_linear.cc index 0b88bf89a..d917106a7 100644 --- a/src/model/non_linear_solver_linear.cc +++ b/src/model/non_linear_solver_linear.cc @@ -1,71 +1,70 @@ /** * @file non_linear_solver_linear.cc * * @author Nicolas Richart * * @date Tue Aug 25 00:57:00 2015 * * @brief Implementation of the default NonLinearSolver * * @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 "non_linear_solver_linear.hh" #include "dof_manager_default.hh" #include "solver_callback.hh" -#include "static_communicator.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolverLinear::NonLinearSolverLinear( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id), dof_manager(dof_manager), solver(dof_manager, "J", id + ":sparse_solver", memory_id) { this->supported_type.insert(_nls_linear); this->checkIfTypeIsSupported(); } /* -------------------------------------------------------------------------- */ NonLinearSolverLinear::~NonLinearSolverLinear() {} /* ------------------------------------------------------------------------ */ void NonLinearSolverLinear::solve(SolverCallback & solver_callback) { this->dof_manager.updateGlobalBlockedDofs(); solver_callback.predictor(); solver_callback.assembleResidual(); solver_callback.assembleMatrix("J"); this->solver.solve(); solver_callback.corrector(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/non_linear_solver_lumped.cc b/src/model/non_linear_solver_lumped.cc index 4ca27d899..a31f41548 100644 --- a/src/model/non_linear_solver_lumped.cc +++ b/src/model/non_linear_solver_lumped.cc @@ -1,102 +1,102 @@ /** * @file non_linear_solver_lumped.cc * * @author Nicolas Richart * * @date Tue Aug 25 00:57:00 2015 * * @brief Implementation of the default NonLinearSolver * * @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 "non_linear_solver_lumped.hh" #include "dof_manager_default.hh" #include "solver_callback.hh" -#include "static_communicator.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolverLumped::NonLinearSolverLumped( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id), dof_manager(dof_manager) { this->supported_type.insert(_nls_lumped); this->checkIfTypeIsSupported(); this->registerParam("b_a2x", this->alpha, 1., _pat_parsmod, "Conversion coefficient between x and A^{-1} b"); } /* -------------------------------------------------------------------------- */ NonLinearSolverLumped::~NonLinearSolverLumped() {} /* ------------------------------------------------------------------------ */ void NonLinearSolverLumped::solve(SolverCallback & solver_callback) { this->dof_manager.updateGlobalBlockedDofs(); solver_callback.predictor(); auto & x = this->dof_manager.getGlobalSolution(); const auto & b = this->dof_manager.getResidual(); x.resize(b.size()); this->dof_manager.updateGlobalBlockedDofs(); const Array & blocked_dofs = this->dof_manager.getGlobalBlockedDOFs(); solver_callback.assembleResidual(); const auto & A = this->dof_manager.getLumpedMatrix("M"); // alpha is the conversion factor from from force/mass to acceleration needed // in model coupled with atomistic \todo find a way to define alpha per dof // type this->solveLumped(A, x, b, blocked_dofs, alpha); this->dof_manager.splitSolutionPerDOFs(); solver_callback.corrector(); } /* -------------------------------------------------------------------------- */ void NonLinearSolverLumped::solveLumped(const Array & A, Array & x, const Array & b, const Array & blocked_dofs, Real alpha) { auto A_it = A.begin(); auto x_it = x.begin(); auto x_end = x.end(); auto b_it = b.begin(); auto blocked_it = blocked_dofs.begin(); for (; x_it != x_end; ++x_it, ++b_it, ++A_it, ++blocked_it) { if (!(*blocked_it)) { *x_it = alpha *(*b_it / *A_it); } } } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/non_linear_solver_newton_raphson.cc b/src/model/non_linear_solver_newton_raphson.cc index 3582f9135..2c4c41af3 100644 --- a/src/model/non_linear_solver_newton_raphson.cc +++ b/src/model/non_linear_solver_newton_raphson.cc @@ -1,185 +1,185 @@ /** * @file non_linear_solver_newton_raphson.cc * * @author Nicolas Richart * * @date Tue Aug 25 00:57:00 2015 * * @brief Implementation of the default NonLinearSolver * * @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 "non_linear_solver_newton_raphson.hh" #include "dof_manager_default.hh" #include "solver_callback.hh" -#include "static_communicator.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLinearSolverNewtonRaphson::NonLinearSolverNewtonRaphson( DOFManagerDefault & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id, UInt memory_id) : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id), dof_manager(dof_manager), solver(dof_manager, "J", id + ":sparse_solver", memory_id), n_iter(0), error(0.), converged(false) { this->supported_type.insert(_nls_newton_raphson_modified); this->supported_type.insert(_nls_newton_raphson); this->supported_type.insert(_nls_linear); this->checkIfTypeIsSupported(); this->registerParam("threshold", convergence_criteria, 1e-10, _pat_parsmod, "Threshold to consider results as converged"); this->registerParam("convergence_type", convergence_criteria_type, _scc_solution, _pat_parsmod, "Type of convergence criteria"); this->registerParam("max_iterations", max_iterations, 10, _pat_parsmod, "Max number of iterations"); this->registerParam("error", error, _pat_readable, "Last reached error"); this->registerParam("nb_iterations", n_iter, _pat_readable, "Last reached number of iterations"); this->registerParam("converged", converged, _pat_readable, "Did last solve converged"); this->registerParam("force_linear_recompute", force_linear_recompute, true, _pat_modifiable, "Force reassembly of the jacobian matrix"); } /* -------------------------------------------------------------------------- */ NonLinearSolverNewtonRaphson::~NonLinearSolverNewtonRaphson() {} /* ------------------------------------------------------------------------ */ void NonLinearSolverNewtonRaphson::solve(SolverCallback & solver_callback) { this->dof_manager.updateGlobalBlockedDofs(); solver_callback.predictor(); solver_callback.assembleResidual(); if (this->non_linear_solver_type == _nls_newton_raphson_modified || (this->non_linear_solver_type == _nls_linear && this->force_linear_recompute)) { solver_callback.assembleMatrix("J"); this->force_linear_recompute = false; } this->n_iter = 0; this->converged = false; if (this->convergence_criteria_type == _scc_residual) { this->converged = this->testConvergence(this->dof_manager.getResidual()); if (this->converged) return; } do { if (this->non_linear_solver_type == _nls_newton_raphson) solver_callback.assembleMatrix("J"); this->solver.solve(); solver_callback.corrector(); // EventManager::sendEvent(NonLinearSolver::AfterSparseSolve(method)); if (this->convergence_criteria_type == _scc_residual) { solver_callback.assembleResidual(); this->converged = this->testConvergence(this->dof_manager.getResidual()); } else { this->converged = this->testConvergence(this->dof_manager.getGlobalSolution()); } if (this->convergence_criteria_type == _scc_solution && !this->converged) solver_callback.assembleResidual(); // this->dump(); this->n_iter++; AKANTU_DEBUG_INFO( "[" << this->convergence_criteria_type << "] Convergence iteration " << std::setw(std::log10(this->max_iterations)) << this->n_iter << ": error " << this->error << (this->converged ? " < " : " > ") << this->convergence_criteria); } while (!this->converged && this->n_iter < this->max_iterations); // this makes sure that you have correct strains and stresses after the // solveStep function (e.g., for dumping) if (this->convergence_criteria_type == _scc_solution) solver_callback.assembleResidual(); if (this->converged) { // this->sendEvent(NonLinearSolver::ConvergedEvent(method)); } else if (this->n_iter == this->max_iterations) { AKANTU_CUSTOM_EXCEPTION(debug::NLSNotConvergedException( this->convergence_criteria, this->n_iter, this->error)); AKANTU_DEBUG_WARNING("[" << this->convergence_criteria_type << "] Convergence not reached after " << std::setw(std::log10(this->max_iterations)) << this->n_iter << " iteration" << (this->n_iter == 1 ? "" : "s") << "!"); } return; } /* -------------------------------------------------------------------------- */ bool NonLinearSolverNewtonRaphson::testConvergence(const Array & array) { AKANTU_DEBUG_IN(); const Array & blocked_dofs = this->dof_manager.getGlobalBlockedDOFs(); UInt nb_degree_of_freedoms = array.size(); auto arr_it = array.begin(); auto bld_it = blocked_dofs.begin(); Real norm = 0.; for (UInt n = 0; n < nb_degree_of_freedoms; ++n, ++arr_it, ++bld_it) { bool is_local_node = this->dof_manager.isLocalOrMasterDOF(n); if ((! *bld_it) && is_local_node) { norm += *arr_it * *arr_it; } } - StaticCommunicator::getStaticCommunicator().allReduce(norm, _so_sum); + dof_manager.getCommunicator().allReduce(norm, SynchronizerOperation::_sum); norm = std::sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something went wrong in the solve phase"); this->error = norm; return (error < this->convergence_criteria); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index d6b5dae4d..9965a28b7 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1240 +1,1225 @@ /** * @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 "solid_mechanics_model.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" +#include "solid_mechanics_model_tmpl.hh" #include "element_synchronizer.hh" #include "sparse_matrix.hh" -#include "static_communicator.hh" +#include "communicator.hh" #include "synchronizer_registry.hh" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_paraview.hh" #endif #include "material_non_local.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /** * 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(), f_m2a(1.0), displacement(nullptr), previous_displacement(nullptr), displacement_increment(nullptr), mass(nullptr), velocity(nullptr), acceleration(nullptr), external_force(nullptr), internal_force(nullptr), blocked_dofs(nullptr), current_position(nullptr), material_index("material index", id, memory_id), material_local_numbering("material local numbering", id, memory_id), material_selector(new DefaultMaterialSelector(material_index)), is_default_material_selector(true), increment_flag(false), are_materials_instantiated(false) { //, pbc_synch(nullptr) { AKANTU_DEBUG_IN(); this->registerFEEngineObject("SolidMechanicsFEEngine", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper("paraview_all", id, true); this->mesh.addDumpMesh(mesh, Model::spatial_dimension, _not_ghost, _ek_regular); #endif this->initDOFManager(); this->registerDataAccessor(*this); if (this->mesh.isDistributed()) { auto & synchronizer = this->mesh.getElementSynchronizer(); this->registerSynchronizer(synchronizer, _gst_material_id); this->registerSynchronizer(synchronizer, _gst_smm_mass); this->registerSynchronizer(synchronizer, _gst_smm_stress); this->registerSynchronizer(synchronizer, _gst_smm_boundary); this->registerSynchronizer(synchronizer, _gst_for_dump); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); if (is_default_material_selector) { delete material_selector; material_selector = nullptr; } for (auto & internal : this->registered_internals) { delete internal.second; } // delete pbc_synch; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setTimeStep(Real time_step, const ID & solver_id) { Model::setTimeStep(time_step, solver_id); #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) { material_index.initialize(mesh, _element_kind = _ek_not_defined, - _default_value = UInt(-1), _with_nb_element = true); + _default_value = UInt(-1), _with_nb_element = + true); material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined, _with_nb_element = true); Model::initFull(options); // initialize pbc if (this->pbc_pair.size() != 0) this->initPBC(); // initialize the materials if (this->parser.getLastParsedFile() != "") { this->instantiateMaterials(); } this->initMaterials(); - this->initBC(*this, *displacement, *displacement_increment, *external_force); + this->initBC(*this, *displacement, *displacement_increment, + *external_force); } /* -------------------------------------------------------------------------- */ TimeStepSolverType SolidMechanicsModel::getDefaultSolverType() const { return _tsst_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions SolidMechanicsModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_dynamic_lumped: { options.non_linear_solver_type = _nls_lumped; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case _tsst_static: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } case _tsst_dynamic: { if (this->method == _explicit_consistent_mass) { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; } else { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_trapezoidal_rule_2; options.solution_type["displacement"] = IntegrationScheme::_displacement; } break; } default: AKANTU_EXCEPTION(type << " is not a valid time step solver type"); } return options; } /* -------------------------------------------------------------------------- */ std::tuple SolidMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) { switch (method) { case _explicit_lumped_mass: { return std::make_tuple("explicit_lumped", _tsst_dynamic_lumped); } case _explicit_consistent_mass: { return std::make_tuple("explicit", _tsst_dynamic); } case _static: { return std::make_tuple("static", _tsst_static); } case _implicit_dynamic: { return std::make_tuple("implicit", _tsst_dynamic); } default: return std::make_tuple("unknown", _tsst_not_defined); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType) { auto & dof_manager = this->getDOFManager(); /* ------------------------------------------------------------------------ */ // for alloc type of solvers this->allocNodalField(this->displacement, spatial_dimension, "displacement"); this->allocNodalField(this->previous_displacement, spatial_dimension, "previous_displacement"); this->allocNodalField(this->displacement_increment, spatial_dimension, "displacement_increment"); this->allocNodalField(this->internal_force, spatial_dimension, "internal_force"); this->allocNodalField(this->external_force, spatial_dimension, "external_force"); this->allocNodalField(this->blocked_dofs, spatial_dimension, "blocked_dofs"); this->allocNodalField(this->current_position, spatial_dimension, "current_position"); // initialize the current positions this->current_position->copy(this->mesh.getNodes()); /* ------------------------------------------------------------------------ */ if (!dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); dof_manager.registerDOFsIncrement("displacement", *this->displacement_increment); dof_manager.registerDOFsPrevious("displacement", *this->previous_displacement); } /* ------------------------------------------------------------------------ */ // for dynamic if (time_step_solver_type == _tsst_dynamic || time_step_solver_type == _tsst_dynamic_lumped) { this->allocNodalField(this->velocity, spatial_dimension, "velocity"); this->allocNodalField(this->acceleration, spatial_dimension, "acceleration"); if (!dof_manager.hasDOFsDerivatives("displacement", 1)) { dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity); dof_manager.registerDOFsDerivative("displacement", 2, *this->acceleration); } } } /* -------------------------------------------------------------------------- */ 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); } /* -------------------------------------------------------------------------- */ /** * 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::assembleResidual() { AKANTU_DEBUG_IN(); /* ------------------------------------------------------------------------ */ // computes the internal forces this->assembleInternalForces(); /* ------------------------------------------------------------------------ */ this->getDOFManager().assembleToResidual("displacement", *this->external_force, 1); this->getDOFManager().assembleToResidual("displacement", *this->internal_force, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MatrixType SolidMechanicsModel::getMatrixType(const ID & matrix_id) { // \TODO check the materials to know what is the correct answer if (matrix_id == "C") return _mt_not_defined; return _symmetric; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } else if (matrix_id == "M") { this->assembleMass(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { this->assembleMassLumped(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::beforeSolveStep() { for (auto & material : materials) material->beforeSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::afterSolveStep() { for (auto & material : materials) material->afterSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::predictor() { ++displacement_release; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::corrector() { ++displacement_release; } /* -------------------------------------------------------------------------- */ /** * 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(); // compute the stresses of local elements AKANTU_DEBUG_INFO("Compute local stresses"); for (auto & material : materials) { material->computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ if (this->non_local_manager) this->non_local_manager->computeAllNonLocalStresses(); // communicate the stresses AKANTU_DEBUG_INFO("Send data for residual assembly"); this->asynchronousSynchronize(_gst_smm_stress); // assemble the forces due to local stresses AKANTU_DEBUG_INFO("Assemble residual for local elements"); for (auto & material : materials) { material->assembleInternalForces(_not_ghost); } // finalize communications AKANTU_DEBUG_INFO("Wait distant stresses"); this->waitEndSynchronize(_gst_smm_stress); // assemble the stresses due to ghost elements AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for (auto & material : materials) { material->assembleInternalForces(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); // Check if materials need to recompute the matrix bool need_to_reassemble = false; for (auto & material : materials) { need_to_reassemble |= material->hasStiffnessMatrixChanged(); } if (need_to_reassemble) { this->getDOFManager().getMatrix("K").clear(); // call compute stiffness matrix on each local elements for (auto & material : materials) { material->assembleStiffnessMatrix(_not_ghost); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { if (this->current_position_release == this->displacement_release) return; this->current_position->copy(this->mesh.getNodes()); auto cpos_it = this->current_position->begin(Model::spatial_dimension); auto cpos_end = this->current_position->end(Model::spatial_dimension); auto disp_it = this->displacement->begin(Model::spatial_dimension); for (; cpos_it != cpos_end; ++cpos_it, ++disp_it) { *cpos_it += *disp_it; } this->current_position_release = this->displacement_release; } /* -------------------------------------------------------------------------- */ const Array & SolidMechanicsModel::getCurrentPosition() { this->updateCurrentPosition(); return *this->current_position; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateDataForNonLocalCriterion( ElementTypeMapReal & criterion) { const ID field_name = criterion.getName(); for (auto & material : materials) { if (!material->isInternal(field_name, _ek_regular)) continue; for (auto ghost_type : ghost_types) { material->flattenInternal(field_name, criterion, ghost_type, _ek_regular); } } } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors - StaticCommunicator::getStaticCommunicator().allReduce(min_dt, _so_min); + mesh.getCommunicator().allReduce(min_dt, SynchronizerOperation::_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Real min_dt = std::numeric_limits::max(); this->updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; - elem.kind = _ek_regular; for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, _ek_regular)) { elem.type = type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); auto mat_indexes = material_index(type, ghost_type).begin(); auto mat_loc_num = material_local_numbering(type, ghost_type).begin(); Array X(0, nb_nodes_per_element * Model::spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, type, _not_ghost); auto X_el = X.begin(Model::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, type); Real el_c = this->materials[*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(); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); if (this->getDOFManager().hasLumpedMatrix("M")) { auto m_it = this->mass->begin(Model::spatial_dimension); auto m_end = this->mass->end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (UInt n = 0; m_it != m_end; ++n, ++m_it, ++v_it) { const Vector & v = *v_it; const Vector & m = *m_it; 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; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (m(i) > std::numeric_limits::epsilon()) mv2 += v(i) * v(i) * m(i); } } ekin += mv2; } } else if (this->getDOFManager().hasMatrix("M")) { Array Mv(nb_nodes, Model::spatial_dimension); this->getDOFManager().getMatrix("M").matVecMul(*this->velocity, Mv); auto mv_it = Mv.begin(Model::spatial_dimension); auto mv_end = Mv.end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (; mv_it != mv_end; ++mv_it, ++v_it) { ekin += v_it->dot(*mv_it); } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } - StaticCommunicator::getStaticCommunicator().allReduce(ekin, _so_sum); + mesh.getCommunicator().allReduce(ekin, SynchronizerOperation::_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, Model::spatial_dimension); Array filter_element(1, 1, index); getFEEngine().interpolateOnIntegrationPoints(*velocity, vel_on_quad, Model::spatial_dimension, type, _not_ghost, filter_element); Array::vector_iterator vit = vel_on_quad.begin(Model::spatial_dimension); Array::vector_iterator vend = vel_on_quad.end(Model::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(); auto incr_or_velo_it = this->velocity->begin(Model::spatial_dimension); if (this->method == _static) { incr_or_velo_it = this->displacement_increment->begin(Model::spatial_dimension); } auto ext_force_it = external_force->begin(Model::spatial_dimension); auto int_force_it = internal_force->begin(Model::spatial_dimension); auto boun_it = blocked_dofs->begin(Model::spatial_dimension); Real work = 0.; UInt nb_nodes = this->mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n, ++ext_force_it, ++int_force_it, ++boun_it, ++incr_or_velo_it) { const auto & int_force = *int_force_it; const auto & ext_force = *ext_force_it; const auto & boun = *boun_it; const auto & incr_or_velo = *incr_or_velo_it; 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; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (boun(i)) work -= int_force(i) * incr_or_velo(i); else work += ext_force(i) * incr_or_velo(i); } } } - StaticCommunicator::getStaticCommunicator().allReduce(work, _so_sum); + mesh.getCommunicator().allReduce(work, SynchronizerOperation::_sum); if (this->method != _static) work *= this->getTimeStep(); 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.; for (auto & material : materials) energy += material->getEnergy(energy_id); /// reduction sum over all processors - StaticCommunicator::getStaticCommunicator().allReduce(energy, _so_sum); + mesh.getCommunicator().allReduce(energy, SynchronizerOperation::_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); } 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(); for (auto && ghost_type : ghost_types) { for (auto type : mesh.elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { UInt nb_element = this->mesh.getNbElement(type, ghost_type); if (!material_index.exists(type, ghost_type)) { this->material_index.alloc(nb_element, 1, type, ghost_type); this->material_local_numbering.alloc(nb_element, 1, type, ghost_type, UInt(-1)); } else { this->material_index(type, ghost_type).resize(nb_element); this->material_local_numbering(type, ghost_type) .resize(nb_element, UInt(-1)); } } } ElementTypeMapArray filter("new_element_filter", this->getID(), this->getMemoryID()); for (auto & elem : element_list) { 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); for (auto & material : materials) material->onElementsAdded(element_list, event); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved( const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) { // this->getFEEngine().initShapeFunctions(_not_ghost); // this->getFEEngine().initShapeFunctions(_ghost); for (auto & material : materials) { material->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array & nodes_list, const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if (displacement) { displacement->resize(nb_nodes, 0.); ++displacement_release; } if (mass) mass->resize(nb_nodes, 0.); if (velocity) velocity->resize(nb_nodes, 0.); if (acceleration) acceleration->resize(nb_nodes, 0.); if (external_force) external_force->resize(nb_nodes, 0.); if (internal_force) internal_force->resize(nb_nodes, 0.); if (blocked_dofs) blocked_dofs->resize(nb_nodes, 0.); if (current_position) current_position->resize(nb_nodes, 0.); if (previous_displacement) previous_displacement->resize(nb_nodes, 0.); if (displacement_increment) displacement_increment->resize(nb_nodes, 0.); for (auto & material : materials) { material->onNodesAdded(nodes_list, event); } need_to_reassemble_lumped_mass = true; need_to_reassemble_mass = true; 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); ++displacement_release; } 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 (displacement_increment) mesh.removeNodesFromArray(*displacement_increment, new_numbering); if (previous_displacement) mesh.removeNodesFromArray(*previous_displacement, new_numbering); // if (method != _explicit_lumped_mass) { // this->initSolver(); // } } /* -------------------------------------------------------------------------- */ 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 : " << Model::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; for (auto & material : materials) { material->printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeNonLocal() { this->non_local_manager->synchronize(*this, _gst_material_id); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type) { for (auto & mat : materials) { MaterialNonLocalInterface * mat_non_local; if ((mat_non_local = dynamic_cast(mat.get())) == nullptr) continue; ElementTypeMapArray quadrature_points_coordinates( "quadrature_points_coordinates_tmp_nl", this->id, this->memory_id); quadrature_points_coordinates.initialize(this->getFEEngine(), _nb_component = spatial_dimension, _ghost_type = ghost_type); for (auto & type : quadrature_points_coordinates.elementTypes( Model::spatial_dimension, ghost_type)) { this->getFEEngine().computeIntegrationPointsCoordinates( quadrature_points_coordinates(type, ghost_type), type, ghost_type); } mat_non_local->initMaterialNonLocal(); mat_non_local->insertIntegrationPointsInNeighborhoods( ghost_type, quadrature_points_coordinates); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeNonLocalStresses( const GhostType & ghost_type) { for (auto & mat : materials) { try { auto & mat_non_local = dynamic_cast(*mat); mat_non_local.computeNonLocalStresses(ghost_type); } catch (std::bad_cast &) { } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & material : materials) { if (material->isInternal(field_name, kind)) material->flattenInternal(field_name, internal_flat, ghost_type, kind); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateNonLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & mat : materials) { try { auto & mat_non_local = dynamic_cast(*mat); mat_non_local.updateNonLocalInternals(internal_flat, field_name, ghost_type, kind); } catch (std::bad_cast &) { } } } /* -------------------------------------------------------------------------- */ FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) { return dynamic_cast( getFEEngineClassBoundary(name)); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::splitElementByMaterial( - const Array & elements, Array * elements_per_mat) const { + const Array & elements, + std::vector> & elements_per_mat) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; - const Array * mat_indexes = NULL; - const Array * mat_loc_num = NULL; - - Array::const_iterator it = elements.begin(); - Array::const_iterator end = elements.end(); - for (; it != end; ++it) { - Element el = *it; + const Array * mat_indexes = nullptr; + const Array * mat_loc_num = nullptr; + for (auto && el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; mat_indexes = &(this->material_index(el.type, el.ghost_type)); mat_loc_num = &(this->material_local_numbering(el.type, el.ghost_type)); } UInt old_id = el.element; el.element = (*mat_loc_num)(old_id); elements_per_mat[(*mat_indexes)(old_id)].push_back(el); } } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModel::getNbData(const Array & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; UInt nb_nodes_per_element = 0; for (const Element & el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch (tag) { case _gst_material_id: { size += elements.size() * sizeof(UInt); break; } case _gst_smm_mass: { size += nb_nodes_per_element * sizeof(Real) * Model::spatial_dimension; // mass vector break; } case _gst_smm_for_gradu: { size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real); // displacement break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * Model::spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } case _gst_for_dump: { // displacement, velocity, acceleration, residual, force size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real) * 5; break; } default: {} } if (tag != _gst_material_id) { - Array * elements_per_mat = new Array[materials.size()]; - this->splitElementByMaterial(elements, elements_per_mat); - - for (UInt i = 0; i < materials.size(); ++i) { - size += materials[i]->getNbData(elements_per_mat[i], tag); - } - delete[] elements_per_mat; + splitByMaterial(elements, [&](auto && mat, auto && elements) { + size += mat.getNbData(elements, tag); + }); } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); switch (tag) { case _gst_material_id: { this->packElementalDataHelper(material_index, buffer, elements, false, getFEEngine()); break; } case _gst_smm_mass: { packNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { packNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_for_dump: { packNodalDataHelper(*displacement, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*acceleration, buffer, elements, mesh); packNodalDataHelper(*internal_force, buffer, elements, mesh); packNodalDataHelper(*external_force, buffer, elements, mesh); break; } case _gst_smm_boundary: { packNodalDataHelper(*external_force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id) { - Array * elements_per_mat = new Array[materials.size()]; - splitElementByMaterial(elements, elements_per_mat); - - for (UInt i = 0; i < materials.size(); ++i) { - materials[i]->packData(buffer, elements_per_mat[i], tag); - } - - delete[] elements_per_mat; + splitByMaterial(elements, [&](auto && mat, auto && elements) { + mat.packData(buffer, elements, tag); + }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); switch (tag) { case _gst_material_id: { for (auto && element : elements) { UInt recv_mat_index; buffer >> recv_mat_index; UInt & mat_index = material_index(element); if (mat_index != UInt(-1)) continue; // add ghosts element to the correct material mat_index = recv_mat_index; UInt index = materials[mat_index]->addElement(element); material_local_numbering(element) = index; } break; } case _gst_smm_mass: { unpackNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_gradu: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_for_dump: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*acceleration, buffer, elements, mesh); unpackNodalDataHelper(*internal_force, buffer, elements, mesh); unpackNodalDataHelper(*external_force, buffer, elements, mesh); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*external_force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id) { - Array * elements_per_mat = new Array[materials.size()]; - splitElementByMaterial(elements, elements_per_mat); - - for (UInt i = 0; i < materials.size(); ++i) { - materials[i]->unpackData(buffer, elements_per_mat[i], tag); - } - - delete[] elements_per_mat; + splitByMaterial(elements, [&](auto && mat, auto && elements) { + mat.unpackData(buffer, elements, tag); + }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModel::getNbData(const Array & dofs, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch (tag) { case _gst_smm_uv: { size += sizeof(Real) * Model::spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * Model::spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * Model::spatial_dimension; break; } case _gst_for_dump: { size += sizeof(Real) * Model::spatial_dimension * 5; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size * dofs.size(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const Array & dofs, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); switch (tag) { case _gst_smm_uv: { packDOFDataHelper(*displacement, buffer, dofs); packDOFDataHelper(*velocity, buffer, dofs); break; } case _gst_smm_res: { packDOFDataHelper(*internal_force, buffer, dofs); break; } case _gst_smm_mass: { packDOFDataHelper(*mass, buffer, dofs); break; } case _gst_for_dump: { packDOFDataHelper(*displacement, buffer, dofs); packDOFDataHelper(*velocity, buffer, dofs); packDOFDataHelper(*acceleration, buffer, dofs); packDOFDataHelper(*internal_force, buffer, dofs); packDOFDataHelper(*external_force, buffer, dofs); break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const Array & dofs, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); switch (tag) { case _gst_smm_uv: { unpackDOFDataHelper(*displacement, buffer, dofs); unpackDOFDataHelper(*velocity, buffer, dofs); break; } case _gst_smm_res: { unpackDOFDataHelper(*internal_force, buffer, dofs); break; } case _gst_smm_mass: { unpackDOFDataHelper(*mass, buffer, dofs); break; } case _gst_for_dump: { unpackDOFDataHelper(*displacement, buffer, dofs); unpackDOFDataHelper(*velocity, buffer, dofs); unpackDOFDataHelper(*acceleration, buffer, dofs); unpackDOFDataHelper(*internal_force, buffer, dofs); unpackDOFDataHelper(*external_force, buffer, dofs); break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/solver/sparse_matrix.cc b/src/solver/sparse_matrix.cc index 93323ff14..161262b8e 100644 --- a/src/solver/sparse_matrix.cc +++ b/src/solver/sparse_matrix.cc @@ -1,80 +1,80 @@ /** * @file sparse_matrix.cc * * @author Nicolas Richart * * @date creation: Mon Dec 13 2010 * @date last modification: Mon Nov 16 2015 * * @brief implementation of the SparseMatrix 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 /* -------------------------------------------------------------------------- */ #include "dof_manager.hh" #include "sparse_matrix.hh" -#include "static_communicator.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SparseMatrix::SparseMatrix(DOFManager & dof_manager, const MatrixType & matrix_type, const ID & id) : id(id), _dof_manager(dof_manager), matrix_type(matrix_type), size_(dof_manager.getSystemSize()), nb_non_zero(0) { AKANTU_DEBUG_IN(); const auto & comm = _dof_manager.getCommunicator(); this->nb_proc = comm.getNbProc(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix::SparseMatrix(const SparseMatrix & matrix, const ID & id) : SparseMatrix(matrix._dof_manager, matrix.matrix_type, id) { nb_non_zero = matrix.nb_non_zero; } /* -------------------------------------------------------------------------- */ SparseMatrix::~SparseMatrix() {} /* -------------------------------------------------------------------------- */ Array & operator*=(Array & vect, const SparseMatrix & mat) { Array tmp(vect.size(), vect.getNbComponent(), 0.); mat.matVecMul(vect, tmp); vect.copy(tmp); return vect; } /* -------------------------------------------------------------------------- */ void SparseMatrix::add(const SparseMatrix & B, Real alpha) { B.addMeTo(*this, alpha); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/solver/sparse_solver.cc b/src/solver/sparse_solver.cc index abef9dd92..fae1ce3ed 100644 --- a/src/solver/sparse_solver.cc +++ b/src/solver/sparse_solver.cc @@ -1,89 +1,89 @@ /** * @file solver.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Mon Dec 13 2010 * @date last modification: Tue Jan 19 2016 * * @brief Solver interface 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 "mesh.hh" #include "dof_manager.hh" #include "sparse_solver.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SparseSolver::SparseSolver(DOFManager & dof_manager, const ID & matrix_id, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), Parsable(_st_solver, id), _dof_manager(dof_manager), matrix_id(matrix_id), communicator(dof_manager.getCommunicator()) { AKANTU_DEBUG_IN(); // createSynchronizerRegistry(); // this->synch_registry = new SynchronizerRegistry(*this); // synch_registry->registerSynchronizer(this->matrix->getDOFSynchronizer(), // _gst_solver_solution); // OK this is fishy... - const_cast(this->communicator).registerEventHandler(*this); + const_cast(this->communicator).registerEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseSolver::~SparseSolver() { AKANTU_DEBUG_IN(); this->destroyInternalData(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolver::beforeStaticSolverDestroy() { AKANTU_DEBUG_IN(); try { this->destroyInternalData(); } catch (...) { } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolver::createSynchronizerRegistry() { // this->synch_registry = new SynchronizerRegistry(this); } void SparseSolver::onCommunicatorFinalize() { this->destroyInternalData(); } } // akantu diff --git a/src/solver/sparse_solver.hh b/src/solver/sparse_solver.hh index 40eee3664..dbdbf4f8f 100644 --- a/src/solver/sparse_solver.hh +++ b/src/solver/sparse_solver.hh @@ -1,122 +1,122 @@ /** * @file sparse_solver.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Jan 19 2016 * * @brief interface for solvers * * @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_memory.hh" //#include "data_accessor.hh" #include "parsable.hh" -#include "static_communicator.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLVER_HH__ #define __AKANTU_SOLVER_HH__ namespace akantu { enum SolverParallelMethod { _not_parallel, _fully_distributed, _master_slave_distributed }; class DOFManager; } namespace akantu { class SparseSolver : protected Memory, public Parsable, public CommunicatorEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseSolver(DOFManager & dof_manager, const ID & matrix_id, const ID & id = "solver", const MemoryID & memory_id = 0); virtual ~SparseSolver(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver virtual void initialize() = 0; virtual void analysis(){}; virtual void factorize(){}; virtual void solve(){}; protected: virtual void destroyInternalData(){}; public: virtual void beforeStaticSolverDestroy(); void createSynchronizerRegistry(); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void onCommunicatorFinalize(); // inline virtual UInt getNbDataForDOFs(const Array & dofs, // SynchronizationTag tag) const; // inline virtual void packDOFData(CommunicationBuffer & buffer, // const Array & dofs, // SynchronizationTag tag) const; // inline virtual void unpackDOFData(CommunicationBuffer & buffer, // const Array & dofs, // SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// manager handling the dofs for this SparseMatrix solver DOFManager & _dof_manager; /// The id of the associated matrix ID matrix_id; /// How to parallelize the solve SolverParallelMethod parallel_method; /// Communicator used by the solver - const StaticCommunicator & communicator; + const Communicator & communicator; }; } // akantu #endif /* __AKANTU_SOLVER_HH__ */ diff --git a/src/solver/sparse_solver_mumps.cc b/src/solver/sparse_solver_mumps.cc index 4046a993f..4be72ba7a 100644 --- a/src/solver/sparse_solver_mumps.cc +++ b/src/solver/sparse_solver_mumps.cc @@ -1,441 +1,440 @@ /** * @file sparse_solver_mumps.cc * * @author Nicolas Richart * * @date creation: Mon Dec 13 2010 * @date last modification: Tue Jan 19 2016 * * @brief implem of SparseSolverMumps 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 . * * @section DESCRIPTION * * @subsection Ctrl_param Control parameters * * ICNTL(1), * ICNTL(2), * ICNTL(3) : output streams for error, diagnostics, and global messages * * ICNTL(4) : verbose level : 0 no message - 4 all messages * * ICNTL(5) : type of matrix, 0 assembled, 1 elementary * * ICNTL(6) : control the permutation and scaling(default 7) see mumps doc for * more information * * ICNTL(7) : determine the pivot order (default 7) see mumps doc for more * information * * ICNTL(8) : describe the scaling method used * * ICNTL(9) : 1 solve A x = b, 0 solve At x = b * * ICNTL(10) : number of iterative refinement when NRHS = 1 * * ICNTL(11) : > 0 return statistics * * ICNTL(12) : only used for SYM = 2, ordering strategy * * ICNTL(13) : * * ICNTL(14) : percentage of increase of the estimated working space * * ICNTL(15-17) : not used * * ICNTL(18) : only used if ICNTL(5) = 0, 0 matrix centralized, 1 structure on * host and mumps give the mapping, 2 structure on host and distributed matrix * for facto, 3 distributed matrix * * ICNTL(19) : > 0, Shur complement returned * * ICNTL(20) : 0 rhs dense, 1 rhs sparse * * ICNTL(21) : 0 solution in rhs, 1 solution distributed in ISOL_loc and SOL_loc * allocated by user * * ICNTL(22) : 0 in-core, 1 out-of-core * * ICNTL(23) : maximum memory allocatable by mumps pre proc * * ICNTL(24) : controls the detection of "null pivot rows" * * ICNTL(25) : * * ICNTL(26) : * * ICNTL(27) : * * ICNTL(28) : 0 automatic choice, 1 sequential analysis, 2 parallel analysis * * ICNTL(29) : 0 automatic choice, 1 PT-Scotch, 2 ParMetis */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "dof_manager_default.hh" #include "dof_synchronizer.hh" #include "sparse_matrix_aij.hh" #if defined(AKANTU_USE_MPI) -#include "mpi_type_wrapper.hh" -#include "static_communicator_mpi.hh" +#include "mpi_communicator_data.hh" #endif #include "sparse_solver_mumps.hh" /* -------------------------------------------------------------------------- */ // static std::ostream & operator <<(std::ostream & stream, const DMUMPS_STRUC_C // & _this) { // stream << "DMUMPS Data [" << std::endl; // stream << " + job : " << _this.job << std::endl; // stream << " + par : " << _this.par << std::endl; // stream << " + sym : " << _this.sym << std::endl; // stream << " + comm_fortran : " << _this.comm_fortran << std::endl; // stream << " + nz : " << _this.nz << std::endl; // stream << " + irn : " << _this.irn << std::endl; // stream << " + jcn : " << _this.jcn << std::endl; // stream << " + nz_loc : " << _this.nz_loc << std::endl; // stream << " + irn_loc : " << _this.irn_loc << std::endl; // stream << " + jcn_loc : " << _this.jcn_loc << std::endl; // stream << "]"; // return stream; // } namespace akantu { /* -------------------------------------------------------------------------- */ SparseSolverMumps::SparseSolverMumps(DOFManagerDefault & dof_manager, const ID & matrix_id, const ID & id, const MemoryID & memory_id) : SparseSolver(dof_manager, matrix_id, id, memory_id), dof_manager(dof_manager), master_rhs_solution(0, 1) { AKANTU_DEBUG_IN(); this->prank = communicator.whoAmI(); #ifdef AKANTU_USE_MPI this->parallel_method = _fully_distributed; #else // AKANTU_USE_MPI this->parallel_method = _not_parallel; #endif // AKANTU_USE_MPI AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseSolverMumps::~SparseSolverMumps() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::destroyInternalData() { if (this->is_initialized) { this->mumps_data.job = _smj_destroy; // destroy dmumps_c(&this->mumps_data); this->is_initialized = false; } } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::checkInitialized() { if (this->is_initialized) return; this->initialize(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::setOutputLevel() { // Output setup icntl(1) = 0; // error output icntl(2) = 0; // diagnostics output icntl(3) = 0; // information icntl(4) = 0; #if !defined(AKANTU_NDEBUG) DebugLevel dbg_lvl = debug::debugger.getDebugLevel(); if (AKANTU_DEBUG_TEST(dblDump)) { strcpy(this->mumps_data.write_problem, "mumps_matrix.mtx"); } // clang-format off icntl(1) = (dbg_lvl >= dblWarning) ? 6 : 0; icntl(3) = (dbg_lvl >= dblInfo) ? 6 : 0; icntl(2) = (dbg_lvl >= dblTrace) ? 6 : 0; icntl(4) = dbg_lvl >= dblDump ? 4 : dbg_lvl >= dblTrace ? 3 : dbg_lvl >= dblInfo ? 2 : dbg_lvl >= dblWarning ? 1 : 0; // clang-format on #endif } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::initMumpsData() { auto & A = dof_manager.getMatrix(matrix_id); // Default Scaling icntl(8) = 77; // Assembled matrix icntl(5) = 0; /// Default centralized dense second member icntl(20) = 0; icntl(21) = 0; // automatic choice for analysis icntl(28) = 0; UInt size = A.size(); if (prank == 0) { this->master_rhs_solution.resize(size); } this->mumps_data.nz_alloc = 0; this->mumps_data.n = size; switch (this->parallel_method) { case _fully_distributed: icntl(18) = 3; // fully distributed this->mumps_data.nz_loc = A.getNbNonZero(); this->mumps_data.irn_loc = A.getIRN().storage(); this->mumps_data.jcn_loc = A.getJCN().storage(); break; case _not_parallel: case _master_slave_distributed: icntl(18) = 0; // centralized if (prank == 0) { this->mumps_data.nz = A.getNbNonZero(); this->mumps_data.irn = A.getIRN().storage(); this->mumps_data.jcn = A.getJCN().storage(); } else { this->mumps_data.nz = 0; this->mumps_data.irn = NULL; this->mumps_data.jcn = NULL; } break; default: AKANTU_DEBUG_ERROR("This case should not happen!!"); } } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::initialize() { AKANTU_DEBUG_IN(); this->mumps_data.par = 1; // The host is part of computations switch (this->parallel_method) { case _not_parallel: break; case _master_slave_distributed: this->mumps_data.par = 0; // The host is not part of the computations - __attribute__((fallthrough)); + // [[fallthrough]]; un-comment when compiler will get it case _fully_distributed: #ifdef AKANTU_USE_MPI - const StaticCommunicatorMPI & mpi_st_comm = - dynamic_cast( - communicator.getRealStaticCommunicator()); - MPI_Comm mpi_comm = mpi_st_comm.getMPITypeWrapper().getMPICommunicator(); + const MPICommunicatorData & mpi_data = + dynamic_cast( + communicator.getCommunicatorData()); + MPI_Comm mpi_comm = mpi_data.getMPICommunicator(); this->mumps_data.comm_fortran = MPI_Comm_c2f(mpi_comm); #else AKANTU_DEBUG_ERROR( "You cannot use parallel method to solve without activating MPI"); #endif break; } const auto & A = dof_manager.getMatrix(matrix_id); this->mumps_data.sym = 2 * (A.getMatrixType() == _symmetric); this->prank = communicator.whoAmI(); this->setOutputLevel(); this->mumps_data.job = _smj_initialize; // initialize dmumps_c(&this->mumps_data); this->setOutputLevel(); this->is_initialized = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::analysis() { AKANTU_DEBUG_IN(); initMumpsData(); this->mumps_data.job = _smj_analyze; // analyze dmumps_c(&this->mumps_data); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::factorize() { AKANTU_DEBUG_IN(); auto & A = dof_manager.getMatrix(matrix_id); if (parallel_method == _fully_distributed) this->mumps_data.a_loc = A.getA().storage(); else { if (prank == 0) this->mumps_data.a = A.getA().storage(); } this->mumps_data.job = _smj_factorize; // factorize dmumps_c(&this->mumps_data); this->printError(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::solve(Array & x, const Array & b) { auto & synch = this->dof_manager.getSynchronizer(); if (this->prank == 0) { this->master_rhs_solution.resize(this->dof_manager.getSystemSize()); synch.gather(b, this->master_rhs_solution); } else { synch.gather(b); } this->solveInternal(); if (this->prank == 0) { synch.scatter(x, this->master_rhs_solution); } else { synch.scatter(x); } } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::solve() { this->master_rhs_solution.copy(this->dof_manager.getGlobalResidual()); this->solveInternal(); this->dof_manager.setGlobalSolution(this->master_rhs_solution); this->dof_manager.splitSolutionPerDOFs(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::solveInternal() { AKANTU_DEBUG_IN(); this->checkInitialized(); const auto & A = dof_manager.getMatrix(matrix_id); this->setOutputLevel(); if (this->last_profile_release != A.getProfileRelease()) { this->analysis(); this->last_profile_release = A.getProfileRelease(); } if (AKANTU_DEBUG_TEST(dblDump)) { std::stringstream sstr; sstr << prank << ".mtx"; A.saveMatrix("solver_mumps" + sstr.str()); } if (this->last_value_release != A.getValueRelease()) { this->factorize(); this->last_value_release = A.getValueRelease(); } if (prank == 0) { this->mumps_data.rhs = this->master_rhs_solution.storage(); } this->mumps_data.job = _smj_solve; // solve dmumps_c(&this->mumps_data); this->printError(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SparseSolverMumps::printError() { Vector _info_v(2); _info_v[0] = info(1); // to get errors _info_v[1] = -info(1); // to get warnings - StaticCommunicator::getStaticCommunicator().allReduce(_info_v, _so_min); + dof_manager.getCommunicator().allReduce(_info_v, SynchronizerOperation::_min); _info_v[1] = -_info_v[1]; if (_info_v[0] < 0) { // < 0 is an error switch (_info_v[0]) { case -10: AKANTU_DEBUG_ERROR("The matrix is singular"); break; case -9: { icntl(14) += 10; if (icntl(14) != 90) { // std::cout << "Dynamic memory increase of 10%" << std::endl; AKANTU_DEBUG_WARNING("MUMPS dynamic memory is insufficient it will be " "increased allowed to use 10% more"); // change releases to force a recompute this->last_value_release--; this->last_profile_release--; this->solve(); } else { AKANTU_DEBUG_ERROR("The MUMPS workarray is too small INFO(2)=" << info(2) << "No further increase possible"); } break; } default: AKANTU_DEBUG_ERROR("Error in mumps during solve process, check mumps " "user guide INFO(1) = " << _info_v[1]); } } else if (_info_v[1] > 0) { AKANTU_DEBUG_WARNING("Warning in mumps during solve process, check mumps " "user guide INFO(1) = " << _info_v[1]); } } } // akantu diff --git a/src/synchronizer/communication_buffer.hh b/src/synchronizer/communication_buffer.hh index 43f6809c3..f1e86211d 100644 --- a/src/synchronizer/communication_buffer.hh +++ b/src/synchronizer/communication_buffer.hh @@ -1,193 +1,183 @@ /** * @file communication_buffer.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Sun Oct 19 2014 * * @brief Buffer for packing and unpacking data * * @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 "aka_array.hh" +#include "aka_common.hh" #include "element.hh" #ifndef __AKANTU_COMMUNICATION_BUFFER_HH__ #define __AKANTU_COMMUNICATION_BUFFER_HH__ namespace akantu { -template -class CommunicationBufferTemplated { +template class CommunicationBufferTemplated { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit CommunicationBufferTemplated(UInt size) : buffer(size, 1) { ptr_pack = buffer.storage(); ptr_unpack = buffer.storage(); }; CommunicationBufferTemplated() : CommunicationBufferTemplated(0) {} CommunicationBufferTemplated(const CommunicationBufferTemplated & other) { buffer = other.buffer; ptr_pack = buffer.storage(); ptr_unpack = buffer.storage(); } - CommunicationBufferTemplated & operator=(const CommunicationBufferTemplated & other) { + CommunicationBufferTemplated & + operator=(const CommunicationBufferTemplated & other) { if (this != &other) { buffer = other.buffer; ptr_pack = buffer.storage(); ptr_unpack = buffer.storage(); } return *this; } - virtual ~CommunicationBufferTemplated() {}; + virtual ~CommunicationBufferTemplated(){}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: - /// reset to "empty" inline void reset(); /// resize the internal buffer inline void resize(UInt size); /// clear buffer context inline void clear(); private: inline void packResize(UInt size); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: - inline char * storage() { return buffer.storage(); }; - + inline const char * storage() const { return buffer.storage(); }; /* ------------------------------------------------------------------------ */ /* Operators */ /* ------------------------------------------------------------------------ */ public: - /// printing tool template inline std::string extractStream(UInt packet_size); /// packing data - template - inline CommunicationBufferTemplated & operator<< (const T & to_pack); + template + inline CommunicationBufferTemplated & operator<<(const T & to_pack); - template - inline CommunicationBufferTemplated & operator<< (const Vector & to_pack); + template + inline CommunicationBufferTemplated & operator<<(const Vector & to_pack); - template - inline CommunicationBufferTemplated & operator<< (const Matrix & to_pack); + template + inline CommunicationBufferTemplated & operator<<(const Matrix & to_pack); - template - inline CommunicationBufferTemplated & operator<< (const std::vector & to_pack); + template + inline CommunicationBufferTemplated & + operator<<(const std::vector & to_pack); /// unpacking data - template - inline CommunicationBufferTemplated & operator>> (T & to_unpack); + template + inline CommunicationBufferTemplated & operator>>(T & to_unpack); - template - inline CommunicationBufferTemplated & operator>> (Vector & to_unpack); + template + inline CommunicationBufferTemplated & operator>>(Vector & to_unpack); - template - inline CommunicationBufferTemplated & operator>> (Matrix & to_unpack); + template + inline CommunicationBufferTemplated & operator>>(Matrix & to_unpack); - template - inline CommunicationBufferTemplated & operator>> (std::vector & to_unpack); + template + inline CommunicationBufferTemplated & operator>>(std::vector & to_unpack); - inline CommunicationBufferTemplated & operator<< (const std::string & to_pack); - inline CommunicationBufferTemplated & operator>> (std::string & to_unpack); + inline CommunicationBufferTemplated & operator<<(const std::string & to_pack); + inline CommunicationBufferTemplated & operator>>(std::string & to_unpack); private: - - template - inline void packIterable (T & to_pack); - - template - inline void unpackIterable (T & to_pack); + template inline void packIterable(T & to_pack); + template inline void unpackIterable(T & to_pack); /* ------------------------------------------------------------------------ */ /* Accessor */ /* ------------------------------------------------------------------------ */ public: - template - static inline UInt sizeInBuffer(const T & data); - template - static inline UInt sizeInBuffer(const Vector & data); - template - static inline UInt sizeInBuffer(const Matrix & data); + template static inline UInt sizeInBuffer(const T & data); + template static inline UInt sizeInBuffer(const Vector & data); + template static inline UInt sizeInBuffer(const Matrix & data); template static inline UInt sizeInBuffer(const std::vector & data); static inline UInt sizeInBuffer(const std::string & data); /// return the size in bytes of the stored values - inline UInt getPackedSize(){ return ptr_pack - buffer.storage(); }; + inline UInt getPackedSize() const { return ptr_pack - buffer.storage(); }; /// return the size in bytes of data left to be unpacked - inline UInt getLeftToUnpack(){ return buffer.size() - (ptr_unpack - buffer.storage()); }; + inline UInt getLeftToUnpack() const { + return buffer.size() - (ptr_unpack - buffer.storage()); + }; /// return the global size allocated - inline UInt size(){ return buffer.size(); }; + inline UInt size() const { return buffer.size(); }; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: - /// current position for packing char * ptr_pack; /// current position for unpacking char * ptr_unpack; /// storing buffer Array buffer; }; - /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ -#if defined (AKANTU_INCLUDE_INLINE_IMPL) -# include "communication_buffer_inline_impl.cc" +#if defined(AKANTU_INCLUDE_INLINE_IMPL) +#include "communication_buffer_inline_impl.cc" #endif using CommunicationBuffer = CommunicationBufferTemplated; -using DynamicCommunicationBuffer = CommunicationBufferTemplated ; - +using DynamicCommunicationBuffer = CommunicationBufferTemplated; -} // akantu +} // namespace akantu #endif /* __AKANTU_COMMUNICATION_BUFFER_HH__ */ diff --git a/src/synchronizer/communication_descriptor.hh b/src/synchronizer/communication_descriptor.hh index e22d60d03..5856cd7a1 100644 --- a/src/synchronizer/communication_descriptor.hh +++ b/src/synchronizer/communication_descriptor.hh @@ -1,152 +1,153 @@ /** * @file synchronizer_tmpl.hh * * @author Nicolas Richart * * @date Wed Aug 3 13:49:36 2016 * * @brief Implementation of the helper classes for the synchronizer * * @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_array.hh" #include "communication_tag.hh" #include "data_accessor.hh" +#include "communication_request.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ #define __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ namespace akantu { /* ------------------------------------------------------------------------ */ -enum CommunicationSendRecv { _send, _recv, _csr_not_defined }; +enum CommunicationSendRecv { _send, _recv, _csr_not_defined }; /* -------------------------------------------------------------------------- */ struct CommunicationSRType { typedef CommunicationSendRecv type; static const type _begin_ = _send; static const type _end_ = _csr_not_defined; }; typedef safe_enum send_recv_t; namespace { send_recv_t iterate_send_recv{}; } /* ------------------------------------------------------------------------ */ class Communication { public: explicit Communication(const CommunicationSendRecv & type = _csr_not_defined) : _size(0), _type(type) {} Communication(const Communication &) = delete; Communication & operator=(const Communication &) = delete; void resize(UInt size) { this->_size = size; this->_buffer.resize(size); } inline const CommunicationSendRecv & type() const { return this->_type; } inline const UInt & size() const { return this->_size; } inline const CommunicationRequest & request() const { return this->_request; } inline CommunicationRequest & request() { return this->_request; } inline const CommunicationBuffer & buffer() const { return this->_buffer; } inline CommunicationBuffer & buffer() { return this->_buffer; } private: UInt _size; CommunicationBuffer _buffer; CommunicationRequest _request; CommunicationSendRecv _type; }; template class Communications; /* ------------------------------------------------------------------------ */ template class CommunicationDescriptor { public: CommunicationDescriptor(Communication & communication, Array & scheme, Communications & communications, const SynchronizationTag & tag, UInt proc); CommunicationDescriptor(const CommunicationDescriptor &) = default; CommunicationDescriptor & operator=(const CommunicationDescriptor &) = default; /// get the quantity of data in the buffer UInt getNbData() { return communication.size(); } /// set the quantity of data in the buffer void setNbData(UInt size) { communication.resize(size); } /// get the corresponding tag const SynchronizationTag & getTag() const { return tag; } /// get the data buffer CommunicationBuffer & getBuffer(); /// get the corresponding request CommunicationRequest & getRequest(); /// get the communication scheme Array & getScheme(); /// reset the buffer before pack or after unpack void resetBuffer(); /// pack data for entities in the buffer void packData(const DataAccessor & accessor); /// unpack data for entities from the buffer void unpackData(DataAccessor & accessor); /// posts asynchronous send requests void postSend(int hash_id); /// posts asynchronous receive requests void postRecv(int hash_id); /// free the request void freeRequest(); UInt getProc() { return proc; } protected: Communication & communication; Array & scheme; Communications & communications; const SynchronizationTag & tag; UInt proc; UInt rank; UInt counter; }; /* -------------------------------------------------------------------------- */ } // namespace akantu #include "communication_descriptor_tmpl.hh" #endif /* __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ */ diff --git a/src/synchronizer/communication_descriptor_tmpl.hh b/src/synchronizer/communication_descriptor_tmpl.hh index 90d7271f0..7500ee25a 100644 --- a/src/synchronizer/communication_descriptor_tmpl.hh +++ b/src/synchronizer/communication_descriptor_tmpl.hh @@ -1,151 +1,151 @@ /** * @file communication_descriptor_tmpl.hh * * @author Nicolas Richart * * @date Tue Sep 6 14:03:16 2016 * * @brief implementation of CommunicationDescriptor * * @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 "communication_descriptor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATION_DESCRIPTOR_TMPL_HH__ #define __AKANTU_COMMUNICATION_DESCRIPTOR_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* Implementations */ /* -------------------------------------------------------------------------- */ template CommunicationDescriptor::CommunicationDescriptor( Communication & communication, Array & scheme, Communications & communications, const SynchronizationTag & tag, UInt proc) : communication(communication), scheme(scheme), communications(communications), tag(tag), proc(proc), rank(communications.getCommunicator().whoAmI()) { counter = communications.getCounter(tag); } /* -------------------------------------------------------------------------- */ template CommunicationBuffer & CommunicationDescriptor::getBuffer() { return communication.buffer(); } /* -------------------------------------------------------------------------- */ template CommunicationRequest & CommunicationDescriptor::getRequest() { return communication.request(); } /* -------------------------------------------------------------------------- */ template void CommunicationDescriptor::freeRequest() { - const StaticCommunicator & comm = communications.getCommunicator(); - comm.testRequest(communication.request()); + const auto & comm = communications.getCommunicator(); + comm.test(communication.request()); comm.freeCommunicationRequest(communication.request()); communications.decrementPending(tag, communication.type()); } /* -------------------------------------------------------------------------- */ template Array & CommunicationDescriptor::getScheme() { return scheme; } template void CommunicationDescriptor::resetBuffer() { this->communication.buffer().reset(); } /* -------------------------------------------------------------------------- */ template void CommunicationDescriptor::packData( const DataAccessor & accessor) { AKANTU_DEBUG_ASSERT( communication.type() == _send, "Cannot pack data on communication that is not of type _send"); accessor.packData(communication.buffer(), scheme, tag); } /* -------------------------------------------------------------------------- */ template void CommunicationDescriptor::unpackData( DataAccessor & accessor) { AKANTU_DEBUG_ASSERT( communication.type() == _recv, "Cannot unpack data from communication that is not of type _recv"); accessor.unpackData(communication.buffer(), scheme, tag); } /* -------------------------------------------------------------------------- */ template void CommunicationDescriptor::postSend(int hash_id) { AKANTU_DEBUG_ASSERT(communication.type() == _send, "Cannot send a communication that is not of type _send"); Tag comm_tag = Tag::genTag(rank, counter, tag, hash_id); AKANTU_DEBUG_ASSERT(communication.buffer().getPackedSize() == communication.size(), "a problem have been introduced with " << "false sent sizes declaration " << communication.buffer().getPackedSize() << " != " << communication.size()); AKANTU_DEBUG_INFO("Posting send to proc " << proc << " (tag: " << tag << " - " << communication.size() << " data to send) " << " [ " << comm_tag << " ]"); CommunicationRequest & request = communication.request(); request = communications.getCommunicator().asyncSend(communication.buffer(), proc, comm_tag); communications.incrementPending(tag, communication.type()); } /* -------------------------------------------------------------------------- */ template void CommunicationDescriptor::postRecv(int hash_id) { AKANTU_DEBUG_ASSERT(communication.type() == _recv, "Cannot receive data for communication (" << communication.type() << ")that is not of type _recv"); Tag comm_tag = Tag::genTag(proc, counter, tag, hash_id); AKANTU_DEBUG_INFO("Posting receive from proc " << proc << " (tag: " << tag << " - " << communication.size() << " data to receive) " << " [ " << comm_tag << " ]"); CommunicationRequest & request = communication.request(); request = communications.getCommunicator().asyncReceive( communication.buffer(), proc, comm_tag); communications.incrementPending(tag, communication.type()); } } // akantu #endif /* __AKANTU_COMMUNICATION_DESCRIPTOR_TMPL_HH__ */ diff --git a/src/synchronizer/real_static_communicator.hh b/src/synchronizer/communication_request.hh similarity index 85% rename from src/synchronizer/real_static_communicator.hh rename to src/synchronizer/communication_request.hh index c9fd88e0c..ba9c858cb 100644 --- a/src/synchronizer/real_static_communicator.hh +++ b/src/synchronizer/communication_request.hh @@ -1,135 +1,111 @@ /** * @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" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ #define __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ class InternalCommunicationRequest { public: InternalCommunicationRequest(UInt source, UInt dest); virtual ~InternalCommunicationRequest(); 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 CommunicationRequest { public: CommunicationRequest( std::shared_ptr request = nullptr) : request(std::move(request)) {} virtual void free() { request.reset(); } void printself(std::ostream & stream, int indent = 0) const { request->printself(stream, indent); }; UInt getSource() const { return request->getSource(); } UInt getDestination() const { return request->getDestination(); } bool isFreed() const { return request.get() == nullptr; } InternalCommunicationRequest & getInternal() { return *request; } private: std::shared_ptr request; }; /* -------------------------------------------------------------------------- */ class CommunicationStatus { public: AKANTU_GET_MACRO(Source, source, Int); UInt size() const { return size_; } AKANTU_GET_MACRO(Tag, tag, Int); AKANTU_SET_MACRO(Source, source, Int); AKANTU_SET_MACRO(Size, size_, UInt); AKANTU_SET_MACRO(Tag, tag, Int); private: Int source{0}; UInt size_{0}; Int tag{0}; }; /* -------------------------------------------------------------------------- */ /// Datatype to pack pairs for MPI_{MIN,MAX}LOC template struct SCMinMaxLoc { T1 min_max; T2 loc; }; -/* -------------------------------------------------------------------------- */ - -class StaticCommunicator; - -/* -------------------------------------------------------------------------- */ -class RealStaticCommunicator { -public: - RealStaticCommunicator(__attribute__((unused)) int & argc, - __attribute__((unused)) char **& argv) { - prank = -1; - psize = -1; - }; - virtual ~RealStaticCommunicator(){}; - - friend class StaticCommunicator; - - Int getNbProc() { return this->psize; } - Int whoAmI() { return this->prank; } - -protected: - Int prank; - Int psize; -}; - } // akantu #endif /* __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ */ diff --git a/src/synchronizer/communication_tag.hh b/src/synchronizer/communication_tag.hh index 15b1a1ef0..c4ffc2b46 100644 --- a/src/synchronizer/communication_tag.hh +++ b/src/synchronizer/communication_tag.hh @@ -1,119 +1,114 @@ /** * @file communication_tag.hh * * @author Nicolas Richart * * @date Wed Aug 24 12:40:55 2016 * * @brief Description of the communication tags * * @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 "static_communicator.hh" -/* -------------------------------------------------------------------------- */ - #ifndef __AKANTU_COMMUNICATION_TAG_HH__ #define __AKANTU_COMMUNICATION_TAG_HH__ namespace akantu { /** * tag = |__________20_________|___8____|_4_| * | proc | num mes| ct| */ class Tag { public: Tag() : tag(0), hash(0) {} Tag(int val) : tag(val), hash(0) {} Tag(int val, int hash) : tag(val), hash(hash) {} operator int() const { return int(max_tag == 0 ? tag : (uint32_t(tag) % max_tag)); } /// generates a tag template static inline Tag genTag(int proc, UInt msg_count, CommTag tag) { int _tag = ((((proc & 0xFFFFF) << 12) + ((msg_count & 0xFF) << 4) + ((int)tag & 0xF))); Tag t(_tag); return t; } /// generates a tag and hashes it template static inline Tag genTag(int proc, UInt msg_count, CommTag tag, int hash) { Tag t = genTag(proc, msg_count, tag); t.tag = t.tag ^ hash; t.hash = hash; return t; } virtual void printself(std::ostream & stream, int) const { int t = tag; stream << "TAG("; if (hash != 0) t = t ^ hash; stream << (t >> 12) << ":" << (t >> 4 & 0xFF) << ":" << (t & 0xF) << " -> " << std::hex << "0x"<< int(*this); if (hash != 0) stream << " {hash: 0x" << hash << "}"; stream << " [0x" << this->max_tag << "]"; stream << ")"; } enum CommTags : int { _SIZES = 1, _CONNECTIVITY = 2, _DATA = 3, _PARTITIONS = 4, _NB_NODES = 5, _NODES = 6, _COORDINATES = 7, _NODES_TYPE = 8, _MESH_DATA = 9, _ELEMENT_GROUP = 10, _NODE_GROUP = 11, _MODIFY_SCHEME = 12, _GATHER_INITIALIZATION = 1, _GATHER = 2, _SCATTER = 3, _SYNCHRONIZE = 15, }; private: static void setMaxTag(int _max_tag) { max_tag = _max_tag; } friend void initialize(const std::string &, int &, char **&); private: int tag; int hash; static int max_tag; }; /* -------------------------------------------------------------------------- */ inline std::ostream & operator<<(std::ostream & stream, const Tag & _this) { _this.printself(stream, 0); return stream; } /* -------------------------------------------------------------------------- */ } #endif /* __AKANTU_COMMUNICATION_TAG_HH__ */ diff --git a/src/synchronizer/communications.hh b/src/synchronizer/communications.hh index a25243627..528a8274f 100644 --- a/src/synchronizer/communications.hh +++ b/src/synchronizer/communications.hh @@ -1,273 +1,272 @@ /** * @file communications.hh * * @author Nicolas Richart * * @date Wed Aug 24 13:56:14 2016 * * @brief * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "communication_descriptor.hh" +#include "communicator.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_HH__ #define __AKANTU_COMMUNICATIONS_HH__ namespace akantu { -namespace debug { - class CommunicationException : public Exception { - public: - CommunicationException() - : Exception("An exception happen during a communication process.") {} - }; -} // namespace debug - /* -------------------------------------------------------------------------- */ template class Communications { public: using Scheme = Array; protected: using CommunicationPerProcs = std::map; using CommunicationsPerTags = std::map; using CommunicationSchemes = std::map; using Request = std::map>; friend class CommunicationDescriptor; public: using scheme_iterator = typename CommunicationSchemes::iterator; using const_scheme_iterator = typename CommunicationSchemes::const_iterator; /* ------------------------------------------------------------------------ */ class iterator; class tag_iterator; /* ------------------------------------------------------------------------ */ public: CommunicationPerProcs & getCommunications(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ bool hasPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; UInt getPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ iterator begin(const SynchronizationTag & tag, const CommunicationSendRecv & sr); iterator end(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ iterator waitAny(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void waitAll(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void incrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void decrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void freeRequests(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ Scheme & createScheme(UInt proc, const CommunicationSendRecv & sr); void resetSchemes(const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void setCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size, const CommunicationSendRecv & sr); public: - explicit Communications(const StaticCommunicator & communicator); + explicit Communications(const Communicator & communicator); /* ------------------------------------------------------------------------ */ class IterableCommunicationDesc { public: IterableCommunicationDesc(Communications & communications, SynchronizationTag tag, CommunicationSendRecv sr) : communications(communications), tag(std::move(tag)), sr(std::move(sr)) {} - decltype(auto) begin() { return communications.begin(tag, sr); } - decltype(auto) end() { return communications.end(tag, sr); } + auto begin() { return communications.begin(tag, sr); } + auto end() { return communications.end(tag, sr); } private: Communications & communications; SynchronizationTag tag; CommunicationSendRecv sr; }; - decltype(auto) iterateRecv(const SynchronizationTag & tag) { + auto iterateRecv(const SynchronizationTag & tag) { return IterableCommunicationDesc(*this, tag, _recv); } - decltype(auto) iterateSend(const SynchronizationTag & tag) { + auto iterateSend(const SynchronizationTag & tag) { return IterableCommunicationDesc(*this, tag, _send); } /* ------------------------------------------------------------------------ */ - iterator begin_send(const SynchronizationTag & tag); - iterator end_send(const SynchronizationTag & tag); + // iterator begin_send(const SynchronizationTag & tag); + // iterator end_send(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ - iterator begin_recv(const SynchronizationTag & tag); - iterator end_recv(const SynchronizationTag & tag); + // iterator begin_recv(const SynchronizationTag & tag); + // iterator end_recv(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ class IterableTags { public: explicit IterableTags(Communications & communications) : communications(communications) {} decltype(auto) begin() { return communications.begin_tag(); } decltype(auto) end() { return communications.end_tag(); } private: Communications & communications; }; decltype(auto) iterateTags() { return IterableTags(*this); } tag_iterator begin_tag(); tag_iterator end_tag(); /* ------------------------------------------------------------------------ */ bool hasCommunication(const SynchronizationTag & tag) const; void incrementCounter(const SynchronizationTag & tag); UInt getCounter(const SynchronizationTag & tag) const; + bool hasCommunicationSize(const SynchronizationTag & tag) const; + void invalidateSizes(); + /* ------------------------------------------------------------------------ */ bool hasPendingRecv(const SynchronizationTag & tag) const; bool hasPendingSend(const SynchronizationTag & tag) const; - const StaticCommunicator & getCommunicator() const; + const auto & getCommunicator() const; /* ------------------------------------------------------------------------ */ iterator waitAnyRecv(const SynchronizationTag & tag); iterator waitAnySend(const SynchronizationTag & tag); void waitAllRecv(const SynchronizationTag & tag); void waitAllSend(const SynchronizationTag & tag); void freeSendRequests(const SynchronizationTag & tag); void freeRecvRequests(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ class IterableSchemes { public: IterableSchemes(Communications & communications, CommunicationSendRecv sr) : communications(communications), sr(std::move(sr)) {} decltype(auto) begin() { return communications.begin_scheme(sr); } decltype(auto) end() { return communications.end_scheme(sr); } private: Communications & communications; CommunicationSendRecv sr; }; class ConstIterableSchemes { public: ConstIterableSchemes(const Communications & communications, CommunicationSendRecv sr) : communications(communications), sr(std::move(sr)) {} decltype(auto) begin() const { return communications.begin_scheme(sr); } decltype(auto) end() const { return communications.end_scheme(sr); } private: const Communications & communications; CommunicationSendRecv sr; }; decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) { return IterableSchemes(*this, sr); } decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) const { return ConstIterableSchemes(*this, sr); } decltype(auto) iterateSendSchemes() { return IterableSchemes(*this, _send); } decltype(auto) iterateSendSchemes() const { return ConstIterableSchemes(*this, _send); } decltype(auto) iterateRecvSchemes() { return IterableSchemes(*this, _recv); } decltype(auto) iterateRecvSchemes() const { return ConstIterableSchemes(*this, _recv); } scheme_iterator begin_scheme(const CommunicationSendRecv & sr); scheme_iterator end_scheme(const CommunicationSendRecv & sr); const_scheme_iterator begin_scheme(const CommunicationSendRecv & sr) const; const_scheme_iterator end_scheme(const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_send_scheme(); scheme_iterator end_send_scheme(); const_scheme_iterator begin_send_scheme() const; const_scheme_iterator end_send_scheme() const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_recv_scheme(); scheme_iterator end_recv_scheme(); const_scheme_iterator begin_recv_scheme() const; const_scheme_iterator end_recv_scheme() const; /* ------------------------------------------------------------------------ */ Scheme & createSendScheme(UInt proc); Scheme & createRecvScheme(UInt proc); /* ------------------------------------------------------------------------ */ Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr); const Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ void resetSchemes(); /* ------------------------------------------------------------------------ */ void setSendCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void setRecvCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void initializeCommunications(const SynchronizationTag & tag); protected: CommunicationSchemes schemes[2]; CommunicationsPerTags communications[2]; + std::map comm_counter; std::map pending_communications[2]; - const StaticCommunicator & communicator; + std::map comm_size_computed; + + const Communicator & communicator; }; } // namespace akantu #include "communications_tmpl.hh" #endif /* __AKANTU_COMMUNICATIONS_HH__ */ diff --git a/src/synchronizer/communications_tmpl.hh b/src/synchronizer/communications_tmpl.hh index 06798ec9e..6b07dae12 100644 --- a/src/synchronizer/communications_tmpl.hh +++ b/src/synchronizer/communications_tmpl.hh @@ -1,541 +1,560 @@ /** * @file communications_tmpl.hh * * @author Nicolas Richart * * @date Tue Sep 6 17:14:06 2016 * * @brief Implementation of Communications * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "communications.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_TMPL_HH__ #define __AKANTU_COMMUNICATIONS_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template class Communications::iterator { typedef typename std::map::iterator communication_iterator; public: iterator() : communications(NULL) {} iterator(scheme_iterator scheme_it, communication_iterator comm_it, Communications & communications, const SynchronizationTag & tag) : scheme_it(scheme_it), comm_it(comm_it), communications(&communications), tag(tag) {} iterator & operator=(const iterator & other) { if (this != &other) { this->scheme_it = other.scheme_it; this->comm_it = other.comm_it; this->communications = other.communications; this->tag = other.tag; } return *this; } iterator & operator++() { ++scheme_it; ++comm_it; return *this; } CommunicationDescriptor operator*() { AKANTU_DEBUG_ASSERT( scheme_it->first == comm_it->first, "The two iterators are not in phase, something wrong" << " happened, time to take out your favorite debugger (" << scheme_it->first << " != " << comm_it->first << ")"); return CommunicationDescriptor(comm_it->second, scheme_it->second, *communications, tag, scheme_it->first); } bool operator==(const iterator & other) const { return scheme_it == other.scheme_it && comm_it == other.comm_it; } bool operator!=(const iterator & other) const { return scheme_it != other.scheme_it || comm_it != other.comm_it; } private: scheme_iterator scheme_it; communication_iterator comm_it; Communications * communications; SynchronizationTag tag; }; /* -------------------------------------------------------------------------- */ template class Communications::tag_iterator { typedef std::map::const_iterator internal_iterator; public: tag_iterator(const internal_iterator & it) : it(it) {} tag_iterator & operator++() { ++it; return *this; } SynchronizationTag operator*() { return it->first; } bool operator==(const tag_iterator & other) const { return it == other.it; } bool operator!=(const tag_iterator & other) const { return it != other.it; } private: internal_iterator it; }; /* -------------------------------------------------------------------------- */ template typename Communications::CommunicationPerProcs & Communications::getCommunications(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto comm_it = this->communications[sr].find(tag); if (comm_it == this->communications[sr].end()) AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No known communications for the tag: " << tag); return comm_it->second; } /* ---------------------------------------------------------------------- */ template UInt Communications::getPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) const { const std::map & pending = pending_communications[sr]; auto it = pending.find(tag); if (it == pending.end()) return 0; return it->second; } /* -------------------------------------------------------------------------- */ template bool Communications::hasPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) const { return this->hasCommunication(tag) && (this->getPending(tag, sr) != 0); } /* ---------------------------------------------------------------------- */ template typename Communications::iterator Communications::begin(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); return iterator(this->schemes[sr].begin(), comms.begin(), *this, tag); } template typename Communications::iterator Communications::end(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); return iterator(this->schemes[sr].end(), comms.end(), *this, tag); } /* ---------------------------------------------------------------------- */ template typename Communications::iterator Communications::waitAny(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); auto it = comms.begin(); auto end = comms.end(); std::vector requests; for (; it != end; ++it) { auto & request = it->second.request(); - if(!request.isFreed()) + if (!request.isFreed()) requests.push_back(request); } UInt req_id = communicator.waitAny(requests); if (req_id != UInt(-1)) { auto & request = requests[req_id]; UInt proc = sr == _recv ? request.getSource() : request.getDestination(); return iterator(this->schemes[sr].find(proc), comms.find(proc), *this, tag); } else { return this->end(tag, sr); } } /* ---------------------------------------------------------------------- */ template void Communications::waitAll(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { auto & comms = this->getCommunications(tag, sr); auto it = comms.begin(); auto end = comms.end(); std::vector requests; for (; it != end; ++it) { requests.push_back(it->second.request()); } communicator.waitAll(requests); } template void Communications::incrementPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) { ++(pending_communications[sr][tag]); } template void Communications::decrementPending( const SynchronizationTag & tag, const CommunicationSendRecv & sr) { --(pending_communications[sr][tag]); } template void Communications::freeRequests(const SynchronizationTag & tag, const CommunicationSendRecv & sr) { iterator it = this->begin(tag, sr); iterator end = this->end(tag, sr); for (; it != end; ++it) { (*it).freeRequest(); } } /* -------------------------------------------------------------------------- */ template typename Communications::Scheme & Communications::createScheme(UInt proc, const CommunicationSendRecv & sr) { // scheme_iterator it = schemes[sr].find(proc); // if (it != schemes[sr].end()) { // AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), // "Communication scheme(" // << sr // << ") already created for proc: " << // proc); // } return schemes[sr][proc]; } template void Communications::resetSchemes(const CommunicationSendRecv & sr) { scheme_iterator it = this->schemes[sr].begin(); scheme_iterator end = this->schemes[sr].end(); for (; it != end; ++it) { it->second.resize(0); } } /* -------------------------------------------------------------------------- */ template void Communications::setCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size, const CommunicationSendRecv & sr) { - // accessor that creates if it does not exists + // accessor that fails if it does not exists + comm_size_computed[tag] = true; // TODO: need perhaps to be split based on sr auto & comms = this->communications[sr]; - auto & comms_per_tag = comms[tag]; + auto & comms_per_tag = comms.at(tag); - comms_per_tag[proc].resize(size); + comms_per_tag.at(proc).resize(size); } /* -------------------------------------------------------------------------- */ template void Communications::initializeCommunications( const SynchronizationTag & tag) { for (auto t = send_recv_t::begin(); t != send_recv_t::end(); ++t) { pending_communications[*t].insert(std::make_pair(tag, 0)); auto & comms = this->communications[*t]; auto & comms_per_tag = comms.insert(std::make_pair(tag, CommunicationPerProcs())) .first->second; for (auto pair : this->schemes[*t]) { comms_per_tag.emplace(std::piecewise_construct, std::forward_as_tuple(pair.first), std::forward_as_tuple(*t)); } } comm_counter.insert(std::make_pair(tag, 0)); } /* -------------------------------------------------------------------------- */ template -Communications::Communications(const StaticCommunicator & communicator) +Communications::Communications(const Communicator & communicator) : communicator(communicator) {} /* ---------------------------------------------------------------------- */ -template -typename Communications::iterator -Communications::begin_send(const SynchronizationTag & tag) { - return this->begin(tag, _send); -} - -template -typename Communications::iterator -Communications::end_send(const SynchronizationTag & tag) { - return this->end(tag, _send); -} - -/* ---------------------------------------------------------------------- */ -template -typename Communications::iterator -Communications::begin_recv(const SynchronizationTag & tag) { - return this->begin(tag, _recv); -} - -template -typename Communications::iterator -Communications::end_recv(const SynchronizationTag & tag) { - return this->end(tag, _recv); -} +// template +// typename Communications::iterator +// Communications::begin_send(const SynchronizationTag & tag) { +// return this->begin(tag, _send); +// } + +// template +// typename Communications::iterator +// Communications::end_send(const SynchronizationTag & tag) { +// return this->end(tag, _send); +// } + +// /* ---------------------------------------------------------------------- */ +// template +// typename Communications::iterator +// Communications::begin_recv(const SynchronizationTag & tag) { +// return this->begin(tag, _recv); +// } + +// template +// typename Communications::iterator +// Communications::end_recv(const SynchronizationTag & tag) { +// return this->end(tag, _recv); +// } /* -------------------------------------------------------------------------- */ template typename Communications::tag_iterator Communications::begin_tag() { return tag_iterator(comm_counter.begin()); } template typename Communications::tag_iterator Communications::end_tag() { return tag_iterator(comm_counter.end()); } /* -------------------------------------------------------------------------- */ template typename Communications::scheme_iterator Communications::begin_scheme(const CommunicationSendRecv & sr) { return this->schemes[sr].begin(); } template typename Communications::scheme_iterator Communications::end_scheme(const CommunicationSendRecv & sr) { return this->schemes[sr].end(); } /* -------------------------------------------------------------------------- */ template typename Communications::const_scheme_iterator Communications::begin_scheme(const CommunicationSendRecv & sr) const { return this->schemes[sr].begin(); } template typename Communications::const_scheme_iterator Communications::end_scheme(const CommunicationSendRecv & sr) const { return this->schemes[sr].end(); } /* -------------------------------------------------------------------------- */ template typename Communications::scheme_iterator Communications::begin_send_scheme() { return this->begin_scheme(_send); } template typename Communications::scheme_iterator Communications::end_send_scheme() { return this->end_scheme(_send); } /* -------------------------------------------------------------------------- */ template typename Communications::const_scheme_iterator Communications::begin_send_scheme() const { return this->begin_scheme(_send); } template typename Communications::const_scheme_iterator Communications::end_send_scheme() const { return this->end_scheme(_send); } /* -------------------------------------------------------------------------- */ template typename Communications::scheme_iterator Communications::begin_recv_scheme() { return this->begin_scheme(_recv); } template typename Communications::scheme_iterator Communications::end_recv_scheme() { return this->end_scheme(_recv); } /* -------------------------------------------------------------------------- */ template typename Communications::const_scheme_iterator Communications::begin_recv_scheme() const { return this->begin_scheme(_recv); } template typename Communications::const_scheme_iterator Communications::end_recv_scheme() const { return this->end_scheme(_recv); } /* ------------------------------------------------------------------------ */ template bool Communications::hasCommunication( const SynchronizationTag & tag) const { return (communications[_send].find(tag) != communications[_send].end()); } template void Communications::incrementCounter(const SynchronizationTag & tag) { auto it = comm_counter.find(tag); if (it == comm_counter.end()) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No counter initialized in communications for the tags: " << tag); } ++(it->second); } template UInt Communications::getCounter(const SynchronizationTag & tag) const { auto it = comm_counter.find(tag); if (it == comm_counter.end()) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "No counter initialized in communications for the tags: " << tag); } return it->second; } +template +bool Communications::hasCommunicationSize( + const SynchronizationTag & tag) const { + auto it = comm_size_computed.find(tag); + if (it == comm_size_computed.end()) { + return false; + } + + return it->second; +} + +template void Communications::invalidateSizes() { + for (auto && pair : comm_size_computed) { + pair.second = true; + } +} + template bool Communications::hasPendingRecv( const SynchronizationTag & tag) const { return this->hasPending(tag, _recv); } template bool Communications::hasPendingSend( const SynchronizationTag & tag) const { return this->hasPending(tag, _send); } template -const StaticCommunicator & Communications::getCommunicator() const { +const auto & Communications::getCommunicator() const { return communicator; } /* -------------------------------------------------------------------------- */ template typename Communications::iterator Communications::waitAnyRecv(const SynchronizationTag & tag) { return this->waitAny(tag, _recv); } template typename Communications::iterator Communications::waitAnySend(const SynchronizationTag & tag) { return this->waitAny(tag, _send); } template void Communications::waitAllRecv(const SynchronizationTag & tag) { this->waitAll(tag, _recv); } template void Communications::waitAllSend(const SynchronizationTag & tag) { this->waitAll(tag, _send); } template void Communications::freeSendRequests(const SynchronizationTag & tag) { this->freeRequests(tag, _send); } template void Communications::freeRecvRequests(const SynchronizationTag & tag) { this->freeRequests(tag, _recv); } /* -------------------------------------------------------------------------- */ template typename Communications::Scheme & Communications::createSendScheme(UInt proc) { return createScheme(proc, _send); } template typename Communications::Scheme & Communications::createRecvScheme(UInt proc) { return createScheme(proc, _recv); } /* -------------------------------------------------------------------------- */ template void Communications::resetSchemes() { resetSchemes(_send); resetSchemes(_recv); } /* -------------------------------------------------------------------------- */ template typename Communications::Scheme & Communications::getScheme(UInt proc, const CommunicationSendRecv & sr) { return this->schemes[sr].find(proc)->second; } /* -------------------------------------------------------------------------- */ template const typename Communications::Scheme & -Communications::getScheme(UInt proc, const CommunicationSendRecv & sr) const { +Communications::getScheme(UInt proc, + const CommunicationSendRecv & sr) const { return this->schemes[sr].find(proc)->second; } /* -------------------------------------------------------------------------- */ template void Communications::setSendCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size) { this->setCommunicationSize(tag, proc, size, _send); } template void Communications::setRecvCommunicationSize( const SynchronizationTag & tag, UInt proc, UInt size) { this->setCommunicationSize(tag, proc, size, _recv); } -} // akantu +} // namespace akantu #endif /* __AKANTU_COMMUNICATIONS_TMPL_HH__ */ diff --git a/src/synchronizer/communicator.cc b/src/synchronizer/communicator.cc new file mode 100644 index 000000000..3a479e1cb --- /dev/null +++ b/src/synchronizer/communicator.cc @@ -0,0 +1,174 @@ +/** + * @file static_communicator.cc + * + * @author Nicolas Richart + * + * @date creation: Fri Jun 18 2010 + * @date last modification: Tue Jan 19 2016 + * + * @brief implementation of the common part of the static communicator + * + * @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 "communicator.hh" +/* -------------------------------------------------------------------------- */ + +namespace akantu { + +UInt InternalCommunicationRequest::counter = 0; + +/* -------------------------------------------------------------------------- */ +InternalCommunicationRequest::InternalCommunicationRequest(UInt source, + UInt dest) + : source(source), destination(dest) { + this->id = counter++; +} + +/* -------------------------------------------------------------------------- */ +InternalCommunicationRequest::~InternalCommunicationRequest() {} + +/* -------------------------------------------------------------------------- */ +void InternalCommunicationRequest::printself(std::ostream & stream, + int indent) const { + std::string space; + for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) + ; + + stream << space << "CommunicationRequest [" << std::endl; + stream << space << " + id : " << id << std::endl; + stream << space << " + source : " << source << std::endl; + stream << space << " + destination : " << destination << std::endl; + stream << space << "]" << std::endl; +} + +/* -------------------------------------------------------------------------- */ +Communicator::~Communicator() { + FinalizeCommunicatorEvent * event = new FinalizeCommunicatorEvent(*this); + this->sendEvent(*event); + this->barrier(); + delete event; +} + +/* -------------------------------------------------------------------------- */ +Communicator & Communicator::getStaticCommunicator() { + AKANTU_DEBUG_IN(); + + if (!static_communicator) { + int nb_args = 0; + char ** null = nullptr; + static_communicator = std::make_unique(nb_args, null, private_member{}); + } + + AKANTU_DEBUG_OUT(); + return *static_communicator; +} + +/* -------------------------------------------------------------------------- */ +Communicator & Communicator::getStaticCommunicator(int & argc, char **& argv) { + if (!static_communicator) + static_communicator = std::make_unique(argc, argv, private_member{}); + return getStaticCommunicator(); +} + +} // namespace akantu + +#ifdef AKANTU_USE_MPI +# include "communicator_mpi_inline_impl.cc" +#else +# include "communicator_dummy_inline_impl.cc" +#endif + +namespace akantu { +/* -------------------------------------------------------------------------- */ +/* Template instantiation */ +/* -------------------------------------------------------------------------- */ +#define AKANTU_COMM_INSTANTIATE(T) \ + template void Communicator::probe(Int sender, Int tag, \ + CommunicationStatus & status) const; \ + template bool Communicator::asyncProbe( \ + Int sender, Int tag, CommunicationStatus & status) const; \ + template void Communicator::sendImpl( \ + const T * buffer, Int size, Int receiver, Int tag, \ + const CommunicationMode & mode) const; \ + template void Communicator::receiveImpl(T * buffer, Int size, Int sender, \ + Int tag) const; \ + template CommunicationRequest Communicator::asyncSendImpl( \ + const T * buffer, Int size, Int receiver, Int tag, \ + const CommunicationMode & mode) const; \ + template CommunicationRequest Communicator::asyncReceiveImpl( \ + T * buffer, Int size, Int sender, Int tag) const; \ + template void Communicator::allGatherImpl(T * values, int nb_values) \ + const; \ + template void Communicator::allGatherVImpl(T * values, int * nb_values) \ + const; \ + template void Communicator::gatherImpl(T * values, int nb_values, \ + int root) const; \ + template void Communicator::gatherImpl( \ + T * values, int nb_values, T * gathered, int nb_gathered) const; \ + template void Communicator::gatherVImpl(T * values, int * nb_values, \ + int root) const; \ + template void Communicator::broadcastImpl(T * values, int nb_values, \ + int root) const; \ + template void Communicator::allReduceImpl( \ + T * values, int nb_values, const SynchronizerOperation & op) const + +#define MIN_MAX_REAL SCMinMaxLoc + +AKANTU_COMM_INSTANTIATE(bool); +AKANTU_COMM_INSTANTIATE(Real); +AKANTU_COMM_INSTANTIATE(UInt); +AKANTU_COMM_INSTANTIATE(Int); +AKANTU_COMM_INSTANTIATE(char); +AKANTU_COMM_INSTANTIATE(NodeType); +AKANTU_COMM_INSTANTIATE(MIN_MAX_REAL); + +#if AKANTU_INTEGER_SIZE > 4 +AKANTU_COMM_INSTANTIATE(int); +#endif + +// template void Communicator::send>( +// SCMinMaxLoc * buffer, Int size, Int receiver, Int tag); +// template void Communicator::receive>( +// SCMinMaxLoc * buffer, Int size, Int sender, Int tag); +// template CommunicationRequest +// Communicator::asyncSend>( +// SCMinMaxLoc * buffer, Int size, Int receiver, Int tag); +// template CommunicationRequest +// Communicator::asyncReceive>( +// SCMinMaxLoc * buffer, Int size, Int sender, Int tag); +// template void Communicator::probe>( +// Int sender, Int tag, CommunicationStatus & status); +// template void Communicator::allGather>( +// SCMinMaxLoc * values, int nb_values); +// template void Communicator::allGatherV>( +// SCMinMaxLoc * values, int * nb_values); +// template void Communicator::gather>( +// SCMinMaxLoc * values, int nb_values, int root); +// template void Communicator::gatherV>( +// SCMinMaxLoc * values, int * nb_values, int root); +// template void Communicator::broadcast>( +// SCMinMaxLoc * values, int nb_values, int root); +// template void Communicator::allReduce>( +// SCMinMaxLoc * values, int nb_values, +// const SynchronizerOperation & op); +} // akantu diff --git a/src/synchronizer/communicator.hh b/src/synchronizer/communicator.hh new file mode 100644 index 000000000..4ece11d46 --- /dev/null +++ b/src/synchronizer/communicator.hh @@ -0,0 +1,456 @@ +/** + * @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 . + * + */ +/* -------------------------------------------------------------------------- */ +#include "aka_array.hh" +#include "aka_common.hh" +#include "aka_event_handler_manager.hh" +#include "communication_buffer.hh" +#include "communication_request.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_STATIC_COMMUNICATOR_HH__ +#define __AKANTU_STATIC_COMMUNICATOR_HH__ + +namespace akantu { + +namespace debug { + class CommunicationException : public Exception { + public: + CommunicationException() + : Exception("An exception happen during a communication process.") {} + }; +} // namespace debug + +/// @enum SynchronizerOperation reduce operation that the synchronizer can +/// perform +enum class SynchronizerOperation { + _sum, + _min, + _max, + _prod, + _land, + _band, + _lor, + _bor, + _lxor, + _bxor, + _min_loc, + _max_loc, + _null +}; + +enum class CommunicationMode { _auto, _synchronous, _ready }; + +namespace { + int _any_source = -1; +} +} // namespace akantu + +namespace akantu { + +struct CommunicatorInternalData { + virtual ~CommunicatorInternalData() = default; +}; + +class Communicator; + +struct FinalizeCommunicatorEvent { + explicit FinalizeCommunicatorEvent(const Communicator & comm) + : communicator(comm) {} + const Communicator & communicator; +}; + +class CommunicatorEventHandler { +public: + virtual ~CommunicatorEventHandler() {} + virtual void onCommunicatorFinalize() {} + +private: + inline void sendEvent(const FinalizeCommunicatorEvent &) { + onCommunicatorFinalize(); + } + + template friend class EventHandlerManager; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class Communicator : public EventHandlerManager { + struct private_member {}; + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + Communicator(int & argc, char **& argv, const private_member &); + virtual ~Communicator(); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ +public: + /* ------------------------------------------------------------------------ */ + /* Point to Point */ + /* ------------------------------------------------------------------------ */ + template + inline void receive(Array & values, Int sender, Int tag) const { + return this->receiveImpl( + values.storage(), values.size() * values.getNbComponent(), sender, tag); + } + template + inline void + receive(Tensor & values, Int sender, Int tag, + std::enable_if_t::value> * = nullptr) const { + return this->receiveImpl(values.storage(), values.size(), sender, tag); + } + template + inline void receive(CommunicationBufferTemplated & values, + Int sender, Int tag) const { + return this->receiveImpl(values.storage(), values.size(), sender, tag); + } + template + inline void + receive(T & values, Int sender, Int tag, + std::enable_if_t::value> * = nullptr) const { + return this->receiveImpl(&values, 1, sender, tag); + } + /* ------------------------------------------------------------------------ */ + template + inline void + send(const Array & values, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto) const { + return this->sendImpl(values.storage(), + values.size() * values.getNbComponent(), receiver, + tag, mode); + } + template + inline void + send(const Tensor & values, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto, + std::enable_if_t::value> * = nullptr) const { + return this->sendImpl(values.storage(), values.size(), receiver, tag, mode); + } + template + inline void + send(const CommunicationBufferTemplated & values, Int receiver, + Int tag, + const CommunicationMode & mode = CommunicationMode::_auto) const { + return this->sendImpl(values.storage(), values.size(), receiver, tag, mode); + } + template + inline void + send(const T & values, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto, + std::enable_if_t::value> * = nullptr) const { + return this->sendImpl(&values, 1, receiver, tag, mode); + } + + /* ------------------------------------------------------------------------ */ + template + inline CommunicationRequest + asyncSend(const Array & values, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto) const { + return this->asyncSendImpl(values.storage(), + values.size() * values.getNbComponent(), + receiver, tag, mode); + } + template + inline CommunicationRequest + asyncSend(const std::vector & values, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto) const { + return this->asyncSendImpl(values.data(), values.size(), receiver, tag, + mode); + } + + template + inline CommunicationRequest + asyncSend(const Tensor & values, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto, + std::enable_if_t::value> * = nullptr) const { + return this->asyncSendImpl(values.storage(), values.size(), receiver, tag, + mode); + } + template + inline CommunicationRequest + asyncSend(const CommunicationBufferTemplated & values, + Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto) const { + return this->asyncSendImpl(values.storage(), values.size(), receiver, tag, + mode); + } + template + inline CommunicationRequest + asyncSend(const T & values, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto, + std::enable_if_t::value> * = nullptr) const { + return this->asyncSendImpl(&values, 1, receiver, tag, mode); + } + + /* ------------------------------------------------------------------------ */ + template + inline CommunicationRequest asyncReceive(Array & values, Int sender, + Int tag) const { + return this->asyncReceiveImpl( + values.storage(), values.size() * values.getNbComponent(), sender, tag); + } + template + inline CommunicationRequest asyncReceive(std::vector & values, Int sender, + Int tag) const { + return this->asyncReceiveImpl(values.data(), values.size(), sender, tag); + } + + template ::value>> + inline CommunicationRequest asyncReceive(Tensor & values, Int sender, + Int tag) const { + return this->asyncReceiveImpl(values.storage(), values.size(), sender, tag); + } + template + inline CommunicationRequest + asyncReceive(CommunicationBufferTemplated & values, Int sender, + Int tag) const { + return this->asyncReceiveImpl(values.storage(), values.size(), sender, tag); + } + + /* ------------------------------------------------------------------------ */ + template + void probe(Int sender, Int tag, CommunicationStatus & status) const; + + template + bool asyncProbe(Int sender, Int tag, CommunicationStatus & status) const; + + /* ------------------------------------------------------------------------ */ + /* Collectives */ + /* ------------------------------------------------------------------------ */ + template + inline void allReduce(Array & values, + const SynchronizerOperation & op) const { + this->allReduceImpl(values.storage(), + values.size() * values.getNbComponent(), op); + } + + template + inline void + allReduce(Tensor & values, const SynchronizerOperation & op, + std::enable_if_t::value> * = nullptr) const { + this->allReduceImpl(values.storage(), values.size(), op); + } + + template + inline void + allReduce(T & values, const SynchronizerOperation & op, + std::enable_if_t::value> * = nullptr) const { + this->allReduceImpl(&values, 1, op); + } + + /* ------------------------------------------------------------------------ */ + template inline void allGather(Array & values) const { + AKANTU_DEBUG_ASSERT(UInt(psize) == values.size(), + "The array size is not correct"); + this->allGatherImpl(values.storage(), values.getNbComponent()); + } + + template ::value>> + inline void allGather(Tensor & values) const { + AKANTU_DEBUG_ASSERT(UInt(psize) == values.size(), + "The vector size is not correct"); + this->allGatherImpl(values.storage(), 1); + } + + /* ------------------------------------------------------------------------ */ + template + inline void allGatherV(Array & values, Array sizes) const { + this->allGatherVImpl(values.storage(), sizes.storage()); + } + + /* ------------------------------------------------------------------------ */ + template + inline void reduce(Array & values, const SynchronizerOperation & op, + int root = 0) const { + this->reduceImpl(values.storage(), values.size() * values.getNbComponent(), + op, root); + } + + /* ------------------------------------------------------------------------ */ + template + inline void + gather(Tensor & values, int root = 0, + std::enable_if_t::value> * = nullptr) const { + this->gatherImpl(values.storage(), values.getNbComponent(), root); + } + template + inline void + gather(T values, int root = 0, + std::enable_if_t::value> * = nullptr) const { + this->gatherImpl(&values, 1, root); + } + /* ------------------------------------------------------------------------ */ + template + inline void + gather(Tensor & values, Array & gathered, + std::enable_if_t::value> * = nullptr) const { + AKANTU_DEBUG_ASSERT(values.size() == gathered.getNbComponent(), + "The array size is not correct"); + gathered.resize(psize); + this->gatherImpl(values.data(), values.size(), gathered.storage(), + gathered.getNbComponent()); + } + + template + inline void + gather(T values, Array & gathered, + std::enable_if_t::value> * = nullptr) const { + this->gatherImpl(&values, 1, gathered.storage(), 1); + } + + /* ------------------------------------------------------------------------ */ + template + inline void gatherV(Array & values, Array sizes, int root = 0) const { + this->gatherVImpl(values.storage(), sizes.storage(), root); + } + + /* ------------------------------------------------------------------------ */ + template + inline void broadcast(Array & values, int root = 0) const { + this->broadcastImpl(values.storage(), + values.size() * values.getNbComponent(), root); + } + template + inline void broadcast(CommunicationBufferTemplated & values, + int root = 0) const { + this->broadcastImpl(values.storage(), values.size(), root); + } + template inline void broadcast(T & values, int root = 0) const { + this->broadcastImpl(&values, 1, root); + } + + /* ------------------------------------------------------------------------ */ + void barrier() const; + CommunicationRequest asyncBarrier() const; + + /* ------------------------------------------------------------------------ */ + /* Request handling */ + /* ------------------------------------------------------------------------ */ + bool test(CommunicationRequest & request) const; + bool testAll(std::vector & request) const; + void wait(CommunicationRequest & request) const; + void waitAll(std::vector & requests) const; + UInt waitAny(std::vector & requests) const; + inline void freeCommunicationRequest(CommunicationRequest & request) const; + inline void + freeCommunicationRequest(std::vector & requests) const; + + template + inline void + receiveAnyNumber(std::vector & send_requests, + Array receive_buffer, MsgProcessor && processor, + TagGen && tag_gen) const; + +protected: + template + void + sendImpl(const T * buffer, Int size, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto) const; + + template + void receiveImpl(T * buffer, Int size, Int sender, Int tag) const; + + template + CommunicationRequest asyncSendImpl( + const T * buffer, Int size, Int receiver, Int tag, + const CommunicationMode & mode = CommunicationMode::_auto) const; + + template + CommunicationRequest asyncReceiveImpl(T * buffer, Int size, Int sender, + Int tag) const; + + template + void allReduceImpl(T * values, int nb_values, + const SynchronizerOperation & op) const; + + template void allGatherImpl(T * values, int nb_values) const; + template void allGatherVImpl(T * values, int * nb_values) const; + + template + void reduceImpl(T * values, int nb_values, const SynchronizerOperation & op, + int root = 0) const; + template + void gatherImpl(T * values, int nb_values, int root = 0) const; + + template + void gatherImpl(T * values, int nb_values, T * gathered, + int nb_gathered = 0) const; + + template + void gatherVImpl(T * values, int * nb_values, int root = 0) const; + + template + void broadcastImpl(T * values, int nb_values, int root = 0) const; + + /* ------------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------------ */ +public: + Int getNbProc() const { return psize; }; + Int whoAmI() const { return prank; }; + + static Communicator & getStaticCommunicator(); + static Communicator & getStaticCommunicator(int & argc, char **& argv); + + int getMaxTag() const; + int getMinTag() const; + + AKANTU_GET_MACRO(CommunicatorData, (*communicator_data), decltype(auto)); + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +private: + static std::unique_ptr static_communicator; + +protected: + Int prank{0}; + Int psize{1}; + std::unique_ptr communicator_data; +}; + +inline std::ostream & operator<<(std::ostream & stream, + const CommunicationRequest & _this) { + _this.printself(stream); + return stream; +} + +} // namespace akantu + +#include "communicator_inline_impl.hh" + +#endif /* __AKANTU_STATIC_COMMUNICATOR_HH__ */ diff --git a/src/synchronizer/communicator_dummy_inline_impl.cc b/src/synchronizer/communicator_dummy_inline_impl.cc new file mode 100644 index 000000000..d96bb2585 --- /dev/null +++ b/src/synchronizer/communicator_dummy_inline_impl.cc @@ -0,0 +1,107 @@ +/** + * @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 . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "communicator.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +#include +/* -------------------------------------------------------------------------- */ + +namespace akantu { + +template +void Communicator::sendImpl(const T *, Int, Int, Int, + const CommunicationMode &) const {} +template +void Communicator::receiveImpl(T *, Int, Int, Int) const {} + +template +CommunicationRequest +Communicator::asyncSendImpl(const T *, Int, Int, Int, + const CommunicationMode &) const { + return std::shared_ptr( + new InternalCommunicationRequest(0, 0)); +} + +template +CommunicationRequest Communicator::asyncReceiveImpl(T *, Int, Int, Int) const { + return std::shared_ptr( + new InternalCommunicationRequest(0, 0)); +} + +template +void Communicator::probe(Int, Int, CommunicationStatus &) const {} +template +bool Communicator::asyncProbe(Int, Int, CommunicationStatus &) const { return true; } + +bool Communicator::test(CommunicationRequest &) const { return true; } + +void Communicator::wait(CommunicationRequest &) const {} +void Communicator::waitAll(std::vector &) const {} +UInt Communicator::waitAny(std::vector &) const { + return UInt(-1); +} + +void Communicator::barrier() const {} + +template +void Communicator::reduceImpl(T *, int, const SynchronizerOperation &, + int) const {} + +template +void Communicator::allReduceImpl(T *, int, + const SynchronizerOperation &) const {} + +template inline void Communicator::allGatherImpl(T *, int) const {} +template +inline void Communicator::allGatherVImpl(T *, int *) const {} + +template +inline void Communicator::gatherImpl(T *, int, int) const {} +template +void Communicator::gatherImpl(T * values, int nb_values, T * gathered, + int) const { + static_assert(std::is_trivially_copyable{}, + "Cannot send this type of data"); + std::memcpy(gathered, values, nb_values); +} + +template +inline void Communicator::gatherVImpl(T *, int *, int) const {} +template +inline void Communicator::broadcastImpl(T *, int, int) const {} + +int Communicator::getMaxTag() const { return std::numeric_limits::max(); } +int Communicator::getMinTag() const { return 0; } + +} // namespace akantu diff --git a/src/synchronizer/communicator_inline_impl.hh b/src/synchronizer/communicator_inline_impl.hh new file mode 100644 index 000000000..c7d036b92 --- /dev/null +++ b/src/synchronizer/communicator_inline_impl.hh @@ -0,0 +1,89 @@ +/** + * @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 . + * + */ +/* -------------------------------------------------------------------------- */ +#include "communicator.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef __AKANTU_STATIC_COMMUNICATOR_INLINE_IMPL_HH__ +#define __AKANTU_STATIC_COMMUNICATOR_INLINE_IMPL_HH__ + +namespace akantu { +/* -------------------------------------------------------------------------- */ +inline void +Communicator::freeCommunicationRequest(CommunicationRequest & request) const { + request.free(); +} + +/* -------------------------------------------------------------------------- */ +inline void Communicator::freeCommunicationRequest( + std::vector & requests) const { + std::vector::iterator it; + for (it = requests.begin(); it != requests.end(); ++it) { + it->free(); + } +} + +/* -------------------------------------------------------------------------- */ +template +inline void Communicator::receiveAnyNumber( + std::vector & send_requests, Array receive_buffer, + MsgProcessor && processor, TagGen && tag_gen) const { + CommunicationRequest barrier_request; + bool got_all = false, are_send_finished = false; + while (not got_all) { + bool are_receives_ready = true; + while (are_receives_ready) { + auto && tag = std::forward(tag_gen)(); + CommunicationStatus status; + are_receives_ready = + asyncProbe(_any_source, tag, status); + if (are_receives_ready) { + receive_buffer.resize(status.size()); + receive(receive_buffer, status.getSource(), tag); + std::forward(processor)(status.getSource(), + receive_buffer); + } + } + + if (not are_send_finished) { + are_send_finished = testAll(send_requests); + if (are_send_finished) + barrier_request = asyncBarrier(); + } + + if (are_send_finished) { + got_all = test(barrier_request); + } + } +} +} // namespace akantu + +#endif /* __AKANTU_STATIC_COMMUNICATOR_INLINE_IMPL_HH__ */ diff --git a/src/synchronizer/communicator_mpi_inline_impl.cc b/src/synchronizer/communicator_mpi_inline_impl.cc new file mode 100644 index 000000000..a5e72fe98 --- /dev/null +++ b/src/synchronizer/communicator_mpi_inline_impl.cc @@ -0,0 +1,465 @@ +/** + * @file static_communicator_mpi.cc + * + * @author Nicolas Richart + * + * @date creation: Sun Sep 26 2010 + * @date last modification: Thu Jan 21 2016 + * + * @brief StaticCommunicatorMPI 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 "aka_iterators.hh" +#include "communicator.hh" +#include "mpi_communicator_data.hh" +/* -------------------------------------------------------------------------- */ +#include +#include +#include +#include +/* -------------------------------------------------------------------------- */ +#include +/* -------------------------------------------------------------------------- */ + +#if (defined(__GNUC__) || defined(__GNUG__)) +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION < 60000 +namespace std { +template <> struct hash { + using argument_type = akantu::SynchronizerOperation; + size_t operator()(const argument_type & e) const noexcept { + auto ue = underlying_type_t(e); + return uh(ue); + } + + private: + const hash> uh{}; + }; +} // namespace std +#endif +#endif + + +namespace akantu { + +class CommunicationRequestMPI : public InternalCommunicationRequest { +public: + CommunicationRequestMPI(UInt source, UInt dest) + : InternalCommunicationRequest(source, dest), + request(std::make_unique()) {} + MPI_Request & getMPIRequest() { return *request; }; + +private: + std::unique_ptr request; +}; + +namespace { + template inline MPI_Datatype getMPIDatatype(); + MPI_Op getMPISynchronizerOperation(const SynchronizerOperation & op) { + std::unordered_map _operations{ + {SynchronizerOperation::_sum, MPI_SUM}, + {SynchronizerOperation::_min, MPI_MIN}, + {SynchronizerOperation::_max, MPI_MAX}, + {SynchronizerOperation::_prod, MPI_PROD}, + {SynchronizerOperation::_land, MPI_LAND}, + {SynchronizerOperation::_band, MPI_BAND}, + {SynchronizerOperation::_lor, MPI_LOR}, + {SynchronizerOperation::_bor, MPI_BOR}, + {SynchronizerOperation::_lxor, MPI_LXOR}, + {SynchronizerOperation::_bxor, MPI_BXOR}, + {SynchronizerOperation::_min_loc, MPI_MINLOC}, + {SynchronizerOperation::_max_loc, MPI_MAXLOC}, + {SynchronizerOperation::_null, MPI_OP_NULL}}; + return _operations[op]; + } + + template MPI_Datatype inline getMPIDatatype() { + return MPI_DATATYPE_NULL; + } + +#define SPECIALIZE_MPI_DATATYPE(type, mpi_type) \ + template <> MPI_Datatype inline getMPIDatatype() { return mpi_type; } + +#define COMMA , + SPECIALIZE_MPI_DATATYPE(char, MPI_CHAR) + SPECIALIZE_MPI_DATATYPE(float, MPI_FLOAT) + SPECIALIZE_MPI_DATATYPE(double, MPI_DOUBLE) + SPECIALIZE_MPI_DATATYPE(long double, MPI_LONG_DOUBLE) + SPECIALIZE_MPI_DATATYPE(signed int, MPI_INT) + SPECIALIZE_MPI_DATATYPE(NodeType, getMPIDatatype()) + SPECIALIZE_MPI_DATATYPE(unsigned int, MPI_UNSIGNED) + SPECIALIZE_MPI_DATATYPE(signed long int, MPI_LONG) + SPECIALIZE_MPI_DATATYPE(unsigned long int, MPI_UNSIGNED_LONG) + SPECIALIZE_MPI_DATATYPE(signed long long int, MPI_LONG_LONG) + SPECIALIZE_MPI_DATATYPE(unsigned long long int, MPI_UNSIGNED_LONG_LONG) + SPECIALIZE_MPI_DATATYPE(SCMinMaxLoc, MPI_DOUBLE_INT) + SPECIALIZE_MPI_DATATYPE(SCMinMaxLoc, MPI_FLOAT_INT) + SPECIALIZE_MPI_DATATYPE(bool, MPI_CXX_BOOL) + + inline int getMPISource(int src) { + if (src == _any_source) + return MPI_ANY_SOURCE; + return src; + } + + decltype(auto) convertRequests(std::vector & requests) { + std::vector mpi_requests(requests.size()); + + for (auto && request_pair : zip(requests, mpi_requests)) { + auto && req = std::get<0>(request_pair); + auto && mpi_req = std::get<1>(request_pair); + mpi_req = dynamic_cast(req.getInternal()) + .getMPIRequest(); + } + return mpi_requests; + } + +} // namespace + +// this is ugly but shorten the code a lot +#define MPIDATA \ + (*reinterpret_cast(communicator_data.get())) + +/* -------------------------------------------------------------------------- */ +/* Implementation */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +Communicator::Communicator(int & /*argc*/, char **& /*argv*/, + const private_member & /*unused*/) + : communicator_data(std::make_unique()) { + prank = MPIDATA.rank(); + psize = MPIDATA.size(); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::sendImpl(const T * buffer, Int size, Int receiver, Int tag, + const CommunicationMode & mode) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Datatype type = getMPIDatatype(); + + switch (mode) { + case CommunicationMode::_auto: + MPI_Send(buffer, size, type, receiver, tag, communicator); + break; + case CommunicationMode::_synchronous: + MPI_Ssend(buffer, size, type, receiver, tag, communicator); + break; + case CommunicationMode::_ready: + MPI_Rsend(buffer, size, type, receiver, tag, communicator); + break; + } +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::receiveImpl(T * buffer, Int size, Int sender, + Int tag) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Status status; + MPI_Datatype type = getMPIDatatype(); + MPI_Recv(buffer, size, type, getMPISource(sender), tag, communicator, + &status); +} + +/* -------------------------------------------------------------------------- */ +template +CommunicationRequest +Communicator::asyncSendImpl(const T * buffer, Int size, Int receiver, Int tag, + const CommunicationMode & mode) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + CommunicationRequestMPI * request = + new CommunicationRequestMPI(prank, receiver); + MPI_Request & req = request->getMPIRequest(); + + MPI_Datatype type = getMPIDatatype(); + + switch (mode) { + case CommunicationMode::_auto: + MPI_Isend(buffer, size, type, receiver, tag, communicator, &req); + break; + case CommunicationMode::_synchronous: + MPI_Issend(buffer, size, type, receiver, tag, communicator, &req); + break; + case CommunicationMode::_ready: + MPI_Irsend(buffer, size, type, receiver, tag, communicator, &req); + break; + } + return std::shared_ptr(request); +} + +/* -------------------------------------------------------------------------- */ +template +CommunicationRequest Communicator::asyncReceiveImpl(T * buffer, Int size, + Int sender, Int tag) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + CommunicationRequestMPI * request = + new CommunicationRequestMPI(sender, prank); + MPI_Datatype type = getMPIDatatype(); + + MPI_Request & req = request->getMPIRequest(); + MPI_Irecv(buffer, size, type, getMPISource(sender), tag, communicator, &req); + return std::shared_ptr(request); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::probe(Int sender, Int tag, + CommunicationStatus & status) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Status mpi_status; + MPI_Probe(getMPISource(sender), tag, communicator, &mpi_status); + + MPI_Datatype type = getMPIDatatype(); + int count; + MPI_Get_count(&mpi_status, type, &count); + + status.setSource(mpi_status.MPI_SOURCE); + status.setTag(mpi_status.MPI_TAG); + status.setSize(count); +} + +/* -------------------------------------------------------------------------- */ +template +bool Communicator::asyncProbe(Int sender, Int tag, + CommunicationStatus & status) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Status mpi_status; + int test; + MPI_Iprobe(getMPISource(sender), tag, communicator, &test, &mpi_status); + + if (not test) + return false; + + MPI_Datatype type = getMPIDatatype(); + int count; + MPI_Get_count(&mpi_status, type, &count); + + status.setSource(mpi_status.MPI_SOURCE); + status.setTag(mpi_status.MPI_TAG); + status.setSize(count); + return true; +} + +/* -------------------------------------------------------------------------- */ +bool Communicator::test(CommunicationRequest & request) const { + MPI_Status status; + int flag; + CommunicationRequestMPI & req_mpi = + dynamic_cast(request.getInternal()); + MPI_Request & req = req_mpi.getMPIRequest(); + +#if !defined(AKANTU_NDEBUG) + int ret = +#endif + MPI_Test(&req, &flag, &status); + + AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Test."); + return (flag != 0); +} + +/* -------------------------------------------------------------------------- */ +bool Communicator::testAll(std::vector & requests) const { + int are_finished; + auto && mpi_requests = convertRequests(requests); + MPI_Testall(mpi_requests.size(), mpi_requests.data(), &are_finished, + MPI_STATUSES_IGNORE); + return are_finished != 0 ? true : false; +} + +/* -------------------------------------------------------------------------- */ +void Communicator::wait(CommunicationRequest & request) const { + MPI_Status status; + CommunicationRequestMPI & req_mpi = + dynamic_cast(request.getInternal()); + MPI_Request & req = req_mpi.getMPIRequest(); + MPI_Wait(&req, &status); +} + +/* -------------------------------------------------------------------------- */ +void Communicator::waitAll(std::vector & requests) const { + auto && mpi_requests = convertRequests(requests); + MPI_Waitall(mpi_requests.size(), mpi_requests.data(), MPI_STATUSES_IGNORE); +} + +/* -------------------------------------------------------------------------- */ +UInt Communicator::waitAny(std::vector & requests) const { + auto && mpi_requests = convertRequests(requests); + + int pos; + MPI_Waitany(mpi_requests.size(), mpi_requests.data(), &pos, + MPI_STATUSES_IGNORE); + + if (pos != MPI_UNDEFINED) { + return pos; + } else { + return UInt(-1); + } +} + +/* -------------------------------------------------------------------------- */ +void Communicator::barrier() const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Barrier(communicator); +} + +/* -------------------------------------------------------------------------- */ +CommunicationRequest Communicator::asyncBarrier() const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + CommunicationRequestMPI * request = new CommunicationRequestMPI(0, 0); + + MPI_Request & req = request->getMPIRequest(); + MPI_Ibarrier(communicator, &req); + + return std::shared_ptr(request); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::reduceImpl(T * values, int nb_values, + const SynchronizerOperation & op, + int root) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Datatype type = getMPIDatatype(); + + MPI_Reduce(MPI_IN_PLACE, values, nb_values, type, + getMPISynchronizerOperation(op), root, communicator); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::allReduceImpl(T * values, int nb_values, + const SynchronizerOperation & op) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Datatype type = getMPIDatatype(); + + MPI_Allreduce(MPI_IN_PLACE, values, nb_values, type, + getMPISynchronizerOperation(op), communicator); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::allGatherImpl(T * values, int nb_values) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Datatype type = getMPIDatatype(); + + MPI_Allgather(MPI_IN_PLACE, nb_values, type, values, nb_values, type, + communicator); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::allGatherVImpl(T * values, int * nb_values) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + std::vector displs(psize); + displs[0] = 0; + for (int i = 1; i < psize; ++i) { + displs[i] = displs[i - 1] + nb_values[i - 1]; + } + + MPI_Datatype type = getMPIDatatype(); + MPI_Allgatherv(MPI_IN_PLACE, *nb_values, type, values, nb_values, + displs.data(), type, communicator); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::gatherImpl(T * values, int nb_values, int root) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + T *send_buf = NULL, *recv_buf = NULL; + if (prank == root) { + send_buf = (T *)MPI_IN_PLACE; + recv_buf = values; + } else { + send_buf = values; + } + + MPI_Datatype type = getMPIDatatype(); + MPI_Gather(send_buf, nb_values, type, recv_buf, nb_values, type, root, + communicator); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::gatherImpl(T * values, int nb_values, T * gathered, + int nb_gathered) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + T * send_buf = values; + T * recv_buf = gathered; + + if (nb_gathered == 0) + nb_gathered = nb_values; + + MPI_Datatype type = getMPIDatatype(); + MPI_Gather(send_buf, nb_values, type, recv_buf, nb_gathered, type, + this->prank, communicator); +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::gatherVImpl(T * values, int * nb_values, int root) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + int * displs = nullptr; + if (prank == root) { + displs = new int[psize]; + displs[0] = 0; + for (int i = 1; i < psize; ++i) { + displs[i] = displs[i - 1] + nb_values[i - 1]; + } + } + + T *send_buf = NULL, *recv_buf = NULL; + if (prank == root) { + send_buf = (T *)MPI_IN_PLACE; + recv_buf = values; + } else + send_buf = values; + + MPI_Datatype type = getMPIDatatype(); + + MPI_Gatherv(send_buf, *nb_values, type, recv_buf, nb_values, displs, type, + root, communicator); + + if (prank == root) { + delete[] displs; + } +} + +/* -------------------------------------------------------------------------- */ +template +void Communicator::broadcastImpl(T * values, int nb_values, int root) const { + MPI_Comm communicator = MPIDATA.getMPICommunicator(); + MPI_Datatype type = getMPIDatatype(); + MPI_Bcast(values, nb_values, type, root, communicator); +} + +/* -------------------------------------------------------------------------- */ +int Communicator::getMaxTag() const { return MPIDATA.getMaxTag(); } +int Communicator::getMinTag() const { return 0; } + +/* -------------------------------------------------------------------------- */ + +} // namespace akantu diff --git a/src/synchronizer/dof_synchronizer.cc b/src/synchronizer/dof_synchronizer.cc index adb612d2e..d08294119 100644 --- a/src/synchronizer/dof_synchronizer.cc +++ b/src/synchronizer/dof_synchronizer.cc @@ -1,281 +1,281 @@ /** * @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 "aka_iterators.hh" #include "dof_manager_default.hh" #include "mesh.hh" #include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /** * A DOFSynchronizer needs a mesh and the number of degrees of freedom * per node to be created. In the constructor computes the local and global dof * number for each dof. The member * proc_informations (std vector) is resized with the number of mpi * processes. Each entry in the vector is a PerProcInformations object * that contains the interactions of the current mpi process (prank) with the * mpi process corresponding to the position of that entry. Every * ProcInformations object contains one array with the dofs that have * to be sent to prank and a second one with dofs that willl be received form * prank. * This information is needed for the asychronous communications. The * constructor sets up this information. */ DOFSynchronizer::DOFSynchronizer(DOFManagerDefault & dof_manager, const ID & id, MemoryID memory_id, - const StaticCommunicator & comm) + const Communicator & comm) : SynchronizerImpl(id, memory_id, comm), root(0), dof_manager(dof_manager), root_dofs(0, 1, "dofs-to-receive-from-master"), dof_changed(true) { std::vector dof_ids = dof_manager.getDOFIDs(); // Transfers nodes to global equation numbers in new schemes for (ID dof_id : dof_ids) { registerDOFs(dof_id); } this->initScatterGatherCommunicationScheme(); } /* -------------------------------------------------------------------------- */ DOFSynchronizer::~DOFSynchronizer() {} /* -------------------------------------------------------------------------- */ void DOFSynchronizer::registerDOFs(const ID & dof_id) { if (this->nb_proc == 1) return; if (dof_manager.getSupportType(dof_id) != _dst_nodal) return; using const_scheme_iterator = Communications::const_scheme_iterator; const auto equation_numbers = dof_manager.getLocalEquationNumbers(dof_id); const auto & associated_nodes = dof_manager.getDOFsAssociatedNodes(dof_id); const auto & node_synchronizer = dof_manager.getMesh().getNodeSynchronizer(); const auto & node_communications = node_synchronizer.getCommunications(); auto transcode_node_to_global_dof_scheme = [this, &associated_nodes, &equation_numbers](const_scheme_iterator it, const_scheme_iterator end, const CommunicationSendRecv & sr) -> void { for (; it != end; ++it) { auto & scheme = communications.createScheme(it->first, sr); const auto & node_scheme = it->second; for (auto & node : node_scheme) { auto an_begin = associated_nodes.begin(); auto an_it = an_begin; auto an_end = associated_nodes.end(); std::vector global_dofs_per_node; while ((an_it = std::find(an_it, an_end, node)) != an_end) { UInt pos = an_it - an_begin; UInt local_eq_num = equation_numbers(pos); UInt global_eq_num = dof_manager.localToGlobalEquationNumber(local_eq_num); global_dofs_per_node.push_back(global_eq_num); ++an_it; } std::sort(global_dofs_per_node.begin(), global_dofs_per_node.end()); std::transform(global_dofs_per_node.begin(), global_dofs_per_node.end(), global_dofs_per_node.begin(), [this](UInt g) -> UInt { UInt l = dof_manager.globalToLocalEquationNumber(g); return l; }); for (auto & leqnum : global_dofs_per_node) { scheme.push_back(leqnum); } } } }; for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { auto ncs_it = node_communications.begin_scheme(*sr_it); auto ncs_end = node_communications.end_scheme(*sr_it); transcode_node_to_global_dof_scheme(ncs_it, ncs_end, *sr_it); } dof_changed = true; } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::initScatterGatherCommunicationScheme() { AKANTU_DEBUG_IN(); if (this->nb_proc == 1) { dof_changed = false; AKANTU_DEBUG_OUT(); return; } UInt nb_dofs = dof_manager.getLocalSystemSize(); this->root_dofs.clear(); this->master_receive_dofs.clear(); Array dofs_to_send; for (UInt n = 0; n < nb_dofs; ++n) { if (dof_manager.isLocalOrMasterDOF(n)) { auto & receive_per_proc = master_receive_dofs[this->root]; UInt global_dof = dof_manager.localToGlobalEquationNumber(n); root_dofs.push_back(n); receive_per_proc.push_back(global_dof); dofs_to_send.push_back(global_dof); } } if (this->rank == UInt(this->root)) { Array nb_dof_per_proc(this->nb_proc); communicator.gather(dofs_to_send.size(), nb_dof_per_proc); std::vector requests; for (UInt p = 0; p < nb_proc; ++p) { if (p == UInt(this->root)) continue; auto & receive_per_proc = master_receive_dofs[p]; receive_per_proc.resize(nb_dof_per_proc(p)); if (nb_dof_per_proc(p) != 0) requests.push_back(communicator.asyncReceive( receive_per_proc, p, Tag::genTag(p, 0, Tag::_GATHER_INITIALIZATION, this->hash_id))); } communicator.waitAll(requests); communicator.freeCommunicationRequest(requests); } else { communicator.gather(dofs_to_send.size(), this->root); AKANTU_DEBUG(dblDebug, "I have " << nb_dofs << " dofs (" << dofs_to_send.size() << " to send to master proc"); if (dofs_to_send.size() != 0) communicator.send(dofs_to_send, this->root, Tag::genTag(this->rank, 0, Tag::_GATHER_INITIALIZATION, this->hash_id)); } dof_changed = false; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool DOFSynchronizer::hasChanged() { - communicator.allReduce(dof_changed, _so_lor); + communicator.allReduce(dof_changed, SynchronizerOperation::_lor); return dof_changed; } /* -------------------------------------------------------------------------- */ void DOFSynchronizer::onNodesAdded(const Array & nodes_list) { auto dof_ids = dof_manager.getDOFIDs(); const auto & node_synchronizer = dof_manager.getMesh().getNodeSynchronizer(); const auto & node_communications = node_synchronizer.getCommunications(); std::set relevant_nodes; std::map> nodes_per_proc[2]; for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { auto sit = node_communications.begin_scheme(*sr_it); auto send = node_communications.end_scheme(*sr_it); for (; sit != send; ++sit) { auto proc = sit->first; const auto & scheme = sit->second; for (auto node : nodes_list) { if (scheme.find(node) == UInt(-1)) continue; relevant_nodes.insert(node); nodes_per_proc[*sr_it][proc].push_back(node); } } } std::map> dofs_per_proc[2]; for (auto & dof_id : dof_ids) { const auto & associated_nodes = dof_manager.getDOFsAssociatedNodes(dof_id); const auto & local_equation_numbers = dof_manager.getEquationsNumbers(dof_id); for (auto tuple : zip(associated_nodes, local_equation_numbers)) { UInt assoc_node; UInt local_eq_num; std::tie(assoc_node, local_eq_num) = tuple; for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { for (auto & pair : nodes_per_proc[*sr_it]) { if (std::find(pair.second.end(), pair.second.end(), assoc_node) != pair.second.end()) { dofs_per_proc[*sr_it][pair.first].push_back(local_eq_num); } } } } } for (auto sr_it = send_recv_t::begin(); sr_it != send_recv_t::end(); ++sr_it) { for (auto & pair : dofs_per_proc[*sr_it]) { std::sort(pair.second.begin(), pair.second.end(), [this] (UInt la, UInt lb) -> bool { UInt ga = dof_manager.localToGlobalEquationNumber(la); UInt gb = dof_manager.localToGlobalEquationNumber(lb); return ga < gb; }); auto & scheme = communications.getScheme(pair.first, *sr_it); for(auto leq : pair.second) { scheme.push_back(leq); } } } dof_changed = true; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/dof_synchronizer.hh b/src/synchronizer/dof_synchronizer.hh index f7b6f19ba..9e1eeb9a7 100644 --- a/src/synchronizer/dof_synchronizer.hh +++ b/src/synchronizer/dof_synchronizer.hh @@ -1,112 +1,113 @@ /** * @file dof_synchronizer.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Fri Jun 17 2011 * @date last modification: Tue Dec 08 2015 * * @brief Synchronize Array of DOFs * * @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_array.hh" #include "aka_common.hh" #include "synchronizer_impl.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Mesh; class DOFManagerDefault; } #ifndef __AKANTU_DOF_SYNCHRONIZER_HH__ #define __AKANTU_DOF_SYNCHRONIZER_HH__ namespace akantu { class DOFSynchronizer : public SynchronizerImpl { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DOFSynchronizer( DOFManagerDefault & dof_manager, const ID & id = "dof_synchronizer", MemoryID memory_id = 0, - const StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator()); + const Communicator & comm = Communicator::getStaticCommunicator()); virtual ~DOFSynchronizer(); virtual void registerDOFs(const ID & dof_id); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template /// Gather the DOF value on the root proccessor void gather(const Array & to_gather, Array & gathered); /// Gather the DOF value on the root proccessor template void gather(const Array & to_gather); /// Scatter a DOF Array form root to all processors template void scatter(Array & scattered, const Array & to_scatter); /// Scatter a DOF Array form root to all processors template void scatter(Array & scattered); template void synchronize(Array & vector) const; template