/* This file is part of the OpenLB library * * Copyright (C) 2006, 2007 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 * Template specializations for some computationally intensive LB * functions of the header file lbHelpers.h, for the D3Q7 grid. */ #ifndef LB_HELPERS_D3Q7_H #define LB_HELPERS_D3Q7_H #include "rtlbmDescriptors.h" namespace olb { /** partial template specialization for D3Q7DescriptorBase. */ template struct lbDynamicsHelpers > { using SpecializedCellBase = CellBase>; template using SpecializedDescriptor = descriptors::D3Q7; static T equilibrium( int iPop, T rho, const T u[3], T uSqr ) { typedef descriptors::D3Q7<> L; T c_u = descriptors::c(iPop,0)*u[0] + descriptors::c(iPop,1)*u[1]; return rho * descriptors::t(iPop) * ( 1. + 3.*c_u + 4.5*c_u*c_u - 1.5*uSqr ) - descriptors::t(iPop); } static T equilibriumFirstOrder( int iPop, T rho, const T u[3] ) { typedef descriptors::D3Q7<> L; T c_u = descriptors::c(iPop,0) * u[0] + descriptors::c(iPop,1) * u[1] + descriptors::c(iPop,2) * u[2]; return rho*descriptors::t(iPop)*((T)1 + c_u*descriptors::invCs2())-descriptors::t(iPop); } /// RLB advection diffusion collision step static T rlbCollision( SpecializedCellBase& cell, T rho, const T u[3], T omega ) { typedef descriptors::D3Q7<> L; const T uSqr = u[0] * u[0] + u[1] * u[1] + u[2] * u[2]; const T Cs2 = (T)1 / descriptors::invCs2(); T rho_1 = rho - (T)1; cell[0] = ( (T)1 - (T)3 * Cs2 ) * rho_1; //f[0]=(1-3c_s^2)(rho-1) const T omega_ = (T)1 - omega; const T f1_4 = omega_ * ( cell[1] - cell[4] ); const T f2_5 = omega_ * ( cell[2] - cell[5] ); const T f3_6 = omega_ * ( cell[3] - cell[6] ); rho_1 *= Cs2; const T ux_ = omega * rho * u[0]; cell[1] = (T)0.5 * ( rho_1 + f1_4 - ux_ ); //f[1]=1/2*(c_s^2(rho-1)+(1-omega)*(f[1]-f[4])-omega*rho*u[x]) cell[4] = (T)0.5 * ( rho_1 - f1_4 + ux_ ); //f[4]=1/2*(c_s^2(rho-1)-(1-omega)*(f[1]-f[4])+omega*rho*u[x]) const T uy_ = omega * rho * u[1]; cell[2] = (T)0.5 * ( rho_1 + f2_5 - uy_ ); //f[2]=1/2*(c_s^2(rho-1)+(1-omega)*(f[2]-f[5])-omega*rho*u[y]) cell[5] = (T)0.5 * ( rho_1 - f2_5 + uy_ ); //f[5]=1/2*(c_s^2(rho-1)-(1-omega)*(f[2]-f[5])+omega*rho*u[y]) const T uz_ = omega * rho * u[2]; cell[3] = (T)0.5 * ( rho_1 + f3_6 - uz_ ); //f[3]=1/2*(c_s^2(rho-1)+(1-omega)*(f[3]-f[6])-omega*rho*u[y]) cell[6] = (T)0.5 * ( rho_1 - f3_6 + uz_ ); //f[6]=1/2*(c_s^2(rho-1)-(1-omega)*(f[3]-f[6])+omega*rho*u[y]) return uSqr; } // BGK advection diffusion collision step static T bgkCollision( SpecializedCellBase& cell, T rho, const T u[3], T omega ) { const T Cs2 = 0.25; const T uSqr = u[0] * u[0] + u[1] * u[1] + u[2] * u[2]; const T omega_ = (T)1 - omega; const T omega_2 = (T)0.5 * omega; T rho_ = ( rho - (T)1 ); cell[0] = omega_ * cell[0] + omega * ( (T)1 - (T)3 * Cs2 ) * rho_; const T jx = rho * u[0]; const T jy = rho * u[1]; const T jz = rho * u[2]; rho_ *= Cs2; cell[1] = omega_ * cell[1] + omega_2 * ( rho_ - jx ); cell[2] = omega_ * cell[2] + omega_2 * ( rho_ - jy ); cell[3] = omega_ * cell[3] + omega_2 * ( rho_ - jz ); cell[4] = omega_ * cell[4] + omega_2 * ( rho_ + jx ); cell[5] = omega_ * cell[5] + omega_2 * ( rho_ + jy ); cell[6] = omega_ * cell[6] + omega_2 * ( rho_ + jz ); return uSqr; } /// Paper: Mink et al. 2016 DOI: 10.1016/j.jocs.2016.03.014 /// omega is expected to be one static T sinkCollision( SpecializedCellBase& cell, T intensity, T omega, T sink ) { // fi = (1-w) fi + w fi^{eq} - absorption fi; // where fi^{eq} = rho ti and t0 = 1/4, t1=...t6=1/8 // note: cell[i] = fi - ti const T omega_ = (T)1 - omega; T ti = 0.25; cell[0] = omega_ * ( cell[0] + ti ) + omega * intensity * ti - sink * ( cell[0] + ti ) - ti; ti = 0.125; cell[1] = omega_ * ( cell[1] + ti ) + omega * intensity * ti - sink * ( cell[1] + ti ) - ti; cell[2] = omega_ * ( cell[2] + ti ) + omega * intensity * ti - sink * ( cell[2] + ti ) - ti; cell[3] = omega_ * ( cell[3] + ti ) + omega * intensity * ti - sink * ( cell[3] + ti ) - ti; cell[4] = omega_ * ( cell[4] + ti ) + omega * intensity * ti - sink * ( cell[4] + ti ) - ti; cell[5] = omega_ * ( cell[5] + ti ) + omega * intensity * ti - sink * ( cell[5] + ti ) - ti; cell[6] = omega_ * ( cell[6] + ti ) + omega * intensity * ti - sink * ( cell[6] + ti ) - ti; return 0.0; } // MRT advection-diffusion functions static void computeMomentaEquilibrium(T momentaEq[7], T rho, const T u[3], T uSqr) { // (Maria Lloret) // momentaEq[0] = rho; // momentaEq[1] = rho * u[0]; // momentaEq[2] = rho * u[1]; // momentaEq[3] = rho * u[2]; // momentaEq[4] = -rho * (T) 3 / (T) 4; // momentaEq[5] = T(); // momentaEq[6] = T(); // Li, Yang et al 2016: The directions are modified for the OpenLB definition momentaEq[0] = rho; momentaEq[1] = rho * u[0]; momentaEq[2] = rho * u[1]; momentaEq[3] = rho * u[2]; momentaEq[4] = rho * (T) 3 / (T) 4; //(Maria Lloret) -rho*(T)3/(T)4; momentaEq[5] = T(); momentaEq[6] = T(); } static void computeMomenta(T momenta[7], SpecializedCellBase const& cell) { /* The implementation is based on the "Passive heat transfer * in a turbulent channel flow simulation using large eddy * simulation based on the lattice Boltzmann method framework" * by Hong Wu, Jiao Wang, Zhi Tao * (Maria Lloret) */ // momenta[0] = cell[0] + cell[1] + cell[2] + cell[3] + cell[4] + cell[5] + cell[6]; // momenta[1] = -cell[1] + cell[4]; // momenta[2] = -cell[2] + cell[5]; // momenta[3] = -cell[3] + cell[6]; // momenta[4] = -(T) 6 * cell[0] + cell[1] + cell[2] + cell[3] + cell[4] + cell[5] + cell[6] - (T) 3 / (T) 4; // momenta[5] = cell[1] - cell[2] + cell[4] - cell[5]; // momenta[6] = cell[1] + cell[2] - (T) 2 * cell[3] + cell[4] + cell[5] - (T) 2 * cell[6]; // Li, Yang et al 2016: The directions are modified for the OpenLB definition momenta[0] = cell[0] + cell[1] + cell[2] + cell[3] + cell[4] + cell[5] + cell[6]; momenta[1] = cell[1] - cell[3]; momenta[2] = -cell[2] + cell[5]; momenta[3] = cell[4] - cell[6]; momenta[4] = (T) 6 * cell[0] - cell[1] - cell[2] - cell[3] - cell[4] - cell[5] - cell[6] + (T) 3 / (T) 4; momenta[5] = (T) 2 * cell[1] - cell[2] + (T) 2 * cell[3] - cell[4] - cell[5] - cell[6]; momenta[6] = cell[2] - cell[4] + cell[5] - cell[6]; } static T mrtCollision( SpecializedCellBase& cell, const T rho, const T u[3], const T invM_S[7][7]) { T uSqr = util::normSqr(u); T momenta[7]; T momentaEq[7]; computeMomenta(momenta, cell); computeMomentaEquilibrium(momentaEq, rho, u, uSqr); // std::cout << "momenta = "; // for (int i=0; i < 7; ++i) { // std::cout << momenta[i] << ", "; // } // std::cout << std::endl; // std::cout << "momentaEq = "; // for (int i=0; i < 7; ++i) { // std::cout << momentaEq[i] << ", "; // } // std::cout << std::endl; T mom1 = momenta[1] - momentaEq[1]; T mom2 = momenta[2] - momentaEq[2]; T mom3 = momenta[3] - momentaEq[3]; T mom4 = momenta[4] - momentaEq[4]; T mom5 = momenta[5] - momentaEq[5]; T mom6 = momenta[6] - momentaEq[6]; cell[0] -= invM_S[0][1]*mom1 + invM_S[0][2]*mom2 + invM_S[0][3]*mom3 + invM_S[0][4]*mom4 + invM_S[0][5]*mom5 + invM_S[0][6]*mom6; cell[1] -= invM_S[1][1]*mom1 + invM_S[1][2]*mom2 + invM_S[1][3]*mom3 + invM_S[1][4]*mom4 + invM_S[1][5]*mom5 + invM_S[1][6]*mom6; cell[2] -= invM_S[2][1]*mom1 + invM_S[2][2]*mom2 + invM_S[2][3]*mom3 + invM_S[2][4]*mom4 + invM_S[2][5]*mom5 + invM_S[2][6]*mom6; cell[3] -= invM_S[3][1]*mom1 + invM_S[3][2]*mom2 + invM_S[3][3]*mom3 + invM_S[3][4]*mom4 + invM_S[3][5]*mom5 + invM_S[3][6]*mom6; cell[4] -= invM_S[4][1]*mom1 + invM_S[4][2]*mom2 + invM_S[4][3]*mom3 + invM_S[4][4]*mom4 + invM_S[4][5]*mom5 + invM_S[4][6]*mom6; cell[5] -= invM_S[5][1]*mom1 + invM_S[5][2]*mom2 + invM_S[5][3]*mom3 + invM_S[5][4]*mom4 + invM_S[5][5]*mom5 + invM_S[5][6]*mom6; cell[6] -= invM_S[6][1]*mom1 + invM_S[6][2]*mom2 + invM_S[6][3]*mom3 + invM_S[6][4]*mom4 + invM_S[6][5]*mom5 + invM_S[6][6]*mom6; return uSqr; } static void computeFneq ( SpecializedCellBase const& cell, T fNeq[7], T rho, const T u[3] ) { // std::cout << "WARNING: First order equilibrium function is used for the calculation of the non-equilibrium parts!" << std::endl; for (int iPop=0; iPop < 7; ++iPop) { fNeq[iPop] = cell[iPop] - equilibriumFirstOrder(iPop, rho, u); } } static T computeRho(SpecializedCellBase const& cell) { T rho = cell[0] + cell[1] + cell[2] + cell[3] + cell[4] + cell[5] + cell[6] + (T)1; return rho; } static void computeRhoU(SpecializedCellBase const& cell, T& rho, T u[3]) { rho = cell[0] + cell[1] + cell[2] + cell[3] + cell[4] + cell[5] + cell[6] + (T)1; T invRho= 1./rho; u[0] = ( cell[4] - cell[1] )*invRho; u[1] = ( cell[5] - cell[2] )*invRho; u[2] = ( cell[6] - cell[3] )*invRho; } static void computeRhoJ(SpecializedCellBase const& cell, T& rho, T j[3]) { rho = cell[0] + cell[1] + cell[2] + cell[3] + cell[4] + cell[5] + cell[6] + (T)1; j[0] = ( cell[4] - cell[1] ); j[1] = ( cell[5] - cell[2] ); j[2] = ( cell[6] - cell[3] ); } static void computeJ(SpecializedCellBase const& cell, T j[3]) { j[0] = ( cell[4] - cell[1] ); j[1] = ( cell[5] - cell[2] ); j[2] = ( cell[6] - cell[3] ); } static void computeStress(SpecializedCellBase const& cell, T rho, const T u[3], T pi[6]) { // printf("ERROR: Stress tensor not defined in D3Q7!\n"); } static void computeAllMomenta(SpecializedCellBase const& cell, T& rho, T u[3], T pi[6]) { assert(false); } }; } // namespace olb #endif