From 5b53ddcd38470d94374ad45272e9181683352823 Mon Sep 17 00:00:00 2001 From: Sebastian Eibl <sebastian.eibl@fau.de> Date: Wed, 31 May 2017 17:07:04 +0200 Subject: [PATCH] made save/load block data work for pe --- src/pe/basic.h | 1 + src/pe/ccd/HashGrids.cpp | 24 +++++++ src/pe/ccd/HashGrids.h | 1 + src/pe/ccd/ICCD.h | 3 +- src/pe/rigidbody/StorageDataHandling.h | 25 ++++--- src/pe/utility/CreateWorld.cpp | 91 ++++++++++++++++++-------- src/pe/utility/CreateWorld.h | 8 +++ tests/pe/CMakeLists.txt | 3 + tests/pe/SerializeDeserialize.cpp | 60 +++++++++-------- 9 files changed, 152 insertions(+), 64 deletions(-) diff --git a/src/pe/basic.h b/src/pe/basic.h index 874531d82..25bf84ca0 100644 --- a/src/pe/basic.h +++ b/src/pe/basic.h @@ -47,4 +47,5 @@ #include "pe/synchronization/SyncNextNeighbors.h" #include "pe/synchronization/SyncShadowOwners.h" +#include "pe/utility/CreateWorld.h" #include "pe/utility/GetBody.h" diff --git a/src/pe/ccd/HashGrids.cpp b/src/pe/ccd/HashGrids.cpp index b135767f8..e126e554d 100644 --- a/src/pe/ccd/HashGrids.cpp +++ b/src/pe/ccd/HashGrids.cpp @@ -746,6 +746,30 @@ void HashGrids::clear() } //************************************************************************************************* + +//************************************************************************************************* +/*!\brief clears all bodies from the hash grid and reloads bodies from bodystorage and shadowbodystorage + * + * \return void + */ +void HashGrids::reloadBodies() +{ + clear(); + + for (auto bodyIt = bodystorage_.begin(); bodyIt != bodystorage_.end(); ++bodyIt) + { + add( *bodyIt ); + } + if( &bodystorage_ != &bodystorageShadowCopies_ ) + { + for (auto bodyIt = bodystorageShadowCopies_.begin(); bodyIt != bodystorageShadowCopies_.end(); ++bodyIt) + { + add( *bodyIt ); + } + } +} +//************************************************************************************************* + //**Implementation of ICCD interface ******************************************************** //************************************************************************************************* /*!\brief Contact generation between colliding rigid bodies. diff --git a/src/pe/ccd/HashGrids.h b/src/pe/ccd/HashGrids.h index 442fabe37..060be9447 100644 --- a/src/pe/ccd/HashGrids.h +++ b/src/pe/ccd/HashGrids.h @@ -272,6 +272,7 @@ public: /*!\name Utility functions */ //@{ void clear (); + void reloadBodies(); //@} //********************************************************************************************** diff --git a/src/pe/ccd/ICCD.h b/src/pe/ccd/ICCD.h index cb4bf9759..d3922b5ed 100644 --- a/src/pe/ccd/ICCD.h +++ b/src/pe/ccd/ICCD.h @@ -38,7 +38,8 @@ public: virtual PossibleContacts& generatePossibleContacts( WcTimingTree* tt = NULL ) = 0; PossibleContacts& getPossibleContacts() {return contacts_;} - virtual int getObservedBodyCount() const = 0; + virtual void reloadBodies() {}; + virtual int getObservedBodyCount() const = 0; protected: PossibleContacts contacts_; }; diff --git a/src/pe/rigidbody/StorageDataHandling.h b/src/pe/rigidbody/StorageDataHandling.h index 6e60e5f6f..e12df0494 100644 --- a/src/pe/rigidbody/StorageDataHandling.h +++ b/src/pe/rigidbody/StorageDataHandling.h @@ -29,6 +29,7 @@ #include "pe/communication/DynamicMarshalling.h" #include "blockforest/BlockDataHandling.h" +#include "core/Abort.h" namespace walberla{ namespace pe{ @@ -37,14 +38,14 @@ namespace pe{ template<typename BodyTuple> class StorageDataHandling : public domain_decomposition::BlockDataHandling<Storage>{ public: - Storage * initialize( IBlock * const /*block*/ ) {return new Storage();} - - /// must be thread-safe ! - virtual inline void serialize( IBlock * const block, const BlockDataID & id, mpi::SendBuffer & buffer ); - /// must be thread-safe ! - virtual inline Storage * deserialize( IBlock * const block ); - /// must be thread-safe ! - virtual inline void deserialize( IBlock * const block, const BlockDataID & id, mpi::RecvBuffer & buffer ); + Storage * initialize( IBlock * const /*block*/ ) {return new Storage();} + + /// must be thread-safe ! + virtual inline void serialize( IBlock * const block, const BlockDataID & id, mpi::SendBuffer & buffer ); + /// must be thread-safe ! + virtual inline Storage * deserialize( IBlock * const block ); + /// must be thread-safe ! + virtual inline void deserialize( IBlock * const block, const BlockDataID & id, mpi::RecvBuffer & buffer ); }; template<typename BodyTuple> @@ -55,6 +56,10 @@ inline void StorageDataHandling<BodyTuple>::serialize( IBlock * const block, con buffer << localBodyStorage.size(); for (auto bodyIt = localBodyStorage.begin(); bodyIt != localBodyStorage.end(); ++bodyIt) { + if ( !block->getAABB().contains( bodyIt->getPosition()) ) + { + WALBERLA_ABORT( "Body to be stored not contained within block!" ); + } marshal( buffer, RigidBodyCopyNotification( **bodyIt ) ); MarshalDynamically<BodyTuple>::execute( buffer, **bodyIt ); } @@ -84,6 +89,10 @@ inline void StorageDataHandling<BodyTuple>::deserialize( IBlock * const block, c BodyID bd = UnmarshalDynamically<BodyTuple>::execute(buffer, objparam.geomType_, math::AABB(-inf, -inf, -inf, inf, inf, inf), block->getAABB()); bd->setRemote( false ); + if ( !block->getAABB().contains( bd->getPosition()) ) + { + WALBERLA_ABORT("Loaded body not contained within block!" ); + } WALBERLA_ASSERT_EQUAL(localBodyStorage.find( bd->getSystemID() ), localBodyStorage.end()); localBodyStorage.add(bd); diff --git a/src/pe/utility/CreateWorld.cpp b/src/pe/utility/CreateWorld.cpp index 94a6854f4..35dc07984 100644 --- a/src/pe/utility/CreateWorld.cpp +++ b/src/pe/utility/CreateWorld.cpp @@ -14,7 +14,6 @@ // with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // //! \file CreateWorld.cpp -//! \author Klaus Iglberger //! \author Sebastian Eibl <sebastian.eibl@fau.de> // //====================================================================================================================== @@ -34,12 +33,10 @@ namespace walberla { namespace pe { -shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& mainConf) +shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain, + Vector3<uint_t> blocks, + const Vector3<bool> isPeriodic) { - math::AABB simulationDomain = math::AABB( Vec3(0,0,0), mainConf.getParameter<Vec3>("simulationDomain", Vec3(10, 10, 10))); - Vector3<uint_t> blocks = mainConf.getParameter<Vector3<uint_t>>("blocks", Vector3<uint_t>(3, 3, 3)); - Vector3<bool> isPeriodic = mainConf.getParameter<Vector3<bool>>("isPeriodic", Vector3<bool>(true, true, true)); - if (isPeriodic[0] && blocks[0]<2) { WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic x direction (" << blocks[0] << ")! Setting to 2..." ); @@ -56,46 +53,61 @@ shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& m blocks[2] = 2; } -// const uint_t numberOfProcesses = blocks[0] * blocks[1] * blocks[2]; + return blockforest::createBlockForest( simulationDomain, + blocks[0], blocks[1], blocks[2], + blocks[0], blocks[1], blocks[2], + isPeriodic[0],isPeriodic[1],isPeriodic[2], + false ); +} - if( !mainConf.isDefined( "sbfFile" ) ) +shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain, + Vector3<uint_t> blocks, + const Vector3<bool> isPeriodic, + const bool setupRun, + const std::string sbffile) +{ + if (isPeriodic[0] && blocks[0]<2) { - WALBERLA_LOG_INFO_ON_ROOT( "No setup file specified: Creation without setup file!" ); - - return blockforest::createBlockForest( simulationDomain, - blocks[0], blocks[1], blocks[2], - blocks[0], blocks[1], blocks[2], - isPeriodic[0],isPeriodic[1],isPeriodic[2], - false ); + WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic x direction (" << blocks[0] << ")! Setting to 2..." ); + blocks[0] = 2; + } + if (isPeriodic[1] && blocks[1]<2) + { + WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic y direction (" << blocks[1] << ")! Setting to 2..." ); + blocks[1] = 2; + } + if (isPeriodic[2] && blocks[2]<2) + { + WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic z direction (" << blocks[2] << ")! Setting to 2..." ); + blocks[2] = 2; } - // sbf file given -> try to load or save domain decomposition - std::string sbffile = mainConf.getParameter< std::string >( "sbfFile" ); WALBERLA_LOG_INFO_ON_ROOT( "Setup file specified: Using " << sbffile ); - bool setupRun = mainConf.getParameter< bool >( "setupRun", true ); if (setupRun) { - WALBERLA_LOG_INFO_ON_ROOT("Setup run. For production run specify 'setupRun = true'"); + WALBERLA_LOG_INFO_ON_ROOT("Setup run. For production run specify 'setupRun = false'"); if( MPIManager::instance()->numProcesses() > 1 ) - WALBERLA_ABORT( "In this mode you need to start with just one process!" ); + WALBERLA_LOG_WARNING_ON_ROOT( "Setup run with more than one process! Only root is doing work! I hope you know what you are doing!" ); - WALBERLA_LOG_INFO_ON_ROOT( "Creating the block structure ..." ); + WALBERLA_ROOT_SECTION() + { + WALBERLA_LOG_INFO_ON_ROOT( "Creating the block structure ..." ); - SetupBlockForest sforest; + SetupBlockForest sforest; - sforest.addWorkloadMemorySUIDAssignmentFunction( blockforest::uniformWorkloadAndMemoryAssignment ); + sforest.addWorkloadMemorySUIDAssignmentFunction( blockforest::uniformWorkloadAndMemoryAssignment ); - sforest.init( simulationDomain, blocks[0], blocks[1], blocks[2], isPeriodic[0], isPeriodic[1], isPeriodic[2] ); + sforest.init( simulationDomain, blocks[0], blocks[1], blocks[2], isPeriodic[0], isPeriodic[1], isPeriodic[2] ); - // calculate process distribution + // calculate process distribution + sforest.balanceLoad( blockforest::StaticLevelwiseCurveBalance(true), blocks[0] * blocks[1] * blocks[2] ); - sforest.balanceLoad( blockforest::StaticLevelwiseCurveBalance(true), blocks[0] * blocks[1] * blocks[2] ); + sforest.saveToFile( sbffile.c_str() ); - sforest.saveToFile( sbffile.c_str() ); - - WALBERLA_LOG_INFO_ON_ROOT( "SetupBlockForest successfully saved to file!" ) + WALBERLA_LOG_INFO_ON_ROOT( "SetupBlockForest successfully saved to file!" ); + } return shared_ptr<BlockForest>(); } @@ -108,5 +120,26 @@ shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& m return shared_ptr< BlockForest >( new BlockForest( uint_c( MPIManager::instance()->rank() ), sbffile.c_str(), true, false ) ); } +shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& mainConf) +{ + math::AABB simulationDomain = math::AABB( Vec3(0,0,0), mainConf.getParameter<Vec3>("simulationDomain", Vec3(10, 10, 10))); + Vector3<uint_t> blocks = mainConf.getParameter<Vector3<uint_t>>("blocks", Vector3<uint_t>(3, 3, 3)); + Vector3<bool> isPeriodic = mainConf.getParameter<Vector3<bool>>("isPeriodic", Vector3<bool>(true, true, true)); + + if( !mainConf.isDefined( "sbfFile" ) ) + { + WALBERLA_LOG_INFO_ON_ROOT( "No setup file specified: Creation without setup file!" ); + + return createBlockForest( simulationDomain, blocks, isPeriodic); + } + + // sbf file given -> try to load or save domain decomposition + std::string sbffile = mainConf.getParameter< std::string >( "sbfFile" ); + WALBERLA_LOG_INFO_ON_ROOT( "Setup file specified: Using " << sbffile ); + + bool setupRun = mainConf.getParameter< bool >( "setupRun", true ); + return createBlockForest(simulationDomain, blocks, isPeriodic, setupRun, sbffile); +} + } // namespace pe } // namespace walberla diff --git a/src/pe/utility/CreateWorld.h b/src/pe/utility/CreateWorld.h index 20d5b3424..69842960e 100644 --- a/src/pe/utility/CreateWorld.h +++ b/src/pe/utility/CreateWorld.h @@ -31,6 +31,14 @@ namespace walberla { namespace pe { +shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain, + Vector3<uint_t> blocks, + const Vector3<bool> isPeriodic); +shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain, + Vector3<uint_t> blocks, + const Vector3<bool> isPeriodic, + const bool setupRun, + const std::string sbffile); shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& mainConf); } // namespace pe diff --git a/tests/pe/CMakeLists.txt b/tests/pe/CMakeLists.txt index bf6297265..40ff645e1 100644 --- a/tests/pe/CMakeLists.txt +++ b/tests/pe/CMakeLists.txt @@ -4,6 +4,9 @@ # ################################################################################################### +waLBerla_link_files_to_builddir( *.cfg ) +waLBerla_link_files_to_builddir( *.sbf ) + waLBerla_compile_test( NAME PE_BODYFLAGS FILES BodyFlags.cpp DEPENDS core ) waLBerla_execute_test( NAME PE_BODYFLAGS PROCESSES 8) diff --git a/tests/pe/SerializeDeserialize.cpp b/tests/pe/SerializeDeserialize.cpp index 6fb932c02..ae03c0f49 100644 --- a/tests/pe/SerializeDeserialize.cpp +++ b/tests/pe/SerializeDeserialize.cpp @@ -36,7 +36,6 @@ using namespace walberla; using namespace walberla::pe; -using namespace walberla::blockforest; typedef boost::tuple<Sphere> BodyTuple ; @@ -44,22 +43,17 @@ void createDump() { using namespace walberla::grid_generator; - BodyStorage globalStorage; + shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>(); // create blocks - shared_ptr< StructuredBlockForest > forest = blockforest::createUniformBlockGrid( - uint_c( 2), uint_c( 2), uint_c( 2), // number of blocks in x,y,z direction - uint_c( 1), uint_c( 1), uint_c( 1), // how many cells per block (x,y,z) - real_c(10), // dx: length of one cell in physical coordinates - 0, // max blocks per process - false, false, // include metis / force metis - false, false, false ); // full periodicity + auto forest = shared_ptr< BlockForest >( new BlockForest( uint_c( MPIManager::instance()->rank() ), "SerializeDeserialize.sbf", true, false ) ); - BlockDataID storageID = forest->addBlockData( createStorageDataHandling<BodyTuple>() ); + auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage"); + auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD"); for (auto it = SCIterator(forest->getDomain(), Vec3(-1,-1,-1), 3); it != SCIterator(); ++it) { - createSphere( globalStorage, forest->getBlockStorage(), storageID, 0, *it, 1); + createSphere( *globalBodyStorage, *forest, storageID, 0, *it, 1); } WALBERLA_LOG_DEVEL_ON_ROOT("dumping body storage"); @@ -68,9 +62,11 @@ void createDump() for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt) { BodyStorage& localStorage = (*(blockIt->getData< Storage >( storageID )))[0]; - WALBERLA_LOG_DEVEL("DUMPING BLOCK"); - WALBERLA_LOG_DEVEL("aabb: " << blockIt->getAABB()); + WALBERLA_LOG_DEVEL("DUMPING BLOCK (" << blockIt->getId() << ") " << blockIt->getAABB() ); WALBERLA_LOG_DEVEL("#bodies: " << localStorage.size()); + + ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID ); + WALBERLA_CHECK_EQUAL( ccd->getObservedBodyCount(), 1000 ); } } @@ -78,33 +74,34 @@ void checkDump() { using namespace walberla::grid_generator; -// BodyStorage globalStorage; + shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>(); // create blocks - shared_ptr< StructuredBlockForest > forest = blockforest::createUniformBlockGrid( - uint_c( 2), uint_c( 2), uint_c( 2), // number of blocks in x,y,z direction - uint_c( 1), uint_c( 1), uint_c( 1), // how many cells per block (x,y,z) - real_c(10), // dx: length of one cell in physical coordinates - 0, // max blocks per process - false, false, // include metis / force metis - false, false, false ); // full periodicity - + auto forest = shared_ptr< BlockForest >( new BlockForest( uint_c( MPIManager::instance()->rank() ), "SerializeDeserialize.sbf", true, false ) ); + auto storageID = forest->loadBlockData("BodyStorageDump.dump", createStorageDataHandling<BodyTuple>(), "Storage"); + auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD"); - BlockDataID storageID = forest->loadBlockData("BodyStorageDump.dump", createStorageDataHandling<BodyTuple>()); + for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt) + { + ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID ); + ccd->reloadBodies(); + } for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt) { + ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID ); + WALBERLA_CHECK_EQUAL( ccd->getObservedBodyCount(), 1000 ); + BodyStorage& localStorage = (*(blockIt->getData< Storage >( storageID )))[0]; - WALBERLA_LOG_DEVEL("CHECKING BLOCK"); - WALBERLA_LOG_DEVEL("aabb: " << blockIt->getAABB()); + WALBERLA_LOG_DEVEL("CHECKING BLOCK (" << blockIt->getId() << ") " << blockIt->getAABB() ); WALBERLA_LOG_DEVEL("#bodies: " << localStorage.size()); auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID); for (auto it = SCIterator(forest->getDomain(), Vec3(-1,-1,-1), 3); it != SCIterator(); ++it) { if (blockIt->getAABB().contains(*it)) { - WALBERLA_CHECK_FLOAT_EQUAL( bodyIt->getPosition(), *it); + WALBERLA_CHECK_FLOAT_EQUAL( bodyIt->getPosition(), *it, blockIt->getAABB()); ++bodyIt; } } @@ -116,10 +113,21 @@ int main( int argc, char ** argv ) walberla::debug::enterTestMode(); walberla::MPIManager::instance()->initializeMPI( &argc, &argv ); + MPIManager::instance()->useWorldComm(); SetBodyTypeIDs<BodyTuple>::execute(); +// save SetupBlockForest, if you want to do that run with only one process + createBlockForest( math::AABB(0,0,0,60,60,60), + Vector3<uint_t>(2,2,2), // number of blocks + Vector3<bool>(false, false, false), // periodicity + true, // setup run? + "SerializeDeserialize.sbf" ); // sbf filename + + WALBERLA_LOG_DEVEL_ON_ROOT("*** DUMPING ***"); createDump(); + WALBERLA_MPI_BARRIER(); + WALBERLA_LOG_DEVEL_ON_ROOT("*** CHECKING ***"); checkDump(); return EXIT_SUCCESS; -- GitLab