summaryrefslogtreecommitdiff
path: root/src/particles/hlbm
diff options
context:
space:
mode:
Diffstat (limited to 'src/particles/hlbm')
-rw-r--r--src/particles/hlbm/hlbmDynamics2D.h110
-rw-r--r--src/particles/hlbm/hlbmDynamics2D.hh261
-rw-r--r--src/particles/hlbm/hlbmDynamics3D.h108
-rw-r--r--src/particles/hlbm/hlbmDynamics3D.hh317
4 files changed, 796 insertions, 0 deletions
diff --git a/src/particles/hlbm/hlbmDynamics2D.h b/src/particles/hlbm/hlbmDynamics2D.h
new file mode 100644
index 0000000..afc7bb5
--- /dev/null
+++ b/src/particles/hlbm/hlbmDynamics2D.h
@@ -0,0 +1,110 @@
+/* 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
+ * <http://www.openlb.net/>
+ *
+ * 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_2D_H
+#define PARTICLEDYNAMICS_2D_H
+
+#include "core/superLattice2D.h"
+#include "functors/analytical/indicator/smoothIndicatorBaseF2D.h"
+
+
+namespace olb {
+
+template<typename T, typename DESCRIPTOR>
+class ParticleDynamics2D {
+private:
+ SuperLattice2D<T, DESCRIPTOR>& _sLattice;
+ UnitConverter<T,DESCRIPTOR> const& _converter;
+ SuperGeometry2D<T>& _superGeometry;
+ std::shared_ptr<IndicatorF2D<T> > _indicatorF;
+ std::vector<SmoothIndicatorF2D<T,T,true>* > _vectorOfIndicator;
+ T _lengthX;
+ T _lengthY;
+ Vector<T,2> _accExt;
+ bool _escapeFromDomain=false;
+ bool _oldWallCollision=true;
+
+public:
+ ParticleDynamics2D(SuperLattice2D<T, DESCRIPTOR>& sLattice,
+ UnitConverter<T,DESCRIPTOR> const& converter,
+ SuperGeometry2D<T>& superGeometry,
+ T lengthX, T lengthY, Vector<T,2> accExt = Vector<T,2> (0.,0.))
+ : _sLattice(sLattice),
+ _converter(converter),
+ _superGeometry(superGeometry),
+ _lengthX(lengthX),
+ _lengthY(lengthY),
+ _accExt(accExt)
+ {}
+
+ ParticleDynamics2D(SuperLattice2D<T, DESCRIPTOR>& sLattice,
+ UnitConverter<T,DESCRIPTOR> const& converter,
+ SuperGeometry2D<T>& superGeometry, std::shared_ptr<IndicatorF2D<T> > indicatorF,
+ bool escapeFromDomain, bool oldWallCollision=false,
+ Vector<T,2> accExt = Vector<T,2> (0.,0.))
+ : _sLattice(sLattice),
+ _converter(converter),
+ _superGeometry(superGeometry),
+ _indicatorF(indicatorF),
+ _accExt(accExt),
+ _escapeFromDomain(escapeFromDomain),
+ _oldWallCollision(oldWallCollision)
+ {}
+
+ void addCircle(Vector< T, 2> center, T radius, T density, T epsilon,
+ Vector<S,2> vel = Vector<S,2> (0.,0.));
+
+ void addCuboid(Vector< T, 2> center, T xLength, T yLength, T density,
+ T epsilon, T theta=0, Vector<S,2> vel = Vector<S,2> (0.,0.));
+
+ void addTriangle(Vector< T, 2> center, T radius, T density, T epsilon,
+ T theta, Vector<S,2> vel = Vector<S,2> (0.,0.));
+
+ void addParticle(SmoothIndicatorF2D<T, T, true>& indicator);
+
+ void computeBoundaryForce(std::vector<SmoothIndicatorF2D<T,T,true>* >& indicator);
+
+ void addWallColl(SmoothIndicatorF2D<T,T,true>& indicator, T delta);
+
+ void verletIntegration(SmoothIndicatorF2D<T,T,true>& indicator);
+
+ void updateParticleDynamics(std::string name, SmoothIndicatorF2D<T,T,true>& indicator);
+
+ void checkAndRemoveEscaped();
+
+ void addParticleField(SmoothIndicatorF2D<T,T,true>& indicator);
+
+ void simulateTimestep(std::string name);
+
+ void print();
+
+ void load(std::string filename, T epsilon);
+
+ void save(std::string filename);
+
+};
+
+}
+
+#endif
diff --git a/src/particles/hlbm/hlbmDynamics2D.hh b/src/particles/hlbm/hlbmDynamics2D.hh
new file mode 100644
index 0000000..95e996f
--- /dev/null
+++ b/src/particles/hlbm/hlbmDynamics2D.hh
@@ -0,0 +1,261 @@
+/* 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
+ * <http://www.openlb.net/>
+ *
+ * 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_2D_HH
+#define PARTICLEDYNAMICS_2D_HH
+
+#include "functors/analytical/indicator/indicCalc2D.h"
+#include "functors/lattice/superLatticeLocalF2D.h"
+#include "hlbmDynamics2D.h"
+
+namespace olb {
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::addCircle(Vector< T, 2> center, T radius, T density, T epsilon, Vector<S,2> vel)
+{
+ _vectorOfIndicator.push_back (
+ new SmoothIndicatorCircle2D<T,T,true>(center, radius, epsilon, density, vel) );
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::addCuboid(Vector< T, 2> center, T xLength, T yLength, T density, T epsilon, T theta, Vector<S,2> vel)
+{
+ _vectorOfIndicator.push_back (
+ new SmoothIndicatorCuboid2D<T,T,true>(center, xLength, yLength, epsilon, theta, density, vel) );
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::addTriangle(Vector< T, 2> center, T radius, T density, T epsilon, T theta, Vector<S,2> vel)
+{
+ _vectorOfIndicator.push_back (
+ new SmoothIndicatorTriangle2D<T,T,true>(center, radius, epsilon, theta, density, vel) );
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::addParticle(SmoothIndicatorF2D<T,T,true>& indicator)
+{
+ _vectorOfIndicator.push_back(&indicator);
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::computeBoundaryForce(std::vector<SmoothIndicatorF2D<T,T,true>* >& indicator)
+{
+ SuperLatticePorousMomentumLossForce2D<T, DESCRIPTOR> force(_sLattice, _superGeometry, indicator,_converter);
+ T sumF[force.getTargetDim()];
+ for (int i=0; i<force.getTargetDim(); i++) {
+ sumF[i]=0.;
+ }
+ int input[1];
+ force(sumF, input);
+ for (typename std::vector<SmoothIndicatorF2D<T,T,true>* >::size_type iInd=0; iInd!=indicator.size(); iInd++) {
+ /// get particle acceleration through boundary force and gravity (and buoyancy)
+ Vector<T,2> acceleration2;
+ Vector<T,2> force;
+ force[0] = sumF[0+4*iInd];
+ force[1] = sumF[1+4*iInd];
+ acceleration2[0] = sumF[0+4*iInd] / indicator[iInd]->getMass() + _accExt[0];
+ acceleration2[1] = sumF[1+4*iInd] / indicator[iInd]->getMass() + _accExt[1];
+ indicator[iInd]->setForce( force );
+ indicator[iInd]->setAcc2( acceleration2 );
+ indicator[iInd]->setAlpha2( sumF[2+4*iInd] / indicator[iInd]->getMofi() );
+ }
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::addWallColl(SmoothIndicatorF2D<T,T,true>& indicator, T delta)
+{
+ T w1 = 1e-7 / 2.;
+ T w = 1e-7 / 2.;
+
+ T rad = indicator.getRadius();
+ T massInv = 1. / indicator.getMass();
+
+ std::vector<T> dx(2, T());
+ dx[0] = _lengthX - indicator.getPos()[0];
+ dx[1] = _lengthY - indicator.getPos()[1];
+
+ for (int i = 0; i < 2; 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::verletIntegration(SmoothIndicatorF2D<T,T,true>& indicator)
+{
+ T time = _converter.getConversionFactorTime();
+ T time2 = time*time;
+
+ Vector<T,2> position, velocity;
+ Vector<T,4> rotationMatrix;
+ for (int i=0; i<2; 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;
+ }
+ indicator.setPos(position);
+ indicator.setVel(velocity);
+ indicator.setAcc(indicator.getAcc2());
+
+ indicator.setTheta( std::fmod( indicator.getTheta() + indicator.getOmega() * time + (0.5 * indicator.getAlpha() * time2), 2.*M_PI ) );
+ T avgAlpha = (indicator.getAlpha() + indicator.getAlpha2()) * 0.5;
+ indicator.setOmega( indicator.getOmega() + avgAlpha * time);
+ indicator.setAlpha( indicator.getAlpha2() );
+
+ T cos = std::cos(indicator.getTheta());
+ T sin = std::sin(indicator.getTheta());
+
+ rotationMatrix[0] = cos;
+ rotationMatrix[1] = -sin;
+ rotationMatrix[2] = sin;
+ rotationMatrix[3] = cos;
+ indicator.setRotationMatrix(rotationMatrix);
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::updateParticleDynamics(std::string name, SmoothIndicatorF2D<T,T,true>& indicator)
+{
+ this->verletIntegration(indicator);
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::checkAndRemoveEscaped()
+{
+ for (auto i=_vectorOfIndicator.begin(); i!=_vectorOfIndicator.end(); i++) {
+ auto internal = std::make_shared<IndicatorLayer2D<T> > (*_indicatorF.get(), -_converter.getConversionFactorLength()+(**i).getEpsilon() );
+ IndicMinus2D<T> layer(_indicatorF, internal);
+ SuperLatticeIndicatorSmoothIndicatorIntersection2D<T,DESCRIPTOR,true> 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::addParticleField(SmoothIndicatorF2D<T,T,true>& indicator)
+{
+ /// Analytical2D functor for particle motion (trans+rot)
+ ParticleU2D<T,T,DESCRIPTOR> velocity(indicator, _converter);
+ _sLattice.setExternalParticleField(_superGeometry, velocity, indicator);
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::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<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::print()
+{
+ OstreamManager clout(std::cout, "ParticleDynamics2D");
+ 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)= " << std::setw(13) << (**i).getCircumRadius() <<std::endl;
+ clout << " |Mass(kg)= " << std::setw(13) << (**i).getMass() << std::endl;
+ clout << " |Position(m)= (" << std::setw(13) << (**i).getPos()[0] << ", " << std::setw(13) << (**i).getPos()[1] << ")" << std::endl;
+ clout << " |Angle(°)= " << std::setw(13) << (**i).getTheta()*(180/M_PI) << std::endl;
+ clout << " |Velocity(m/s)= (" << std::setw(13) <<(**i).getVel()[0] << ", " << std::setw(13) << (**i).getVel()[1] << ")" << std::endl;
+ clout << " |Ang. velocity(°/s)= " << std::setw(13) << (**i).getOmega()*(180/M_PI) << std::endl;
+ clout << " |Hydro. Force(N)= (" << std::setw(13) <<(**i).getForce()[0] << ", " << std::setw(13) << (**i).getForce()[1] << ")" << std::endl;
+ clout << " |Acceleration(m/s^2)= (" << std::setw(13) << (**i).getAcc()[0] << ", " << std::setw(13) << (**i).getAcc()[1] << ")" << std::endl;
+ clout << " |Ang. acc.(°/s^2)= " << std::setw(13) << (**i).getAlpha()*(180/M_PI) << std::endl;
+ }
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::load(std::string filename, T epsilon)
+{
+ std::ifstream iout( (singleton::directories().getLogOutDir() + filename).c_str() );
+
+ while (iout) {
+ std::string name = "";
+ iout >> name;
+
+ if (name == "circle") {
+ T radius = T(), mass = T();
+ Vector<T, 2> center = {T(), T()};
+ Vector<T, 2> vel = {T(), T()};
+ iout >> center[0] >> center[1] >> radius >> mass >> vel[0] >> vel[1];
+ addCircle(center, radius, mass, epsilon, vel);
+ }
+ }
+
+ iout.close();
+}
+
+// WORKS ONLY FOR CIRCLES FOR NOW!!
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics2D<T, DESCRIPTOR>::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() == "circle") {
+ fout << (**i).name() << " "
+ << (**i).getPos()[0] << " " << (**i).getPos()[1] << " "
+ << (**i).getCircumRadius() << " " << (**i).getMass() << " "
+ << (**i).getVel()[0] << " " << (**i).getVel()[1]
+ << std::endl;
+ }
+ }
+
+ fout.close();
+}
+
+}
+
+#endif
diff --git a/src/particles/hlbm/hlbmDynamics3D.h b/src/particles/hlbm/hlbmDynamics3D.h
new file mode 100644
index 0000000..b39219b
--- /dev/null
+++ b/src/particles/hlbm/hlbmDynamics3D.h
@@ -0,0 +1,108 @@
+/* DESCRIPTOR Boltzmann sample, written in C++, using the OpenLB
+ * library
+ *
+ * Copyright (C) 2006-2016 Thomas Henn, Fabian Klemens, Robn Trunk, Davide Dapelo
+ * E-mail contact: info@openlb.net
+ * The most recent release of OpenLB can be downloaded at
+ * <http://www.openlb.net/>
+ *
+ * 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_H
+#define PARTICLEDYNAMICS_3D_H
+
+#include "core/superLattice3D.h"
+#include "functors/analytical/indicator/smoothIndicatorBaseF3D.h"
+
+namespace olb {
+
+template<typename T, typename DESCRIPTOR>
+class ParticleDynamics3D {
+private:
+ SuperLattice3D<T, DESCRIPTOR>& _sLattice;
+ UnitConverter<T,DESCRIPTOR> const& _converter;
+ SuperGeometry3D<T>& _superGeometry;
+ std::shared_ptr<IndicatorF3D<T> > _indicatorF;
+ std::vector<SmoothIndicatorF3D<T,T,true>* > _vectorOfIndicator;
+ T _lengthX;
+ T _lengthY;
+ T _lengthZ;
+ Vector<T,3> _accExt;
+ bool _escapeFromDomain=false;
+ bool _oldWallCollision=true;
+
+public:
+ ParticleDynamics3D(SuperLattice3D<T, DESCRIPTOR>& sLattice,
+ UnitConverter<T,DESCRIPTOR> const& converter,
+ SuperGeometry3D<T>& superGeometry,
+ T lengthX, T lengthY, T lengthZ,
+ Vector<T,3> accExt = Vector<T,3> (0.,0.,0.))
+ : _sLattice(sLattice),
+ _converter(converter),
+ _superGeometry(superGeometry),
+ _lengthX(lengthX),
+ _lengthY(lengthY),
+ _lengthZ(lengthZ),
+ _accExt(accExt)
+ {}
+
+ ParticleDynamics3D(SuperLattice3D<T, DESCRIPTOR>& sLattice,
+ UnitConverter<T,DESCRIPTOR> const& converter,
+ SuperGeometry3D<T>& superGeometry,
+ std::shared_ptr<IndicatorF3D<T> > indicatorF,
+ bool escapeFromDomain, bool oldWallCollision=false,
+ Vector<T,3> accExt = Vector<T,3> (0.,0.,0.))
+ : _sLattice(sLattice),
+ _converter(converter),
+ _superGeometry(superGeometry),
+ _indicatorF(indicatorF),
+ _accExt(accExt),
+ _escapeFromDomain(escapeFromDomain),
+ _oldWallCollision(oldWallCollision)
+ {}
+
+ void addCuboid(Vector< T, 3> center, T xLength, T yLength, T zLength, T mass, T epsilon, Vector< T, 3 > theta, Vector<S,3> vel = Vector<S,3> (0.,0.,0.));
+ void addSphere(Vector< T, 3> center, T radius, T epsilon, T density, Vector<S,3> vel = Vector<S,3> (0.,0.,0.));
+ void addParticle(SmoothIndicatorF3D<T, T, true>& indicator);
+
+ void computeBoundaryForce(std::vector<SmoothIndicatorF3D<T, T, true>* >& indicator);
+
+ void addWallColl(SmoothIndicatorF3D<T, T, true>& indicator, T delta);
+
+ void verletIntegration(SmoothIndicatorF3D<T, T, true>& indicator);
+
+ void updateParticleDynamics(std::string name, SmoothIndicatorF3D<T, T, true>& indicator);
+
+ void checkAndRemoveEscaped();
+
+ void addParticleField(SmoothIndicatorF3D<T, T, true>& indicator);
+
+ void simulateTimestep(std::string name);
+
+ void print();
+
+ void load(std::string filename, T epsilon);
+
+ void save(std::string filename);
+
+ void eulerIntegration(SmoothIndicatorF3D<T,T,true>& indicator);
+
+};
+
+}
+
+#endif
diff --git a/src/particles/hlbm/hlbmDynamics3D.hh b/src/particles/hlbm/hlbmDynamics3D.hh
new file mode 100644
index 0000000..bc86b90
--- /dev/null
+++ b/src/particles/hlbm/hlbmDynamics3D.hh
@@ -0,0 +1,317 @@
+/* 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
+ * <http://www.openlb.net/>
+ *
+ * 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::addCuboid(Vector< T, 3> center, T xLength, T yLength, T zLength, T density, T epsilon, Vector< T, 3 > theta, Vector<S,3> vel)
+{
+ _vectorOfIndicator.push_back (
+ new SmoothIndicatorCuboid3D<T, T, true>(center, xLength, yLength, zLength, density, epsilon, theta, vel) );
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::addSphere(Vector< T, 3> center, T radius, T epsilon, T density, Vector<S,3> vel)
+{
+ _vectorOfIndicator.push_back (
+ new SmoothIndicatorSphere3D<T, T, true>(center, radius, density, epsilon, vel) );
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::addParticle(SmoothIndicatorF3D<T, T, true>& indicator)
+{
+ _vectorOfIndicator.push_back(&indicator);
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::computeBoundaryForce(std::vector<SmoothIndicatorF3D<T,T,true>* >& indicator)
+{
+ SuperLatticePorousMomentumLossForce3D<T, DESCRIPTOR> force(_sLattice, _superGeometry, indicator, _converter);
+ T sumF[force.getTargetDim()];
+ for (int i=0; i<force.getTargetDim(); i++) {
+ sumF[i]=0.;
+ }
+
+ int input[1];
+ force(sumF, input);
+ for (typename std::vector<SmoothIndicatorF3D<T, T, true>* >::size_type iInd=0; iInd!=indicator.size(); iInd++) {
+ /// get particle acceleration through boundary force and gravity (and buoyancy)
+ Vector<T,3> acceleration2;
+ Vector<T,3> force;
+ Vector<T,3> 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::addWallColl(SmoothIndicatorF3D<T, T, true>& indicator, T delta)
+{
+ T w1 = delta * .5;
+ T w = delta * .5;
+
+ T rad = indicator.getRadius();
+ T massInv = 1. / indicator.getMass();
+
+ std::vector<T> 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::verletIntegration(SmoothIndicatorF3D<T, T, true>& indicator)
+{
+ T time = _converter.getConversionFactorTime();
+ T time2 = time*time;
+
+ Vector<T,3> position, velocity, theta, omega, alpha;
+ Vector<T,9> 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::updateParticleDynamics(std::string name, SmoothIndicatorF3D<T, T, true>& 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::checkAndRemoveEscaped()
+{
+ for (auto i=_vectorOfIndicator.begin(); i!=_vectorOfIndicator.end(); i++) {
+ auto internal = std::make_shared<IndicatorLayer3D<T> > (*_indicatorF.get(), -_converter.getConversionFactorLength()+(**i).getEpsilon() );
+ IndicMinus3D<T> layer(_indicatorF, internal);
+ SuperLatticeIndicatorSmoothIndicatorIntersection3D<T,DESCRIPTOR,true> 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::addParticleField(SmoothIndicatorF3D<T, T, true>& indicator)
+{
+ /// Analytical3D functor for particle motion (trans+rot)
+ ParticleU3D<T,T,DESCRIPTOR> velocity(indicator, _converter);
+ _sLattice.setExternalParticleField(_superGeometry, velocity, indicator);
+}
+
+template<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::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<T, 3> center = {T(), T(), T()};
+ Vector<T, 3> 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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::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<typename T, typename DESCRIPTOR>
+void ParticleDynamics3D<T, DESCRIPTOR>::eulerIntegration(SmoothIndicatorF3D<T,T,true>& indicator) {
+ T time = _converter.getConversionFactorTime();
+
+ Vector<T,3> position, velocity, theta, omega, alpha;
+ Vector<T,9> 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