/* This file is part of the OpenLB library * * Copyright (C) 2016 Thomas Henn, Mathias J. Krause, Jonas Latt * 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 for porous -- generic implementation. */ #ifndef POROUS_BGK_DYNAMICS_HH #define POROUS_BGK_DYNAMICS_HH #include "porousBGKdynamics.h" #include "core/cell.h" #include "dynamics.h" #include "core/util.h" #include "lbHelpers.h" #include "math.h" namespace olb { ////////////////////// Class PorousBGKdynamics ////////////////////////// template PorousBGKdynamics::PorousBGKdynamics ( T omega_, Momenta& momenta_) : BGKdynamics(omega_,momenta_), omega(omega_) { } template void PorousBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* porosity = cell.template getFieldPointer(); for (int i=0; i::bgkCollision(cell, rho, u, omega); statistics.incrementStats(rho, uSqr); } template T PorousBGKdynamics::getOmega() const { return omega; } template void PorousBGKdynamics::setOmega(T omega_) { omega = omega_; } //////////////////// Class ExtendedPorousBGKdynamics //////////////////// template ExtendedPorousBGKdynamics::ExtendedPorousBGKdynamics ( T omega_, Momenta& momenta_) : BGKdynamics(omega_,momenta_), omega(omega_) { } template void ExtendedPorousBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* porosity = cell.template getFieldPointer(); T* localVelocity = cell.template getFieldPointer(); cell.template setField(u); for (int i=0; i::bgkCollision(cell, rho, u, omega); statistics.incrementStats(rho, uSqr); } template T ExtendedPorousBGKdynamics::getOmega() const { return omega; } template void ExtendedPorousBGKdynamics::setOmega(T omega_) { omega = omega_; } //////////////////// Class SubgridParticleBGKdynamics //////////////////// template SubgridParticleBGKdynamics::SubgridParticleBGKdynamics ( T omega_, Momenta& momenta_) : BGKdynamics(omega_,momenta_), omega(omega_) { _fieldTmp[0] = T(); _fieldTmp[1] = T(); _fieldTmp[2] = T(); _fieldTmp[3] = T(); } template void SubgridParticleBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* porosity = cell.template getFieldPointer(); T* extVelocity = cell.template getFieldPointer(); // if (porosity[0] != 0) { // cout << "extVelocity: " << extVelocity[0] << " " << extVelocity[1] << " " << extVelocity[2] << " " << std::endl; // cout << "porosity: " << porosity[0] << std::endl; // } for (int i=0; i::bgkCollision(cell, rho, u, omega); statistics.incrementStats(rho, uSqr); cell.template setField(0); cell.template setField(0); cell.template setField(0); } template T SubgridParticleBGKdynamics::getOmega() const { return omega; } template void SubgridParticleBGKdynamics::setOmega(T omega_) { omega = omega_; } //////////////////// Class PorousParticleBGKdynamics //////////////////// template PorousParticleBGKdynamics::PorousParticleBGKdynamics ( T omega_, Momenta& momenta_) : BGKdynamics(omega_,momenta_), omega(omega_) {} template void PorousParticleBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T tmpMomentumLoss[DESCRIPTOR::d] = { }; T* const velNumerator = cell.template getFieldPointer(); T* const external = cell.template getFieldPointer(); // TODO: Remove implicit layout requirements in favor of descriptor fields T* const velDenominator = cell.template getFieldPointer(); // use HLBM with Shan-Chen forcing as in previous versions #ifdef HLBM_FORCING_SHANCHEN if (*velDenominator > std::numeric_limits::epsilon()) { effectiveVelocity::calculate(velNumerator, u); const T tmp_uSqr = util::normSqr(u); for(int tmp_i=0; tmp_i::equilibrium(tmp_iPop, rho, u, tmp_uSqr)-cell[tmp_iPop]); } } } T uSqr = lbHelpers::bgkCollision(cell, rho, u, omega); // use Kuperstokh forcing by default #else T uSqr = lbHelpers::bgkCollision(cell, rho, u, omega); T uPlus[DESCRIPTOR::d] = { }; T diff[DESCRIPTOR::q] = {}; if (*velDenominator > std::numeric_limits::epsilon()) { for(int iDim=0; iDim::calculate(external, uPlus); const T uPlusSqr = util::normSqr(uPlus); for(int tmp_iPop=0; tmp_iPop::equilibrium(tmp_iPop, rho, uPlus, uPlusSqr) - lbHelpers::equilibrium(tmp_iPop, rho, u, uSqr); cell[tmp_iPop] += diff[tmp_iPop]; for(int iDim=0; iDim(tmp_iPop,iDim) * diff[tmp_iPop]; } } // alternate option to calculate the force //for(int iDim=0; iDim template struct PorousParticleBGKdynamics::effectiveVelocity { static void calculate(T* pExternal, T* pVelocity) { for (int i=0; i() - DESCRIPTOR::q]) * (pExternal[DESCRIPTOR::template index() - DESCRIPTOR::q +i] / pExternal[DESCRIPTOR::template index() - DESCRIPTOR::q] - pVelocity[i]); } pExternal[DESCRIPTOR::template index() - DESCRIPTOR::q] = 1.; pExternal[DESCRIPTOR::template index() - DESCRIPTOR::q] = 0.; } }; // TODO: Update for meta descriptor template template struct PorousParticleBGKdynamics::effectiveVelocity { static void calculate(T* pExternal, T* pVelocity) { for (int i=0; i() - Lattice::q]) * pVelocity[i]; } } }; template T PorousParticleBGKdynamics::getOmega() const { return omega; } template void PorousParticleBGKdynamics::setOmega(T omega_) { omega = omega_; } //////////////////// Class KrauseHBGKdynamics //////////////////// template KrauseHBGKdynamics::KrauseHBGKdynamics (T omega_, Momenta& momenta_, T smagoConst_, T dx_, T dt_ ) : BGKdynamics(omega_,momenta_), omega(omega_), smagoConst(smagoConst_), preFactor(computePreFactor(omega_,smagoConst_) ) { _fieldTmp[0] = T(1); _fieldTmp[1] = T(); _fieldTmp[2] = T(); _fieldTmp[3] = T(); } template void KrauseHBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; T newOmega[DESCRIPTOR::q]; this->_momenta.computeRhoU(cell, rho, u); computeOmega(this->getOmega(), cell, preFactor, rho, u, newOmega); T vel_denom = *cell.template getFieldPointer(); if (vel_denom > std::numeric_limits::epsilon()) { T porosity = *cell.template getFieldPointer(); // prod(1-smoothInd) T* vel_num = cell.template getFieldPointer(); porosity = 1.-porosity; // 1-prod(1-smoothInd) for (int i=0; i::bgkCollision(cell, rho, u, newOmega); statistics.incrementStats(rho, uSqr); cell.template setField(_fieldTmp[0]); cell.template setField({_fieldTmp[1], _fieldTmp[2]}); cell.template setField(_fieldTmp[3]); } template T KrauseHBGKdynamics::getOmega() const { return omega; } template void KrauseHBGKdynamics::setOmega(T omega) { this->setOmega(omega); preFactor = computePreFactor(omega, smagoConst); } template T KrauseHBGKdynamics::computePreFactor(T omega, T smagoConst) { return (T)smagoConst*smagoConst*descriptors::invCs2()*descriptors::invCs2()*2*sqrt(2); } template void KrauseHBGKdynamics::computeOmega(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*fNeq))-tau_mol); /// Effective realaxation time tau_eff = tau_mol + tau_turb; newOmega[iPop] = 1./tau_eff; } } //////////////////// Class ParticlePorousBGKdynamics //////////////////// /* template ParticlePorousBGKdynamics::ParticlePorousBGKdynamics ( T omega_, Momenta& momenta_) : BGKdynamics(omega_,momenta_), omega(omega_) { } template void ParticlePorousBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* porosity = cell.template getFieldPointer(); T* localVelocity = cell.template getFieldPointer(); for (int i=0; i::bgkCollision(cell, rho, u, omega); statistics.incrementStats(rho, uSqr); // *cell.template getFieldPointer() = 1; // *cell.template getFieldPointer() = 0.; // *(cell.template getFieldPointer()+1) = 0.; } template T ParticlePorousBGKdynamics::getOmega() const { return omega; } template void ParticlePorousBGKdynamics::setOmega(T omega_) { omega = omega_; } */ //////////////////// Class SmallParticleBGKdynamics //////////////////// template SmallParticleBGKdynamics::SmallParticleBGKdynamics ( T omega_, Momenta& momenta_) : BGKdynamics(omega_,momenta_), omega(omega_) { } template void SmallParticleBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d]; this->_momenta.computeRhoU(cell, rho, u); T* porosity = cell.template getFieldPointer(); T* localVelocity = cell.template getFieldPointer(); //cout << porosity[0] << " " << localVelocity[0]<< " " << localVelocity[1]<< " " << localVelocity[2]<::bgkCollision(cell, rho, u, omega); statistics.incrementStats(rho, uSqr); } template T SmallParticleBGKdynamics::getOmega() const { return omega; } template void SmallParticleBGKdynamics::setOmega(T omega_) { omega = omega_; } ////////////////////// Class PSMBGKdynamics ////////////////////////// /** \param omega relaxation parameter, related to the dynamic viscosity * \param momenta a Momenta object to know how to compute velocity momenta */ template PSMBGKdynamics::PSMBGKdynamics ( T omega_, Momenta& momenta_, int mode_ ) : BGKdynamics(omega_, momenta_), omega(omega_), paramA(1. / omega_ - 0.5) { mode = (Mode) mode_; } template void PSMBGKdynamics::computeU (Cell const& cell, T u[DESCRIPTOR::d] ) const { T rho; this->_momenta.computeRhoU(cell, rho, u); // T epsilon = 1. - *(cell.template getFieldPointer()); // // speed up paramB // T paramB = (epsilon * paramA) / ((1. - epsilon) + paramA); // // speed up paramC // T paramC = (1. - paramB); // for (int iVel=0; iVel()[iVel]; // } } template void PSMBGKdynamics::computeRhoU (Cell const& cell, T& rho, T u[DESCRIPTOR::d] ) const { this->_momenta.computeRhoU(cell, rho, u); // T epsilon = 1. - *(cell.template getFieldPointer()); // // speed up paramB // T paramB = (epsilon * paramA) / ((1. - epsilon) + paramA); // // speed up paramC // T paramC = (1. - paramB); // for (int iVel=0; iVel()[iVel]; // } } template void PSMBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d], uSqr; T epsilon = 1. - *(cell.template getFieldPointer()); this->_momenta.computeRhoU(cell, rho, u); // velocity at the boundary T u_s[DESCRIPTOR::d]; for (int i = 0; i < DESCRIPTOR::d; i++) { u_s[i] = (cell.template getFieldPointer())[i]; } if (epsilon < 1e-5) { uSqr = lbHelpers::bgkCollision(cell, rho, u, omega); } else { // speed up paramB T paramB = (epsilon * paramA) / ((1. - epsilon) + paramA); // speed up paramC T paramC = (1. - paramB); T omega_s[DESCRIPTOR::q]; T cell_tmp[DESCRIPTOR::q]; const T uSqr_s = util::normSqr(u_s); uSqr = util::normSqr(u); for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) { cell_tmp[iPop] = cell[iPop]; switch(mode){ case M2: omega_s[iPop] = (lbDynamicsHelpers::equilibrium(iPop, rho, u_s, uSqr_s ) - cell[iPop]) + (1 - omega) * (cell[iPop] - lbDynamicsHelpers::equilibrium(iPop, rho, u, uSqr )); break; case M3: omega_s[iPop] = (cell[descriptors::opposite(iPop)] - lbDynamicsHelpers::equilibrium(descriptors::opposite(iPop), rho, u_s, uSqr_s )) - (cell[iPop] - lbDynamicsHelpers::equilibrium(iPop, rho, u_s, uSqr_s )); } } uSqr = lbHelpers::bgkCollision(cell, rho, u, omega); for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) { cell[iPop] = cell_tmp[iPop] + paramC * (cell[iPop] - cell_tmp[iPop]); cell[iPop] += paramB * omega_s[iPop]; } for (int iVel=0; iVel(u); } statistics.incrementStats(rho, uSqr); } template T PSMBGKdynamics::getOmega() const { return omega; } template void PSMBGKdynamics::setOmega(T omega_) { paramA = (1. / omega_ - 0.5); omega = omega_; } ////////////////////// Class ForcedPSMBGKdynamics ////////////////////////// /** \param omega relaxation parameter, related to the dynamic viscosity * \param momenta a Momenta object to know how to compute velocity momenta */ template ForcedPSMBGKdynamics::ForcedPSMBGKdynamics ( T omega_, Momenta& momenta_, int mode_ ) : ForcedBGKdynamics(omega_, momenta_), omega(omega_), paramA(1. / omega_ - 0.5) { mode = (Mode) mode_; } template void ForcedPSMBGKdynamics::computeU (Cell const& cell, T u[DESCRIPTOR::d] ) const { T rho; this->_momenta.computeRhoU(cell, rho, u); T epsilon = 1. - *(cell.template getFieldPointer()); // speed up paramB T paramB = (epsilon * paramA) / ((1. - epsilon) + paramA); // speed up paramC T paramC = (1. - paramB); for (int iVel=0; iVel()[iVel] / (T)2.) + paramB * cell.template getFieldPointer()[iVel]; } } template void ForcedPSMBGKdynamics::computeRhoU (Cell const& cell, T& rho, T u[DESCRIPTOR::d] ) const { this->_momenta.computeRhoU(cell, rho, u); T epsilon = 1. - *(cell.template getFieldPointer()); // speed up paramB T paramB = (epsilon * paramA) / ((1. - epsilon) + paramA); // speed up paramC T paramC = (1. - paramB); for (int iVel=0; iVel()[iVel] / (T)2.) + paramB * cell.template getFieldPointer()[iVel]; } } template void ForcedPSMBGKdynamics::collide ( Cell& cell, LatticeStatistics& statistics ) { T rho, u[DESCRIPTOR::d], uSqr; T epsilon = 1. - *(cell.template getFieldPointer()); this->_momenta.computeRhoU(cell, rho, u); T* force = cell.template getFieldPointer(); for (int iVel=0; iVel())[i]; } if (epsilon < 1e-5) { uSqr = lbHelpers::bgkCollision(cell, rho, u, omega); lbHelpers::addExternalForce(cell, u, omega, rho); } else { // speed up paramB T paramB = (epsilon * paramA) / ((1. - epsilon) + paramA); // speed up paramC T paramC = (1. - paramB); T omega_s[DESCRIPTOR::q]; T cell_tmp[DESCRIPTOR::q]; const T uSqr_s = util::normSqr(u_s); for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) { cell_tmp[iPop] = cell[iPop]; switch(mode){ case M2: omega_s[iPop] = (lbDynamicsHelpers::equilibrium(iPop, rho, u_s, uSqr_s ) - cell[iPop]) + (1 - omega) * (cell[iPop] - lbDynamicsHelpers::equilibrium(iPop, rho, u, uSqr )); break; case M3: omega_s[iPop] = (cell[descriptors::opposite(iPop)] - lbDynamicsHelpers::equilibrium(descriptors::opposite(iPop), rho, u_s, uSqr_s )) - (cell[iPop] - lbDynamicsHelpers::equilibrium(iPop, rho, u_s, uSqr_s )); } } uSqr = lbHelpers::bgkCollision(cell, rho, u, omega); lbHelpers::addExternalForce(cell, u, omega, rho); for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) { cell[iPop] = cell_tmp[iPop] + paramC * (cell[iPop] - cell_tmp[iPop]); cell[iPop] += paramB * omega_s[iPop]; } for (int iVel=0; iVel(u); } statistics.incrementStats(rho, uSqr); } template T ForcedPSMBGKdynamics::getOmega() const { return omega; } template void ForcedPSMBGKdynamics::setOmega(T omega_) { paramA = (1. / omega_ - 0.5); omega = omega_; } } // olb #endif