/* DESCRIPTOR Boltzmann sample, written in C++, using the OpenLB * library * * Copyright (C) 2006-2016 Thomas Henn, Fabian Klemens, Robin Trunk, Davide Dapelo * E-mail contact: info@openlb.net * The most recent release of OpenLB can be downloaded at * * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef PARTICLEDYNAMICS_3D_HH #define PARTICLEDYNAMICS_3D_HH #include "hlbmDynamics3D.h" namespace olb { template void ParticleDynamics3D::addCuboid(Vector< T, 3> center, T xLength, T yLength, T zLength, T density, T epsilon, Vector< T, 3 > theta, Vector vel) { _vectorOfIndicator.push_back ( new SmoothIndicatorCuboid3D(center, xLength, yLength, zLength, density, epsilon, theta, vel) ); } template void ParticleDynamics3D::addSphere(Vector< T, 3> center, T radius, T epsilon, T density, Vector vel) { _vectorOfIndicator.push_back ( new SmoothIndicatorSphere3D(center, radius, density, epsilon, vel) ); } template void ParticleDynamics3D::addParticle(SmoothIndicatorF3D& indicator) { _vectorOfIndicator.push_back(&indicator); } template void ParticleDynamics3D::computeBoundaryForce(std::vector* >& indicator) { SuperLatticePorousMomentumLossForce3D force(_sLattice, _superGeometry, indicator, _converter); T sumF[force.getTargetDim()]; for (int i=0; i* >::size_type iInd=0; iInd!=indicator.size(); iInd++) { /// get particle acceleration through boundary force and gravity (and buoyancy) Vector acceleration2; Vector force; Vector alpha2; force[0] = sumF[0+7*iInd]; force[1] = sumF[1+7*iInd]; force[2] = sumF[2+7*iInd]; acceleration2[0] = sumF[0+7*iInd] / indicator[iInd]->getMass() + _accExt[0]; acceleration2[1] = sumF[1+7*iInd] / indicator[iInd]->getMass() + _accExt[1]; acceleration2[2] = sumF[2+7*iInd] / indicator[iInd]->getMass() + _accExt[2]; alpha2[0] = sumF[3+7*iInd] / indicator[iInd]->getMofi()[0]; alpha2[1] = sumF[4+7*iInd] / indicator[iInd]->getMofi()[1]; alpha2[2] = sumF[5+7*iInd] / indicator[iInd]->getMofi()[2]; indicator[iInd]->setForce( force ); indicator[iInd]->setAcc2( acceleration2 ); indicator[iInd]->setAlpha2( alpha2 ); } } template void ParticleDynamics3D::addWallColl(SmoothIndicatorF3D& indicator, T delta) { T w1 = delta * .5; T w = delta * .5; T rad = indicator.getRadius(); T massInv = 1. / indicator.getMass(); std::vector dx(3, T()); dx[0] = _lengthX - _converter.getPhysDeltaX() - indicator.getPos()[0]; dx[1] = _lengthY - _converter.getPhysDeltaX() - indicator.getPos()[1]; dx[2] = indicator.getPos()[2] - _converter.getPhysDeltaX(); for (int i = 0; i < 3; i++) { if (dx[i] <= rad) { indicator.getAcc2()[i] += massInv * -dx[i] * (rad - dx[i]) / w1; } if (indicator.getPos()[i] <= rad) { indicator.getAcc2()[i] += massInv * indicator.getPos()[i] * (rad - indicator.getPos()[i]) / w1; } if (dx[i] > rad && dx[i] <= rad + delta) { indicator.getAcc2()[i] += massInv * -dx[i] * std::pow((rad + delta - dx[i]), 2) / w; } if (indicator.getPos()[i] > rad && indicator.getPos()[i] <= rad + delta) { indicator.getAcc2()[i] += massInv * indicator.getPos()[i] * std::pow((rad + delta - indicator.getPos()[i]), 2) / w; } } } template void ParticleDynamics3D::verletIntegration(SmoothIndicatorF3D& indicator) { T time = _converter.getConversionFactorTime(); T time2 = time*time; Vector position, velocity, theta, omega, alpha; Vector rotationMatrix; for (int i=0; i<3; i++) { position[i] = indicator.getPos()[i] + indicator.getVel()[i] * time + (0.5 * indicator.getAcc()[i] * time2); T avgAcc = (indicator.getAcc()[i] + indicator.getAcc2()[i]) * 0.5; velocity[i] = indicator.getVel()[i] + avgAcc * time; theta[i] = std::fmod( indicator.getTheta()[i] + indicator.getOmega()[i] * time + (0.5 * indicator.getAlpha()[i] * time2), 2.*M_PI ); T avgAlpha = (indicator.getAlpha()[i] + indicator.getAlpha2()[i]) * 0.5; omega[i] = indicator.getOmega()[i] + avgAlpha * time; } indicator.setPos( position ); indicator.setVel( velocity ); indicator.setAcc( indicator.getAcc2() ); indicator.setTheta( theta ); indicator.setOmega( omega ); indicator.setAlpha( indicator.getAlpha2() ); T cos0 = std::cos(indicator.getTheta()[0]); T cos1 = std::cos(indicator.getTheta()[1]); T cos2 = std::cos(indicator.getTheta()[2]); T sin0 = std::sin(indicator.getTheta()[0]); T sin1 = std::sin(indicator.getTheta()[1]); T sin2 = std::sin(indicator.getTheta()[2]); rotationMatrix[0] = cos1 * cos2; rotationMatrix[1] = sin0*sin1*cos2 - cos0*sin2; rotationMatrix[2] = cos0*sin1*cos2 + sin0*sin2; rotationMatrix[3] = cos1*sin2; rotationMatrix[4] = sin0*sin1*sin2 + cos0*cos2; rotationMatrix[5] = cos0*sin1*sin2 - sin0*cos2; rotationMatrix[6] = -sin1; rotationMatrix[7] = sin0*cos1; rotationMatrix[8] = cos0*cos1; indicator.setRotationMatrix( rotationMatrix ); } template void ParticleDynamics3D::updateParticleDynamics(std::string name, SmoothIndicatorF3D& indicator) { if (name == "euler") { this->eulerIntegration(indicator); } else if (name == "verlet") { this->verletIntegration(indicator); } else { std::cout << "ERROR: no valid integration...use 'euler' or 'verlet'" << std::endl; } } template void ParticleDynamics3D::checkAndRemoveEscaped() { for (auto i=_vectorOfIndicator.begin(); i!=_vectorOfIndicator.end(); i++) { auto internal = std::make_shared > (*_indicatorF.get(), -_converter.getConversionFactorLength()+(**i).getEpsilon() ); IndicMinus3D layer(_indicatorF, internal); SuperLatticeIndicatorSmoothIndicatorIntersection3D intersection( _sLattice, _superGeometry, layer, **i ); int input[1]; T output[1] = {0.}; intersection(output, input); if (output[0] == 1) { _vectorOfIndicator.erase(i); if (i==_vectorOfIndicator.end() ) { break; } } } } template void ParticleDynamics3D::addParticleField(SmoothIndicatorF3D& indicator) { /// Analytical3D functor for particle motion (trans+rot) ParticleU3D velocity(indicator, _converter); _sLattice.setExternalParticleField(_superGeometry, velocity, indicator); } template void ParticleDynamics3D::simulateTimestep(std::string name) { // Remove particles from domain if _escapeFromDomain is toggled if (_escapeFromDomain) checkAndRemoveEscaped(); // Compute force acting on particles boundary computeBoundaryForce(_vectorOfIndicator); // Update particle dynamics and porous particle field for (auto i=_vectorOfIndicator.begin(); i!=_vectorOfIndicator.end(); i++) { updateParticleDynamics(name, **i); addParticleField(**i); } } template void ParticleDynamics3D::print() { OstreamManager clout(std::cout, "ParticleDynamics3D"); clout << "Number of particles=" << _vectorOfIndicator.size() << std::endl; int count = 0; for (auto i=_vectorOfIndicator.begin(); i!=_vectorOfIndicator.end(); i++) { clout << "Particle " << ++count << " (" << (**i).name() << "):" << std::endl; clout << " |Circum radius(m)= " << setw(13) << (**i).getCircumRadius() << std::endl; clout << " |Mass(kg)= " << setw(13) << (**i).getMass() << std::endl; clout << " |Position(m)= (" << setw(13) << (**i).getPos()[0] << ", " << setw(13) << (**i).getPos()[1] << ", " << setw(13) << (**i).getPos()[2] << ")" << std::endl; clout << " |Angle(°)= (" << setw(13) << (**i).getTheta()[0]*(180/M_PI) << ", " << setw(13) << (**i).getTheta()[1]*(180/M_PI) << ", " << setw(13) << (**i).getTheta()[2]*(180/M_PI) << ")" << std::endl; clout << " |Velocity(m/s)= (" << setw(13) << (**i).getVel()[0] << ", " << setw(13) << (**i).getVel()[1] << ", " << setw(13) << (**i).getVel()[2] << ")" << std::endl; clout << " |Ang. velocity(°/s)= (" << setw(13) << (**i).getOmega()[0]*(180/M_PI) << ", " << setw(13) << (**i).getOmega()[1]*(180/M_PI) << ", " << setw(13) << (**i).getOmega()[2]*(180/M_PI) << ")" << std::endl; clout << " |Hydro. Force(N)= (" << setw(13) << (**i).getForce()[0] << ", " << setw(13) << (**i).getForce()[1] << ", " << setw(13) << (**i).getForce()[2] << ")" << std::endl; clout << " |Acceleration(m/s^2)= (" << setw(13) << (**i).getAcc()[0] << ", " << setw(13) << (**i).getAcc()[1] << ", " << setw(13) << (**i).getAcc()[2] << ")" << std::endl; clout << " |Ang. acc.(°/s^2)= (" << setw(13) << (**i).getAlpha()[0]*(180/M_PI) << ", " << setw(13) << (**i).getAlpha()[1]*(180/M_PI) << ", " << setw(13) << (**i).getAlpha()[1]*(180/M_PI) << ")" << std::endl; } } // WORKS ONLY FOR SPHERES FOR NOW!! template void ParticleDynamics3D::load(std::string filename, T epsilon) { std::ifstream iout( (singleton::directories().getLogOutDir() + filename).c_str() ); while (iout) { std::string name = ""; iout >> name; if (name == "sphere") { T radius = T(), mass = T(); Vector center = {T(), T(), T()}; Vector vel = {T(), T(), T()}; iout >> center[0] >> center[1] >> center[2] >> radius >> mass >> vel[0] >> vel[1] >> vel[2]; addSphere(center, radius, epsilon, mass, vel); } } iout.close(); } // WORKS ONLY FOR SPHERES FOR NOW!! template void ParticleDynamics3D::save(std::string filename) { std::ofstream fout( (singleton::directories().getLogOutDir() + filename).c_str() ); for (auto i=_vectorOfIndicator.begin(); i!=_vectorOfIndicator.end(); i++) { if ((**i).name() == "sphere") { fout << (**i).name() << " " << (**i).getPos()[0] << " " << (**i).getPos()[1] << " " << (**i).getPos()[2] << " " << (**i).getCircumRadius() << " " << (**i).getMass() << " " << (**i).getVel()[0] << " " << (**i).getVel()[1] << " " << (**i).getVel()[2] << std::endl; } } fout.close(); } template void ParticleDynamics3D::eulerIntegration(SmoothIndicatorF3D& indicator) { T time = _converter.getConversionFactorTime(); Vector position, velocity, theta, omega, alpha; Vector rotationMatrix; for (int i=0; i<3; i++) { velocity[i] = indicator.getVel()[i] + indicator.getAcc2()[i] * time; position[i] = indicator.getPos()[i] + indicator.getVel()[i] * time; omega[i] = indicator.getOmega()[i] + indicator.getAlpha2()[i] * time; theta[i] = indicator.getTheta()[i] + indicator.getOmega()[i] * time; } indicator.setPos( position ); indicator.setVel( velocity ); indicator.setAcc( indicator.getAcc2() ); indicator.setTheta( theta ); indicator.setOmega( omega ); indicator.setAlpha( indicator.getAlpha2() ); T cos0 = std::cos(indicator.getTheta()[0]); T cos1 = std::cos(indicator.getTheta()[1]); T cos2 = std::cos(indicator.getTheta()[2]); T sin0 = std::sin(indicator.getTheta()[0]); T sin1 = std::sin(indicator.getTheta()[1]); T sin2 = std::sin(indicator.getTheta()[2]); rotationMatrix[0] = cos1 * cos2; rotationMatrix[1] = sin0*sin1*cos2 - cos0*sin2; rotationMatrix[2] = cos0*sin1*cos2 + sin0*sin2; rotationMatrix[3] = cos1*sin2; rotationMatrix[4] = sin0*sin1*sin2 + cos0*cos2; rotationMatrix[5] = cos0*sin1*sin2 - sin0*cos2; rotationMatrix[6] = -sin1; rotationMatrix[7] = sin0*cos1; rotationMatrix[8] = cos0*cos1; indicator.setRotationMatrix( rotationMatrix ); } } #endif