/* This file is part of the OpenLB library * * Copyright (C) 2012-2015 Mathias J. Krause, Jonas Latt, Patrick Nathen * 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. */ /** \file * BGK Dynamics with adjusted omega -- generic implementation. */ #ifndef SMAGORINSKY_BGK_DYNAMICS_HH #define SMAGORINSKY_BGK_DYNAMICS_HH #include "smagorinskyBGKdynamics.h" #include "core/cell.h" #include "core/util.h" #include "lbHelpers.h" #include "math.h" #include // For shear kalman Smagorinsky - Populations namespace olb { /// Smagorinsky Dynamics template SmagorinskyDynamics::SmagorinskyDynamics(T smagoConst_) : smagoConst(smagoConst_), preFactor(computePreFactor()) { } template T SmagorinskyDynamics::computePreFactor() { return (T)smagoConst*smagoConst*descriptors::invCs2()*descriptors::invCs2()*2*sqrt(2); } template T SmagorinskyDynamics::getPreFactor() { return preFactor; } template T SmagorinskyDynamics::getSmagoConst() { return smagoConst; } ///////////////////////// ADM BGK ///////////////////////////// /*template ADMBGKdynamics::ADMBGKdynamics(T omega_, Momenta& momenta_ ) : BGKdynamics(omega_,momenta_), omega(omega_) { } template void ADMBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T uSqr = lbHelpers::bgkCollision(cell, *cell., cell[velocityBeginsAt], omega); statistics.incrementStats(*cell[rhoIsAt], uSqr); }*/ ///////////////////////// ForcedADM BGK ///////////////////////////// template ForcedADMBGKdynamics::ForcedADMBGKdynamics ( T omega_, Momenta& momenta_ ) : BGKdynamics(omega_,momenta_), omega(omega_) { } template void ForcedADMBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { OstreamManager clout(std::cout,"Forced ADM collide:"); T rho, u[DESCRIPTOR::d], utst[DESCRIPTOR::d]; // this->momenta.computeAllMomenta(cell, rho, utst, pi); T* rho_fil = cell.template getFieldPointer(); T* u_filX = cell.template getFieldPointer(); T* u_filY = cell.template getFieldPointer(); T* u_filZ = cell.template getFieldPointer(); u[0] = *u_filX;/// *rho_fil; u[1] = *u_filY;/// *rho_fil; u[2] = *u_filZ;/// *rho_fil; T* force = cell.template getFieldPointer(); for (int iVel=0; iVel::bgkCollision(cell, *rho_fil, u, omega); lbHelpers::addExternalForce(cell, u, omega); statistics.incrementStats(rho, uSqr); } ///////////////////// Class ConSmagorinskyBGKdynamics ////////////////////////// /////////////////// Consistent Smagorinsky BGK --> Malaspinas/Sagaut ////////////// template ConSmagorinskyBGKdynamics::ConSmagorinskyBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_) { } template T ConSmagorinskyBGKdynamics::computeEffectiveOmega (Cell& cell) { T H[util::TensorVal::n]; T conSmagoR[DESCRIPTOR::q]; T S[util::TensorVal::n]; T tau_mol = 1./this->getOmega(); T cs2 = 1./descriptors::invCs2(); T smagoConst = this->getSmagoConst(); T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(2*PiNeqNormSqr); //Strain rate Tensor if (PiNeqNorm != 0) { T Phi = (-0.5*(-rho*tau_mol*cs2+sqrt(rho*rho*tau_mol*tau_mol*cs2*cs2+2.0*(smagoConst*smagoConst)*rho*PiNeqNorm))/(smagoConst*smagoConst*rho*PiNeqNorm)); for (int n = 0; n < util::TensorVal::n; ++n) { S[n] = Phi*pi[n]; } } else { for (int n = 0; n < util::TensorVal::n; ++n) { S[n] = 0; } } //Strain rate Tensor Norm T SNormSqr = S[0]*S[0] + 2.0*S[1]*S[1] + S[2]*S[2]; if (util::TensorVal::n == 6) { SNormSqr += S[2]*S[2] + S[3]*S[3] + 2.0*S[4]*S[4] + S[5]*S[5]; } T SNorm = sqrt(2*SNormSqr); //consistent Samagorinsky additional R term for (int q = 0; q < DESCRIPTOR::q; ++q) { T t = descriptors::t(q); //lattice weights //Hermite-Polynom H = c*c-cs^2*kronDelta H[0] = descriptors::c(q,0)*descriptors::c(q,0)-cs2; H[1] = descriptors::c(q,0)*descriptors::c(q,1); H[2] = descriptors::c(q,1)*descriptors::c(q,1)-cs2;//2D if (util::TensorVal::n == 6) { H[2] = descriptors::c(q,0)*descriptors::c(q,2);//3D H[3] = descriptors::c(q,1)*descriptors::c(q,1)-cs2; H[4] = descriptors::c(q,1)*descriptors::c(q,2); H[5] = descriptors::c(q,2)*descriptors::c(q,2)-cs2; } //contraction or scalar product H*S T contractHS = H[0]*S[0] + 2.0*H[1]*S[1] + H[2]*S[2]; if (util::TensorVal::n == 6) { contractHS += H[2]*S[2] + H[3]*S[3] + 2.0*H[4]*S[4] + H[5]*S[5]; } //additional term conSmagoR[q] = t*this->getPreFactor()*SNorm*contractHS; } return conSmagoR[0]; } /////////////////// Consistent Strain Smagorinsky BGK --> Malaspinas/Sagaut ////////////// template ConStrainSmagorinskyBGKdynamics::ConStrainSmagorinskyBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_) { } template T ConStrainSmagorinskyBGKdynamics::computeEffectiveOmega(Cell& cell) { T S[util::TensorVal::n]; T cs2 = 1./descriptors::invCs2(); T tau_mol = 1./this->getOmega(); T smagoConst_ = this->getSmagoConst(); T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2.0*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(2*PiNeqNormSqr); //Strain Tensor if ( !util::nearZero(PiNeqNorm) ) { T Phi = (-0.5*(-rho*tau_mol*cs2+sqrt(rho*rho*tau_mol*tau_mol*cs2*cs2+2.0*(smagoConst_*smagoConst_)*rho*PiNeqNorm))/(smagoConst_*smagoConst_*rho*PiNeqNorm)); for (int n = 0; n < util::TensorVal::n; ++n) { S[n] = Phi*pi[n]; } } else { for (int n = 0; n < util::TensorVal::n; ++n) { S[n] = 0; } } //Strain Tensor Norm T SNormSqr = S[0]*S[0] + 2.0*S[1]*S[1] + S[2]*S[2]; if (util::TensorVal::n == 6) { SNormSqr += S[2]*S[2] + S[3]*S[3] + 2.0*S[4]*S[4] + S[5]*S[5]; } T SNorm = sqrt(2*SNormSqr); /// Turbulent realaxation time T tau_turb = pow(smagoConst_,2)*SNorm/cs2; /// Effective realaxation time T tau_eff = tau_mol+tau_turb; T omega_new= 1./tau_eff; return omega_new; } ///////////////////////// DYNAMIC SMAGO BGK ///////////////////////////// template DynSmagorinskyBGKdynamics::DynSmagorinskyBGKdynamics ( T omega_, Momenta& momenta_) : SmagorinskyBGKdynamics(omega_, momenta_, T(0.)) { } template T DynSmagorinskyBGKdynamics::computeEffectiveOmega(Cell& cell) { // computation of the relaxation time T v_t = 0; T* dynSmago = cell.template getFieldPointer(); T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(PiNeqNormSqr); //v_t = *dynSmago*dx*dx*PiNeqNorm; v_t = *dynSmago*PiNeqNorm; T tau_t = 3*v_t; T tau_0 = 1/this->getOmega(); T omega_new = 1/(tau_t+tau_0); return omega_new; } ///////////////////SHEAR IMPROVED SMAGORINSKY////////////////////////// template ShearSmagorinskyBGKdynamics::ShearSmagorinskyBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_) { } template void ShearSmagorinskyBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T newOmega = computeEffectiveOmega(cell,statistics.getTime()); T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T uSqr = lbHelpers::bgkCollision(cell, rho, u, newOmega); statistics.incrementStats(rho, uSqr); } template T ShearSmagorinskyBGKdynamics::getEffectiveOmega(Cell& cell) { T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); // computation of the relaxation time T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(PiNeqNormSqr); T* avShear = cell.template getFieldPointer(); T tau_0 = 1./this->getOmega(); T PiNeqNorm_SISM = PiNeqNorm - *avShear; T tau_t = 0.5*(sqrt(tau_0*tau_0+(this->getPreFactor()*PiNeqNorm_SISM/rho))-tau_0); T omega_new = 1./(tau_t+tau_0); return omega_new; } template T ShearSmagorinskyBGKdynamics::computeEffectiveOmega(Cell& cell, int iT) { OstreamManager clout(std::cout,"shearImprovedCollide"); T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); // computation of the relaxation time T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(PiNeqNormSqr); T* avShear = cell.template getFieldPointer(); *avShear = (*avShear*iT + PiNeqNorm)/(iT+1); T tau_0 = 1./this->getOmega(); T PiNeqNorm_SISM = PiNeqNorm - *avShear; T tau_t = 0.5*(sqrt(tau_0*tau_0+(this->getPreFactor()*PiNeqNorm_SISM/rho))-tau_0); T omega_new = 1./(tau_t+tau_0); return omega_new; } ///////////////////////// FORCED SHEAR SMAGO BGK ///////////////////////////// template ShearSmagorinskyForcedBGKdynamics::ShearSmagorinskyForcedBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyForcedBGKdynamics(omega_, momenta_, smagoConst_) { } template void ShearSmagorinskyForcedBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T newOmega = computeEffectiveOmega(cell, statistics.getTime()); T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* force = cell.template getFieldPointer(); for (int iVel=0; iVel::bgkCollision(cell, rho, u, newOmega); lbHelpers::addExternalForce(cell, u, newOmega, rho); statistics.incrementStats(rho, uSqr); } template T ShearSmagorinskyForcedBGKdynamics::getEffectiveOmega(Cell& cell) { T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); // computation of the relaxation time T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(PiNeqNormSqr); T* avShear = cell.template getFieldPointer(); T tau_0 = 1./this->getOmega(); T PiNeqNorm_SISM = PiNeqNorm - *avShear; T tau_t = 0.5*(sqrt(tau_0*tau_0+(this->getPreFactor()*PiNeqNorm_SISM/rho))-tau_0); T omega_new = 1./(tau_t+tau_0); return omega_new; } template T ShearSmagorinskyForcedBGKdynamics::computeEffectiveOmega(Cell& cell, int iT) { OstreamManager clout(std::cout,"shearImprovedCollide"); T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); //Creation of body force tensor (rho/2.)*(G_alpha*U_beta + U_alpha*G_Beta) T ForceTensor[util::TensorVal::n]; int iPi = 0; for (int Alpha=0; Alpha()[Alpha]*u[Beta] + u[Alpha]*cell.template getFieldPointer()[Beta]); ++iPi; } } // Creation of second-order moment off-equilibrium tensor for (int iPi=0; iPi < util::TensorVal::n; ++iPi){ pi[iPi] += ForceTensor[iPi]; } // computation of the relaxation time T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(PiNeqNormSqr); T* avShear = cell.template getFieldPointer(); *avShear = (*avShear*iT+PiNeqNorm)/(iT+1); T tau_0 = 1./this->getOmega(); T PiNeqNorm_SISM = PiNeqNorm - *avShear; T tau_t = 0.5*(sqrt(tau_0*tau_0+(this->getPreFactor()*PiNeqNorm_SISM/rho))-tau_0); T omega_new = 1./(tau_t+tau_0); return omega_new; } ////////////////////// Class SmagorinskyBGKdynamics ////////////////////////// /** \param vs2_ speed of sound * \param momenta_ a Momenta object to know how to compute velocity momenta * \param momenta_ a Momenta object to know how to compute velocity momenta */ template SmagorinskyBGKdynamics::SmagorinskyBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyDynamics(smagoConst_), BGKdynamics(omega_,momenta_) { } template void SmagorinskyBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T newOmega = computeEffectiveOmega(cell); T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T uSqr = lbHelpers::bgkCollision(cell, rho, u, newOmega); statistics.incrementStats(rho, uSqr); } template T SmagorinskyBGKdynamics::getEffectiveOmega(Cell& cell) { T newOmega = computeEffectiveOmega(cell); return newOmega; } template T SmagorinskyBGKdynamics::computeEffectiveOmega(Cell& cell) { T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(PiNeqNormSqr); /// Molecular realaxation time T tau_mol = 1. /this->getOmega(); /// Turbulent realaxation time T tau_turb = 0.5*(sqrt(tau_mol*tau_mol + this->getPreFactor()/rho*PiNeqNorm) - tau_mol); /// Effective realaxation time T tau_eff = tau_mol+tau_turb; T omega_new= 1./tau_eff; return omega_new; } ///////////////////////// FORCED SMAGO BGK ///////////////////////////// template SmagorinskyForcedBGKdynamics::SmagorinskyForcedBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyDynamics(smagoConst_), ForcedBGKdynamics(omega_,momenta_) { } template void SmagorinskyForcedBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T newOmega = computeEffectiveOmega(cell); T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* force = cell.template getFieldPointer(); for (int iVel=0; iVel::bgkCollision(cell, rho, u, newOmega); lbHelpers::addExternalForce(cell, u, newOmega, rho); statistics.incrementStats(rho, uSqr); } template T SmagorinskyForcedBGKdynamics::getEffectiveOmega(Cell& cell) { T newOmega = computeEffectiveOmega(cell); return newOmega; } template T SmagorinskyForcedBGKdynamics::computeEffectiveOmega(Cell& cell) { T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); //Creation of body force tensor (rho/2.)*(G_alpha*U_beta + U_alpha*G_Beta) T ForceTensor[util::TensorVal::n]; int iPi = 0; for (int Alpha=0; Alpha()[Alpha]*u[Beta] + u[Alpha]*cell.template getFieldPointer()[Beta]); ++iPi; } } // Creation of second-order moment off-equilibrium tensor for (int iPi=0; iPi < util::TensorVal::n; ++iPi){ pi[iPi] += ForceTensor[iPi]; } T PiNeqNormSqr = pi[0]*pi[0] + 2.0*pi[1]*pi[1] + pi[2]*pi[2]; if (util::TensorVal::n == 6) { PiNeqNormSqr += pi[2]*pi[2] + pi[3]*pi[3] + 2*pi[4]*pi[4] +pi[5]*pi[5]; } T PiNeqNorm = sqrt(PiNeqNormSqr); /// Molecular realaxation time T tau_mol = 1. /this->getOmega(); /// Turbulent realaxation time T tau_turb = 0.5*(sqrt(tau_mol*tau_mol + this->getPreFactor()/rho*PiNeqNorm) - tau_mol); /// Effective realaxation time T tau_eff = tau_mol+tau_turb; T omega_new= 1./tau_eff; return omega_new; } ///////////////////////// External TAU EFF LES BGK ///////////////////////////// template ExternalTauEffLESBGKdynamics::ExternalTauEffLESBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_) { } template void ExternalTauEffLESBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T newTau = *(cell.template getFieldPointer()); T newOmega = 1./newTau; T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T uSqr = lbHelpers::bgkCollision(cell, rho, u, newOmega); statistics.incrementStats(rho, uSqr); } ///////////////////////// External TAU EFF FORCED LES BGK ///////////////////////////// template ExternalTauEffLESForcedBGKdynamics::ExternalTauEffLESForcedBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyForcedBGKdynamics(omega_, momenta_, smagoConst_) { } template void ExternalTauEffLESForcedBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T newTau = *(cell.template getFieldPointer()); T newOmega = 1./newTau; T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* force = cell.template getFieldPointer(); for (int iVel=0; iVel::bgkCollision(cell, rho, u, newOmega); lbHelpers::addExternalForce(cell, u, newOmega, rho); statistics.incrementStats(rho, uSqr); } ///////////////////////// FORCED Linear Velocity SMAGO BGK ///////////////////////////// template SmagorinskyLinearVelocityForcedBGKdynamics::SmagorinskyLinearVelocityForcedBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyForcedBGKdynamics(omega_, momenta_, smagoConst_) { } template void SmagorinskyLinearVelocityForcedBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; this->_momenta.computeAllMomenta(cell, rho, u, pi); T newOmega = computeEffectiveOmega(cell); T* force = cell.template getFieldPointer(); int nDim = DESCRIPTOR::d; T forceSave[nDim]; // adds a+Bu to force, where // d=2: a1=v[0], a2=v[1], B11=v[2], B12=v[3], B21=v[4], B22=v[5] // d=2: a1=v[0], a2=v[1], a3=v[2], B11=v[3], B12=v[4], B13=v[5], B21=v[6], B22=v[7], B23=v[8], B31=v[9], B32=v[10], B33=v[11] T* v = cell.template getFieldPointer(); for (int iDim=0; iDim::bgkCollision(cell, rho, u, newOmega); lbHelpers::addExternalForce(cell, u, newOmega, rho); statistics.incrementStats(rho, uSqr); // Writing back to froce fector for (int iVel=0; iVel KrauseBGKdynamics::KrauseBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_), preFactor(computePreFactor() ) { } template void KrauseBGKdynamics::collide(Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; T newOmega[DESCRIPTOR::q]; this->_momenta.computeRhoU(cell, rho, u); computeEffectiveOmega(this->getOmega(), cell, preFactor, rho, u, newOmega); T uSqr = lbHelpers::bgkCollision(cell, rho, u, newOmega); statistics.incrementStats(rho, uSqr); } template T KrauseBGKdynamics::getEffectiveOmega(Cell& cell) { T rho, uTemp[DESCRIPTOR::d], pi[util::TensorVal::n]; T newOmega[DESCRIPTOR::q]; this->_momenta.computeAllMomenta(cell, rho, uTemp, pi); computeEffectiveOmega(this->getOmega(), cell, preFactor, rho, uTemp, newOmega); T newOmega_average = 0.; for (int iPop=0; iPop T KrauseBGKdynamics::computePreFactor() { return (T)this->getSmagoConst()*this->getSmagoConst()*3*descriptors::invCs2()*descriptors::invCs2()*2*sqrt(2); } template void KrauseBGKdynamics::computeEffectiveOmega(T omega0, Cell& cell, T preFactor_, T rho, T u[DESCRIPTOR::d], T newOmega[DESCRIPTOR::q]) { T uSqr = u[0]*u[0]; for (int iDim=0; iDim::equilibrium(iPop, rho, u, uSqr)); /// Turbulent realaxation time T tau_turb = 0.5*(sqrt(tau_mol*tau_mol + preFactor_/rho*fNeq) - tau_mol); /// Effective realaxation time T tau_eff = tau_mol + tau_turb; newOmega[iPop] = 1./tau_eff; } } ////////////////////// Class WALEBGKdynamics ////////////////////////// /** \param vs2_ speed of sound * \param momenta_ a Momenta object to know how to compute velocity momenta * \param momenta_ a Momenta object to know how to compute velocity momenta */ template WALEBGKdynamics::WALEBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_) { this->preFactor = this->getSmagoConst()*this->getSmagoConst(); } template T WALEBGKdynamics::computePreFactor() { return (T)this->getSmagoConst()*this->getSmagoConst(); } template T WALEBGKdynamics::computeEffectiveOmega(Cell& cell_) { // velocity gradient tensor T g[3][3]; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { g[i][j] = *(cell_.template getFieldPointer()+(i*3 + j)); } } // strain rate tensor T s[3][3]; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { s[i][j] = (g[i][j] + g[j][i]) / 2.; } } // traceless symmetric part of the square of the velocity gradient tensor T G[3][3]; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { G[i][j] = 0.; } } for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { for ( int k = 0; k < 3; k++) { G[i][j] += (g[i][k]*g[k][j] + g[j][k]*g[k][i]) / 2.; // The change } } } T trace = 0.; for ( int i = 0; i < 3; i++) { trace += (1./3.) * g[i][i] * g[i][i]; } for ( int i = 0; i < 3; i++) { G[i][i] -= trace; } // inner product of the traceless symmetric part of the square of the velocity gradient tensor T G_ip = 0; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { G_ip = G[i][j] * G[i][j]; } } // inner product of the strain rate T s_ip = 0; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { s_ip = s[i][j] * s[i][j]; } } // Turbulent relaxation time T tau_turb = 3. * this->getPreFactor() * (pow(G_ip,1.5) / (pow(s_ip,2.5) + pow(G_ip,1.25))); if ((pow(s_ip,2.5) + pow(G_ip,1.25)) == 0) { tau_turb = 0.; } // Physical turbulent viscosity must be equal or higher that zero if (tau_turb < 0.) { tau_turb = 0.; } /// Molecular relaxation time T tau_mol = 1. /this->getOmega(); /// Effective relaxation time T tau_eff = tau_mol + tau_turb; T omega_new = 1. / tau_eff; return omega_new; } ////////////////////// Class WALEForcedBGKdynamics ////////////////////////// /** \param vs2_ speed of sound * \param momenta_ a Momenta object to know how to compute velocity momenta * \param momenta_ a Momenta object to know how to compute velocity momenta */ template WALEForcedBGKdynamics::WALEForcedBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_) : SmagorinskyForcedBGKdynamics(omega_, momenta_, smagoConst_) { this->preFactor = this->getSmagoConst()*this->getSmagoConst(); } template T WALEForcedBGKdynamics::computePreFactor() { return (T)this->getSmagoConst()*this->getSmagoConst(); } template T WALEForcedBGKdynamics::computeEffectiveOmega(Cell& cell_) { // velocity gradient tensor T g[3][3]; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { g[i][j] = *(cell_.template getFieldPointer()+(i*3 + j)); } } // strain rate tensor T s[3][3]; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { s[i][j] = (g[i][j] + g[j][i]) / 2.; } } // traceless symmetric part of the square of the velocity gradient tensor T G[3][3]; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { G[i][j] = 0.; } } for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { for ( int k = 0; k < 3; k++) { G[i][j] += (g[i][k]*g[k][j] + g[j][k]*g[k][i]) / 2.; // The change } } } T trace = 0.; for ( int i = 0; i < 3; i++) { trace += (1./3.) * g[i][i] * g[i][i]; } for ( int i = 0; i < 3; i++) { G[i][i] -= trace; } // inner product of the traceless symmetric part of the square of the velocity gradient tensor T G_ip = 0; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { G_ip = G[i][j] * G[i][j]; } } // inner product of the strain rate T s_ip = 0; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { s_ip = s[i][j] * s[i][j]; } } // Turbulent relaxation time T tau_turb = 3. * this->getPreFactor() * (pow(G_ip,1.5) / (pow(s_ip,2.5) + pow(G_ip,1.25))); if ((pow(s_ip,2.5) + pow(G_ip,1.25)) == 0) { tau_turb = 0.; } // Physical turbulent viscosity must be equal or higher that zero if (tau_turb < 0.) { tau_turb = 0.; } /// Molecular relaxation time T tau_mol = 1. /this->getOmega(); /// Effective relaxation time T tau_eff = tau_mol + tau_turb; T omega_new = 1. / tau_eff; return omega_new; } //////////////// Class ShearKalmanFDSmagorinskyBGKdynamics /////////////////// /** \param vs2_ speed of sound * \param momenta_ a Momenta object to know how to compute velocity momenta * \param momenta_ a Momenta object to know how to compute velocity momenta */ template FDKalmanShearSmagorinskyBGKdynamics::FDKalmanShearSmagorinskyBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_, T u_char_lat, T f_char_lat) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_), VarInVelKal(pow(2.0*(4.0 * std::atan(1.0))*(u_char_lat*f_char_lat)/sqrt(3),2)), UCharLat(u_char_lat) { this->preFactor = this->getSmagoConst() * this->getSmagoConst() * descriptors::invCs2(); } template T FDKalmanShearSmagorinskyBGKdynamics::getEffectiveOmega(Cell& cell) { T FNSR; computeNormStrainRate(cell, FNSR); T INSR; computeNormStrainRate(cell, INSR); // Turbulent relaxation time T tau_turb = 0.; if (INSR > FNSR) { tau_turb = this->getPreFactor() * (INSR - FNSR); } /// Molecular relaxation time T tau_mol = 1. /this->getOmega(); /// Effective Omega T omega_new = 1. / tau_mol + tau_turb; return omega_new; } template T FDKalmanShearSmagorinskyBGKdynamics::computePreFactor() { return this->getSmagoConst()*this->getSmagoConst()*descriptors::invCs2(); } template T FDKalmanShearSmagorinskyBGKdynamics::computeOmega(Cell& cell) { OstreamManager clout(std::cout,"shearImprovedKalmanFDCollide"); // Kalman procedure to update the filtered velocity KalmanStep(cell); // Norm of filtered Strain Rate T FNSR; computeNormStrainRate(cell, FNSR); // Norm of Instantaneous Strain Rate T INSR; computeNormStrainRate(cell, INSR); T tau_turb = 0.; if (INSR > FNSR) { tau_turb = this->getPreFactor() * (INSR - FNSR); } /// Molecular relaxation time T tau_mol = 1. /this->getOmega(); /// Effective Omega T omega_new = 1. / tau_mol + tau_turb; return omega_new; } template void FDKalmanShearSmagorinskyBGKdynamics::computeNormStrainRate(Cell& cell, T& NormStrainRate) { int Dim = DESCRIPTOR::d; // Velocity gradient in 2D-3D T VG[Dim][Dim]; for ( int i = 0; i < Dim; i++) { for ( int j = 0; j < Dim; j++) { VG[i][j] = *(cell.template getFieldPointer()+(i*Dim + j)); } } // Strain rate tensor T S[Dim][Dim]; for ( int i = 0; i < Dim; i++) { for ( int j = 0; j < Dim; j++) { S[i][j] = (VG[i][j] + VG[j][i]) / 2.; } } // inner product of the strain tensor T SIP = 0; for ( int i = 0; i < Dim; i++) { for ( int j = 0; j < Dim; j++) { SIP = S[i][j] * S[i][j]; } } // Norm of the strain rate tensor NormStrainRate = sqrt(2. * SIP); } template void FDKalmanShearSmagorinskyBGKdynamics::KalmanStep(Cell& cell) { // 1. Prediction Step T* ErrorCovariance = cell.template getFieldPointer(); ErrorCovariance[0] += VarInVelKal; // 2. Update Step // 2.1. Smooothing Factor : K T* Variance = cell.template getFieldPointer(); T K = ErrorCovariance[0]/(ErrorCovariance[0] + Variance[0]); // 2.2. Kalman filtered Velocity -> Kalman filtered Populations //T* KalmanPopulation = cell.template getFieldPointer(); T u[DESCRIPTOR::d] = {0., 0., 0.}; cell.computeU(u); T* KalmanVel = cell.template getFieldPointer(); for (int iVel=0; iVel(KalU_InstU),epsilon*pow(UCharLat,2)); } ////////////////////////////////////////////////////////////////////////////// //////////// Shear Improved - Kalman Filter - Smagorinsky BGK //////////////// template ShearKalmanSmagorinskyBGKdynamics::ShearKalmanSmagorinskyBGKdynamics(T omega_, Momenta& momenta_, T smagoConst_, T u_char_lat, T f_char_lat) : SmagorinskyBGKdynamics(omega_, momenta_, smagoConst_), VarInVelKal(pow(2.0*(4.0 * std::atan(1.0))*(u_char_lat*f_char_lat)/sqrt(3),2)), UCharLat(u_char_lat) { } template T ShearKalmanSmagorinskyBGKdynamics::getEffectiveOmega(Cell& cell) { OstreamManager clout(std::cout,"shearImprovedKalmanCollide"); // Compute the norm of second moment of non-equilibrium Instantaneous distribution [n+1][n+1] T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; cell.computeAllMomenta(rho, u, pi); T PiNeqNormSqrn1; computeNormSOM(pi, rho, PiNeqNormSqrn1); // Compute the norm of second moment of non-equilibrium filtered distribution // Filtered Stress at time n+1 T KalmanPiNeqNormSqrN1, KalmanUN1[DESCRIPTOR::d], KalmanPiNeqN1[util::TensorVal::n]; computeKalmanUStress(cell,KalmanUN1,KalmanPiNeqN1); computeNormSOM(KalmanPiNeqN1, KalmanPiNeqNormSqrN1); T tau_mol = 1./this->getOmega(); T tau_sgs = T(0.); if (PiNeqNormSqrn1 > KalmanPiNeqNormSqrN1) { tau_sgs = 0.5*( ( pow(tau_mol,2.0) + ( this->getPreFactor()*( sqrt( PiNeqNormSqrn1)-sqrt(KalmanPiNeqNormSqrN1) ) ) ) - tau_mol ); } T EffectiveOmega = 1.0/(tau_mol + tau_sgs); return EffectiveOmega; } template T ShearKalmanSmagorinskyBGKdynamics::computeEffectiveOmega(Cell& cell) { OstreamManager clout(std::cout,"shearImprovedKalmanCollide"); // Update the filtered velocity wit a Kalman procedure KalmanStep(cell); // Compute the norm of second moment of non-equilibrium Instantaneous distribution [n+1][n+1] T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; cell.computeAllMomenta(rho, u, pi); T PiNeqNormSqrn1; computeNormSOM(pi, rho, PiNeqNormSqrn1); // Compute the norm of second moment of non-equilibrium filtered distribution // Filtered Stress at time n+1 T KalmanPiNeqNormSqrN1, KalmanUN1[DESCRIPTOR::d], KalmanPiNeqN1[util::TensorVal::n]; computeKalmanUStress(cell,KalmanUN1,KalmanPiNeqN1); computeNormSOM(KalmanPiNeqN1, KalmanPiNeqNormSqrN1); T tau_mol = 1./this->getOmega(); T tau_sgs = T(0.); if (PiNeqNormSqrn1 > KalmanPiNeqNormSqrN1) { tau_sgs = 0.5*( ( pow(tau_mol,2.0) + ( this->getPreFactor()*( sqrt( PiNeqNormSqrn1)-sqrt(KalmanPiNeqNormSqrN1) ) ) ) - tau_mol ); } T EffectiveOmega = 1.0/(tau_mol + tau_sgs); return EffectiveOmega; } template void ShearKalmanSmagorinskyBGKdynamics::KalmanStep(Cell& cell) { // The Kalman filter procedure // T rho, u[DESCRIPTOR::d], pi[util::TensorVal::n]; cell.computeAllMomenta(rho, u, pi); T* KalmanPopulation = cell.template getFieldPointer(); if (KalmanPopulation[0] == (T)-1.0){ for (int iPop=0; iPop(); *ErrorCovariance += VarInVelKal; // 2. Update Step // 2.1. Smoothing Factor : K T* Variance = cell.template getFieldPointer(); T K = *ErrorCovariance/(*ErrorCovariance + *Variance); // 2.2. Kalman filtered Velocity -> Kalman filtered Populations for (int iPop=0; iPop(KalU_InstU),epsilon*pow(UCharLat,2)); // Fin filtering procedure // } template void ShearKalmanSmagorinskyBGKdynamics::computeKalmanUStress(Cell& cell, T (&KalmanU)[DESCRIPTOR::d],T (&KalmanPi)[util::TensorVal::n] ) { computeKalmanU(cell,KalmanU); computeKalmanStress(cell,KalmanU,KalmanPi); } template void ShearKalmanSmagorinskyBGKdynamics::computeKalmanU(Cell& cell, T (&KalmanU)[DESCRIPTOR::d]) { T* KalmanPopulation = cell.template getFieldPointer(); for (int iD=0; iD < DESCRIPTOR::d; ++iD) { KalmanU[iD] = T(); } for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) { for (int iD=0; iD < DESCRIPTOR::d; ++iD) { KalmanU[iD] += KalmanPopulation[iPop]*descriptors::c(iPop,iD); } } } template void ShearKalmanSmagorinskyBGKdynamics::computeKalmanStress(Cell& cell, T (&KalmanU)[DESCRIPTOR::d],T (&KalmanPi)[util::TensorVal::n] ) { T* KalmanPopulation = cell.template getFieldPointer(); T rhoRelative = T(0.); for (int iPop = 0; iPop < DESCRIPTOR::q; iPop++) { rhoRelative += KalmanPopulation[iPop]; } int iPi = 0; for (int iAlpha=0; iAlpha < DESCRIPTOR::d; ++iAlpha) { for (int iBeta=iAlpha; iBeta < DESCRIPTOR::d; ++iBeta) { KalmanPi[iPi] = T(); for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) { KalmanPi[iPi] += descriptors::c(iPop,iAlpha)*descriptors::c(iPop,iBeta) * KalmanPopulation[iPop]; } // stripe off equilibrium contribution KalmanPi[iPi] -= KalmanU[iAlpha]*KalmanU[iBeta]; if (iAlpha==iBeta) { KalmanPi[iPi] -= rhoRelative/descriptors::invCs2(); } ++iPi; } } } template void ShearKalmanSmagorinskyBGKdynamics::computeAndupdateTauSgs(Cell& cell, T rho, T pi[util::TensorVal::n], T KalmanPiNeqN[util::TensorVal::n], T KalmanPiNeqN1[util::TensorVal::n], T K, T &tau_sgs) { // Compute the norm of second moment of non-equilibrium filtered distribution T KalmanPiNeqNormSqrN; computeNormSOM(KalmanPiNeqN, KalmanPiNeqNormSqrN); // Compute the norm of cross second moment of non-equilibrium filtered-Instantaneous distribution [n+1] T KalmanInstPiNeqNormSqrN; computeNormSOM(KalmanPiNeqN, pi, rho, KalmanInstPiNeqNormSqrN); // Compute the norm of second moment of non-equilibrium Instantaneous distribution [n+1][n+1] T PiNeqNormSqrn; computeNormSOM(pi, rho, PiNeqNormSqrn); computeTauSgs(cell, rho, KalmanPiNeqNormSqrN, KalmanInstPiNeqNormSqrN, PiNeqNormSqrn, K, tau_sgs); // Compute the norm of second moment of non-equilibrium filtered distribution T KalmanPiNeqNormSqrN1; computeNormSOM(KalmanPiNeqN1, KalmanPiNeqNormSqrN1); updateTauSgsKalman(cell, KalmanPiNeqNormSqrN, KalmanInstPiNeqNormSqrN, PiNeqNormSqrn, KalmanPiNeqNormSqrN1, K, tau_sgs); } template void ShearKalmanSmagorinskyBGKdynamics::computeNormSOM(T pi[util::TensorVal::n], T &piNorm) { // Compute the norm of second moment of non-equilibrium filtered distribution <-><-> piNorm = pow(pi[0],2) + 2.0*pow(pi[1],2) + pow(pi[2],2); if (util::TensorVal::n == 6) { piNorm += pow(pi[2],2) + pow(pi[3],2) + 2*pow(pi[4],2) + pow(pi[5],2); } } template void ShearKalmanSmagorinskyBGKdynamics::computeNormSOM(T pi1[util::TensorVal::n], T pi2[util::TensorVal::n], T rho, T &piNorm) { // Compute the norm of cross second moment of non-equilibrium filtered-Instantaneous distribution <->[-] piNorm = pi1[0]*pi2[0] + 2.0*pi1[1]*pi2[1] + pi1[2]*pi2[2]; if (util::TensorVal::n == 6) { piNorm += pi1[2]*pi2[2] + pi1[3]*pi2[3] + 2*pi1[4]*pi2[4] + pi1[5]*pi2[5]; } piNorm /= rho; } template void ShearKalmanSmagorinskyBGKdynamics::computeNormSOM(T pi[util::TensorVal::n], T rho, T &piNorm) { // Compute the norm of second moment of non-equilibrium Instantaneous distribution [-][-] computeNormSOM(pi, piNorm); piNorm /= pow(rho,2.0); } template void ShearKalmanSmagorinskyBGKdynamics::computeTauSgs(Cell& cell, T rho, T KalmanPiNeqNormSqr, T KalmanInstPiNeqNormSqr, T PiNeqNormSqr, T K, T &tau_sgs) { T tau_mol = this->getOmega(); T tau_eff_n = tau_mol + *(cell.template getFieldPointer()); T F = 1.0/(pow(this->getSmagoConst()/descriptors::invCs2(),2.0)/(2.0*tau_eff_n)); // Coefficients of 4th polynomial : Ax^4 + Bx^3 + Cx^2 + Dx + E = 0 T A = pow(F,2.0); T B = 2.0*A*tau_mol; T C = F*pow(tau_mol,2.0) - (2.0*F*sqrt(2.0*PiNeqNormSqr)*tau_eff_n) - (pow((1.0-K),2.0)*2.0*KalmanPiNeqNormSqr); T D = -((2.0*F*sqrt(2.0*PiNeqNormSqr)*tau_mol*tau_eff_n) + (2.0*pow((1.0-K),2.0)*tau_mol*2.0*KalmanPiNeqNormSqr) + (2.0*K*(1.0-K)*2.0*KalmanInstPiNeqNormSqr*tau_eff_n) ); T E = ((1-pow(K,2.0))*2.0*PiNeqNormSqr*pow(tau_eff_n,2.0)) + (pow((1.0-K)*tau_mol,2.0)*2.0*KalmanPiNeqNormSqr) - (2.0*K*(1.0-K)*2.0*KalmanInstPiNeqNormSqr*tau_mol*tau_eff_n); std::complex Roots[4]; computeRoots4thPoly(A, B, C, D, E, Roots); tau_sgs = 0.; for ( int i = 0; i < 4; i++){ if (std::imag(Roots[i]) == T(0.)) { if (std::real(Roots[i]) > tau_sgs){ tau_sgs = std::real(Roots[i]); } } } /// Update the value of instantaneous effective omega //T* EffectiveOmega = cell.template getFieldPointer(); //*EffectiveOmega = 1.0/(tau_mol + tau_sgs); } template void ShearKalmanSmagorinskyBGKdynamics::computeRoots4thPoly(T A, T B, T C, T D, T E, std::complex (&Roots)[4]) { T p = T((8.*A*C - 3.*pow(B,2.0))/(8.0*pow(A,2.0))); T q = T((pow(B,3.0) - 4.0*A*B*C + 8.0*pow(A,2.0)*D)/(8.0*pow(A,3.0))); T Delta0 = T(pow(C,2.0) - 3.0*B*D + 12.0*A*E); T Delta1 = 2.0*pow(C,3.0) - 9.0*B*C*D + 27*pow(B,2.0)*E + 27.0*A*pow(D,2.0) - 72.0*A*C*E; // Discriminant std::complex Dis = (pow(Delta1,2.0) - 4.0*pow(Delta0,3.0))/(-27.0); std::complex Q = pow((Delta1+sqrt(Dis*(-27.0)))/2.0,1.0/3.0); std::complex S = 0.5*sqrt((-2.0*p/3.0)+((1.0/(3.0*A))*(Q+(Delta0/Q)))); std::complex cas1, cas2; for ( int i = 0; i < 2; i++) { for ( int j = 0; j < 2; j++) { cas1 = T(2*i-1); cas2 = T(2*j-1); Roots[2*i+j] = (-B/4*A) + cas1*S + (cas2*0.5*sqrt((-4.0*S*S)+(2.0*p)+(q/S))); } } } template void ShearKalmanSmagorinskyBGKdynamics::updateTauSgsKalman(Cell& cell, T NN, T Nn1, T n1n1, T N1N1, T K, T tau_sgs_n1) { T tau_mol = this->getOmega(); T* tau_sgs_N = cell.template getFieldPointer(); //T tau_eff_N = tau_mol + *tau_sgs_N; //T tau_eff_n1 = *(cell[EffectiveOmegaIsAt]); T tau_eff_n1 = *tau_sgs_N; // T A; // if (!util::nearZero(tau_sgs_n1)) { // A = sqrt( pow((1-K) * (*tau_sgs_N) / tau_eff_N,2.0) * sqrt(NN) // + 2.0 * K * (1.0-K) * (*tau_sgs_N * tau_sgs_n1) * sqrt(Nn1) / (tau_eff_N * tau_eff_n1) // + pow(K * tau_sgs_n1 / tau_eff_n1,2.0) * sqrt(n1n1) // ); // } else { // A = sqrt( pow((1-K) * (*tau_sgs_N) / tau_eff_N,2.0) * sqrt(NN)); // } // // A /= sqrt(N1N1); // // *tau_sgs_N = tau_mol/((1.0/A)-1.0); *tau_sgs_N = (sqrt(2.0*N1N1) /(sqrt(2.0*n1n1) -(2.0*pow(1./(this->getSmagoConst()*descriptors::invCs2()),2.0)*tau_sgs_n1*tau_eff_n1) ) )*tau_eff_n1; if ((*tau_sgs_N - tau_mol) > T(0.)){ *tau_sgs_N -= tau_mol; } else { *tau_sgs_N = T(0.); } } } #endif