void testHelperFunctions( const std::string & meshFile, const uint_t numTotalBlocks ) { auto mesh = make_shared<MeshType>(); mesh::readAndBroadcast( meshFile, *mesh); auto triDist = make_shared< mesh::TriangleDistance<MeshType> >( mesh ); auto distanceOctree = make_shared< DistanceOctree< MeshType > >( triDist ); const real_t meshVolume = real_c( computeVolume( *mesh ) ); const real_t blockVolume = meshVolume / real_c( numTotalBlocks ); static const real_t cellsPersBlock = real_t(1000); const real_t cellVolume = blockVolume / cellsPersBlock; const real_t dx = std::pow( cellVolume, real_t(1) / real_t(3) ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with createStructuredBlockStorageInsideMesh with block size" ); auto sbf0 = mesh::createStructuredBlockStorageInsideMesh( distanceOctree, dx, numTotalBlocks ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with createStructuredBlockStorageInsideMesh with block size" ); Vector3<uint_t> blockSize( sbf0->getNumberOfXCells(), sbf0->getNumberOfYCells(), sbf0->getNumberOfZCells() ); auto sbf1 = mesh::createStructuredBlockStorageInsideMesh( distanceOctree, dx, blockSize ); auto exteriorAabb = computeAABB( *mesh ).getScaled( real_t(2) ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with createStructuredBlockStorageInsideMesh with block size" ); auto sbf2 = mesh::createStructuredBlockStorageOutsideMesh( exteriorAabb, distanceOctree, dx, numTotalBlocks ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with createStructuredBlockStorageInsideMesh with block size" ); blockSize = Vector3<uint_t>( sbf2->getNumberOfXCells(), sbf2->getNumberOfYCells(), sbf2->getNumberOfZCells() ); auto sbf3 = mesh::createStructuredBlockStorageOutsideMesh( exteriorAabb, distanceOctree, dx, blockSize ); }
// function sweep void simpleSweep( IBlock * block, BlockDataID fieldBlockDataID ) { // retrieve the field from the block auto field = block->getData< Field<real_t,1> >( fieldBlockDataID ); // some bogus "algorithm" for( auto iter = field->begin(); iter != field->end(); ++iter ) { if( *iter > real_c(ARBITRARY_VALUE) ) *iter /= real_c(2); else *iter *= real_c(2); } }
void operator()( IBlock * block ) { // the fieldID is now a member! (was set by the constructor) auto field = block->getData< Field<real_t,1> >( fieldID_ ); // some bogus "algorithm" for( auto iter = field->begin(); iter != field->end(); ++iter ) { if( *iter > real_c(ARBITRARY_VALUE) ) *iter /= real_c(2); else *iter *= real_c(2); } }
Field<real_t,1> * createFields( IBlock * const block, StructuredBlockStorage * const storage ) { return new Field<real_t,1> ( storage->getNumberOfXCells( *block ), // number of cells in x direction for this block storage->getNumberOfYCells( *block ), // number of cells in y direction for this block storage->getNumberOfZCells( *block ), // number of cells in z direction for this block real_c(0) ); // initial value }
int main( int argc, char ** argv ) { walberla::Environment env( argc, argv ); // create blocks shared_ptr< StructuredBlockForest > blocks = blockforest::createUniformBlockGrid( uint_c( 3), uint_c(2), uint_c( 4), // number of blocks in x,y,z direction uint_c(10), uint_c(8), uint_c(12), // how many cells per block (x,y,z) real_c(0.5), // dx: length of one cell in physical coordinates false, // one block per process? - "false" means all blocks to one process false, false, false ); // no periodicity // add a field to all blocks - and store the returned block data ID which is needed to access the field BlockDataID fieldID = blocks->addStructuredBlockData< Field<real_t,1> >( &createFields, "My Field" ); // iterate all blocks and initialize with random values for( auto blockIterator = blocks->begin(); blockIterator != blocks->end(); ++blockIterator ) { IBlock & currentBlock = *blockIterator; // get the field stored on the current block Field<real_t,1> * field = currentBlock.getData< Field<real_t,1> >( fieldID ); // iterate the field and set random values for( auto iter = field->begin(); iter != field->end(); ++iter ) *iter = real_c( rand() % ARBITRARY_VALUE ); } // create time loop const uint_t numberOfTimesteps = uint_c(10); // number of time steps for non-gui runs SweepTimeloop timeloop( blocks, numberOfTimesteps ); // registering the function sweep auto pointerToTwoArgFunction = & simpleSweep; auto pointerToOneArgFunction = std::bind( pointerToTwoArgFunction, std::placeholders::_1, fieldID ); timeloop.add() << Sweep( pointerToOneArgFunction, "BogusAlgorithm" ); // registering the class sweep timeloop.add() << Sweep( SimpleSweep(fieldID), "BogusAlgorithmButNowAsFunctor" ); // two sweeps were registered, so both are executed in each time step GUI gui( timeloop, blocks, argc, argv ); gui.run(); return EXIT_SUCCESS; }
/*!\brief Returns the squirmer's surface velocity at a given relative position. * * \param rpos The relative global coordinate. * \return The local surface velocity of the squirmer. */ const Vec3 Squirmer::getSquirmerVelocity( const Vec3& rpos ) const { const auto rs = rpos.getNormalized(); const auto e = getQuaternion().rotate(Vec3(0.0,0.0,1.0)).getNormalized(); const auto v0 = getSquirmerVelocity(); const auto beta = getSquirmerBeta(); return ((e * rs) * rs - e) * real_c(1.5) * v0 * (1 + beta * (e * rs)); }
real_t getSphereSphereOverlap(const real_t d, const real_t r1, const real_t r2) { WALBERLA_ASSERT_GREATER(d, r1); WALBERLA_ASSERT_GREATER(d, r2); //http://math.stackexchange.com/questions/297751/overlapping-spheres if (d > r1+r2) return 0; else return math::M_PI / (real_c(12.0) * d) * (r1 + r2 - d) * (r1 + r2 - d) * (d*d + 2*d*(r1+r2) - 3*(r1-r2)*(r1-r2)); }
void test(const shared_ptr< DistanceOctree< MeshType > > & distanceOctree, const MeshType & mesh, const AABB & domainAABB, Vector3<uint_t> numBlocks) { Vector3<real_t> blockSize(domainAABB.xSize() / real_c(numBlocks[0]), domainAABB.ySize() / real_c(numBlocks[1]), domainAABB.zSize() / real_c(numBlocks[2])); real_t maxError = blockSize.min() / real_t(10); SetupBlockForest setupBlockforest; setupBlockforest.addRootBlockExclusionFunction(F(distanceOctree, maxError)); setupBlockforest.addWorkloadMemorySUIDAssignmentFunction(blockforest::uniformWorkloadAndMemoryAssignment); setupBlockforest.init(domainAABB, numBlocks[0], numBlocks[1], numBlocks[2], false, false, false); WALBERLA_LOG_DEVEL(setupBlockforest.toString()); std::vector< Vector3<real_t> > vertexPositions; vertexPositions.reserve(mesh.n_vertices()); for (auto vIt = mesh.vertices_begin(); vIt != mesh.vertices_end(); ++vIt) { vertexPositions.push_back(toWalberla(mesh.point(*vIt))); } std::vector< const blockforest::SetupBlock* > setupBlocks; setupBlockforest.getBlocks(setupBlocks); // Check wether all vertices are located in allocated blocks std::vector< Vector3<real_t> > uncoveredVertices(vertexPositions); for (auto bIt = setupBlocks.begin(); bIt != setupBlocks.end(); ++bIt) { const AABB & aabb = (*bIt)->getAABB(); uncoveredVertices.erase(std::remove_if(uncoveredVertices.begin(), uncoveredVertices.end(), PointInAABB(aabb)), uncoveredVertices.end()); } WALBERLA_CHECK(uncoveredVertices.empty(), "Not all vertices of the mesh are located in allocated blocks!"); //setupBlockforest.assignAllBlocksToRootProcess(); //setupBlockforest.writeVTKOutput( "setupblockforest" ); }
ExprSystemInitFunction::ExprSystemInitFunction( const shared_ptr<StructuredBlockForest> & blocks ) : blocks_( blocks ), cell_(), symbolTable_( new exprtk::symbol_table<real_t>() ), expr_( new std::map<std::string, Expression>() ) { // add constants symbolTable_->add_constant( "n_x", real_c( blocks_->getNumberOfXCells() ) ); symbolTable_->add_constant( "n_y", real_c( blocks_->getNumberOfYCells() ) ); symbolTable_->add_constant( "n_z", real_c( blocks_->getNumberOfZCells() ) ); // add variables symbolTable_->add_variable( "x" , cell_[0] ); symbolTable_->add_variable( "y" , cell_[1] ); symbolTable_->add_variable( "z" , cell_[2] ); // add global constants (pi, e, etc.) symbolTable_->add_constants(); // register symbols with expressions (*expr_)[ "u_x" ].register_symbol_table( *symbolTable_ ); (*expr_)[ "u_y" ].register_symbol_table( *symbolTable_ ); (*expr_)[ "u_z" ].register_symbol_table( *symbolTable_ ); (*expr_)[ "rho" ].register_symbol_table( *symbolTable_ ); }
/*! Loops over measurements and updates them if necessary *******************************************************************************************************************/ void PerformanceMeter::updateCellCounts() { WALBERLA_ASSERT_GREATER( timer_.getCounter(), 0 ); uint_t ts = timer_.getCounter(); for( auto measureIt = measurements_.begin(); measureIt != measurements_.end(); ++measureIt ) { if( measureIt->countingFreq > 0 && ts % measureIt->countingFreq == 0 ) { uint_t cells = 0; for( auto block = blockStorage_.begin(); block != blockStorage_.end(); ++block ) cells += measureIt->countFunction( *block ); real_t cellsLastTimeStep = real_c ( cells ); measureIt->counts += 1; real_t rCounts = real_c( measureIt->counts ); measureIt->avgCellsPerTimeStep = (rCounts - real_t(1.0) ) / rCounts * measureIt->avgCellsPerTimeStep + real_t(1.0) / rCounts * cellsLastTimeStep; } } }
SquirmerID createSquirmer( BodyStorage& globalStorage, BlockStorage& blocks, BlockDataID storageID, id_t uid, const Vec3& gpos, real_t radius, real_t squirmerVelocity, real_t squirmerBeta, MaterialID material, bool global, bool communicating, bool infiniteMass ) { WALBERLA_ASSERT_UNEQUAL( Squirmer::getStaticTypeID(), std::numeric_limits<id_t>::max(), "Squirmer TypeID not initalized!"); // Checking the radius if( radius <= real_c(0) ) throw std::invalid_argument( "Invalid squirmer radius" ); SquirmerID squirmer = nullptr; if (global) { const id_t sid = UniqueID<RigidBody>::createGlobal(); WALBERLA_ASSERT_EQUAL(communicating, false); WALBERLA_ASSERT_EQUAL(infiniteMass, true); SquirmerPtr sq = std::make_unique<Squirmer>(sid, uid, gpos, Vec3(0,0,0), Quat(), radius, squirmerVelocity, squirmerBeta, material, global, false, true); squirmer = static_cast<SquirmerID>(&globalStorage.add(std::move(sq))); } else { for (auto& block : blocks){ if (block.getAABB().contains(gpos)) { const id_t sid( UniqueID<RigidBody>::create() ); BodyStorage& bs = (*block.getData<Storage>(storageID))[0]; SquirmerPtr sq = std::make_unique<Squirmer>(sid, uid, gpos, Vec3(0,0,0), Quat(), radius, squirmerVelocity, squirmerBeta, material, global, communicating, infiniteMass); sq->MPITrait.setOwner(Owner(MPIManager::instance()->rank(), block.getId().getID())); squirmer = static_cast<SquirmerID>(&bs.add( std::move(sq) )); } } } if (squirmer != nullptr) { // Logging the successful creation of the squirmer WALBERLA_LOG_DETAIL( "Created squirmer " << squirmer->getSystemID() << "\n" << " User-ID = " << uid << "\n" << " Global position = " << gpos << "\n" << " Radius = " << radius << "\n" << " LinVel = " << squirmer->getLinearVel() << "\n" << " Material = " << Material::getName( material ) ); } return squirmer; }
/*! Prints all added measurements to the given output stream on specified process * \param os Output stream where results are printed * \param targetRank the MPI world rank of the process that should print. * or a negative value, if all process should print. *******************************************************************************************************************/ void PerformanceMeter::print( std::ostream & os, int targetRank ) { if( measurements_.size() == 0) return; std::vector<real_t> totalNrCells; reduce( totalNrCells, targetRank ); if ( MPIManager::instance()->worldRank() == targetRank || targetRank < 0 ) { os << "Performance Results: " << std::endl; for( uint_t i = 0; i < measurements_.size(); ++i ) { real_t res = totalNrCells[i] / real_c( timer_.average() ); res *= measurements_[i].scaling; os << " - "; os << std::setw (16) << std::left << measurements_[i].name ; os << std::setw (8) << std::right << res << std::endl; } } }
void main( int argc, char ** argv ) { Environment env(argc, argv); WALBERLA_UNUSED(env); walberla::mpi::MPIManager::instance()->useWorldComm(); //init domain partitioning auto forest = blockforest::createBlockForest( AABB(0,0,0,20,20,20), // simulation domain Vector3<uint_t>(2,2,2), // blocks in each direction Vector3<bool>(false, false, false) // periodicity ); domain::BlockForestDomain domain(forest); //init data structures data::ParticleStorage ps(100); //initialize particle auto uid = createSphere(ps, domain); WALBERLA_LOG_DEVEL_ON_ROOT("uid: " << uid); //init kernels mpi::ReduceProperty RP; mpi::SyncNextNeighbors SNN; //sync SNN(ps, domain); auto pIt = ps.find(uid); if (pIt != ps.end()) { pIt->getForceRef() += Vec3(real_c(walberla::mpi::MPIManager::instance()->rank())); } RP.operator()<ForceTorqueNotification>(ps); if (walberla::mpi::MPIManager::instance()->rank() == 0) { WALBERLA_CHECK_FLOAT_EQUAL( pIt->getForce(), Vec3(real_t(28)) ); } else { WALBERLA_CHECK_FLOAT_EQUAL( pIt->getForce(), Vec3(real_t(walberla::mpi::MPIManager::instance()->rank())) ); } }
int main(int argc, char **argv) { walberla::Environment env( argc, argv ); const uint_t cells [] = { 1,1,1 }; const uint_t blockCount [] = { 1, 1,1 }; const uint_t nrOfTimeSteps = 20; // Create BlockForest auto blocks = blockforest::createUniformBlockGrid(blockCount[0],blockCount[1],blockCount[2], //blocks cells[0],cells[1],cells[2], //cells 1, //dx false, //one block per process true,true,true); //periodicity // In addition to the normal GhostLayerField's we allocated additionally a field containing the whole global simulation domain for each block // we can then check if the GhostLayer communication is correct, by comparing the small field to the corresponding part of the big field BlockDataID pdfField = field::addToStorage<PdfField>( blocks, "Src" ); // Init src field with some values for( auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt ) // block loop { // Init PDF field PdfField * src = blockIt->getData<PdfField>(pdfField); for( auto cellIt = src->beginWithGhostLayerXYZ(); cellIt != src->end(); ++cellIt ) // over all x,y,z,f { for( auto d = stencil::D3Q19::begin(); d != stencil::D3Q19::end(); ++d ) cellIt.getF( d.toIdx() ) = real_c( d.toIdx() ); } } // Create TimeLoop SweepTimeloop timeloop (blocks, nrOfTimeSteps ); GUI gui (timeloop, blocks, argc, argv); gui.run(); //timeloop.singleStep(); return EXIT_SUCCESS; }
/*******************************************************************************************************************//** * \brief Query if n is prime. * * \param n The number to be checked. * * \return true if n is prime, false if not. **********************************************************************************************************************/ bool isPrime( const uint_t n ) { switch(n) { case 0: case 1: return false; case 2: return true; default: if( n % 2 == 0 ) return false; uint_t sqrtN = uint_c( std::sqrt( real_c(n) ) ); for( uint_t i = 3; i <= sqrtN; i += 2 ) if( n % i == 0 ) return false; break; } return true; }
/*! Collects the result of the PerformanceMeter from all MPI_Processes * * \param targetRank MPI world rank of the process where the PerformanceMeter is reduced to * on all other processes a null pointer is returned. If targetRank < 0 all processes * have a valid result * * \return a map of measurement-name to measurement value if (worldRank == targetRank ) || targetRank < 0 * and a null pointer otherwise *******************************************************************************************************************/ shared_ptr< std::map<std::string, real_t> > PerformanceMeter::getReduced ( int targetRank ) { typedef std::map<std::string, real_t> ResultMap; shared_ptr < ResultMap > res; std::vector<real_t> totalNrCells; reduce( totalNrCells, targetRank ); if ( MPIManager::instance()->worldRank() == targetRank || targetRank < 0 ) { res = make_shared< ResultMap > (); for( uint_t i = 0; i < measurements_.size(); ++i ) { real_t value = totalNrCells[i] / real_c( timer_.average() ); value *= measurements_[i].scaling; (*res) [ measurements_[i].name ] = value; } } return res; }
void checkSphWallLubricationForce() { const uint_t timestep (timeloop_->getCurrentTimeStep()+1); // variables for output of total force - requires MPI-reduction pe::Vec3 forceSphr1(0); // temporary variables real_t gap (0); for( auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt ) { for( auto curSphereIt = pe::BodyIterator::begin<pe::Sphere>( *blockIt, bodyStorageID_); curSphereIt != pe::BodyIterator::end<pe::Sphere>(); ++curSphereIt ) { pe::SphereID sphereI = ( curSphereIt.getBodyID() ); if ( sphereI->getID() == id1_ ) { for( auto globalBodyIt = globalBodyStorage_->begin(); globalBodyIt != globalBodyStorage_->end(); ++globalBodyIt) { if( globalBodyIt->getID() == id2_ ) { pe::PlaneID planeJ = static_cast<pe::PlaneID>( globalBodyIt.getBodyID() ); gap = pe::getSurfaceDistance(sphereI, planeJ); break; } } break; } } } WALBERLA_MPI_SECTION() { mpi::reduceInplace( gap, mpi::MAX ); } WALBERLA_ROOT_SECTION() { if (gap < real_comparison::Epsilon<real_t>::value ) { gap = walberla::math::Limits<real_t>::inf(); WALBERLA_LOG_INFO_ON_ROOT( "Sphere still too far from wall to calculate gap!" ); } else { WALBERLA_LOG_INFO_ON_ROOT( "Gap between sphere and wall: " << gap ); } } // get force on sphere for( auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt ) { for( auto bodyIt = pe::BodyIterator::begin<pe::Sphere>( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end<pe::Sphere>(); ++bodyIt ) { if( bodyIt->getID() == id1_ ) { forceSphr1 += bodyIt->getForce(); } } } // MPI reduction of pe forces over all processes WALBERLA_MPI_SECTION() { mpi::reduceInplace( forceSphr1[0], mpi::SUM ); mpi::reduceInplace( forceSphr1[1], mpi::SUM ); mpi::reduceInplace( forceSphr1[2], mpi::SUM ); } WALBERLA_LOG_INFO_ON_ROOT("Total force on sphere " << id1_ << " : " << forceSphr1); if ( print_ ) { WALBERLA_ROOT_SECTION() { std::ofstream file1; std::string filename1("Gap_LubricationForceBody1.txt"); file1.open( filename1.c_str(), std::ofstream::app ); file1.setf( std::ios::unitbuf ); file1.precision(15); file1 << gap << " " << forceSphr1[0] << std::endl; file1.close(); } } WALBERLA_ROOT_SECTION() { if ( timestep == uint_t(26399) ) { // according to the formula from Ding & Aidun 2003 // F = 6 * M_PI * rho_L * nu_L * relative velocity of both bodies=relative velocity of the sphere * r * r * 1/gap // the correct analytically calculated value is 339.292006996217 // in this geometry setup the relative error is 0.183515322065561 % real_t analytical = real_c(6.0) * walberla::math::M_PI * real_c(1.0) * nu_L_ * real_c(-vel_[0]) * radius_ * radius_ * real_c(1.0)/gap; real_t relErr = std::fabs( analytical - forceSphr1[0] ) / analytical * real_c(100.0); WALBERLA_CHECK_LESS( relErr, real_t(1) ); } } }
void checkSphSphLubricationForce() { const uint_t timestep (timeloop_->getCurrentTimeStep()+1); // variables for output of total force - requires MPI-reduction pe::Vec3 forceSphr1(0); pe::Vec3 forceSphr2(0); // temporary variables real_t gap (0); // calculate gap between the two spheres for( auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt ) { for( auto curSphereIt = pe::BodyIterator::begin<pe::Sphere>( *blockIt, bodyStorageID_); curSphereIt != pe::BodyIterator::end<pe::Sphere>(); ++curSphereIt ) { pe::SphereID sphereI = ( curSphereIt.getBodyID() ); if ( sphereI->getID() == id1_ ) { for( auto blockIt2 = blocks_->begin(); blockIt2 != blocks_->end(); ++blockIt2 ) { for( auto oSphereIt = pe::BodyIterator::begin<pe::Sphere>( *blockIt2, bodyStorageID_); oSphereIt != pe::BodyIterator::end<pe::Sphere>(); ++oSphereIt ) { pe::SphereID sphereJ = ( oSphereIt.getBodyID() ); if ( sphereJ->getID() == id2_ ) { gap = pe::getSurfaceDistance( sphereI, sphereJ ); break; } } } break; } } } WALBERLA_MPI_SECTION() { mpi::reduceInplace( gap, mpi::MAX ); } WALBERLA_ROOT_SECTION() { if (gap < real_comparison::Epsilon<real_t>::value ) { // shadow copies have not been synced yet as the spheres are outside the overlap region gap = walberla::math::Limits<real_t>::inf(); WALBERLA_LOG_INFO_ON_ROOT( "Spheres still too far apart to calculate gap!" ); } else { WALBERLA_LOG_INFO_ON_ROOT( "Gap between sphere 1 and 2: " << gap ); } } // get force on spheres for( auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt ) { for( auto bodyIt = pe::BodyIterator::begin<pe::Sphere>( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end<pe::Sphere>(); ++bodyIt ) { if( bodyIt->getID() == id1_ ) { forceSphr1 += bodyIt->getForce(); } else if( bodyIt->getID() == id2_ ) { forceSphr2 += bodyIt->getForce(); } } } // MPI reduction of pe forces over all processes WALBERLA_MPI_SECTION() { mpi::reduceInplace( forceSphr1[0], mpi::SUM ); mpi::reduceInplace( forceSphr1[1], mpi::SUM ); mpi::reduceInplace( forceSphr1[2], mpi::SUM ); mpi::reduceInplace( forceSphr2[0], mpi::SUM ); mpi::reduceInplace( forceSphr2[1], mpi::SUM ); mpi::reduceInplace( forceSphr2[2], mpi::SUM ); } WALBERLA_LOG_INFO_ON_ROOT("Total force on sphere " << id1_ << " : " << forceSphr1); WALBERLA_LOG_INFO_ON_ROOT("Total force on sphere " << id2_ << " : " << forceSphr2); if ( print_ ) { WALBERLA_ROOT_SECTION() { std::ofstream file1; std::string filename1("Gap_LubricationForceBody1.txt"); file1.open( filename1.c_str(), std::ofstream::app ); file1.setf( std::ios::unitbuf ); file1.precision(15); file1 << gap << " " << forceSphr1[0] << std::endl; file1.close(); std::ofstream file2; std::string filename2("Gap_LubricationForceBody2.txt"); file2.open( filename2.c_str(), std::ofstream::app ); file2.setf( std::ios::unitbuf ); file2.precision(15); file2 << gap << " " << forceSphr2[0] << std::endl; file2.close(); } } WALBERLA_ROOT_SECTION() { if ( timestep == uint_t(1000) ) { // both force x-components should be the same only with inverted signs WALBERLA_CHECK_FLOAT_EQUAL ( forceSphr2[0], -forceSphr1[0] ); // according to the formula from Ding & Aidun 2003 // F = 3/2 * M_PI * rho_L * nu_L * relative velocity of both spheres * r * r * 1/gap // the correct analytically calculated value is 339.2920063998 // in this geometry setup the relative error is 0.1246489711 % real_t analytical = real_c(3.0)/real_c(2.0) * walberla::math::M_PI * real_c(1.0) * nu_L_ * real_c(2.0) * real_c(vel_[0]) * radius_ * radius_ * real_c(1.0)/gap; real_t relErr = std::fabs( analytical - forceSphr2[0] ) / analytical * real_c(100.0); WALBERLA_CHECK_LESS( relErr, real_t(1) ); } } }
static void test() { for( uint_t i = 0; i < 5; ++i ) { SetupBlockForest forest; forest.addRefinementSelectionFunction( refinementSelectionFunctionAll ); real_t xmin = math::realRandom( real_c(-100), real_c(100) ); real_t xmax = math::realRandom( xmin + real_c(10), real_c(120) ); real_t ymin = math::realRandom( real_c(-100), real_c(100) ); real_t ymax = math::realRandom( ymin + real_c(10), real_c(120) ); real_t zmin = math::realRandom( real_c(-100), real_c(100) ); real_t zmax = math::realRandom( zmin + real_c(10), real_c(120) ); AABB domain( xmin, ymin, zmin, xmax, ymax, zmax ); forest.init( domain, math::intRandom( uint_t(5), uint_t(20) ), math::intRandom( uint_t(5), uint_t(20) ), math::intRandom( uint_t(5), uint_t(20) ), math::boolRandom(), math::boolRandom(), math::boolRandom() ); checkNeighborhoodConsistency( forest ); checkCollectorConsistency( forest ); } for( uint_t i = 0; i < 5; ++i ) { SetupBlockForest forest; forest.addRefinementSelectionFunction( refinementSelectionFunctionRandom ); real_t xmin = math::realRandom( real_c(-100), real_c(100) ); real_t xmax = math::realRandom( xmin + real_c(10), real_c(120) ); real_t ymin = math::realRandom( real_c(-100), real_c(100) ); real_t ymax = math::realRandom( ymin + real_c(10), real_c(120) ); real_t zmin = math::realRandom( real_c(-100), real_c(100) ); real_t zmax = math::realRandom( zmin + real_c(10), real_c(120) ); AABB domain( xmin, ymin, zmin, xmax, ymax, zmax ); forest.init( domain, math::intRandom( uint_t(5), uint_t(20) ), math::intRandom( uint_t(5), uint_t(20) ), math::intRandom( uint_t(5), uint_t(20) ), math::boolRandom(), math::boolRandom(), math::boolRandom() ); checkNeighborhoodConsistency( forest ); checkCollectorConsistency( forest ); } }
void test( const std::string & meshFile, const uint_t numProcesses, const uint_t numTotalBlocks ) { auto mesh = make_shared<MeshType>(); mesh::readAndBroadcast( meshFile, *mesh); auto aabb = computeAABB( *mesh ); auto domainAABB = aabb.getScaled( typename MeshType::Scalar(3) ); auto triDist = make_shared< mesh::TriangleDistance<MeshType> >( mesh ); auto distanceOctree = make_shared< DistanceOctree< MeshType > >( triDist ); const real_t meshVolume = real_c( computeVolume( *mesh ) ); const real_t blockVolume = meshVolume / real_c( numTotalBlocks ); static const real_t cellsPersBlock = real_t(1000); const real_t cellVolume = blockVolume / cellsPersBlock; const Vector3<real_t> cellSize( std::pow( cellVolume, real_t(1) / real_t(3) ) ); ComplexGeometryStructuredBlockforestCreator bfc( domainAABB, cellSize, makeExcludeMeshInterior( distanceOctree, cellSize.min() ) ); auto wl = mesh::makeMeshWorkloadMemory( distanceOctree, cellSize ); wl.setInsideCellWorkload(0); wl.setOutsideCellWorkload(1); wl.setForceZeroMemoryOnZeroWorkload(true); bfc.setWorkloadMemorySUIDAssignmentFunction( wl ); bfc.setRefinementSelectionFunction( makeRefinementSelection( distanceOctree, 5, cellSize[0], cellSize[0] * real_t(5) ) ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with StaticLevelwiseCurveBalanceWeighted Partitioner" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseCurveBalanceWeighted() ); auto sbf_default = bfc.createSetupBlockForest( Vector3<uint_t>(64,64,64), numProcesses ); //sbf_default->writeVTKOutput("sbf_default"); WALBERLA_LOG_INFO_ON_ROOT( sbf_default->toString() ); return; #ifdef WALBERLA_BUILD_WITH_PARMETIS WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_KWAY, no commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( blockforest::StaticLevelwiseParMetis::PARMETIS_PART_KWAY ) ); auto sbf = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf->writeVTKOutput("sbf"); WALBERLA_LOG_INFO_ON_ROOT( sbf->toString() ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_KWAY, commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( commInXDirection, blockforest::StaticLevelwiseParMetis::PARMETIS_PART_KWAY ) ); auto sbf_edge = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf_edge->writeVTKOutput("sbf_edge"); WALBERLA_LOG_INFO_ON_ROOT( sbf_edge->toString() ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_GEOM_KWAY, no commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( blockforest::StaticLevelwiseParMetis::PARMETIS_PART_GEOM_KWAY ) ); auto sbf_geom = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf_geom->writeVTKOutput("sbf_geom"); WALBERLA_LOG_INFO_ON_ROOT( sbf_geom->toString() ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_GEOM_KWAY, commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( commInXDirection, blockforest::StaticLevelwiseParMetis::PARMETIS_PART_GEOM_KWAY ) ); auto sbf_geom_edge = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf_geom_edge->writeVTKOutput("sbf_geom_edge"); WALBERLA_LOG_INFO_ON_ROOT( sbf_geom_edge->toString() ); #endif }
int main(int argc, char **argv ) { walberla::Environment env( argc, argv ); const uint_t cells [] = { 6,5,3 }; const uint_t blockCount [] = { 4, 3,2 }; const uint_t nrOfTimeSteps = 20; // Create BlockForest auto blocks = blockforest::createUniformBlockGrid(blockCount[0],blockCount[1],blockCount[2], //blocks cells[0],cells[1],cells[2], //cells 1, //dx false, //one block per process true,true,true); //periodicity LatticeModel latticeModel( lbm::collision_model::SRT(1.5 ) ); // In addition to the normal GhostLayerField's we allocated additionally a field containing the whole global simulation domain for each block // we can then check if the GhostLayer communication is correct, by comparing the small field to the corresponding part of the big field BlockDataID pdfField = lbm::addPdfFieldToStorage( blocks, "PdfField", latticeModel ); BlockDataID scalarField1 = field::addToStorage<ScalarField>( blocks, "ScalarFieldOneGl", real_t(0), field::zyxf, 1 ); BlockDataID scalarField2 = field::addToStorage<ScalarField>( blocks, "ScalarFieldTwoGl", real_t(0), field::zyxf, 2 ); BlockDataID vectorField = field::addToStorage<VectorField>( blocks, "VectorField", Vector3<real_t>(0,0,0) ); BlockDataID flagField = field::addFlagFieldToStorage<FField>( blocks, "FlagField" ); // Init src field with some values for( auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt ) // block loop { // Init PDF field PdfField * src = blockIt->getData<PdfField>(pdfField); for( auto cellIt = src->begin(); cellIt != src->end(); ++cellIt ) // over all x,y,z,f { Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() ); blocks->transformBlockLocalToGlobalCell(cell, *blockIt); *cellIt = real_c( ( cell[0] + cell[1] + cell[2] + cellIt.f() ) % cell_idx_t(42) ); } // Init scalarField1 ScalarField * sf = blockIt->getData<ScalarField> ( scalarField1 ); for( auto cellIt = sf->beginWithGhostLayer(); cellIt != sf->end(); ++cellIt ) // over all x,y,z { Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() ); blocks->transformBlockLocalToGlobalCell(cell, *blockIt); *cellIt = real_c( ( cell[0] + cell[1] + cell[2] ) % cell_idx_t(42) ); } // Init scalarField2 sf = blockIt->getData<ScalarField> ( scalarField2 ); for( auto cellIt = sf->beginWithGhostLayer(); cellIt != sf->end(); ++cellIt ) // over all x,y,z { Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() ); blocks->transformBlockLocalToGlobalCell(cell, *blockIt); *cellIt = real_c( ( cell[0] + cell[1] + cell[2] ) % cell_idx_t(42) ); } // Init vector field VectorField * vf = blockIt->getData<VectorField> ( vectorField ); for ( auto cellIt = vf->beginWithGhostLayer(); cellIt != vf->end(); ++cellIt ) { Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() ); blocks->transformBlockLocalToGlobalCell(cell, *blockIt); *cellIt = Vector3<real_t>( real_c(cell[0]), real_c(cell[1]), real_c(cell[2]) ); } // Init Flag field FField * ff = blockIt->getData<FField> ( flagField ); auto flag1 = ff->registerFlag( "AFlag 1" ); auto flag2 = ff->registerFlag( "BFlag 2" ); for ( auto cellIt = ff->beginWithGhostLayer(); cellIt != ff->end(); ++cellIt ) { Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() ); blocks->transformBlockLocalToGlobalCell( cell, *blockIt ); if ( ( cell[0] + cell[1] + cell[2] ) % 2 ) addFlag( cellIt, flag1); else addFlag( cellIt, flag2); } } // Create TimeLoop SweepTimeloop timeloop (blocks, nrOfTimeSteps ); GUI gui (timeloop, blocks, argc, argv); lbm::connectToGui<LatticeModel>( gui ); gui.run(); //timeloop.singleStep(); return EXIT_SUCCESS; }
void ExprSystemInitFunction::setGlobalCell( const Cell & cell ) { cell_[0] = real_c( cell.x() ); cell_[1] = real_c( cell.y() ); cell_[2] = real_c( cell.z() ); }
void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount) { int i, j; scale *= o->normalize_factor; BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); /* compute a new htilda */ #pragma omp parallel for private(i, j) for (i = 0; i < o->_M; ++i) { /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */ for (j = 0; j <= o->_N / 2; ++j) { fftw_complex exp_param1; fftw_complex exp_param2; fftw_complex conj_param; init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t); init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t); exp_complex(exp_param1, exp_param1); exp_complex(exp_param2, exp_param2); conj_complex(conj_param, o->_h0_minus[i * o->_N + j]); mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1); mul_complex_c(exp_param2, conj_param, exp_param2); add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2); mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale); } } #pragma omp parallel sections private(i, j) { #pragma omp section { if (o->_do_disp_y) { /* y displacement */ fftw_execute(o->_disp_y_plan); } } /* section 1 */ #pragma omp section { if (o->_do_chop) { /* x displacement */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; fftw_complex minus_i; init_complex(minus_i, 0.0, -1.0); init_complex(mul_param, -scale, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, minus_i); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); mul_complex_f(mul_param, mul_param, ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? 0.0f : o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_disp_x_plan); } } /* section 2 */ #pragma omp section { if (o->_do_chop) { /* z displacement */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; fftw_complex minus_i; init_complex(minus_i, 0.0, -1.0); init_complex(mul_param, -scale, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, minus_i); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); mul_complex_f(mul_param, mul_param, ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? 0.0f : o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_disp_z_plan); } } /* section 3 */ #pragma omp section { if (o->_do_jacobian) { /* Jxx */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); mul_complex_f(mul_param, mul_param, ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? 0.0f : o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_Jxx_plan); for (i = 0; i < o->_M; ++i) { for (j = 0; j < o->_N; ++j) { o->_Jxx[i * o->_N + j] += 1.0; } } } } /* section 4 */ #pragma omp section { if (o->_do_jacobian) { /* Jzz */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); mul_complex_f(mul_param, mul_param, ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? 0.0f : o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_Jzz_plan); for (i = 0; i < o->_M; ++i) { for (j = 0; j < o->_N; ++j) { o->_Jzz[i * o->_N + j] += 1.0; } } } } /* section 5 */ #pragma omp section { if (o->_do_jacobian) { /* Jxz */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); mul_complex_f(mul_param, mul_param, ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? 0.0f : o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_Jxz_plan); } } /* section 6 */ #pragma omp section { /* fft normals */ if (o->_do_normals) { for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; init_complex(mul_param, 0.0, -1.0); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); mul_complex_f(mul_param, mul_param, o->_kx[i]); init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_N_x_plan); } } /* section 7 */ #pragma omp section { if (o->_do_normals) { for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; init_complex(mul_param, 0.0, -1.0); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); mul_complex_f(mul_param, mul_param, o->_kz[i]); init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_N_z_plan); #if 0 for (i = 0; i < o->_M; ++i) { for (j = 0; j < o->_N; ++j) { o->_N_y[i * o->_N + j] = 1.0f / scale; } } (MEM01) #endif o->_N_y = 1.0f / scale; } } /* section 8 */ } /* omp sections */ BLI_rw_mutex_unlock(&o->oceanmutex); }
void TimeStep::operator()() { if( numberOfSubIterations_ == 1 ) { forceEvaluationFunc_(); collisionResponse_.timestep( timeStepSize_ ); synchronizeFunc_(); } else { // during the intermediate time steps of the collision response, the currently acting forces // (interaction forces, gravitational force, ...) have to remain constant. // Since they are reset after the call to collision response, they have to be stored explicitly before. // Then they are set again after each intermediate step. // generate map from all known bodies (process local) to total forces/torques // this has to be done on a block-local basis, since the same body could reside on several blocks from this process using BlockID_T = domain_decomposition::IBlockID::IDType; std::map< BlockID_T, std::map< walberla::id_t, std::array< real_t, 6 > > > forceTorqueMap; for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) { BlockID_T blockID = blockIt->getId().getID(); auto& blockLocalForceTorqueMap = forceTorqueMap[blockID]; // iterate over local and remote bodies and store force/torque in map for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) { auto & f = blockLocalForceTorqueMap[ bodyIt->getSystemID() ]; const auto & force = bodyIt->getForce(); const auto & torque = bodyIt->getTorque(); f = {{force[0], force[1], force[2], torque[0], torque[1], torque[2] }}; } } // perform pe time steps const real_t subTimeStepSize = timeStepSize_ / real_c( numberOfSubIterations_ ); for( uint_t i = 0; i != numberOfSubIterations_; ++i ) { // in the first iteration, forces are already set if( i != 0 ) { for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) { BlockID_T blockID = blockIt->getId().getID(); auto& blockLocalForceTorqueMap = forceTorqueMap[blockID]; // re-set stored force/torque on bodies for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) { const auto f = blockLocalForceTorqueMap.find( bodyIt->getSystemID() ); if( f != blockLocalForceTorqueMap.end() ) { const auto & ftValues = f->second; bodyIt->addForce ( ftValues[0], ftValues[1], ftValues[2] ); bodyIt->addTorque( ftValues[3], ftValues[4], ftValues[5] ); } } } } // evaluate forces (e.g. lubrication forces) forceEvaluationFunc_(); collisionResponse_.timestep( subTimeStepSize ); synchronizeFunc_(); } } }