Skip to content
Snippets Groups Projects
Commit b82710b7 authored by Sebastian Eibl's avatar Sebastian Eibl
Browse files

updated pe documentation

second tutorial added
updated older tutorials
made tutorials also tests
parent 7c341cfa
Branches
Tags
No related merge requests found
...@@ -45,30 +45,30 @@ int main( int argc, char ** argv ) ...@@ -45,30 +45,30 @@ int main( int argc, char ** argv )
real_t spacing = real_c(1.0); real_t spacing = real_c(1.0);
real_t radius = real_c(0.4); real_t radius = real_c(0.4);
real_t vMax = real_c(1.0); real_t vMax = real_c(1.0);
int simulationSteps = 200; int simulationSteps = 10;
real_t dt = real_c(0.01); real_t dt = real_c(0.01);
//! [Parameters] //! [Parameters]
WALBERLA_LOG_INFO("*** GLOBALBODYSTORAGE ***"); WALBERLA_LOG_INFO_ON_ROOT("*** GLOBALBODYSTORAGE ***");
//! [GlobalBodyStorage] //! [GlobalBodyStorage]
shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>(); shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
//! [GlobalBodyStorage] //! [GlobalBodyStorage]
WALBERLA_LOG_INFO("*** BLOCKFOREST ***"); WALBERLA_LOG_INFO_ON_ROOT("*** BLOCKFOREST ***");
// create forest // create forest
//! [BlockForest] //! [BlockForest]
shared_ptr< BlockForest > forest = createBlockForest( AABB(0,0,0,20,20,20), // simulation domain shared_ptr< BlockForest > forest = createBlockForest( AABB(0,0,0,20,20,20), // simulation domain
Vector3<uint_t>(1,1,1), // blocks in each direction Vector3<uint_t>(2,2,2), // blocks in each direction
Vector3<bool>(false, false, false) // periodicity Vector3<bool>(false, false, false) // periodicity
); );
//! [BlockForest] //! [BlockForest]
if (!forest) if (!forest)
{ {
WALBERLA_LOG_INFO( "No BlockForest created ... exiting!"); WALBERLA_LOG_INFO_ON_ROOT( "No BlockForest created ... exiting!");
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
WALBERLA_LOG_INFO("*** STORAGEDATAHANDLING ***"); WALBERLA_LOG_INFO_ON_ROOT("*** STORAGEDATAHANDLING ***");
// add block data // add block data
//! [StorageDataHandling] //! [StorageDataHandling]
auto storageID = forest->addBlockData(createStorageDataHandling<BodyTypeTuple>(), "Storage"); auto storageID = forest->addBlockData(createStorageDataHandling<BodyTypeTuple>(), "Storage");
...@@ -78,7 +78,7 @@ int main( int argc, char ** argv ) ...@@ -78,7 +78,7 @@ int main( int argc, char ** argv )
auto fcdID = forest->addBlockData(fcd::createGenericFCDDataHandling<BodyTypeTuple, fcd::AnalyticCollideFunctor>(), "FCD"); auto fcdID = forest->addBlockData(fcd::createGenericFCDDataHandling<BodyTypeTuple, fcd::AnalyticCollideFunctor>(), "FCD");
//! [AdditionalBlockData] //! [AdditionalBlockData]
WALBERLA_LOG_INFO("*** INTEGRATOR ***"); WALBERLA_LOG_INFO_ON_ROOT("*** INTEGRATOR ***");
//! [Integrator] //! [Integrator]
cr::HCSITS cr(globalBodyStorage, forest, storageID, ccdID, fcdID); cr::HCSITS cr(globalBodyStorage, forest, storageID, ccdID, fcdID);
cr.setMaxIterations( 10 ); cr.setMaxIterations( 10 );
...@@ -87,13 +87,13 @@ int main( int argc, char ** argv ) ...@@ -87,13 +87,13 @@ int main( int argc, char ** argv )
cr.setGlobalLinearAcceleration( Vec3(0,0,0) ); cr.setGlobalLinearAcceleration( Vec3(0,0,0) );
//! [Integrator] //! [Integrator]
WALBERLA_LOG_INFO("*** BodyTypeTuple ***"); WALBERLA_LOG_INFO_ON_ROOT("*** BodyTypeTuple ***");
// initialize body type ids // initialize body type ids
//! [SetBodyTypeIDs] //! [SetBodyTypeIDs]
SetBodyTypeIDs<BodyTypeTuple>::execute(); SetBodyTypeIDs<BodyTypeTuple>::execute();
//! [SetBodyTypeIDs] //! [SetBodyTypeIDs]
WALBERLA_LOG_INFO("*** SETUP - START ***"); WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - START ***");
//! [Material] //! [Material]
const real_t static_cof ( real_c(0.1) / 2 ); // Coefficient of static friction. Note: pe doubles the input coefficient of friction for material-material contacts. const real_t static_cof ( real_c(0.1) / 2 ); // Coefficient of static friction. Note: pe doubles the input coefficient of friction for material-material contacts.
const real_t dynamic_cof ( static_cof ); // Coefficient of dynamic friction. Similar to static friction for low speed friction. const real_t dynamic_cof ( static_cof ); // Coefficient of dynamic friction. Similar to static friction for low speed friction.
...@@ -124,26 +124,28 @@ int main( int argc, char ** argv ) ...@@ -124,26 +124,28 @@ int main( int argc, char ** argv )
if (sp != NULL) ++numParticles; if (sp != NULL) ++numParticles;
} }
} }
WALBERLA_LOG_INFO("#particles created: " << numParticles); WALBERLA_LOG_INFO_ON_ROOT("#particles created: " << numParticles);
syncNextNeighbors<BodyTypeTuple>(*forest, storageID);
//! [Gas] //! [Gas]
WALBERLA_LOG_INFO("*** SETUP - END ***"); WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - END ***");
WALBERLA_LOG_INFO("*** SIMULATION - START ***"); WALBERLA_LOG_INFO_ON_ROOT("*** SIMULATION - START ***");
//! [GameLoop] //! [GameLoop]
for (int i=0; i < simulationSteps; ++i) for (int i=0; i < simulationSteps; ++i)
{ {
if( i % 10 == 0 ) if( i % 10 == 0 )
{ {
WALBERLA_LOG_DEVEL( "Timestep " << i << " / " << simulationSteps ); WALBERLA_LOG_PROGRESS_ON_ROOT( "Timestep " << i << " / " << simulationSteps );
} }
cr.timestep( real_c(dt) ); cr.timestep( real_c(dt) );
syncNextNeighbors<BodyTypeTuple>(*forest, storageID);
} }
//! [GameLoop] //! [GameLoop]
WALBERLA_LOG_INFO("*** SIMULATION - END ***"); WALBERLA_LOG_INFO_ON_ROOT("*** SIMULATION - END ***");
WALBERLA_LOG_INFO("*** GETTING STATISTICAL INFORMATION ***"); WALBERLA_LOG_INFO_ON_ROOT("*** GETTING STATISTICAL INFORMATION ***");
//! [PostProcessing] //! [PostProcessing]
Vec3 meanVelocity(0,0,0); Vec3 meanVelocity(0,0,0);
for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt) for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
......
...@@ -22,9 +22,13 @@ Next the waLBerla environment is initalized, the random number generator is seed ...@@ -22,9 +22,13 @@ Next the waLBerla environment is initalized, the random number generator is seed
The BlockForest is the main datastructure in the waLBerla framework. It is responsible for the domain decomposition and The BlockForest is the main datastructure in the waLBerla framework. It is responsible for the domain decomposition and
holds all the blocks with their data. For more information about the general design of the waLBerla framework please refer holds all the blocks with their data. For more information about the general design of the waLBerla framework please refer
to \ref tutorial_basics_01 and the documentation of domain_decomposition::BlockStorage. For this tutorial the number of blocks to \ref tutorial_basics_01 and the documentation of domain_decomposition::BlockStorage. You can choose the number of blocks
in each direction is fixed to 1 and has to stay like that. In tutorial 2 we will talk about using more than one block and you want to have in each direction. In a parallel simulation these blocks get assigned to different processes. You should
parallelism. make sure that you always have at least as many blocks as processes. The number of processes you want your simulation to run
with is specified when you start your programm with mpiexec.
\attention If you run a simulation with periodic boundaries you need at least three blocks in the direction of periodicity!
\snippet 01_ConfinedGas.cpp BlockForest \snippet 01_ConfinedGas.cpp BlockForest
There are two types of storages to store particle information. One is the global body storage which is responsible for very There are two types of storages to store particle information. One is the global body storage which is responsible for very
...@@ -59,10 +63,15 @@ which returns a SphereID of the created sphere. This SphereID acts like a pointe ...@@ -59,10 +63,15 @@ which returns a SphereID of the created sphere. This SphereID acts like a pointe
If for various reasons the sphere was not created the return value is NULL. If for various reasons the sphere was not created the return value is NULL.
\attention Before accessing the underlying sphere you should always check for NULL! \attention Before accessing the underlying sphere you should always check for NULL!
After you have initialized all particles you should synchronize the simulation to make sure that all information is
distributed correctly. Two synchronization methods are available syncNextNeighbors() and syncShadowOwners().
\snippet 01_ConfinedGas.cpp Gas \snippet 01_ConfinedGas.cpp Gas
Since the setup is finished now we can run the simulation loop. The simulation loop is as simple as: Since the setup is finished now we can run the simulation loop. The simulation loop is as simple as:
\snippet 01_ConfinedGas.cpp GameLoop \snippet 01_ConfinedGas.cpp GameLoop
cr::ICR::timestep() evolves your simulation in time. The subsequent sychronization keeps all particles that are known to more
than one process in sync.
After the simulation is finished we can collect the results. In this case we only calculate the mean velocity of all particles. After the simulation is finished we can collect the results. In this case we only calculate the mean velocity of all particles.
The particles can be easily accessed via the LocalBodyIterator. This iterator allows us to iterate through all particles and The particles can be easily accessed via the LocalBodyIterator. This iterator allows us to iterate through all particles and
...@@ -70,7 +79,7 @@ access their properties. ...@@ -70,7 +79,7 @@ access their properties.
\snippet 01_ConfinedGas.cpp PostProcessing \snippet 01_ConfinedGas.cpp PostProcessing
Congratulation! You successfully created your first rigid body simulation. Congratulation! You successfully created your first rigid body simulation.
In the next tutorial we will look at possible extensions which can make your live easier as well as how to run parallel simulations. In the next tutorial we will look at possible extensions which can make your live easier.
*/ */
......
ConfinedGasExtended
{
simulationCorner < 0, 0, 0 >;
simulationDomain < 20, 20, 20 >;
blocks < 2, 2, 2 >;
isPeriodic < 0, 0, 0 >;
}
//======================================================================================================================
//
// 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 02_ConfinedGasExtended.cpp
//! \author Sebastian Eibl <sebastian.eibl@fau.de>
//
//======================================================================================================================
#include <pe/basic.h>
#include <pe/statistics/BodyStatistics.h>
#include <pe/vtk/SphereVtkOutput.h>
#include <core/Abort.h>
#include <core/Environment.h>
#include <core/grid_generator/HCPIterator.h>
#include <core/grid_generator/SCIterator.h>
#include <core/logging/Logging.h>
#include <core/timing/TimingTree.h>
#include <core/waLBerlaBuildInfo.h>
#include <postprocessing/sqlite/SQLite.h>
#include <vtk/VTKOutput.h>
using namespace walberla;
using namespace walberla::pe;
using namespace walberla::timing;
typedef boost::tuple<Sphere, Plane> BodyTuple ;
int main( int argc, char ** argv )
{
Environment env(argc, argv);
logging::Logging::instance()->setStreamLogLevel(logging::Logging::INFO);
logging::Logging::instance()->setFileLogLevel(logging::Logging::INFO);
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 * mpi::MPIManager::instance()->worldRank()) );
WcTimingTree tt;
WALBERLA_LOG_INFO_ON_ROOT("*** READING COMMANDLINE ARGUMENTS ***");
bool syncShadowOwners = false;
for( int i = 1; i < argc; ++i )
{
if( std::strcmp( argv[i], "--syncShadowOwners" ) == 0 ) syncShadowOwners = true;
}
WALBERLA_LOG_INFO_ON_ROOT("*** READING CONFIG FILE ***");
auto cfg = env.config();
if (cfg == NULL) WALBERLA_ABORT("No config specified!");
const Config::BlockHandle mainConf = cfg->getBlock( "ConfinedGasExtended" );
const std::string sqlFile = mainConf.getParameter< std::string >( "sqlFile", "ConfinedGas.sqlite" );
//! [SQLProperties]
std::map< std::string, walberla::int64_t > integerProperties;
std::map< std::string, double > realProperties;
std::map< std::string, std::string > stringProperties;
//! [SQLProperties]
stringProperties["walberla_git"] = WALBERLA_GIT_SHA1;
real_t spacing = mainConf.getParameter<real_t>("spacing", real_c(1.0) );
WALBERLA_LOG_INFO_ON_ROOT("spacing: " << spacing);
realProperties["spacing"] = double_c(spacing);
real_t radius = mainConf.getParameter<real_t>("radius", real_c(0.4) );
WALBERLA_LOG_INFO_ON_ROOT("radius: " << radius);
realProperties["radius"] = double_c(radius);
real_t vMax = mainConf.getParameter<real_t>("vMax", real_c(1.0) );
WALBERLA_LOG_INFO_ON_ROOT("vMax: " << vMax);
realProperties["vMax"] = vMax;
int warmupSteps = mainConf.getParameter<int>("warmupSteps", 0 );
WALBERLA_LOG_INFO_ON_ROOT("warmupSteps: " << warmupSteps);
integerProperties["warmupSteps"] = warmupSteps;
int simulationSteps = mainConf.getParameter<int>("simulationSteps", 10 );
WALBERLA_LOG_INFO_ON_ROOT("simulationSteps: " << simulationSteps);
integerProperties["simulationSteps"] = simulationSteps;
real_t dt = mainConf.getParameter<real_t>("dt", real_c(0.01) );
WALBERLA_LOG_INFO_ON_ROOT("dt: " << dt);
realProperties["dt"] = dt;
const int visSpacing = mainConf.getParameter<int>("visSpacing", 1000 );
WALBERLA_LOG_INFO_ON_ROOT("visSpacing: " << visSpacing);
const std::string path = mainConf.getParameter<std::string>("path", "vtk_out" );
WALBERLA_LOG_INFO_ON_ROOT("path: " << path);
WALBERLA_LOG_INFO_ON_ROOT("syncShadowOwners: " << syncShadowOwners);
integerProperties["syncShadowOwners"] = syncShadowOwners;
WALBERLA_LOG_INFO_ON_ROOT("*** GLOBALBODYSTORAGE ***");
shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
WALBERLA_LOG_INFO_ON_ROOT("*** BLOCKFOREST ***");
// create forest
shared_ptr< BlockForest > forest = createBlockForestFromConfig( mainConf );
if (!forest)
{
WALBERLA_LOG_INFO_ON_ROOT( "No BlockForest created ... exiting!");
return EXIT_SUCCESS;
}
WALBERLA_LOG_INFO_ON_ROOT("simulationDomain: " << forest->getDomain());
integerProperties["sim_x"] = int64_c(forest->getDomain().maxCorner()[0]);
integerProperties["sim_y"] = int64_c(forest->getDomain().maxCorner()[1]);
integerProperties["sim_z"] = int64_c(forest->getDomain().maxCorner()[2]);
WALBERLA_LOG_INFO_ON_ROOT("blocks: " << Vector3<uint_t>(forest->getXSize(), forest->getYSize(), forest->getZSize()) );
integerProperties["blocks_x"] = int64_c(forest->getXSize());
integerProperties["blocks_y"] = int64_c(forest->getYSize());
integerProperties["blocks_z"] = int64_c(forest->getZSize());
WALBERLA_LOG_INFO_ON_ROOT("*** BODYTUPLE ***");
// initialize body type ids
SetBodyTypeIDs<BodyTuple>::execute();
WALBERLA_LOG_INFO_ON_ROOT("*** STORAGEDATAHANDLING ***");
// add block data
auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD");
auto fcdID = forest->addBlockData(fcd::createGenericFCDDataHandling<BodyTuple, fcd::AnalyticCollideFunctor>(), "FCD");
WALBERLA_LOG_INFO_ON_ROOT("*** INTEGRATOR ***");
cr::HCSITS cr(globalBodyStorage, forest, storageID, ccdID, fcdID);
cr.setMaxIterations( 10 );
cr.setRelaxationModel( cr::HardContactSemiImplicitTimesteppingSolvers::ApproximateInelasticCoulombContactByDecoupling );
cr.setRelaxationParameter( real_t(0.7) );
cr.setGlobalLinearAcceleration( Vec3(0,0,0) );
WALBERLA_LOG_INFO_ON_ROOT("*** SYNCCALL ***");
boost::function<void(void)> syncCall;
if (!syncShadowOwners)
{
syncCall = boost::bind( pe::syncNextNeighbors<BodyTuple>, boost::ref(*forest), storageID, &tt, real_c(0.0), false );
} else
{
syncCall = boost::bind( pe::syncShadowOwners<BodyTuple>, boost::ref(*forest), storageID, &tt, real_c(0.0), false );
}
//! [Bind Sync Call]
boost::function<void(void)> syncCallWithoutTT;
if (!syncShadowOwners)
{
syncCallWithoutTT = boost::bind( pe::syncNextNeighbors<BodyTuple>, boost::ref(*forest), storageID, static_cast<WcTimingTree*>(NULL), real_c(0.0), false );
} else
{
syncCallWithoutTT = boost::bind( pe::syncShadowOwners<BodyTuple>, boost::ref(*forest), storageID, static_cast<WcTimingTree*>(NULL), real_c(0.0), false );
}
//! [Bind Sync Call]
WALBERLA_LOG_INFO_ON_ROOT("*** VTK ***");
//! [VTK Domain Output]
auto vtkDomainOutput = vtk::createVTKOutput_DomainDecomposition( forest, "domain_decomposition", 1, "vtk_out", "simulation_step" );
//! [VTK Domain Output]
//! [VTK Sphere Output]
auto vtkSphereHelper = make_shared<SphereVtkOutput>(storageID, *forest) ;
auto vtkSphereOutput = vtk::createVTKOutput_PointData(vtkSphereHelper, "Bodies", 1, "vtk_out", "simulation_step", false, false);
//! [VTK Sphere Output]
WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - START ***");
const real_t static_cof ( real_c(0.1) / 2 ); // Coefficient of static friction. Note: pe doubles the input coefficient of friction for material-material contacts.
const real_t dynamic_cof ( static_cof ); // Coefficient of dynamic friction. Similar to static friction for low speed friction.
MaterialID material = createMaterial( "granular", real_t( 1.0 ), 0, static_cof, dynamic_cof, real_t( 0.5 ), 1, 1, 0, 0 );
auto simulationDomain = forest->getDomain();
auto generationDomain = simulationDomain; // simulationDomain.getExtended(-real_c(0.5) * spacing);
createPlane(*globalBodyStorage, 0, Vec3(1,0,0), simulationDomain.minCorner(), material );
createPlane(*globalBodyStorage, 0, Vec3(-1,0,0), simulationDomain.maxCorner(), material );
createPlane(*globalBodyStorage, 0, Vec3(0,1,0), simulationDomain.minCorner(), material );
createPlane(*globalBodyStorage, 0, Vec3(0,-1,0), simulationDomain.maxCorner(), material );
createPlane(*globalBodyStorage, 0, Vec3(0,0,1), simulationDomain.minCorner(), material );
createPlane(*globalBodyStorage, 0, Vec3(0,0,-1), simulationDomain.maxCorner(), material );
uint_t numParticles = uint_c(0);
for (auto blkIt = forest->begin(); blkIt != forest->end(); ++blkIt)
{
IBlock & currentBlock = *blkIt;
for (auto it = grid_generator::SCIterator(currentBlock.getAABB().getIntersection(generationDomain), Vector3<real_t>(spacing, spacing, spacing) * real_c(0.5), spacing); it != grid_generator::SCIterator(); ++it)
{
SphereID sp = pe::createSphere( *globalBodyStorage, *forest, storageID, 0, *it, radius, material);
Vec3 rndVel(math::realRandom<real_t>(-vMax, vMax), math::realRandom<real_t>(-vMax, vMax), math::realRandom<real_t>(-vMax, vMax));
if (sp != NULL) sp->setLinearVel(rndVel);
if (sp != NULL) ++numParticles;
}
}
mpi::reduceInplace(numParticles, mpi::SUM);
WALBERLA_LOG_INFO_ON_ROOT("#particles created: " << numParticles);
WALBERLA_LOG_INFO_ON_ROOT("*** SETUP - END ***");
// synchronize particles
//! [TT Example]
//WcTimingTree tt;
tt.start("Initial Sync");
syncCallWithoutTT();
syncCallWithoutTT();
tt.stop("Initial Sync");
//! [TT Example]
WALBERLA_LOG_INFO_ON_ROOT("*** SIMULATION - START ***");
WcTimingPool tp;
tt.start("Simulation Loop");
tp["Total"].start();
for (int i=0; i < simulationSteps; ++i)
{
if( i % 200 == 0 )
{
WALBERLA_LOG_DEVEL_ON_ROOT( "Timestep " << i << " / " << simulationSteps );
}
tp["Solver"].start();
cr.timestep( real_c(dt) );
tp["Solver"].end();
tp["Sync"].start();
syncCall();
tp["Sync"].end();
if( i % visSpacing == 0 )
{
//! [VTK Output]
vtkDomainOutput->write( );
vtkSphereOutput->write( );
//! [VTK Output]
}
}
tp["Total"].end();
tt.stop("Simulation Loop");
WALBERLA_LOG_INFO_ON_ROOT("*** SIMULATION - END ***");
BodyStatistics bodyStats( forest, storageID );
bodyStats();
WALBERLA_LOG_INFO_ON_ROOT( bodyStats );
integerProperties["numBodies"] = int64_c(bodyStats.numBodies());
integerProperties["numShadowCopies"] = int64_c(bodyStats.numShadowCopies());
//! [TT Log]
auto temp = tt.getReduced( );
WALBERLA_ROOT_SECTION()
{
std::cout << temp;
}
//! [TT Log]
auto tpReduced = tp.getReduced();
//! [SQL Save]
WALBERLA_ROOT_SECTION()
{
auto runId = postprocessing::storeRunInSqliteDB( sqlFile, integerProperties, stringProperties, realProperties );
postprocessing::storeTimingPoolInSqliteDB( sqlFile, runId, *tpReduced, "Timeloop" );
postprocessing::storeTimingTreeInSqliteDB( sqlFile, runId, tt, "TimingTree" );
}
//! [SQL Save]
return EXIT_SUCCESS;
}
namespace walberla {
namespace pe {
/**
\page tutorial_pe_02 Tutorial - Useful Features
This tutorial will introduce some useful features of the waLBerla framework which can make your live easier.
\section tutorial_pe_02_checkpointing Checkpointing
You can checkpoint the current state of your rigid body dynamics simulation at any point to restore it afterwards.
First you have to store the current domain partitioning using blockforest::BlockForest::saveToFile().
\snippet SerializeDeserialize.cpp Dump Blockforest
Then you have to store the current simulation data using domain_decomposition::BlockStorage::saveBlockData().
\snippet SerializeDeserialize.cpp Save Simulation Data
This will store all non global rigid bodies to the file system.
To load everything again you start by creating the blockforest::BlockForest. This time you will use a different
constructor.
\snippet SerializeDeserialize.cpp Load Blockforest
Instead of initializing the Storage BlockDatum like you normally would
\snippet SerializeDeserialize.cpp Init Storage
you have to use domain_decomposition::BlockStorage::loadBlockData()
\snippet SerializeDeserialize.cpp Load Storage
Unfortunately due to a misorder in the loading scheme you have to reload your coarse collision detection.
\snippet SerializeDeserialize.cpp Reload CCD
Hopefully this gets fixed in the future. ;)
\attention This method does not save global bodies nor solver settings. You have to take care to restore these
settings on your own.
A fully working example can be found in the SerializeDeserialize.cpp test of the pe module.
\section tutorial_pe_02_vtk VTK Output
For VTK Output you have to create vtk::VTKOutput objects.
To output the domain partitioning use vtk::createVTKOutput_DomainDecomposition.
\snippet 02_ConfinedGasExtended.cpp VTK Domain Output
To output all sphere particles use vtk::createVTKOutput_PointData in conjunction with SphereVtkOutput:
\snippet 02_ConfinedGasExtended.cpp VTK Sphere Output
Currently only spheres are supported for VTK output but you can easily write your own SphereVtkOutput
and adapt it to the body you like.
To actually write something to disc call vtk::VTKOutput::write():
\snippet 02_ConfinedGasExtended.cpp VTK Output
You can call this every time step if you want. The files will be automatically numbered so that ParaView can
generate an animation.
\section tutorial_pe_02_config Loading from Config
You can specify a config file as the first command line parameter. To access it you can use the
Environment::config() function. You can access subblocks of the config with config::Config::getBlock().
\snippet LoadFromConfig.cpp Load Config
To get values from the config call config::Config::getParameter():
\snippet LoadFromConfig.cpp Config Get Parameter
Certain task already have predefined loading functions. You can for example directly create a BlockForest
from the config file.
\snippet LoadFromConfig.cpp Config BlockForest
The corresponding block in the config file looks like:
\code
simulationCorner < -15, -15, 0 >;
simulationDomain < 12, 23, 34 >;
blocks < 3, 4, 5 >;
isPeriodic < 0, 1, 0 >;
\endcode
Also the HardContact solver can be configured directly from the config file:
\snippet LoadFromConfig.cpp Config HCSITS
The config file looks like:
\code
HCSITSmaxIterations 123;
HCSITSRelaxationParameter 0.123;
HCSITSErrorReductionParameter 0.123;
HCSITSRelaxationModelStr ApproximateInelasticCoulombContactByDecoupling;
globalLinearAcceleration < 1, -2, 3 >;
\endcode
\section tutorial_pe_02_timing Timing
To get additional information where you application spends its time you can use the WcTimingTree.
It will give you a hirarchical view of the time used.
Usage example:
\snippet 02_ConfinedGasExtended.cpp TT Example
Before you output the information you should collect all the information from all the processes if you are running
in parallel.
\snippet 02_ConfinedGasExtended.cpp TT Log
Many build-in functions like solver or synchronization methods come with an additional parameter where you can
specify your timing tree. They will then include detailed information in your timing tree.
\section tutorial_pe_02_sqlite SQLite Output
waLBerla also supports SQLite database for simulation data output. This can come in handy in parallel simulations
as well as in data analysis. To store information in a SQLite database you have to fill three property maps
depending on the type of information you want to store.
\snippet 02_ConfinedGasExtended.cpp SQLProperties
You can then dump the information to disc. timing::TimingPool and timing::TimingTree already have predefined save
functions so you do not have to extract all the information yourself and save it in the property array.
\snippet 02_ConfinedGasExtended.cpp SQL Save
*/
}
}
waLBerla_link_files_to_builddir( *.cfg ) waLBerla_link_files_to_builddir( *.cfg )
waLBerla_add_executable ( NAME 01_Tutorial_ConfinedGas waLBerla_add_executable ( NAME 01_Tutorial_ConfinedGas
FILES 01_ConfinedGas.cpp FILES 01_ConfinedGas.cpp
DEPENDS blockforest core pe ) DEPENDS blockforest core pe )
waLBerla_add_executable ( NAME 02_Tutorial_ConfinedGasExtended
FILES 02_ConfinedGasExtended.cpp
DEPENDS blockforest core pe postprocessing vtk )
waLBerla_execute_test( NO_MODULE_LABEL NAME 01_Tutorial_ConfinedGas PROCESSES 8 )
waLBerla_execute_test( NO_MODULE_LABEL NAME 02_Tutorial_ConfinedGasExtended
COMMAND $<TARGET_FILE:02_Tutorial_ConfinedGasExtended> 02_ConfinedGasExtended.cfg
PROCESSES 8 )
...@@ -23,6 +23,7 @@ all the basic data strcutures and concepts of the framework. ...@@ -23,6 +23,7 @@ all the basic data strcutures and concepts of the framework.
\subsection pe Rigid Body Dynamics (pe) \subsection pe Rigid Body Dynamics (pe)
- \ref tutorial_pe_01 \n - \ref tutorial_pe_01 \n
- \ref tutorial_pe_02 \n
\subsection pdes Solving Partial Differential Equations \subsection pdes Solving Partial Differential Equations
......
...@@ -25,7 +25,7 @@ Please check the documentation of each individual function for more information. ...@@ -25,7 +25,7 @@ Please check the documentation of each individual function for more information.
\subsection FCD What fine collision detection functions are available? \subsection FCD What fine collision detection functions are available?
Please check the documentation of each individual function for more information. Please check the documentation of each individual function for more information.
- fcd::SimpleFCD create via createSimpleFCDDataHandling() (analytic contact detection) - fcd::GenericFCD create via createGenericFCDDataHandling() (for analytic contact detection use fcd::AnalyticCollideFunctor)
\subsection CRSolvers What collision resolution solvers are available? \subsection CRSolvers What collision resolution solvers are available?
Please check the documentation of each individual solver for more information. Please check the documentation of each individual solver for more information.
...@@ -71,6 +71,10 @@ of every collision partner by retrieving the material of Contact::getBody1(), Co ...@@ -71,6 +71,10 @@ of every collision partner by retrieving the material of Contact::getBody1(), Co
you should call RigidBody::getTopSuperBody() and then RigidBody::getMass() you should call RigidBody::getTopSuperBody() and then RigidBody::getMass()
(RigidBody::getInertia()) using the returned rigid body. (RigidBody::getInertia()) using the returned rigid body.
\subsection SyncCalls How can I dynamically switch between sync calls?
You can bind the function to a boost function and call this one.
\snippet 02_ConfinedGasExtended.cpp Bind Sync Call
\section CommonFunctions Important Classes and Functions \section CommonFunctions Important Classes and Functions
**/ **/
......
...@@ -38,12 +38,23 @@ int main( int argc, char ** argv ) ...@@ -38,12 +38,23 @@ int main( int argc, char ** argv )
walberla::debug::enterTestMode(); walberla::debug::enterTestMode();
Environment env(argc, argv); Environment env(argc, argv);
const Config::BlockHandle configBlock = env.config()->getBlock( "LoadFromConfig" ); //! [Load Config]
auto cfg = env.config();
if (cfg == NULL) WALBERLA_ABORT("No config specified!");
const Config::BlockHandle configBlock = cfg->getBlock( "LoadFromConfig" );
//! [Load Config]
//! [Config Get Parameter]
real_t radius = configBlock.getParameter<real_t>("radius", real_c(0.4) );
//! [Config Get Parameter]
WALBERLA_UNUSED(radius);
shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>(); shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
// create blocks // create blocks
//! [Config BlockForest]
shared_ptr<BlockForest> forest = createBlockForestFromConfig( configBlock ); shared_ptr<BlockForest> forest = createBlockForestFromConfig( configBlock );
//! [Config BlockForest]
WALBERLA_CHECK_EQUAL( forest->getXSize(), 3 ); WALBERLA_CHECK_EQUAL( forest->getXSize(), 3 );
WALBERLA_CHECK_EQUAL( forest->getYSize(), 4 ); WALBERLA_CHECK_EQUAL( forest->getYSize(), 4 );
WALBERLA_CHECK_EQUAL( forest->getZSize(), 5 ); WALBERLA_CHECK_EQUAL( forest->getZSize(), 5 );
...@@ -53,9 +64,11 @@ int main( int argc, char ** argv ) ...@@ -53,9 +64,11 @@ int main( int argc, char ** argv )
WALBERLA_CHECK_FLOAT_EQUAL( forest->getDomain().minCorner(), Vec3(-15, -15, 0) ); WALBERLA_CHECK_FLOAT_EQUAL( forest->getDomain().minCorner(), Vec3(-15, -15, 0) );
WALBERLA_CHECK_FLOAT_EQUAL( forest->getDomain().maxCorner(), Vec3(-3, 8, 34) ); WALBERLA_CHECK_FLOAT_EQUAL( forest->getDomain().maxCorner(), Vec3(-3, 8, 34) );
//! [Config HCSITS]
BlockDataID blockDataID; BlockDataID blockDataID;
cr::HCSITS hcsits( globalBodyStorage, forest, blockDataID, blockDataID, blockDataID); cr::HCSITS hcsits( globalBodyStorage, forest, blockDataID, blockDataID, blockDataID);
configure(configBlock, hcsits); configure(configBlock, hcsits);
//! [Config HCSITS]
WALBERLA_CHECK_EQUAL( hcsits.getRelaxationModel(), cr::HCSITS::RelaxationModel::ApproximateInelasticCoulombContactByDecoupling ); WALBERLA_CHECK_EQUAL( hcsits.getRelaxationModel(), cr::HCSITS::RelaxationModel::ApproximateInelasticCoulombContactByDecoupling );
WALBERLA_CHECK_EQUAL( hcsits.getMaxIterations(), 123 ); WALBERLA_CHECK_EQUAL( hcsits.getMaxIterations(), 123 );
WALBERLA_CHECK_FLOAT_EQUAL( hcsits.getRelaxationParameter(), real_t(0.123) ); WALBERLA_CHECK_FLOAT_EQUAL( hcsits.getRelaxationParameter(), real_t(0.123) );
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
// You should have received a copy of the GNU General Public License along // 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/>. // with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
// //
//! \file Synchronization.cpp //! \file SerializeDeserialize.cpp
//! \author Sebastian Eibl <sebastian.eibl@fau.de> //! \author Sebastian Eibl <sebastian.eibl@fau.de>
// //
//====================================================================================================================== //======================================================================================================================
...@@ -46,13 +46,17 @@ void createDump() ...@@ -46,13 +46,17 @@ void createDump()
shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>(); shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
// create blocks // create blocks
auto forest = createBlockForest( math::AABB(0,0,0,60,60,60), //! [Dump Blockforest]
Vector3<uint_t>(2,2,2), // number of blocks auto forest = createBlockForest( math::AABB(0,0,0,60,60,60),
Vector3<bool>(false, false, false)); // periodicity Vector3<uint_t>(2,2,2), // number of blocks
Vector3<bool>(false, false, false)); // periodicity
forest->saveToFile("SerializeDeserialize.sbf"); forest->saveToFile("SerializeDeserialize.sbf");
//! [Dump Blockforest]
auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage"); //! [Init Storage]
auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD"); auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
//! [Init Storage]
auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD");
for (auto it = SCIterator(forest->getDomain(), Vec3(-1,-1,-1), 3); it != SCIterator(); ++it) for (auto it = SCIterator(forest->getDomain(), Vec3(-1,-1,-1), 3); it != SCIterator(); ++it)
{ {
...@@ -60,7 +64,9 @@ void createDump() ...@@ -60,7 +64,9 @@ void createDump()
} }
WALBERLA_LOG_DEVEL_ON_ROOT("dumping body storage"); WALBERLA_LOG_DEVEL_ON_ROOT("dumping body storage");
//! [Save Simulation Data]
forest->saveBlockData("SerializeDeserialize.dump", storageID); forest->saveBlockData("SerializeDeserialize.dump", storageID);
//! [Save Simulation Data]
for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt) for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
{ {
...@@ -80,16 +86,22 @@ void checkDump() ...@@ -80,16 +86,22 @@ void checkDump()
shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>(); shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
// create blocks // create blocks
auto forest = shared_ptr< BlockForest >( new BlockForest( uint_c( MPIManager::instance()->rank() ), "SerializeDeserialize.sbf", true, false ) ); //! [Load Blockforest]
auto forest = make_shared< BlockForest >( uint_c( MPIManager::instance()->rank() ), "SerializeDeserialize.sbf", true, false );
//! [Load Blockforest]
//! [Load Storage]
auto storageID = forest->loadBlockData("SerializeDeserialize.dump", createStorageDataHandling<BodyTuple>(), "Storage"); auto storageID = forest->loadBlockData("SerializeDeserialize.dump", createStorageDataHandling<BodyTuple>(), "Storage");
//! [Load Storage]
auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD"); auto ccdID = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD");
//! [Reload CCD]
for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt) for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
{ {
ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID ); ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
ccd->reloadBodies(); ccd->reloadBodies();
} }
//! [Reload CCD]
for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt) for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
{ {
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment