void testPointUnitSphere( const math::Vector3<real_t> & p ) { static const geometry::Sphere UNIT_SPHERE( math::Vector3<real_t>( 0, 0, 0 ), real_t( 1 ) ); static const real_t EPSILON = real_t(1e-4); real_t q = lbm::intersectionRatioBisection( UNIT_SPHERE, p, -p, EPSILON ); Vector3<real_t> intersectionPoint = p + (-p) * q; real_t intersectionRadius = intersectionPoint.length(); WALBERLA_CHECK_LESS( std::fabs( intersectionRadius - real_t( 1 ) ), EPSILON ); q = lbm::intersectionRatioSphere( UNIT_SPHERE, p, -p ); intersectionPoint = p + ( -p ) * q; intersectionRadius = intersectionPoint.length(); WALBERLA_CHECK_LESS( std::fabs( intersectionRadius - real_t( 1 ) ), EPSILON ); q = lbm::intersectionRatio( UNIT_SPHERE, p, -p, EPSILON ); intersectionPoint = p + ( -p ) * q; intersectionRadius = intersectionPoint.length(); WALBERLA_CHECK_LESS( std::fabs( intersectionRadius - real_t( 1 ) ), EPSILON ); }
void testAABB() { static const math::Vector3<real_t> ZERO( real_t( 0 ), real_t( 0 ), real_t( 0 ) ); static const math::Vector3<real_t> UNIT( real_t( 1 ), real_t( 1 ), real_t( 1 ) ); static const real_t EPSILON = real_t(1e-4); boost::random::mt19937 randomEngine; std::vector<math::AABB> testAABBs; testAABBs.push_back( math::AABB( -UNIT, UNIT ) ); testAABBs.push_back( math::AABB( ZERO, UNIT ) ); testAABBs.push_back( math::AABB( -UNIT, ZERO ) ); for( auto aabbIt = testAABBs.begin(); aabbIt != testAABBs.end(); ++aabbIt ) { const math::AABB outerAABB = aabbIt->getScaled( real_t( 2 ) ); std::vector< std::pair< Vector3<real_t>, Vector3<real_t> > > testPoints; for( int i = 0; i < 100; ++i ) { Vector3<real_t> outerPoint, innerPoint; do { outerPoint = outerAABB.randomPoint( randomEngine ); } while( aabbIt->contains( outerPoint ) ); innerPoint = aabbIt->randomPoint( randomEngine ); testPoints.push_back( std::make_pair( outerPoint, innerPoint - outerPoint ) ); } for( auto pointIt = testPoints.begin(); pointIt != testPoints.end(); ++pointIt ) { const Vector3<real_t> & fluidPoint = pointIt->first; const Vector3<real_t> & direction = pointIt->second; real_t q = lbm::intersectionRatio( *aabbIt, fluidPoint, direction, EPSILON ); Vector3<real_t> intersectionPoint = fluidPoint + direction * q; WALBERLA_CHECK_LESS( std::fabs( aabbIt->sqSignedDistance( intersectionPoint ) ), EPSILON * EPSILON ); q = lbm::intersectionRatioBisection( *aabbIt, fluidPoint, direction, EPSILON ); intersectionPoint = fluidPoint + direction * q; WALBERLA_CHECK_LESS( std::fabs( aabbIt->sqSignedDistance( intersectionPoint ) ), EPSILON * EPSILON ); } } }
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) ); } } }