"git@i10git.cs.fau.de:holzer/walberla.git" did not exist on "cd4341a1f79e912a1cc80dc37ad560bb1095420b"
-
Sebastian Eibl authoredad8c87b3
Forked from
waLBerla / waLBerla
1037 commits behind the upstream repository.
MESA_PD_KernelBenchmark.cpp 21.19 KiB
//======================================================================================================================
//
// 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 MESA_PD_KernelBenchmark.cpp
//! \author Sebastian Eibl <sebastian.eibl@fau.de>
//
//======================================================================================================================
#include "Accessor.h"
#include "check.h"
#include "Contact.h"
#include "CreateParticles.h"
#include "NodeTimings.h"
#include "Parameters.h"
#include "SelectProperty.h"
#include "sortParticleStorage.h"
#include "SQLProperties.h"
#include <mesa_pd/vtk/ParticleVtkOutput.h>
#include <mesa_pd/collision_detection/AnalyticContactDetection.h>
#include <mesa_pd/data/LinkedCells.h>
#include <mesa_pd/data/ParticleAccessor.h>
#include <mesa_pd/data/ParticleStorage.h>
#include <mesa_pd/data/ShapeStorage.h>
#include <mesa_pd/domain/BlockForestDomain.h>
#include <mesa_pd/kernel/AssocToBlock.h>
#include <mesa_pd/kernel/DoubleCast.h>
#include <mesa_pd/kernel/ExplicitEulerWithShape.h>
#include <mesa_pd/kernel/InsertParticleIntoLinkedCells.h>
#include <mesa_pd/kernel/ParticleSelector.h>
#include <mesa_pd/kernel/SpringDashpot.h>
#include <mesa_pd/kernel/SpringDashpotSpring.h>
#include <mesa_pd/mpi/ContactFilter.h>
#include <mesa_pd/mpi/ReduceContactHistory.h>
#include <mesa_pd/mpi/ReduceProperty.h>
#include <mesa_pd/mpi/SyncNextNeighbors.h>
#include <mesa_pd/mpi/SyncNextNeighborsBlockForest.h>
#include <mesa_pd/mpi/notifications/ForceTorqueNotification.h>
#include <mesa_pd/sorting/HilbertCompareFunctor.h>
#include <mesa_pd/sorting/LinearizedCompareFunctor.h>
#include <blockforest/BlockForest.h>
#include <blockforest/Initialization.h>
#include <core/Abort.h>
#include <core/Environment.h>
#include <core/Hostname.h>
#include <core/math/Random.h>
#include <core/math/Sample.h>
#include <core/mpi/Gatherv.h>
#include <core/mpi/RecvBuffer.h>
#include <core/mpi/Reduce.h>
#include <core/mpi/SendBuffer.h>
#include <core/grid_generator/SCIterator.h>
#include <core/logging/Logging.h>
#include <core/OpenMP.h>
#include <core/perf_analysis/extern/likwid.h>
#include <core/timing/Timer.h>
#include <core/timing/TimingPool.h>
#include <core/waLBerlaBuildInfo.h>
#include <sqlite/SQLite.h>
#include <vtk/VTKOutput.h>
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
namespace walberla {
namespace mesa_pd {
class ContactDetection
{
public:
ContactDetection(const std::shared_ptr<domain::BlockForestDomain>& domain)
: domain_(domain)
{
contacts_.reserve(4000000);
}
template <typename T>
inline
void operator()(const size_t idx1, const size_t idx2, T& ac)
{
++contactsChecked_;
if (double_cast_(idx1, idx2, ac, acd_, ac))
{
++contactsDetected_;
if (contact_filter_(acd_.getIdx1(), acd_.getIdx2(), ac, acd_.getContactPoint(),
*domain_))
{
++contactsTreated_;
contacts_.emplace_back(acd_.getIdx1(), acd_.getIdx2(), acd_.getContactPoint(),
acd_.getContactNormal(), acd_.getPenetrationDepth());
}
}
}
inline const auto& getContacts() const {return contacts_;}
inline
void resetCounters()
{
contactsChecked_ = 0;
contactsDetected_ = 0;
contactsTreated_ = 0;
contacts_.clear();
}
inline
int64_t getContactsChecked() const
{
return contactsChecked_;
}
inline
int64_t getContactsDetected() const
{
return contactsDetected_;
}
inline
int64_t getContactsTreated() const
{
return contactsTreated_;
}
private:
kernel::DoubleCast double_cast_;
mpi::ContactFilter contact_filter_;
std::shared_ptr<domain::BlockForestDomain> domain_;
collision_detection::AnalyticContactDetection acd_;
std::vector<Contact> contacts_;
int64_t contactsChecked_ = 0;
int64_t contactsDetected_ = 0;
int64_t contactsTreated_ = 0;
};
template <typename T>
void reportOverRanks(const std::string& info, const T& value)
{
math::Sample sample;
sample.insert(value);
sample.mpiGatherRoot();
WALBERLA_LOG_INFO_ON_ROOT(info);
WALBERLA_LOG_INFO_ON_ROOT(sample.format());
}
int main( int argc, char ** argv )
{
LIKWID_MARKER_INIT;
using namespace walberla::timing;
Environment env(argc, argv);
auto mpiManager = walberla::mpi::MPIManager::instance();
mpiManager->useWorldComm();
logging::Logging::instance()->setStreamLogLevel(logging::Logging::INFO);
logging::Logging::instance()->setFileLogLevel(logging::Logging::INFO);
// logging::Logging::instance()->includeLoggingToFile("KernelBenchmark");
WALBERLA_LOG_INFO_ON_ROOT( "config file: " << argv[1] );
WALBERLA_LOG_INFO_ON_ROOT( "waLBerla Revision: " << WALBERLA_GIT_SHA1 );
math::seedRandomGenerator( static_cast<unsigned int>(1337 * mpiManager->worldRank()) );
WALBERLA_LOG_INFO_ON_ROOT("*** READING CONFIG FILE ***");
auto cfg = env.config();
if (cfg == nullptr) WALBERLA_ABORT("No config specified!");
const Config::BlockHandle mainConf = cfg->getBlock( "GranularGas" );
Parameters params;
loadFromConfig(params, mainConf);
WALBERLA_LOG_INFO_ON_ROOT("*** BLOCKFOREST ***");
// create forest
auto forest = blockforest::createBlockForestFromConfig( mainConf );
if (!forest)
{
WALBERLA_LOG_INFO_ON_ROOT( "No BlockForest created ... exiting!");
return EXIT_SUCCESS;
}
auto domain = std::make_shared<domain::BlockForestDomain>(forest);
LIKWID_MARKER_THREADINIT;
auto simulationDomain = forest->getDomain();
auto localDomain = forest->begin()->getAABB();
for (auto& blk : *forest)
{
localDomain.merge(blk.getAABB());
}
// WALBERLA_LOG_DEVEL_VAR(localDomain);
WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - START ***");
//init data structures
auto ss = std::make_shared<data::ShapeStorage>();
auto ps = std::make_shared<data::ParticleStorage>(100);
ParticleAccessorWithShape accessor(ps, ss);
data::LinkedCells lc(localDomain.getExtended(params.spacing), params.spacing );
auto smallSphere = ss->create<data::Sphere>( params.radius );
ss->shapes[smallSphere]->updateMassAndInertia(real_t(2707));
for (auto& iBlk : *forest)
{
for (auto pt : grid_generator::SCGrid(iBlk.getAABB(),
Vector3<real_t>(params.spacing) * real_c(0.5) + params.shift,
params.spacing))
{
WALBERLA_CHECK(iBlk.getAABB().contains(pt));
createSphere(*ps, pt, params.radius, smallSphere);
// WALBERLA_LOG_DEVEL_VAR_ON_ROOT(pt);
}
}
int64_t numParticles = int64_c(ps->size());
walberla::mpi::reduceInplace(numParticles, walberla::mpi::SUM);
WALBERLA_LOG_INFO_ON_ROOT("#particles created: " << numParticles);
auto shift = (params.spacing - params.radius - params.radius) * real_t(0.5);
auto confiningDomain = simulationDomain.getExtended(shift);
if (!forest->isPeriodic(0))
{
createPlane(*ps, *ss, confiningDomain.minCorner() + params.shift, Vec3(+1,0,0));
createPlane(*ps, *ss, confiningDomain.maxCorner() + params.shift, Vec3(-1,0,0));
}
if (!forest->isPeriodic(1))
{
createPlane(*ps, *ss, confiningDomain.minCorner() + params.shift, Vec3(0,+1,0));
createPlane(*ps, *ss, confiningDomain.maxCorner() + params.shift, Vec3(0,-1,0));
}
if (!forest->isPeriodic(2))
{
createPlane(*ps, *ss, confiningDomain.minCorner() + params.shift, Vec3(0,0,+1));
createPlane(*ps, *ss, confiningDomain.maxCorner() + params.shift, Vec3(0,0,-1));
}
WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - END ***");
WALBERLA_LOG_INFO_ON_ROOT("*** VTK ***");
auto vtkDomainOutput = walberla::vtk::createVTKOutput_DomainDecomposition( forest, "domain_decomposition", 1, params.vtk_out, "simulation_step" );
auto vtkOutput = make_shared<mesa_pd::vtk::ParticleVtkOutput>(ps) ;
auto vtkWriter = walberla::vtk::createVTKOutput_PointData(vtkOutput, "Bodies", 1, params.vtk_out, "simulation_step", false, false);
vtkOutput->addOutput<SelectRank>("rank");
vtkOutput->addOutput<data::SelectParticleOwner>("owner");
vtkOutput->addOutput<SelectIdx>("idx");
// vtkDomainOutput->write();
WALBERLA_LOG_INFO_ON_ROOT("*** SIMULATION - START ***");
// Init kernels
kernel::ExplicitEulerWithShape explicitEulerWithShape( params.dt );
kernel::AssocToBlock assoc(forest);
kernel::InsertParticleIntoLinkedCells ipilc;
kernel::SpringDashpot sd(1);
sd.setDampingT (0, 0, real_t(0));
sd.setFriction (0, 0, real_t(0));
sd.setParametersFromCOR(0, 0, real_t(0.9), params.dt*real_t(20), ss->shapes[smallSphere]->getMass() * real_t(0.5));
kernel::SpringDashpotSpring sds(1);
sds.setParametersFromCOR(0, 0, real_t(0.9), params.dt*real_t(20), ss->shapes[smallSphere]->getMass() * real_t(0.5));
sds.setCoefficientOfFriction(0,0,real_t(0.4));
sds.setStiffnessT(0,0,real_t(0.9) * sds.getStiffnessN(0,0));
mpi::ReduceProperty RP;
mpi::SyncNextNeighbors SNN;
mpi::ReduceContactHistory RCH;
ContactDetection CD(domain);
// initial sync
ps->forEachParticle(false, kernel::SelectLocal(), accessor, assoc, accessor);
SNN(*ps, *domain);
sortParticleStorage(*ps, params.sorting, lc.domain_, uint_c(lc.numCellsPerDim_[0]));
// vtkWriter->write();
for (int64_t outerIteration = 0; outerIteration < params.numOuterIterations; ++outerIteration)
{
WALBERLA_LOG_INFO_ON_ROOT("*** RUNNING OUTER ITERATION " << outerIteration << " ***");
WcTimingPool tp;
LIKWID_MARKER_REGISTER("SNN");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("SNN");
tp["SNN"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
SNN(*ps, *domain);
}
tp["SNN"].end();
LIKWID_MARKER_STOP("SNN");
LIKWID_MARKER_REGISTER("AssocToBlock");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("AssocToBlock");
tp["AssocToBlock"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
ps->forEachParticle(false, kernel::SelectLocal(), accessor, assoc, accessor);
}
tp["AssocToBlock"].end();
LIKWID_MARKER_STOP("AssocToBlock");
LIKWID_MARKER_REGISTER("GenerateLinkedCells");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("GenerateLinkedCells");
tp["GenerateLinkedCells"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
lc.clear();
ps->forEachParticle(true, kernel::SelectAll(), accessor, ipilc, accessor, lc);
}
tp["GenerateLinkedCells"].end();
LIKWID_MARKER_STOP("GenerateLinkedCells");
LIKWID_MARKER_REGISTER("ContactDetection");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("ContactDetection");
tp["ContactDetection"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
CD.resetCounters();
lc.forEachParticlePairHalf(true,
kernel::SelectAll(),
accessor,
CD,
accessor);
}
tp["ContactDetection"].end();
LIKWID_MARKER_STOP("ContactDetection");
LIKWID_MARKER_REGISTER("SpringDashpot");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("SpringDashpot");
tp["SpringDashpot"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
for (auto& c : CD.getContacts())
{
sd(c.idx1_, c.idx2_, accessor, c.contactPoint_, c.contactNormal_, c.penetrationDepth_);
}
}
tp["SpringDashpot"].end();
LIKWID_MARKER_STOP("SpringDashpot");
LIKWID_MARKER_REGISTER("SpringDashpotSpring");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("SpringDashpotSpring");
tp["SpringDashpotSpring"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
for (auto& c : CD.getContacts())
{
sds(c.idx1_, c.idx2_, accessor, c.contactPoint_, c.contactNormal_, c.penetrationDepth_, params.dt);
}
}
tp["SpringDashpotSpring"].end();
LIKWID_MARKER_STOP("SpringDashpotSpring");
LIKWID_MARKER_REGISTER("ReduceForce");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("ReduceForce");
tp["ReduceForce"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
RP.operator()<ForceTorqueNotification>(*ps);
}
tp["ReduceForce"].end();
LIKWID_MARKER_STOP("ReduceForce");
LIKWID_MARKER_REGISTER("ReduceContactHistory");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("ReduceContactHistory");
tp["ReduceContactHistory"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
RCH(*ps);
}
tp["ReduceContactHistory"].end();
LIKWID_MARKER_STOP("ReduceContactHistory");
LIKWID_MARKER_REGISTER("Euler");
WALBERLA_MPI_BARRIER();
LIKWID_MARKER_START("Euler");
tp["Euler"].start();
for (int64_t i=0; i < params.simulationSteps; ++i)
{
ps->forEachParticle(true, kernel::SelectLocal(), accessor, explicitEulerWithShape, accessor);
}
tp["Euler"].end();
LIKWID_MARKER_STOP("Euler");
WALBERLA_LOG_INFO_ON_ROOT("*** SIMULATION - END ***");
if (params.checkSimulation)
{
//if you want to activate checking you have to deactivate sorting
check(*ps, *forest, params.spacing, params.shift);
}
WALBERLA_LOG_INFO_ON_ROOT("*** SQL OUTPUT - START ***");
int64_t contactsChecked = CD.getContactsChecked();
int64_t contactsDetected = CD.getContactsDetected();
int64_t contactsTreated = CD.getContactsTreated();
reportOverRanks("Contacts Checked:", real_c(contactsChecked));
reportOverRanks("Contacts Detected:", real_c(contactsDetected));
reportOverRanks("Contacts Treated:", real_c(contactsTreated));
auto SNNBytesSent = SNN.getBytesSent();
auto SNNBytesReceived = SNN.getBytesReceived();
auto SNNSends = SNN.getNumberOfSends();
auto SNNReceives = SNN.getNumberOfReceives();
auto RPBytesSent = RP.getBytesSent();
auto RPBytesReceived = RP.getBytesReceived();
auto RPSends = RP.getNumberOfSends();
auto RPReceives = RP.getNumberOfReceives();
walberla::mpi::reduceInplace(SNNBytesSent, walberla::mpi::SUM);
walberla::mpi::reduceInplace(SNNBytesReceived, walberla::mpi::SUM);
walberla::mpi::reduceInplace(SNNSends, walberla::mpi::SUM);
walberla::mpi::reduceInplace(SNNReceives, walberla::mpi::SUM);
walberla::mpi::reduceInplace(RPBytesSent, walberla::mpi::SUM);
walberla::mpi::reduceInplace(RPBytesReceived, walberla::mpi::SUM);
walberla::mpi::reduceInplace(RPSends, walberla::mpi::SUM);
walberla::mpi::reduceInplace(RPReceives, walberla::mpi::SUM);
auto cC = walberla::mpi::reduce(contactsChecked, walberla::mpi::SUM);
auto cD = walberla::mpi::reduce(contactsDetected, walberla::mpi::SUM);
auto cT = walberla::mpi::reduce(contactsTreated, walberla::mpi::SUM);
WALBERLA_LOG_DEVEL_ON_ROOT( "SNN bytes communicated: " << SNNBytesSent << " / " << SNNBytesReceived );
WALBERLA_LOG_DEVEL_ON_ROOT( "SNN communication partners: " << SNNSends << " / " << SNNReceives );
WALBERLA_LOG_DEVEL_ON_ROOT( "RP bytes communicated: " << RPBytesSent << " / " << RPBytesReceived );
WALBERLA_LOG_DEVEL_ON_ROOT( "RP communication partners: " << RPSends << " / " << RPReceives );
WALBERLA_LOG_DEVEL_ON_ROOT( "contacts checked/detected/treated: " << cC << " / " << cD << " / " << cT );
auto tp_reduced = tp.getReduced();
WALBERLA_LOG_INFO_ON_ROOT(*tp_reduced);
numParticles = 0;
int64_t numGhostParticles = 0;
ps->forEachParticle(false,
kernel::SelectAll(),
accessor,
[&numParticles, &numGhostParticles](const size_t idx, auto& ac)
{
if (data::particle_flags::isSet( ac.getFlagsRef(idx), data::particle_flags::GHOST))
{
++numGhostParticles;
} else
{
++numParticles;
}
},
accessor);
reportOverRanks("Total Particles:", real_c(ps->size()));
reportOverRanks("Number of Particles:", real_c(numParticles));
reportOverRanks("Number of Ghost Particles:", real_c(numGhostParticles));
auto estGhostParticles = (localDomain.xSize()+2) * (localDomain.ySize()+2) * (localDomain.zSize()+2);
estGhostParticles -= localDomain.xSize() * localDomain.ySize() * localDomain.zSize();
estGhostParticles -= 4*localDomain.xSize() + 4*localDomain.ySize() + 4*localDomain.zSize();
estGhostParticles -= 8;
WALBERLA_LOG_DEVEL_ON_ROOT("Estimation: " << estGhostParticles);
walberla::mpi::reduceInplace(numParticles, walberla::mpi::SUM);
walberla::mpi::reduceInplace(numGhostParticles, walberla::mpi::SUM);
walberla::mpi::reduceInplace(contactsChecked, walberla::mpi::SUM);
walberla::mpi::reduceInplace(contactsDetected, walberla::mpi::SUM);
walberla::mpi::reduceInplace(contactsTreated, walberla::mpi::SUM);
double linkedCellsVolume = lc.domain_.volume();
walberla::mpi::reduceInplace(linkedCellsVolume, walberla::mpi::SUM);
size_t numLinkedCells = lc.cells_.size();
walberla::mpi::reduceInplace(numLinkedCells, walberla::mpi::SUM);
size_t local_aabbs = domain->getNumLocalAABBs();
size_t neighbor_subdomains = domain->getNumNeighborSubdomains();
size_t neighbor_processes = domain->getNumNeighborProcesses();
walberla::mpi::reduceInplace(local_aabbs, walberla::mpi::SUM);
walberla::mpi::reduceInplace(neighbor_subdomains, walberla::mpi::SUM);
walberla::mpi::reduceInplace(neighbor_processes, walberla::mpi::SUM);
uint_t runId = uint_c(-1);
WALBERLA_ROOT_SECTION()
{
std::map< std::string, walberla::int64_t > integerProperties;
std::map< std::string, double > realProperties;
std::map< std::string, std::string > stringProperties;
stringProperties["walberla_git"] = WALBERLA_GIT_SHA1;
stringProperties["tag"] = "mesa_pd";
integerProperties["mpi_num_processes"] = mpiManager->numProcesses();
integerProperties["omp_max_threads"] = omp_get_max_threads();
integerProperties["outerIteration"] = int64_c(outerIteration);
integerProperties["num_particles"] = numParticles;
integerProperties["num_ghost_particles"] = numGhostParticles;
integerProperties["contacts_checked"] = contactsChecked;
integerProperties["contacts_detected"] = contactsDetected;
integerProperties["contacts_treated"] = contactsTreated;
integerProperties["local_aabbs"] = int64_c(local_aabbs);
integerProperties["neighbor_subdomains"] = int64_c(neighbor_subdomains);
integerProperties["neighbor_processes"] = int64_c(neighbor_processes);
integerProperties["SNNBytesSent"] = SNNBytesSent;
integerProperties["SNNBytesReceived"] = SNNBytesReceived;
integerProperties["SNNSends"] = SNNSends;
integerProperties["SNNReceives"] = SNNReceives;
integerProperties["RPBytesSent"] = RPBytesSent;
integerProperties["RPBytesReceived"] = RPBytesReceived;
integerProperties["RPSends"] = RPSends;
integerProperties["RPReceives"] = RPReceives;
realProperties["linkedCellsVolume"] = linkedCellsVolume;
integerProperties["numLinkedCells"] = int64_c(numLinkedCells);
addBuildInfoToSQL( integerProperties, realProperties, stringProperties );
saveToSQL(params, integerProperties, realProperties, stringProperties );
addDomainPropertiesToSQL(*forest, integerProperties, realProperties, stringProperties);
addSlurmPropertiesToSQL(integerProperties, realProperties, stringProperties);
runId = sqlite::storeRunInSqliteDB( params.sqlFile, integerProperties, stringProperties, realProperties );
sqlite::storeTimingPoolInSqliteDB( params.sqlFile, runId, *tp_reduced, "Timeloop" );
}
if (params.storeNodeTimings)
{
storeNodeTimings(runId, params.sqlFile, "NodeTiming", tp);
}
WALBERLA_LOG_INFO_ON_ROOT("*** SQL OUTPUT - END ***");
}
LIKWID_MARKER_CLOSE;
return EXIT_SUCCESS;
}
} // namespace mesa_pd
} // namespace walberla
int main( int argc, char* argv[] )
{
return walberla::mesa_pd::main( argc, argv );
}