summaryrefslogtreecommitdiff
path: root/src/particles/twoWayCouplings
diff options
context:
space:
mode:
authorAdrian Kummerlaender2019-06-24 14:43:36 +0200
committerAdrian Kummerlaender2019-06-24 14:43:36 +0200
commit94d3e79a8617f88dc0219cfdeedfa3147833719d (patch)
treec1a6894679563e271f5c6ea7a17fa3462f7212a3 /src/particles/twoWayCouplings
downloadgrid_refinement_openlb-94d3e79a8617f88dc0219cfdeedfa3147833719d.tar
grid_refinement_openlb-94d3e79a8617f88dc0219cfdeedfa3147833719d.tar.gz
grid_refinement_openlb-94d3e79a8617f88dc0219cfdeedfa3147833719d.tar.bz2
grid_refinement_openlb-94d3e79a8617f88dc0219cfdeedfa3147833719d.tar.lz
grid_refinement_openlb-94d3e79a8617f88dc0219cfdeedfa3147833719d.tar.xz
grid_refinement_openlb-94d3e79a8617f88dc0219cfdeedfa3147833719d.tar.zst
grid_refinement_openlb-94d3e79a8617f88dc0219cfdeedfa3147833719d.zip
Initialize at openlb-1-3
Diffstat (limited to 'src/particles/twoWayCouplings')
-rw-r--r--src/particles/twoWayCouplings/backCouplingModels.h124
-rw-r--r--src/particles/twoWayCouplings/backCouplingModels.hh230
-rw-r--r--src/particles/twoWayCouplings/dragModels3D.h113
-rw-r--r--src/particles/twoWayCouplings/dragModels3D.hh150
-rw-r--r--src/particles/twoWayCouplings/forwardCouplingModels3D.h148
-rw-r--r--src/particles/twoWayCouplings/forwardCouplingModels3D.hh280
-rw-r--r--src/particles/twoWayCouplings/twoWayCouplings3D.h32
-rw-r--r--src/particles/twoWayCouplings/twoWayCouplings3D.hh32
-rw-r--r--src/particles/twoWayCouplings/twoWayHelperFunctionals.h232
-rw-r--r--src/particles/twoWayCouplings/twoWayHelperFunctionals.hh431
10 files changed, 1772 insertions, 0 deletions
diff --git a/src/particles/twoWayCouplings/backCouplingModels.h b/src/particles/twoWayCouplings/backCouplingModels.h
new file mode 100644
index 0000000..8f016d2
--- /dev/null
+++ b/src/particles/twoWayCouplings/backCouplingModels.h
@@ -0,0 +1,124 @@
+/* Lattice Boltzmann sample, written in C++, using the OpenLB
+ * library
+ *
+ * Copyright (C) 2019 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.
+ */
+
+/* Models for Lagrangian back-coupling methods -- header file.
+ */
+
+#ifndef LB_BACK_COUPLING_MODELS_H
+#define LB_BACK_COUPLING_MODELS_H
+
+#include "twoWayHelperFunctionals.h"
+
+namespace olb {
+
+/** Abstact base class for BaseBackCouplingModel.
+ * Its raison d'etre consists of not being templetized in Lattice.
+ */
+template<typename T, template<typename V> class Particle>
+class BackCouplingModel {
+public:
+ /// Class operator to apply the coupling, for overload.
+ virtual bool operator() (Particle<T>* p, int globic, int material, int subCycles=1)=0;
+ /// Resets external field
+ virtual void resetExternalField(int material)=0;
+};
+
+/** Abstact class for all the back-coupling models,
+ * viz., momentum coupling from particle to fluid.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class BaseBackCouplingModel : public BackCouplingModel<T,Particle> {
+public:
+ /// Resets external field
+ virtual void resetExternalField(int material) override;
+protected:
+ /// Constructor
+ BaseBackCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry );
+ UnitConverter<T, Lattice>& _converter; // reference to a UnitConverter
+ SuperGeometry3D<T>& _sGeometry;
+ SuperLattice3D<T, Lattice>& _sLattice; // reference to a lattice
+private:
+ // Pointers to functions to reset fluid force
+ std::shared_ptr<AnalyticalConst3D<T, T> > _zeroAnalytical;
+ std::shared_ptr<AnalyticalComposed3D<T, T> > _zeroField;
+};
+
+/** Back-coupling is performed on the cell containing the particle
+ * and its neighbours within a cube of one lattice spacing, as per in Maier et al. (2017).
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class CubicDeltaBackCouplingModel : public BaseBackCouplingModel<T,Lattice,Particle> {
+public:
+ /// Constructor
+ CubicDeltaBackCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry );
+ /// Class operator to apply the coupling.
+ virtual bool operator() (Particle<T>* p, int globic, int material, int subCycles=1) override;
+protected:
+ int _range = 1;
+ T _delta[4][4][4] = { T() };
+ std::shared_ptr<SuperLatticeSmoothDiracDelta3D<T, Lattice> > _cubicDeltaFunctional;
+};
+
+/** Back-coupling is performed only on the cell containing the particle.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class LocalBackCouplingModel : public BaseBackCouplingModel<T,Lattice,Particle> {
+public:
+ /// Constructor
+ LocalBackCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry );
+ /// Class operator to apply the coupling.
+ virtual bool operator() (Particle<T>* p, int globic, int material, int subCycles=1) override;
+};
+
+/** Class for a generic non-local back-coupling model,
+ * viz., momentum coupling from particle to fluid.
+ * It reproduces the characteristics (viz., smoothing) of an input forward coupling model.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class NonLocalBaseBackCouplingModel : public BaseBackCouplingModel<T,Lattice,Particle> {
+public:
+ /// Constructor
+ NonLocalBaseBackCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry,
+ SmoothingFunctional<T, Lattice>& smoothingFunctional );
+ /// Class operator to apply the coupling.
+ virtual bool operator() (Particle<T>* p, int globic, int material, int subCycles=1) override;
+protected:
+ SmoothingFunctional<T, Lattice>& _smoothingFunctional; // Functional to treat non-local smoothing
+};
+
+}
+
+#endif
diff --git a/src/particles/twoWayCouplings/backCouplingModels.hh b/src/particles/twoWayCouplings/backCouplingModels.hh
new file mode 100644
index 0000000..e88c62a
--- /dev/null
+++ b/src/particles/twoWayCouplings/backCouplingModels.hh
@@ -0,0 +1,230 @@
+/* Lattice Boltzmann sample, written in C++, using the OpenLB
+ * library
+ *
+ * Copyright (C) 2019 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.
+ */
+
+/* Models for Lagrangian back-coupling methods -- generic implementation.
+ */
+
+#ifndef LB_BACK_COUPLING_MODELS_HH
+#define LB_BACK_COUPLING_MODELS_HH
+
+namespace olb {
+
+
+////////////////////// Class BaseBackCouplingModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+BaseBackCouplingModel<T,Lattice,Particle>::BaseBackCouplingModel (
+ UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry )
+ : _converter(converter),
+ _sGeometry(sGeometry),
+ _sLattice(sLattice)
+{
+ _zeroAnalytical = std::make_shared<AnalyticalConst3D<T, T> > (T());
+ _zeroField = std::make_shared<AnalyticalComposed3D<T, T> > (*_zeroAnalytical, *_zeroAnalytical, *_zeroAnalytical);
+}
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+void BaseBackCouplingModel<T,Lattice,Particle>::resetExternalField(int material)
+{
+ // resets external field
+ this->_sLattice.template defineField<descriptors::FORCE>(this->_sGeometry, material, *_zeroField);
+
+ // NECESSARY to communicate values before using them in operator()
+ this->_sLattice.communicate();
+}
+
+
+////////////////////// Class CubicDeltaBackCouplingModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+CubicDeltaBackCouplingModel<T,Lattice,Particle>::CubicDeltaBackCouplingModel (
+ UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry )
+ : BaseBackCouplingModel<T,Lattice,Particle>(converter, sLattice, sGeometry)
+{
+ _cubicDeltaFunctional = std::make_shared<SuperLatticeSmoothDiracDelta3D<T, Lattice> > (
+ this->_sLattice, this->_converter, this->_sGeometry );
+}
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+bool CubicDeltaBackCouplingModel<T,Lattice,Particle>::operator() (Particle<T>* p, int globic, int material, int subCycles)
+{
+ int locIC = this->_sLattice.getLoadBalancer().loc(globic);
+
+ // reading the force from the value stored inside the particle
+ std::vector<T> physForceP = p->getStoreForce(); // physical force acting on the particle
+
+ T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle
+ latticeForceP[0] = physForceP[0] / this->_converter.getConversionFactorForce();
+ latticeForceP[1] = physForceP[1] / this->_converter.getConversionFactorForce();
+ latticeForceP[2] = physForceP[2] / this->_converter.getConversionFactorForce();
+
+ T physPosP[3] = {T(), T(), T()}; // particle's physical position
+ physPosP[0] = (p->getPos()[0]);
+ physPosP[1] = (p->getPos()[1]);
+ physPosP[2] = (p->getPos()[2]);
+
+ // particle's dimensionless position, rounded at neighbouring voxel
+ int latticeRoundedPosP[3] = {0, 0, 0};
+ this->_sLattice.getCuboidGeometry().get(globic).getLatticeR (
+ latticeRoundedPosP, physPosP );
+
+ // smooth Dirac delta
+ this->_cubicDeltaFunctional->operator() (_delta, physPosP, globic);
+
+ T tempDelta = T();
+ T F[3] = {T(), T(), T()}; // dimensionless smoothed force
+
+ for (int i = -_range; i <= _range; ++i) {
+ for (int j = -_range; j <= _range; ++j) {
+ for (int k = -_range; k <= _range; ++k) {
+ if (this->_sGeometry.getBlockGeometry(locIC).getMaterial(
+ latticeRoundedPosP[0] + i, latticeRoundedPosP[1] + j,
+ latticeRoundedPosP[2] + k) == material) {
+
+ tempDelta = _delta[i + _range][j + _range][k + _range];
+
+ F[0] = -latticeForceP[0] * tempDelta / (T)(subCycles);
+ F[1] = -latticeForceP[1] * tempDelta / (T)(subCycles);
+ F[2] = -latticeForceP[2] * tempDelta / (T)(subCycles);
+
+ this->_sLattice.getBlockLattice(locIC).get (
+ latticeRoundedPosP[0] + i,
+ latticeRoundedPosP[1] + j,
+ latticeRoundedPosP[2] + k ).template addField<descriptors::FORCE>( F );
+ }
+ }
+ }
+ }
+ return true;
+}
+
+
+////////////////////// Class LocalDeltaBackCouplingModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+LocalBackCouplingModel<T,Lattice,Particle>::LocalBackCouplingModel (
+ UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry )
+ : BaseBackCouplingModel<T,Lattice,Particle>(converter, sLattice, sGeometry)
+{}
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+bool LocalBackCouplingModel<T,Lattice,Particle>::operator() (Particle<T>* p, int globic, int material, int subCycles)
+{
+ int locIC = this->_sLattice.getLoadBalancer().loc(globic);
+
+ // reading the force from the value stored inside the particle
+ std::vector<T> physForceP = p->getStoreForce(); // physical force acting on the particle
+
+ T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle
+ latticeForceP[0] = physForceP[0] / this->_converter.getConversionFactorForce();
+ latticeForceP[1] = physForceP[1] / this->_converter.getConversionFactorForce();
+ latticeForceP[2] = physForceP[2] / this->_converter.getConversionFactorForce();
+
+ T physPosP[3] = {T(), T(), T()}; // particle's physical position
+ physPosP[0] = (p->getPos()[0]);
+ physPosP[1] = (p->getPos()[1]);
+ physPosP[2] = (p->getPos()[2]);
+
+ // particle's dimensionless position, rounded at neighbouring voxel
+ int latticeRoundedPosP[3] = {0, 0, 0};
+ this->_sLattice.getCuboidGeometry().get(globic).getLatticeR (
+ latticeRoundedPosP, physPosP );
+
+ if (this->_sGeometry.getBlockGeometry(locIC).getMaterial(
+ latticeRoundedPosP[0], latticeRoundedPosP[1],
+ latticeRoundedPosP[2]) == material) {
+
+ T F[3] = {T(), T(), T()}; // dimensionless smoothed force
+ F[0] = -latticeForceP[0] / (T)(subCycles);
+ F[1] = -latticeForceP[1] / (T)(subCycles);
+ F[2] = -latticeForceP[2] / (T)(subCycles);
+
+ this->_sLattice.getBlockLattice(locIC).get (
+ latticeRoundedPosP[0],
+ latticeRoundedPosP[1],
+ latticeRoundedPosP[2] ).template addField<descriptors::FORCE>( F );
+ }
+
+ return true;
+}
+
+
+////////////////////// Class NonLocalBaseBackCouplingModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+NonLocalBaseBackCouplingModel<T,Lattice,Particle>::NonLocalBaseBackCouplingModel (
+ UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry,
+ SmoothingFunctional<T, Lattice>& smoothingFunctional )
+ : BaseBackCouplingModel<T,Lattice,Particle>(converter, sLattice, sGeometry),
+ _smoothingFunctional(smoothingFunctional)
+{}
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+bool NonLocalBaseBackCouplingModel<T,Lattice,Particle>::operator() (Particle<T>* p, int globic, int material, int subCycles)
+{
+ int locIC = this->_sLattice.getLoadBalancer().loc(globic);
+
+ // reading the force from the value stored inside the particle
+ std::vector<T> physForceP = p->getStoreForce(); // physical force acting on the particle
+ T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle
+ latticeForceP[0] = physForceP[0] / this->_converter.getConversionFactorForce();
+ latticeForceP[1] = physForceP[1] / this->_converter.getConversionFactorForce();
+ latticeForceP[2] = physForceP[2] / this->_converter.getConversionFactorForce();
+
+ // Updating force through voxels within kernel smoothing length from the bubble's position
+ for (int i=0; i<this->_smoothingFunctional.getSize(); i++) {
+
+ // Position of the iterated voxel
+ int iLatticePosF[3] = {0, 0, 0};
+ this->_smoothingFunctional.getLatticePos(iLatticePosF, i);
+
+ // Updating iterated voxel
+ if (this->_sGeometry.getBlockGeometry(locIC).getMaterial(
+ iLatticePosF[0], iLatticePosF[1],
+ iLatticePosF[2]) == material) {
+
+ // Weighted force acting on the iterated voxel
+ T F[3] = {T(), T(), T()}; // dimensionless smoothed force
+ F[0] = -latticeForceP[0] * this->_smoothingFunctional.getWeight(i) / (T)(subCycles);
+ F[1] = -latticeForceP[1] * this->_smoothingFunctional.getWeight(i) / (T)(subCycles);
+ F[2] = -latticeForceP[2] * this->_smoothingFunctional.getWeight(i) / (T)(subCycles);
+
+ this->_sLattice.getBlockLattice(locIC).get (
+ iLatticePosF[0], iLatticePosF[1], iLatticePosF[2] ).template addField<descriptors::FORCE>( F );
+ }
+ }
+ return true;
+}
+
+}
+
+#endif
diff --git a/src/particles/twoWayCouplings/dragModels3D.h b/src/particles/twoWayCouplings/dragModels3D.h
new file mode 100644
index 0000000..0f22429
--- /dev/null
+++ b/src/particles/twoWayCouplings/dragModels3D.h
@@ -0,0 +1,113 @@
+/* Lattice Boltzmann sample, written in C++, using the OpenLB
+ * library
+ *
+ * Copyright (C) 2019 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.
+ */
+
+/* Drag force models for Lagrangian two-way coupling -- header file.
+ */
+
+#ifndef LB_DRAG_MODELS_H
+#define LB_DRAG_MODELS_H
+
+#include "functors/lattice/reductionF3D.h"
+#include "twoWayHelperFunctionals.h"
+
+namespace olb {
+
+/** Abstact base class for DragModelBase.
+ * Its raison d'etre consists of not being templetized in Lattice.
+ */
+template<typename T, template<typename V> class Particle>
+class DragModel {
+public:
+ /// Returns the scalar drag coefficient to overload. globicFull = { globic, latticeRoundedP[0, ..., 2] }
+ virtual T operator() (Particle<T>* p, T latticeVelF[], T latticeVelP[], int globicFull[])=0;
+protected:
+ /// Functional to compute particle Reynolds number
+ std::shared_ptr<ParticleReynoldsNumber<T, Particle> > _reP;
+};
+
+/** Abstact class for all the drag models.
+ * The virtual method computeDragCoeff returns the drag coefficient.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class DragModelBase : public DragModel<T,Particle> {
+public:
+ /// Constructor
+ DragModelBase(UnitConverter<T, Lattice>& converter);
+ /// Returns the scalar drag coefficient to overload.
+ //virtual T operator() (Particle<T>* p, T latticeVelF[], T latticeVelP[], int globic)=0;
+protected:
+ UnitConverter<T, Lattice>& _converter; // reference to a UnitConverter
+};
+
+/** Class to compute a drag coefficient Cd=1.83 for low-Re Stokes drag.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class StokesSimplifiedDragModel : public DragModelBase<T,Lattice,Particle> {
+public:
+ /// Constructor
+ StokesSimplifiedDragModel(UnitConverter<T, Lattice>& converter);
+ /// Returns the scalar drag coefficient. globicFull = { globic, latticeRoundedP[0, ..., 2] }
+ virtual T operator() (Particle<T>* p, T latticeVelF[], T latticeVelP[], int globicFull[]) override;
+};
+
+/** Class to compute the standard drag coefficient
+ * as in Morsi and Alexander (1972).
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class MorsiDragModel : public DragModelBase<T,Lattice,Particle> {
+public:
+ /// Constructor
+ MorsiDragModel(UnitConverter<T, Lattice>& converter);
+ /// Returns the scalar drag coefficient. globicFull = { globic, latticeRoundedP[0, ..., 2] }
+ virtual T operator() (Particle<T>* p, T latticeVelF[], T latticeVelP[], int globicFull[]) override;
+};
+
+/** Class to compute the drag coefficient for gas bubbles in a liquid fluid phase
+ * as in Dewsbury et al. (1999).
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class DewsburyDragModel : public DragModelBase<T,Lattice,Particle> {
+public:
+ /// Constructor
+ DewsburyDragModel(UnitConverter<T, Lattice>& converter);
+ /// Returns the scalar drag coefficient. globicFull = { globic, latticeRoundedP[0, ..., 2] }
+ virtual T operator() (Particle<T>* p, T latticeVelF[], T latticeVelP[], int globicFull[]) override;
+};
+
+/** Class to compute the drag coefficient for gas bubbles in a liquid fluid phase
+ * as in Dewsbury et al. (1999), in a power-law fluid.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class PowerLawDewsburyDragModel : public DewsburyDragModel<T,Lattice,Particle> {
+public:
+ /// Constructor
+ PowerLawDewsburyDragModel (
+ UnitConverter<T, Lattice>& converter, SuperLattice3D<T, Lattice>& sLattice );
+};
+
+
+}
+
+#endif
diff --git a/src/particles/twoWayCouplings/dragModels3D.hh b/src/particles/twoWayCouplings/dragModels3D.hh
new file mode 100644
index 0000000..0027544
--- /dev/null
+++ b/src/particles/twoWayCouplings/dragModels3D.hh
@@ -0,0 +1,150 @@
+/* Lattice Boltzmann sample, written in C++, using the OpenLB
+ * library
+ *
+ * Copyright (C) 2019 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.
+ */
+
+/* Drag force models for Lagrangian two-way coupling -- generic implementation.
+ */
+
+#ifndef LB_DRAG_MODELS_HH
+#define LB_DRAG_MODELS_HH
+
+namespace olb {
+
+
+////////////////////// Class DragModelBase ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+DragModelBase<T,Lattice,Particle>::DragModelBase(UnitConverter<T, Lattice>& converter)
+ : _converter(converter)
+{}
+
+
+////////////////////// Class StokesSimplifiedDragModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+StokesSimplifiedDragModel<T,Lattice,Particle>::StokesSimplifiedDragModel(UnitConverter<T, Lattice>& converter)
+ : DragModelBase<T,Lattice,Particle>(converter)
+{}
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+T StokesSimplifiedDragModel<T,Lattice,Particle>::operator() (
+ Particle<T>* p, T latticeVelF[], T latticeVelP[], int globicFull[] )
+{
+ return 1.83;
+}
+
+
+////////////////////// Class MorsiDragModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+MorsiDragModel<T,Lattice,Particle>::MorsiDragModel(UnitConverter<T, Lattice>& converter)
+ : DragModelBase<T,Lattice,Particle>(converter)
+{
+ this->_reP = std::make_shared<NewtonianParticleReynoldsNumber<T,Lattice,Particle> > (this->_converter);
+}
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+T MorsiDragModel<T,Lattice,Particle>::operator() (
+ Particle<T>* p, T latticeVelF[], T latticeVelP[], int globicFull[] )
+{
+ T physVelRelative = this->_converter.getPhysVelocity (
+ sqrt( pow(latticeVelF[0] - latticeVelP[0],2) +
+ pow(latticeVelF[1] - latticeVelP[1],2) +
+ pow(latticeVelF[2] - latticeVelP[2],2) ) );
+
+ T ReP = this->_reP->operator() (p, physVelRelative, globicFull);
+
+ T a[3] = {T(), T(), T()};
+ if (ReP < 0.1) {
+ a[0] = 0.0; a[1] = 24.0; a[2] = 0.0;
+ }
+ else if (ReP < 1.0) {
+ a[0] = 3.69; a[1] = 22.73; a[2] = 0.0903;
+ }
+ else if (ReP < 10.0) {
+ a[0] = 1.222; a[1] = 29.16667; a[2] =-3.8889;
+ }
+ else if (ReP < 100.0) {
+ a[0] = 0.6167; a[1] = 46.5; a[2] =-116.67;
+ }
+ else if (ReP < 1000.0) {
+ a[0] = 0.3644; a[1] = 498.33; a[2] =-2778;
+ }
+ else if (ReP < 5000.0) {
+ a[0] = 0.357; a[1] = 148.62; a[2] =-4.75e4;
+ }
+ else if (ReP < 10000.0) {
+ a[0] = 0.46; a[1] =-490.546; a[2] = 57.87e4;
+ }
+ else {
+ a[0] = 0.5191; a[1] =-1662.5; a[2] = 5.4167e6;
+ }
+
+
+ return ( a[0] + a[1]/ReP + a[2]/(ReP*ReP) ) * physVelRelative;
+}
+
+
+////////////////////// Class DewsburyDragModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+DewsburyDragModel<T,Lattice,Particle>::DewsburyDragModel(UnitConverter<T, Lattice>& converter)
+ : DragModelBase<T,Lattice,Particle>(converter)
+{
+ this->_reP = std::make_shared<NewtonianParticleReynoldsNumber<T,Lattice,Particle> > (this->_converter);
+}
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+T DewsburyDragModel<T,Lattice,Particle>::operator() (
+ Particle<T>* p, T latticeVelF[], T latticeVelP[], int globicFull[] )
+{
+ T physVelRelative = this->_converter.getPhysVelocity (
+ sqrt( pow(latticeVelF[0] - latticeVelP[0],2) +
+ pow(latticeVelF[1] - latticeVelP[1],2) +
+ pow(latticeVelF[2] - latticeVelP[2],2) ) );
+
+ T ReP = this->_reP->operator() (p, physVelRelative, globicFull);
+
+ T Cd = 0.95;
+ if (ReP <= 195.) {
+ Cd = 16./ReP * (1. + 0.173*pow(ReP, 0.657))
+ + 0.413 / (1. + 16300*pow(ReP, -1.09));
+ }
+ return Cd * this->_converter.getLatticeVelocity(physVelRelative);
+}
+
+
+////////////////////// Class PowerLawDewsburyDragModel ////////////////////////
+
+template<typename T, typename Lattice, template<typename V> class Particle>
+PowerLawDewsburyDragModel<T,Lattice,Particle>::PowerLawDewsburyDragModel (
+ UnitConverter<T, Lattice>& converter, SuperLattice3D<T, Lattice>& sLattice )
+ : DewsburyDragModel<T,Lattice,Particle>(converter)
+{
+ this->_reP = std::make_shared<PowerLawParticleReynoldsNumber<T,Lattice,Particle> > (this->_converter, sLattice);
+}
+
+
+}
+
+#endif
diff --git a/src/particles/twoWayCouplings/forwardCouplingModels3D.h b/src/particles/twoWayCouplings/forwardCouplingModels3D.h
new file mode 100644
index 0000000..17ff63c
--- /dev/null
+++ b/src/particles/twoWayCouplings/forwardCouplingModels3D.h
@@ -0,0 +1,148 @@
+/* Lattice Boltzmann sample, written in C++, using the OpenLB
+ * library
+ *
+ * Copyright (C) 2019 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.
+ */
+
+/* Models for Lagrangian forward-coupling methods -- header file.
+ */
+
+#ifndef LB_FORWARD_COUPLING_MODELS_H
+#define LB_FORWARD_COUPLING_MODELS_H
+
+#include "functors/lattice/reductionF3D.h"
+#include "twoWayHelperFunctionals.h"
+
+namespace olb {
+
+/** Abstact base class for LocalBaseCouplingModel.
+ * Its raison d'etre consists of not being templetized in Lattice.
+ */
+template<typename T, template<typename V> class Particle>
+class ForwardCouplingModel {
+public:
+ /// Class operator to apply the coupling, for overload.
+ virtual bool operator() (Particle<T>* p, int globic)=0;
+};
+
+/** Abstact class for all the local forward-coupling models,
+ * viz., momentum coupling from fluid to particle.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class LocalBaseForwardCouplingModel : public ForwardCouplingModel<T,Particle> {
+public:
+ /// Class operator to apply the coupling, for overload.
+ virtual bool operator() (Particle<T>* p, int globic) override;
+protected:
+ /// Constructor
+ LocalBaseForwardCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry,
+ DragModel<T, Particle>& dragModel );
+ SuperGeometry3D<T>& _sGeometry;
+ UnitConverter<T, Lattice>& _converter; // reference to a UnitConverter
+ SuperLattice3D<T, Lattice>& _sLattice; // reference to a lattice
+ DragModel<T, Particle>& _dragModel; // reference to a drag model
+ // Functional to interpolate lattice density at particle's location
+ std::shared_ptr<SuperLatticeInterpDensity3Degree3D<T, Lattice> > _interpLatticeDensity;
+ // Functional to interpolate lattice velocity at particle's location
+ std::shared_ptr<SuperLatticeInterpPhysVelocity3D<T, Lattice> > _interpLatticeVelocity;
+ // Momentum-exchange helper functional
+ std::shared_ptr<TwoWayHelperFunctional<T, Lattice> > _momentumExchange;
+};
+
+/** Class for a naive forward-coupling model.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class NaiveForwardCouplingModel : public LocalBaseForwardCouplingModel<T,Lattice,Particle> {
+public:
+ /// Constructor
+ NaiveForwardCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry,
+ DragModel<T, Particle>& dragModel );
+};
+
+/** Class for a forward-coupling model following the Ladd's mechanism.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class LaddForwardCouplingModel : public LocalBaseForwardCouplingModel<T,Lattice,Particle> {
+public:
+ /// Constructor
+ LaddForwardCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry,
+ DragModel<T, Particle>& dragModel );
+};
+
+/** Abstact class for all the non-local forward-coupling models,
+ * viz., momentum coupling from fluid to particle.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class NonLocalBaseForwardCouplingModel : public ForwardCouplingModel<T,Particle> {
+public:
+ /// Class operator to apply the coupling, for overload.
+ virtual bool operator() (Particle<T>* p, int globic) override;
+protected:
+ /// Constructor
+ NonLocalBaseForwardCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry,
+ DragModel<T, Particle>& dragModel,
+ SmoothingFunctional<T, Lattice>& smoothingFunctional );
+ SuperGeometry3D<T>& _sGeometry;
+ UnitConverter<T, Lattice>& _converter; // reference to a UnitConverter
+ SuperLattice3D<T, Lattice>& _sLattice; // reference to a lattice
+ DragModel<T, Particle>& _dragModel; // reference to a drag model
+ SmoothingFunctional<T, Lattice>& _smoothingFunctional; // Functional to treat non-local smoothing
+ // Functional to interpolate lattice density at particle's location.
+ // It is assumed that it returns the exact value for the exact cell's location!
+ std::shared_ptr<SuperLatticeInterpDensity3Degree3D<T, Lattice> > _interpLatticeDensity;
+ // Functional to interpolate lattice velocity at particle's location
+ // It is assumed that it returns the exact value for the exact cell's location!
+ std::shared_ptr<SuperLatticeInterpPhysVelocity3D<T, Lattice> > _interpLatticeVelocity;
+ // Momentum-exchange helper functional
+ std::shared_ptr<TwoWayHelperFunctional<T, Lattice> > _momentumExchange;
+};
+
+/** Class for a naive, non-local forward-coupling model as in Sungkorn et al. (2011), but with
+ * an extra-normalization of the smoothing function.
+ * Input parameters in attice units.
+ */
+template<typename T, typename Lattice, template<typename V> class Particle>
+class NaiveNonLocalForwardCouplingModel : public NonLocalBaseForwardCouplingModel<T,Lattice,Particle> {
+public:
+ /// Constructor
+ NaiveNonLocalForwardCouplingModel ( UnitConverter<T, Lattice>& converter,
+ SuperLattice3D<T, Lattice>& sLattice,
+ SuperGeometry3D<T>& sGeometry,
+ DragModel<T, Particle>& dragModel,
+ SmoothingFunctional<T, Lattice>& smoothingFunctional );
+};
+
+
+}
+
+#endif
diff --git a/src/particles/twoWayCouplings/forwardCouplingModels3D.hh b/src/particles/twoWayCouplings/forwardCouplingModels3D.hh
new file mode 100644
index 0000000..b07d50b
--- /dev/null
+++ b/src/particles/twoWayCouplings/forwardCouplingModels3D.hh
@@ -0,0 +1,280 @@
+/* Lattice Boltzmann sample, written in C++,