/* This file is part of the OpenLB library
*
* Copyright (C) 2014 Robin Trunk, Mathias J. Krause
* 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 BOUNDARYSIMPLEREFLECTION3D_HH
#define BOUNDARYSIMPLEREFLECTION3D_HH
#include
#include "boundarySimpleReflection3D.h"
namespace olb {
template class PARTICLETYPE>
SimpleReflectBoundary3D::SimpleReflectBoundary3D(T dT, SuperGeometry3D& sg, std::set materials) :
Boundary3D(), _dT(dT), _sg(sg), _materials(materials) {
_matIter = _materials.begin();
}
template class PARTICLETYPE>
void SimpleReflectBoundary3D::applyBoundary(typename std::deque >::iterator& p, ParticleSystem3D& psSys) {
std::vector oldPos(3,T());
oldPos[0] = p->getPos()[0] - _dT * p->getVel()[0];
oldPos[1] = p->getPos()[1] - _dT * p->getVel()[1];
oldPos[2] = p->getPos()[2] - _dT * p->getVel()[2];
std::vector line(3,T());
line[0] = p->getPos()[0] - oldPos[0];
line[1] = p->getPos()[1] - oldPos[1];
line[2] = p->getPos()[2] - oldPos[2];
std::vector reflection(3, T());
int latticeR[4] = { 0,0,0,0 };
bool outer = false;
// get material number (Trigger)
// TODO: take particle radius into account for collision detection
latticeR[0] = p->getCuboid();
_sg.getCuboidGeometry().get(latticeR[0]).getLatticeR(&(latticeR[1]),&p->getPos()[0]);
int mat = _sg.get(latticeR);
for (_matIter = _materials.begin(); _matIter != _materials.end();_matIter++) {
if (mat == *_matIter) {
// compute discrete normal
// TODO: rearrange the if to make computation more efficient
std::vector normal(3, T());
if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2], latticeR[3]) == 1) normal[0] = -1;
if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2], latticeR[3]) == 1) normal[0] = 1;
if (_sg.get(latticeR[0], latticeR[1], latticeR[2] - 1, latticeR[3]) == 1) normal[1] = -1;
if (_sg.get(latticeR[0], latticeR[1], latticeR[2] + 1, latticeR[3]) == 1) normal[1] = 1;
if (_sg.get(latticeR[0], latticeR[1], latticeR[2], latticeR[3] - 1) == 1) normal[2] = -1;
if (_sg.get(latticeR[0], latticeR[1], latticeR[2], latticeR[3] + 1) == 1) normal[2] = 1;
if (normal[0]==0 && normal[1]==0 && normal[2]==0) {
outer = true;
// check for outer edge
if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2] - 1, latticeR[3]) == 1) {
normal[0] = -1;
normal[1] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2] + 1, latticeR[3]) == 1) {
normal[0] = -1;
normal[1] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2] - 1, latticeR[3]) == 1) {
normal[0] = 1;
normal[1] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2] + 1, latticeR[3]) == 1) {
normal[0] = 1;
normal[1] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2], latticeR[3] - 1) == 1) {
normal[0] = -1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2], latticeR[3] + 1) == 1) {
normal[0] = -1;
normal[2] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2], latticeR[3] - 1) == 1) {
normal[0] = 1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2], latticeR[3] + 1) == 1) {
normal[0] = 1;
normal[2] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1], latticeR[2] - 1, latticeR[3] - 1) == 1) {
normal[1] = -1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1], latticeR[2] - 1, latticeR[3] + 1) == 1) {
normal[1] = -1;
normal[2] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1], latticeR[2] + 1, latticeR[3] - 1) == 1) {
normal[1] = +1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1], latticeR[2] + 1, latticeR[3] + 1) == 1) {
normal[1] = +1;
normal[2] = 1;
}
// check for outer corner
else if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2] - 1, latticeR[3] - 1) == 1) {
normal[0] = -1;
normal[1] = -1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2] - 1, latticeR[3] + 1) == 1) {
normal[0] = -1;
normal[1] = -1;
normal[2] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2] + 1, latticeR[3] - 1) == 1) {
normal[0] = -1;
normal[1] = +1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] - 1, latticeR[2] + 1, latticeR[3] + 1) == 1) {
normal[0] = -1;
normal[1] = +1;
normal[2] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2] - 1, latticeR[3] - 1) == 1) {
normal[0] = +1;
normal[1] = -1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2] - 1, latticeR[3] + 1) == 1) {
normal[0] = +1;
normal[1] = -1;
normal[2] = 1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2] + 1, latticeR[3] - 1) == 1) {
normal[0] = +1;
normal[1] = +1;
normal[2] = -1;
}
else if (_sg.get(latticeR[0], latticeR[1] + 1, latticeR[2] + 1, latticeR[3] + 1) == 1) {
normal[0] = +1;
normal[1] = +1;
normal[2] = 1;
}
// Error since normal is still zero
else {
std::cout << "----->>>>> ERROR Normal is ZERO" << std::endl;
outer=false;
}
}
T prod = line[0]*normal[0] + line[1]*normal[1] + line[2]*normal[2];
// if particle has obtuse angle to normal do nothing
if (!outer) {
if (prod >= 0) {
return;
}
}
// if particle has acute angle to normal reverse normal component of velocity
T invNormNormal = 1. / util::norm2(normal);
reflection[0] = line[0] - 2.*prod*normal[0]*invNormNormal;
reflection[1] = line[1] - 2.*prod*normal[1]*invNormNormal;
reflection[2] = line[2] - 2.*prod*normal[2]*invNormNormal;
// compute new velocity vector
T vel = util::norm(p->getVel());
reflection = util::normalize(reflection);
reflection[0] = reflection[0]*vel;
reflection[1] = reflection[1]*vel;
reflection[2] = reflection[2]*vel;
// TODO: take distance to impact point into account, not just 0.5
oldPos[0] += 0.5 * (line[0] + reflection[0]) * _dT;
oldPos[1] += 0.5 * (line[1] + reflection[1]) * _dT;
oldPos[2] += 0.5 * (line[2] + reflection[2]) * _dT;
p->getVel() = reflection;
p->setPos(oldPos);
return;
}
}
}
}
#endif