diff --git a/python/mesa_pd.py b/python/mesa_pd.py index b567d0876b4369a83fa172cdfba95d13cdfd9fee..c80bcf232a49016c87a03030b790ffb72ea426fb 100755 --- a/python/mesa_pd.py +++ b/python/mesa_pd.py @@ -105,6 +105,7 @@ if __name__ == '__main__': mpd.add(kernel.VelocityVerletWithShape()) mpd.add(mpi.BroadcastProperty()) + mpd.add(mpi.ClearGhostOwnerSync()) mpd.add(mpi.ClearNextNeighborSync()) mpd.add(mpi.Notifications(ps)) mpd.add(mpi.ReduceContactHistory()) diff --git a/python/mesa_pd/mpi/ClearGhostOwnerSync.py b/python/mesa_pd/mpi/ClearGhostOwnerSync.py new file mode 100644 index 0000000000000000000000000000000000000000..8fe03ef54b90f948f63e2ce8b3fbc0060cb39728 --- /dev/null +++ b/python/mesa_pd/mpi/ClearGhostOwnerSync.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +from mesa_pd.accessor import create_access +from mesa_pd.utility import generate_file + + +class ClearGhostOwnerSync: + def __init__(self): + self.context = {'properties': [], 'interface': []} + + self.context['interface'].append( + create_access("flags", 'walberla::mesa_pd::data::particle_flags::FlagT', access='g')) + self.context['interface'].append(create_access('ghostOwners', 'std::vector<int>', access='r')) + self.context['interface'].append(create_access('neighborState', 'std::unordered_set<walberla::mpi::MPIRank>', + access='r')) + + def generate(self, module): + ctx = {'module': module, **self.context} + generate_file(module['module_path'], 'mpi/ClearGhostOwnerSync.templ.h', ctx) diff --git a/python/mesa_pd/mpi/__init__.py b/python/mesa_pd/mpi/__init__.py index 223a70c04e5a71d119b2ad58a69167dafee01543..37f0854ad44a0da7adb8420cf7f11578028d8d5c 100644 --- a/python/mesa_pd/mpi/__init__.py +++ b/python/mesa_pd/mpi/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from .BroadcastProperty import BroadcastProperty +from .ClearGhostOwnerSync import ClearGhostOwnerSync from .ClearNextNeighborSync import ClearNextNeighborSync from .Notifications import Notifications from .ReduceContactHistory import ReduceContactHistory @@ -11,6 +12,7 @@ from .SyncNextNeighbors import SyncNextNeighbors from .SyncNextNeighborsNoGhosts import SyncNextNeighborsNoGhosts __all__ = ['BroadcastProperty', + 'ClearGhostOwnerSync', 'ClearNextNeighborSync', 'ReduceContactHistory', 'ReduceProperty', diff --git a/python/mesa_pd/templates/mpi/ClearGhostOwnerSync.templ.h b/python/mesa_pd/templates/mpi/ClearGhostOwnerSync.templ.h new file mode 100644 index 0000000000000000000000000000000000000000..4194abe69f8972f0f001d1040c713450e96cac18 --- /dev/null +++ b/python/mesa_pd/templates/mpi/ClearGhostOwnerSync.templ.h @@ -0,0 +1,89 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla 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 General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ClearGhostOwnerSync.h +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +//====================================================================================================================== +// +// THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!! +// +//====================================================================================================================== + +#pragma once + +#include <mesa_pd/data/Flags.h> + +namespace walberla { +namespace mesa_pd { +namespace mpi { + +/** + * Clear all ghost particles and reset ghost owner information + * + * This kernel requires the following particle accessor interface + * \code + {%- for prop in interface %} + {%- if 'g' in prop.access %} + * const {{prop.type}}& get{{prop.name | capFirst}}(const size_t p_idx) const; + {%- endif %} + {%- if 's' in prop.access %} + * void set{{prop.name | capFirst}}(const size_t p_idx, const {{prop.type}}& v); + {%- endif %} + {%- if 'r' in prop.access %} + * {{prop.type}}& get{{prop.name | capFirst}}Ref(const size_t p_idx); + {%- endif %} + * + {%- endfor %} + * \endcode + * + * \post All ghost particles are deleted. + * \post All ghost owners are reset. + * \post All cached information is reset. + * + * \ingroup mesa_pd_mpi + */ +class ClearGhostOwnerSync +{ +public: + template <typename Accessor> + void operator()(Accessor& ac) const; +}; + +template <typename Accessor> +void ClearGhostOwnerSync::operator()(Accessor& ac) const +{ + for (size_t idx = 0; idx < ac.size(); ) + { + if (data::particle_flags::isSet( ac.getFlags(idx), data::particle_flags::GHOST)) + { + //ghost particle + idx = ac.erase(idx); + continue; + } else + { + //local particle + ac.getGhostOwnersRef(idx).clear(); + ac.getNeighborStateRef(idx).clear(); + } + ++idx; + } +} + +} // namespace mpi +} // namespace mesa_pd +} // namespace walberla diff --git a/src/mesa_pd/mpi/ClearGhostOwnerSync.h b/src/mesa_pd/mpi/ClearGhostOwnerSync.h new file mode 100644 index 0000000000000000000000000000000000000000..aff6b8dcc290d382b79f6acb2ec53c11714fbf28 --- /dev/null +++ b/src/mesa_pd/mpi/ClearGhostOwnerSync.h @@ -0,0 +1,83 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla 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 General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ClearGhostOwnerSync.h +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +//====================================================================================================================== +// +// THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!! +// +//====================================================================================================================== + +#pragma once + +#include <mesa_pd/data/Flags.h> + +namespace walberla { +namespace mesa_pd { +namespace mpi { + +/** + * Clear all ghost particles and reset ghost owner information + * + * This kernel requires the following particle accessor interface + * \code + * const walberla::mesa_pd::data::particle_flags::FlagT& getFlags(const size_t p_idx) const; + * + * std::vector<int>& getGhostOwnersRef(const size_t p_idx); + * + * std::unordered_set<walberla::mpi::MPIRank>& getNeighborStateRef(const size_t p_idx); + * + * \endcode + * + * \post All ghost particles are deleted. + * \post All ghost owners are reset. + * \post All cached information is reset. + * + * \ingroup mesa_pd_mpi + */ +class ClearGhostOwnerSync +{ +public: + template <typename Accessor> + void operator()(Accessor& ac) const; +}; + +template <typename Accessor> +void ClearGhostOwnerSync::operator()(Accessor& ac) const +{ + for (size_t idx = 0; idx < ac.size(); ) + { + if (data::particle_flags::isSet( ac.getFlags(idx), data::particle_flags::GHOST)) + { + //ghost particle + idx = ac.erase(idx); + continue; + } else + { + //local particle + ac.getGhostOwnersRef(idx).clear(); + ac.getNeighborStateRef(idx).clear(); + } + ++idx; + } +} + +} // namespace mpi +} // namespace mesa_pd +} // namespace walberla \ No newline at end of file diff --git a/tests/mesa_pd/CMakeLists.txt b/tests/mesa_pd/CMakeLists.txt index 5cd319e21cc690fa3b3dd97a7a6811a52ee25341..81a8a74cad16373f4b5f39856e7c25a4d13a0f2f 100644 --- a/tests/mesa_pd/CMakeLists.txt +++ b/tests/mesa_pd/CMakeLists.txt @@ -161,6 +161,12 @@ waLBerla_execute_test( NAME MESA_PD_Kernel_VelocityVerletWithShape ) waLBerla_compile_test( NAME MESA_PD_MPI_BroadcastProperty FILES mpi/BroadcastProperty.cpp DEPENDS core ) waLBerla_execute_test( NAME MESA_PD_MPI_BroadcastProperty PROCESSES 8 ) +waLBerla_compile_test( NAME MESA_PD_MPI_ClearGhostOwnerSync FILES mpi/ClearGhostOwnerSync.cpp DEPENDS blockforest core) +waLBerla_execute_test( NAME MESA_PD_MPI_ClearGhostOwnerSync PROCESSES 8 ) + +waLBerla_compile_test( NAME MESA_PD_MPI_ClearNextNeighborSync FILES mpi/ClearNextNeighborSync.cpp DEPENDS blockforest core ) +waLBerla_execute_test( NAME MESA_PD_MPI_ClearNextNeighborSync PROCESSES 8 ) + waLBerla_compile_test( NAME MESA_PD_MPI_Notifications FILES mpi/Notifications.cpp DEPENDS core ) waLBerla_execute_test( NAME MESA_PD_MPI_Notifications ) diff --git a/tests/mesa_pd/mpi/ClearGhostOwnerSync.cpp b/tests/mesa_pd/mpi/ClearGhostOwnerSync.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84bd3f1bc452e4343d228055bb0ed571542e46e3 --- /dev/null +++ b/tests/mesa_pd/mpi/ClearGhostOwnerSync.cpp @@ -0,0 +1,114 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla 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 General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ClearGhostOwnerSync.cpp +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +#include <mesa_pd/data/DataTypes.h> +#include <mesa_pd/domain/BlockForestDomain.h> +#include <mesa_pd/data/ParticleAccessor.h> +#include <mesa_pd/data/ParticleStorage.h> +#include <mesa_pd/data/ShapeStorage.h> +#include <mesa_pd/mpi/ClearGhostOwnerSync.h> +#include <mesa_pd/mpi/SyncGhostOwners.h> + +#include <blockforest/Initialization.h> +#include <core/debug/TestSubsystem.h> +#include <core/Environment.h> +#include <core/grid_generator/SCIterator.h> +#include <core/mpi/Reduce.h> +#include <core/logging/Logging.h> + +namespace walberla { +namespace mesa_pd { + +int main(int argc, char **argv) +{ + walberla::debug::enterTestMode(); + Environment env(argc, argv); + WALBERLA_UNUSED(env); + + const real_t spacing = real_c(1); + const real_t radius = real_c(0.5); + + WALBERLA_LOG_INFO_ON_ROOT("*** MESA_PD ***"); + auto ps = std::make_shared<data::ParticleStorage>(100); + auto ac = data::ParticleAccessor(ps); + auto ss = std::make_shared<data::ShapeStorage>(); + + auto smallSphere = ss->create<data::Sphere>(radius); + ss->shapes[smallSphere]->updateMassAndInertia(real_t(2707)); + + WALBERLA_LOG_INFO_ON_ROOT("*** BLOCKFOREST ***"); + // create forest + auto forest = blockforest::createBlockForest(math::AABB(real_t(0), + real_t(0), + real_t(0), + real_t(6), + real_t(6), + real_t(6)), + Vector3<uint_t>(2, 2, 2), + Vector3<bool>(true, true, true)); + domain::BlockForestDomain domain(forest); + + WALBERLA_CHECK_EQUAL(forest->size(), 1, "please run with 8 processes -> 1 process per block"); + + WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - START ***"); + for (auto &iBlk : *forest) + { + for (auto pt : grid_generator::SCGrid(iBlk.getAABB(), Vector3<real_t>(spacing, spacing, spacing) * real_c(0.2), + spacing)) + { + WALBERLA_CHECK(iBlk.getAABB().contains(pt)); + + auto p = ps->create(); + p->setPosition(pt); + p->setInteractionRadius(radius); + p->setShapeID(smallSphere); + p->setOwner(walberla::mpi::MPIManager::instance()->rank()); + } + } + int64_t numParticles = int64_c(ps->size()); + walberla::mpi::reduceInplace(numParticles, walberla::mpi::SUM); + WALBERLA_LOG_INFO_ON_ROOT("#particles created: " << numParticles); + + WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - END ***"); + + mesa_pd::mpi::ClearGhostOwnerSync CGO; + mesa_pd::mpi::SyncGhostOwners SGO; + SGO(*ps, domain); + SGO(*ps, domain); + SGO(*ps, domain); + CGO(ac); + + for(auto p : *ps) + { + using namespace mesa_pd::data::particle_flags; + WALBERLA_CHECK(!isSet(p.getFlags(), GHOST)); + WALBERLA_CHECK(p.getGhostOwners().empty()); + WALBERLA_CHECK(p.getNeighborState().empty()); + } + + return EXIT_SUCCESS; +} +} //namespace mesa_pd +} // namespace walberla + +int main( int argc, char* argv[] ) +{ + return walberla::mesa_pd::main( argc, argv ); +} diff --git a/tests/mesa_pd/mpi/ClearNextNeighborSync.cpp b/tests/mesa_pd/mpi/ClearNextNeighborSync.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19c1ebfa6ef9cfba8099a64e3fb415ac3c8e0261 --- /dev/null +++ b/tests/mesa_pd/mpi/ClearNextNeighborSync.cpp @@ -0,0 +1,113 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla 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 General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ClearNextNeighborSync.cpp +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +#include <mesa_pd/data/DataTypes.h> +#include <mesa_pd/domain/BlockForestDomain.h> +#include <mesa_pd/data/ParticleAccessor.h> +#include <mesa_pd/data/ParticleStorage.h> +#include <mesa_pd/data/ShapeStorage.h> +#include <mesa_pd/mpi/ClearNextNeighborSync.h> +#include <mesa_pd/mpi/SyncNextNeighbors.h> + +#include <blockforest/Initialization.h> +#include <core/debug/TestSubsystem.h> +#include <core/Environment.h> +#include <core/grid_generator/SCIterator.h> +#include <core/mpi/Reduce.h> +#include <core/logging/Logging.h> + +namespace walberla { +namespace mesa_pd { + +int main(int argc, char **argv) +{ + walberla::debug::enterTestMode(); + Environment env(argc, argv); + WALBERLA_UNUSED(env); + + const real_t spacing = real_c(1); + const real_t radius = real_c(0.5); + + WALBERLA_LOG_INFO_ON_ROOT("*** MESA_PD ***"); + auto ps = std::make_shared<data::ParticleStorage>(100); + auto ac = data::ParticleAccessor(ps); + auto ss = std::make_shared<data::ShapeStorage>(); + + auto smallSphere = ss->create<data::Sphere>(radius); + ss->shapes[smallSphere]->updateMassAndInertia(real_t(2707)); + + WALBERLA_LOG_INFO_ON_ROOT("*** BLOCKFOREST ***"); + // create forest + auto forest = blockforest::createBlockForest(math::AABB(real_t(0), + real_t(0), + real_t(0), + real_t(6), + real_t(6), + real_t(6)), + Vector3<uint_t>(2, 2, 2), + Vector3<bool>(true, true, true)); + domain::BlockForestDomain domain(forest); + + WALBERLA_CHECK_EQUAL(forest->size(), 1, "please run with 8 processes -> 1 process per block"); + + WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - START ***"); + for (auto &iBlk : *forest) + { + for (auto pt : grid_generator::SCGrid(iBlk.getAABB(), Vector3<real_t>(spacing, spacing, spacing) * real_c(0.2), + spacing)) + { + WALBERLA_CHECK(iBlk.getAABB().contains(pt)); + + auto p = ps->create(); + p->setPosition(pt); + p->setInteractionRadius(radius); + p->setShapeID(smallSphere); + p->setOwner(walberla::mpi::MPIManager::instance()->rank()); + } + } + int64_t numParticles = int64_c(ps->size()); + walberla::mpi::reduceInplace(numParticles, walberla::mpi::SUM); + WALBERLA_LOG_INFO_ON_ROOT("#particles created: " << numParticles); + + WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - END ***"); + + mesa_pd::mpi::ClearNextNeighborSync CSNN; + mesa_pd::mpi::SyncNextNeighbors SNN; + SNN(*ps, domain); + SNN(*ps, domain); + SNN(*ps, domain); + CSNN(ac); + + for(auto p : *ps) + { + using namespace mesa_pd::data::particle_flags; + WALBERLA_CHECK(!isSet(p.getFlags(), GHOST)); + WALBERLA_CHECK(p.getGhostOwners().empty()); + } + + return EXIT_SUCCESS; +} +} //namespace mesa_pd +} // namespace walberla + +int main( int argc, char* argv[] ) +{ + return walberla::mesa_pd::main( argc, argv ); +}