$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_2D_HH 00030 #define SHAN_CHEN_PROCESSOR_2D_HH 00031 00032 #include "multiPhysics/shanChenProcessor2D.h" 00033 #include "core/util.h" 00034 #include "finiteDifference/finiteDifference2D.h" 00035 #include "latticeBoltzmann/momentTemplates.h" 00036 #include "latticeBoltzmann/externalFieldAccess.h" 00037 #include "multiPhysics/multiPhaseTemplates2D.h" 00038 00039 00040 namespace plb { 00041 00042 /* *************** ShanChenMultiComponentProcessor2D ***************** */ 00043 00044 template<typename T, template<typename U> class Descriptor> 00045 ShanChenMultiComponentProcessor2D <T,Descriptor>::ShanChenMultiComponentProcessor2D(T G_) 00046 : G(G_) 00047 { } 00048 00049 template<typename T, template<typename U> class Descriptor> 00050 ShanChenMultiComponentProcessor2D <T,Descriptor>::ShanChenMultiComponentProcessor2D ( 00051 T G_, std::vector<T> const& imposedOmega_) 00052 : G(G_), 00053 imposedOmega(imposedOmega_) 00054 { } 00055 00056 template<typename T, template<typename U> class Descriptor> 00057 void ShanChenMultiComponentProcessor2D<T,Descriptor>::process ( 00058 Box2D domain, 00059 std::vector<BlockLattice2D<T,Descriptor>*> lattices ) 00060 { 00061 // Number of species (or components) which are coupled in this Shan/Chen multi-component fluid. 00062 plint numSpecies = (plint) lattices.size(); 00063 // Short-hand notation for the lattice descriptor 00064 typedef Descriptor<T> D; 00065 // Handle to external scalars 00066 enum { 00067 densityOffset = D::ExternalField::densityBeginsAt, 00068 momentumOffset = D::ExternalField::momentumBeginsAt 00069 }; 00070 00071 // Compute per-lattice density and momentum on every site and on each 00072 // lattice, and store result in external scalars; envelope cells are included, 00073 // because they are needed to compute the interaction potential in the following. 00074 // Note that the per-lattice value of the momentum is stored temporarily only, as 00075 // it is corrected later on, based on the common fluid velocity. 00076 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00077 for (plint iX=domain.x0-1; iX<=domain.x1+1; ++iX) { 00078 for (plint iY=domain.y0-1; iY<=domain.y1+1; ++iY) { 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); 00083 Array<T,Descriptor<T>::d> j; 00084 T rhoBar; 00085 cell.getDynamics().computeRhoBarJ(cell,rhoBar,j); 00086 *cell.getExternal(densityOffset) = Descriptor<T>::fullRho(rhoBar); 00087 j.to_cArray(cell.getExternal(momentumOffset)); 00088 } 00089 } 00090 } 00091 00092 // Temporary variable for the relaxation parameters omega. 00093 std::vector<T> omega(numSpecies), invOmega(numSpecies); 00094 // Temporary variable for the common velocity. 00095 Array<T,Descriptor<T>::d> uTot; 00096 // Temporary variable for the interaction potential. 00097 std::vector<Array<T,D::d> > rhoContribution(numSpecies); 00098 00099 // If omega is constant and imposed by the user, copy its value to 00100 // the vector "omega", and compute the inverse. 00101 if (!imposedOmega.empty()) { 00102 omega = imposedOmega; 00103 for (pluint iOmega=0; iOmega<omega.size(); ++iOmega) { 00104 invOmega[iOmega] = (T)1 / omega[iOmega]; 00105 } 00106 } 00107 00108 // Compute the interaction force between the species, and store it by 00109 // means of a velocity correction in the external velocity field. 00110 for (plint iX=domain.x0; iX<=domain.x1; ++iX) { 00111 for (plint iY=domain.y0; iY<=domain.y1; ++iY) { 00112 // Computation of the common density over all populations, weighted by 00113 // the relaxation parameters omega. 00114 T weightedDensity = T(); 00115 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00116 Cell<T,Descriptor> const& cell = lattices[iSpecies]->get(iX,iY); 00117 // Take this opportunity to read omega from the cell, unless the value 00118 // of omega is constant and imposed by the user. 00119 if (imposedOmega.empty()) { 00120 omega[iSpecies] = cell.getDynamics().getOmega(); 00121 invOmega[iSpecies] = (T)1/omega[iSpecies]; 00122 } 00123 weightedDensity += omega[iSpecies] * (*cell.getExternal(densityOffset)); 00124 } 00125 // Computation of the common velocity, shared among all populations. 00126 for (int iD = 0; iD < Descriptor<T>::d; ++iD) { 00127 uTot[iD] = T(); 00128 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00129 T *momentum = lattices[iSpecies]->get(iX,iY).getExternal(momentumOffset); 00130 uTot[iD] += momentum[iD] * omega[iSpecies]; 00131 } 00132 uTot[iD] /= weightedDensity; 00133 } 00134 00135 // Computation of the interaction potential. 00136 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00137 multiPhaseTemplates2D<T,Descriptor>::shanChenInteraction ( 00138 *lattices[iSpecies],rhoContribution[iSpecies],iX,iY ); 00139 } 00140 00141 // Computation and storage of the final velocity, consisting 00142 // of uTot plus the momentum difference due to interaction 00143 // potential and external force 00144 for (plint iSpecies=0; iSpecies<numSpecies; ++iSpecies) { 00145 Cell<T,Descriptor>& cell = lattices[iSpecies]->get(iX,iY); 00146 T *momentum = cell.getExternal(momentumOffset); 00147 for (int iD = 0; iD < D::d; ++iD) { 00148 momentum[iD] = uTot[iD]; 00149 // Initialize force contribution with force from external fields if there 00150 // is any, or with zero otherwise. 00151 T forceContribution = getExternalForceComponent(cell, iD); 00152 // Then, add a contribution from the potential of all other species. 00153 for (plint iPartnerSpecies=0; iPartnerSpecies<numSpecies; ++iPartnerSpecies) { 00154 if (iPartnerSpecies != iSpecies) { 00155 forceContribution -= G * rhoContribution[iPartnerSpecies][iD]; 00156 } 00157 } 00158 momentum[iD] += invOmega[iSpecies]*forceContribution; 00159 // Multiply by rho to convert from velocity to momentum. 00160 momentum[iD] *= *cell.getExternal(densityOffset); 00161 } 00162 } 00163 } 00164 } 00165 } 00166 00167 00168 template<typename T, template<typename U> class Descriptor> 00169 ShanChenMultiComponentProcessor2D<T,Descriptor>* 00170 ShanChenMultiComponentProcessor2D<T,Descriptor>::clone() const 00171 { 00172 return new ShanChenMultiComponentProcessor2D<T,Descriptor>(*this); 00173 } 00174 00175 template<typename T, template<typename U> class Descriptor> 00176 void ShanChenMultiComponentProcessor2D<T,Descriptor>::getTypeOfModification(std::vector<modif::ModifT>& modified) const 00177 { 00178 // All blocks are modified by the Shan/Chen processor. 00179 for (pluint iBlock=0; iBlock<modified.size(); ++iBlock) { 00180 modified[iBlock] = modif::staticVariables; 00181 } 00182 } 00183 00184 00185 /* *************** ShanChenSingleComponentProcessor2D ***************** */ 00186 00187 template<typename T, template<typename U> class Descriptor> 00188 ShanChenSingleComponentProcessor2D<T,Descriptor>::ShanChenSingleComponentProcessor2D ( 00189 T G_, interparticlePotential::PsiFunction<T>* Psi_ ) 00190 : G(G_), 00191 Psi(Psi_) 00192 { } 00193 00194 template<typename T, template<typename U> class Descriptor> 00195 ShanChenSingleComponentProcessor2D<T,Descriptor>::~ShanChenSingleComponentProcessor2D() { 00196 // Pointer to Psi function is owned; delete it in the destructor. 00197 delete Psi; 00198 } 00199 00200 template<typename T, template<typename U> class Descriptor> 00201 ShanChenSingleComponentProcessor2D<T,Descriptor>::ShanChenSingleComponentProcessor2D ( 00202 ShanChenSingleComponentProcessor2D<T,Descriptor> const& rhs ) 00203 : G(rhs.G), 00204 Psi(rhs.Psi->clone()) 00205 { } 00206 00207 template<typename T, template<typename U> class Descriptor> 00208 ShanChenSingleComponentProcessor2D<T,Descriptor>& 00209 ShanChenSingleComponentProcessor2D<T,Descriptor>::operator= ( 00210 ShanChenSingleComponentProcessor2D<T,Descriptor> const& rhs ) 00211 { 00212 G = rhs.G; 00213 delete Psi; Psi = rhs.Psi->clone(); 00214 return *this; 00215 } 00216 00217 template<typename T, template<typename U> class Descriptor> 00218 ShanChenSingleComponentProcessor2D<T,Descriptor>* 00219 ShanChenSingleComponentProcessor2D<T,Descriptor>::clone() const 00220 { 00221 return new ShanChenSingleComponentProcessor2D<T,Descriptor>(*this); 00222 } 00223 00224 template<typename T, template<typename U> class Descriptor> 00225 void ShanChenSingleComponentProcessor2D<T,Descriptor>::getTypeOfModification(std::vector<modif::ModifT>& modified) const 00226 { 00227 modified[0] = modif::nothing; 00228 } 00229 00230 template<typename T, template<typename U> class Descriptor> 00231 void ShanChenSingleComponentProcessor2D<T,Descriptor>::process ( 00232 Box2D domain, BlockLattice2D<T,Descriptor>& lattice ) 00233 { 00234 // Short-hand notation for the lattice descriptor 00235 typedef Descriptor<T> D; 00236 // Handle to external scalars 00237 enum { 00238 densityOffset = D::ExternalField::densityBeginsAt, 00239 momentumOffset = D::ExternalField::momentumBeginsAt 00240 }; 00241 00242 plint nx = domain.getNx() + 2; // Include a one-cell boundary 00243 plint ny = domain.getNy() + 2; // Include a one-cell boundary 00244 plint offsetX = domain.x0-1; 00245 plint offsetY = domain.y0-1; 00246 ScalarField2D<T> psiField(nx,ny); 00247 00248 // Compute density and momentum on every site and store result in external scalars; 00249 // furthermore, evaluate the interaction potential Psi and store it into a ScalarField. 00250 // Envelope cells are included, because they are needed to compute the interaction potential 00251 // in the following. Note that the value of the momentum is stored temporarily only, as 00252 // it is corrected later on to include corrections due to the interaction potential. 00253 for (plint iX=domain.x0-1; iX<=domain.x1+1; ++iX) { 00254 for (plint iY=domain.y0-1; iY<=domain.y1+1; ++iY) { 00255 // Get "intelligent" value of density through cell object, to account 00256 // for the fact that the density value can be user-defined, for example 00257 // on boundaries. 00258 Cell<T,Descriptor>& cell = lattice.get(iX,iY); 00259 T rho = cell.computeDensity(); 00260 // Evaluate potential function psi. 00261 psiField.get(iX-offsetX, iY-offsetY) = Psi->compute(rho); 00262 // Store density into the corresponding external scalar. 00263 *cell.getExternal(densityOffset) = rho; 00264 // Compute momentum through direct access to particle populations, and store 00265 // result in corresponding external scalars. Note that Cell::computeVelocity 00266 // cannot be used, because it returns the velocity of the external scalars, 00267 // not the velocity computed from the particle populations. 00268 Array<T,Descriptor<T>::d> j; 00269 momentTemplates<T,Descriptor>::get_j(cell,j); 00270 for (int iD=0; iD<Descriptor<T>::d; ++iD) { 00271 *(cell.getExternal(momentumOffset)+iD) = j[iD]; 00272 } 00273 } 00274 } 00275 00276 // Compute the interparticle forces, and store they by means of a 00277 // velocity correction in the external velocity field. 00278 for (plint iX=domain.x0; iX<=domain.x1; ++iX) { 00279 for (plint iY=domain.y0; iY<=domain.y1; ++iY) { 00280 Array<T,D::d> rhoContribution; 00281 rhoContribution.resetToZero(); 00282 // Compute the term \sum_i ( t_i psi(x+c_i,t) c_i ) 00283 for (plint iPop = 0; iPop < D::q; ++iPop) { 00284 plint nextX = iX + D::c[iPop][0]; 00285 plint nextY = iY + D::c[iPop][1]; 00286 T psi = psiField.get(nextX-offsetX, nextY-offsetY); 00287 for (int iD = 0; iD < D::d; ++iD) { 00288 rhoContribution[iD] += D::t[iPop] * psi * D::c[iPop][iD]; 00289 } 00290 } 00291 00292 // Computation and storage of the final momentum, including tho momentum 00293 // difference due to interaction potential and the external force. 00294 Cell<T,Descriptor>& cell = lattice.get(iX,iY); 00295 T *momentum = cell.getExternal(momentumOffset); 00296 for (int iD = 0; iD < D::d; ++iD) { 00297 // Initialize force contribution with force from external fields if there 00298 // is any, or with zero otherwise. 00299 T forceContribution = getExternalForceComponent(cell, iD); 00300 // Add interaction term. 00301 T psi = psiField.get(iX-offsetX, iY-offsetY); 00302 forceContribution -= G * psi * rhoContribution[iD]; 00303 // Include into total momentum. 00304 momentum[iD] += (T)1/cell.getDynamics().getOmega()*forceContribution; 00305 } 00306 } 00307 } 00308 } 00309 00310 } // namespace plb 00311 00312 #endif // SHAN_CHEN_PROCESSOR_2D_HH
1.6.3
1.6.3