$treeview $search $mathjax
Palabos  Version 1.1
$projectbrief
$projectbrief
$searchbox

shanChenProcessor3D.hh

Go to the documentation of this file.
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