$treeview $search $mathjax
|
Palabos
Version 1.1
$projectbrief
|
$projectbrief
|
$searchbox |
00001 /* This file is part of the Palabos library. 00002 * 00003 * Copyright (C) 2011 FlowKit Sarl 00004 * Avenue de Chailly 23 00005 * 1012 Lausanne, Switzerland 00006 * E-mail contact: contact@flowkit.com 00007 * 00008 * The most recent release of Palabos can be downloaded at 00009 * <http://www.palabos.org/> 00010 * 00011 * The library Palabos is free software: you can redistribute it and/or 00012 * modify it under the terms of the GNU Affero General Public License as 00013 * published by the Free Software Foundation, either version 3 of the 00014 * License, or (at your option) any later version. 00015 * 00016 * The library is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Affero General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Affero General Public License 00022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00023 */ 00024 00025 /* The original version of this file was written by Orestis Malaspinas 00026 * and Andrea Parmigiani. 00027 */ 00028 00029 #ifndef SHAN_CHEN_PROCESSOR_3D_HH 00030 #define SHAN_CHEN_PROCESSOR_3D_HH 00031 00032 #include "multiPhysics/shanChenProcessor3D.h" 00033 #include "core/util.h" 00034 #include "finiteDifference/finiteDifference3D.h" 00035 #include "latticeBoltzmann/momentTemplates.h" 00036 #include "latticeBoltzmann/externalFieldAccess.h" 00037 #include "multiPhysics/multiPhaseTemplates3D.h" 00038 00039 namespace plb { 00040 00041 /* *************** ShanChenMultiComponentProcessor3D ***************** */ 00042 00043 template<typename T, template<typename U> class Descriptor> 00044 ShanChenMultiComponentProcessor3D <T,Descriptor>::ShanChenMultiComponentProcessor3D(T G_) 00045 : G(G_) 00046 { } 00047 00048 template<typename T, template<typename U> class Descriptor> 00049 ShanChenMultiComponentProcessor3D <T,Descriptor>::ShanChenMultiComponentProcessor3D ( 00050 T G_, std::vector<T> const& imposedOmega_) 00051 : G(G_), 00052 imposedOmega(imposedOmega_) 00053 { } 00054 00055 template<typename T, template<typename U> class Descriptor> 00056 void ShanChenMultiComponentProcessor3D<T,Descriptor>::process ( 00057 Box3D domain, 00058 std::vector<BlockLattice3D<T,Descriptor>*> lattices ) 00059 { 00060 // Number of species (or components) which are coupled in this Shan/Chen multi-component fluid. 00061 plint numSpecies = (plint) lattices.size(); 00062 // Short-hand notation for the lattice descriptor 00063 typedef Descriptor<T> D; 00064 // Handle to external scalars 00065 enum { 00066 densityOffset = D::ExternalField::densityBeginsAt, 00067 momentumOffset = D::ExternalField::momentumBeginsAt 00068 }; 00069 00070 // Compute per-lattice density and momentum on every site and on each 00071 // lattice, and store result in external scalars; envelope cells are included, 00072 // because they are needed to compute the interaction potential in the following. 00073 // Note that the per-lattice value of the momentum is stored temporarily only, as 00074 // it is corrected later on, based on the common fluid velocity. 00075 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00076 for (plint iX=domain.x0-1; iX<=domain.x1+1; ++iX) { 00077 for (plint iY=domain.y0-1; iY<=domain.y1+1; ++iY) { 00078 for (plint iZ=domain.z0-1; iZ<=domain.z1+1; ++iZ) { 00079 // Get "intelligent" value of density through cell object, to account 00080 // for the fact that the density value can be user-defined, for example 00081 // on boundaries. 00082 Cell<T,Descriptor>& cell = lattices[iSpecies]->get(iX,iY,iZ); 00083 Array<T,Descriptor<T>::d> j; 00084 T rhoBar; 00085 cell.getDynamics().computeRhoBarJ(cell,rhoBar,j); 00086 momentTemplates<T,Descriptor>::get_j(cell,j); 00087 *cell.getExternal(densityOffset) = Descriptor<T>::fullRho(rhoBar); 00088 j.to_cArray(cell.getExternal(momentumOffset)); 00089 } 00090 } 00091 } 00092 } 00093 00094 // Temporary variable for the relaxation parameters omega. 00095 std::vector<T> omega(numSpecies), invOmega(numSpecies); 00096 // Temporary variable for total velocity. 00097 Array<T,Descriptor<T>::d> uTot; 00098 // Temporary variable for interaction potential. 00099 std::vector<Array<T,D::d> > rhoContribution(numSpecies); 00100 00101 // If omega is constant and imposed by the user, copy its value to 00102 // the vector "omega", and compute the inverse. 00103 if (!imposedOmega.empty()) { 00104 omega = imposedOmega; 00105 for (pluint iOmega=0; iOmega<omega.size(); ++iOmega) { 00106 invOmega[iOmega] = (T)1 / omega[iOmega]; 00107 } 00108 } 00109 00110 // Compute the interaction force between the species, and store it by 00111 // means of a velocity correction in the external velocity field. 00112 for (plint iX=domain.x0; iX<=domain.x1; ++iX) { 00113 for (plint iY=domain.y0; iY<=domain.y1; ++iY) { 00114 for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) { 00115 // Computation of the common density over all populations, weighted by 00116 // the relaxation parameters omega. 00117 T weightedDensity = T(); 00118 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00119 Cell<T,Descriptor> const& cell = lattices[iSpecies]->get(iX,iY,iZ); 00120 // Take this opportunity to read omega from the cell, unless the value 00121 // of omega is constant and imposed by the user. 00122 if (imposedOmega.empty()) { 00123 omega[iSpecies] = cell.getDynamics().getOmega(); 00124 invOmega[iSpecies] = (T)1/omega[iSpecies]; 00125 } 00126 weightedDensity += omega[iSpecies] * (*cell.getExternal(densityOffset)); 00127 } 00128 // Computation of the common velocity, shared among all populations. 00129 for (int iD = 0; iD < Descriptor<T>::d; ++iD) { 00130 uTot[iD] = T(); 00131 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00132 T *momentum = lattices[iSpecies]->get(iX,iY,iZ).getExternal(momentumOffset); 00133 uTot[iD] += momentum[iD] * omega[iSpecies]; 00134 } 00135 uTot[iD] /= weightedDensity; 00136 } 00137 00138 // Computation of the interaction potential. 00139 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00140 multiPhaseTemplates3D<T,Descriptor>::shanChenInteraction ( 00141 *lattices[iSpecies],rhoContribution[iSpecies],iX,iY,iZ ); 00142 } 00143 00144 // Computation and storage of the final velocity, consisting 00145 // of uTot plus the momentum difference due to interaction 00146 // potential and external force 00147 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00148 Cell<T,Descriptor>& cell = lattices[iSpecies]->get(iX,iY,iZ); 00149 T *momentum = cell.getExternal(momentumOffset); 00150 for (int iD = 0; iD < D::d; ++iD) { 00151 momentum[iD] = uTot[iD]; 00152 // Initialize force contribution with force from external fields if there 00153 // is any, or with zero otherwise. 00154 T forceContribution = getExternalForceComponent(cell, iD); 00155 // Then, add a contribution from the potential of all other species. 00156 for (plint iPartnerSpecies=0; iPartnerSpecies<numSpecies; ++iPartnerSpecies) { 00157 if (iPartnerSpecies != iSpecies) { 00158 forceContribution -= G * rhoContribution[iPartnerSpecies][iD]; 00159 } 00160 } 00161 momentum[iD] += invOmega[iSpecies]*forceContribution; 00162 // Multiply by rho to convert from velocity to momentum. 00163 momentum[iD] *= *cell.getExternal(densityOffset); 00164 } 00165 } 00166 } 00167 } 00168 } 00169 } 00170 00171 00172 template<typename T, template<typename U> class Descriptor> 00173 ShanChenMultiComponentProcessor3D<T,Descriptor>* 00174 ShanChenMultiComponentProcessor3D<T,Descriptor>::clone() const 00175 { 00176 return new ShanChenMultiComponentProcessor3D<T,Descriptor>(*this); 00177 } 00178 00179 template<typename T, template<typename U> class Descriptor> 00180 void ShanChenMultiComponentProcessor3D<T,Descriptor>::getTypeOfModification(std::vector<modif::ModifT>& modified) const 00181 { 00182 // All blocks are modified by the Shan/Chen processor. 00183 for (pluint iBlock=0; iBlock<modified.size(); ++iBlock) { 00184 modified[iBlock] = modif::staticVariables; 00185 } 00186 } 00187 00188 00189 /* *************** ShanChenSingleComponentProcessor3D ***************** */ 00190 00191 template<typename T, template<typename U> class Descriptor> 00192 ShanChenSingleComponentProcessor3D<T,Descriptor>::ShanChenSingleComponentProcessor3D ( 00193 T G_, interparticlePotential::PsiFunction<T>* Psi_ ) 00194 : G(G_), 00195 Psi(Psi_) 00196 { } 00197 00198 template<typename T, template<typename U> class Descriptor> 00199 ShanChenSingleComponentProcessor3D<T,Descriptor>::~ShanChenSingleComponentProcessor3D() { 00200 // Pointer to Psi function is owned; delete it in the destructor. 00201 delete Psi; 00202 } 00203 00204 template<typename T, template<typename U> class Descriptor> 00205 ShanChenSingleComponentProcessor3D<T,Descriptor>::ShanChenSingleComponentProcessor3D ( 00206 ShanChenSingleComponentProcessor3D<T,Descriptor> const& rhs ) 00207 : G(rhs.G), 00208 Psi(rhs.Psi->clone()) 00209 { } 00210 00211 template<typename T, template<typename U> class Descriptor> 00212 ShanChenSingleComponentProcessor3D<T,Descriptor>& 00213 ShanChenSingleComponentProcessor3D<T,Descriptor>::operator= ( 00214 ShanChenSingleComponentProcessor3D<T,Descriptor> const& rhs ) 00215 { 00216 G = rhs.G; 00217 delete Psi; Psi = rhs.Psi->clone(); 00218 return *this; 00219 } 00220 00221 template<typename T, template<typename U> class Descriptor> 00222 ShanChenSingleComponentProcessor3D<T,Descriptor>* 00223 ShanChenSingleComponentProcessor3D<T,Descriptor>::clone() const 00224 { 00225 return new ShanChenSingleComponentProcessor3D<T,Descriptor>(*this); 00226 } 00227 00228 template<typename T, template<typename U> class Descriptor> 00229 void ShanChenSingleComponentProcessor3D<T,Descriptor>::getTypeOfModification(std::vector<modif::ModifT>& modified) const 00230 { 00231 modified[0] = modif::nothing; 00232 } 00233 00234 template<typename T, template<typename U> class Descriptor> 00235 void ShanChenSingleComponentProcessor3D<T,Descriptor>::process ( 00236 Box3D domain, BlockLattice3D<T,Descriptor>& lattice ) 00237 { 00238 // Short-hand notation for the lattice descriptor 00239 typedef Descriptor<T> D; 00240 // Handle to external scalars 00241 enum { 00242 densityOffset = D::ExternalField::densityBeginsAt, 00243 momentumOffset = D::ExternalField::momentumBeginsAt 00244 }; 00245 00246 plint nx = domain.getNx() + 2; // Include a one-cell boundary 00247 plint ny = domain.getNy() + 2; // Include a one-cell boundary 00248 plint nz = domain.getNz() + 2; // Include a one-cell boundary 00249 plint offsetX = domain.x0-1; 00250 plint offsetY = domain.y0-1; 00251 plint offsetZ = domain.z0-1; 00252 ScalarField3D<T> psiField(nx,ny,nz); 00253 00254 // Compute density and momentum on every site and store result in external scalars; 00255 // furthermore, evaluate the interaction potential Psi and store it into a ScalarField. 00256 // Envelope cells are included, because they are needed to compute the interaction potential 00257 // in the following. Note that the value of the momentum is stored temporarily only, as 00258 // it is corrected later on to include corrections due to the interaction potential. 00259 for (plint iX=domain.x0-1; iX<=domain.x1+1; ++iX) { 00260 for (plint iY=domain.y0-1; iY<=domain.y1+1; ++iY) { 00261 for (plint iZ=domain.z0-1; iZ<=domain.z1+1; ++iZ) { 00262 // Get "intelligent" value of density through cell object, to account 00263 // for the fact that the density value can be user-defined, for example 00264 // on boundaries. 00265 Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ); 00266 T rho = cell.computeDensity(); 00267 // Evaluate potential function psi. 00268 psiField.get(iX-offsetX, iY-offsetY, iZ-offsetZ) = Psi->compute(rho); 00269 // Store density into the corresponding external scalar. 00270 *cell.getExternal(densityOffset) = rho; 00271 // Compute momentum through direct access to particle populations, and store 00272 // result in corresponding external scalars. Note that Cell::computeVelocity 00273 // cannot be used, because it returns the velocity of the external scalars, 00274 // not the velocity computed from the particle populations. 00275 Array<T,Descriptor<T>::d> j; 00276 momentTemplates<T,Descriptor>::get_j(cell,j); 00277 for (int iD=0; iD<Descriptor<T>::d; ++iD) { 00278 *(cell.getExternal(momentumOffset)+iD) = j[iD]; 00279 } 00280 } 00281 } 00282 } 00283 00284 // Compute the interparticle forces, and store they by means of a 00285 // velocity correction in the external velocity field. 00286 for (plint iX=domain.x0; iX<=domain.x1; ++iX) { 00287 for (plint iY=domain.y0; iY<=domain.y1; ++iY) { 00288 for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) { 00289 Array<T,D::d> rhoContribution; 00290 rhoContribution.resetToZero(); 00291 // Compute the term \sum_i ( t_i psi(x+c_i,t) c_i ) 00292 for (plint iPop = 0; iPop < D::q; ++iPop) { 00293 plint nextX = iX + D::c[iPop][0]; 00294 plint nextY = iY + D::c[iPop][1]; 00295 plint nextZ = iZ + D::c[iPop][2]; 00296 T psi = psiField.get(nextX-offsetX, nextY-offsetY, nextZ-offsetZ); 00297 for (int iD = 0; iD < D::d; ++iD) { 00298 rhoContribution[iD] += D::t[iPop] * psi * D::c[iPop][iD]; 00299 } 00300 } 00301 00302 // Computation and storage of the final momentum, including tho momentum 00303 // difference due to interaction potential and the external force. 00304 Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ); 00305 T *momentum = cell.getExternal(momentumOffset); 00306 for (int iD = 0; iD < D::d; ++iD) { 00307 // Initialize force contribution with force from external fields if there 00308 // is any, or with zero otherwise. 00309 T forceContribution = getExternalForceComponent(cell, iD); 00310 // Add interaction term. 00311 T psi = psiField.get(iX-offsetX, iY-offsetY, iZ-offsetZ); 00312 forceContribution -= G * psi * rhoContribution[iD]; 00313 // Include into total momentum. 00314 momentum[iD] += (T)1/cell.getDynamics().getOmega()*forceContribution; 00315 } 00316 } 00317 } 00318 } 00319 } 00320 00321 00322 } // namespace plb 00323 00324 #endif // SHAN_CHEN_PROCESSOR_3D_HH
1.6.3
1.6.3