/* 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