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

entropicDynamics.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 /* Orestis Malaspinas contributed this code.
00026  */
00027 
00032 #ifndef ENTROPIC_LB_DYNAMICS_HH
00033 #define ENTROPIC_LB_DYNAMICS_HH
00034 
00035 #include "latticeBoltzmann/dynamicsTemplates.h"
00036 #include "latticeBoltzmann/momentTemplates.h"
00037 #include "latticeBoltzmann/externalForceTemplates.h"
00038 #include "latticeBoltzmann/entropicLbTemplates.h"
00039 #include "complexDynamics/entropicDynamics.h"
00040 #include "core/latticeStatistics.h"
00041 #include "core/dynamicsIdentifiers.h"
00042 #include <algorithm>
00043 #include <limits>
00044 
00045 namespace plb {
00046 
00047 //==============================================================================//
00049 //==============================================================================//
00050 
00051 template<typename T, template<typename U> class Descriptor>
00052 int EntropicDynamics<T,Descriptor>::id =
00053     meta::registerOneParamDynamics<T,Descriptor,EntropicDynamics<T,Descriptor> >("Entropic");
00054 
00058 template<typename T, template<typename U> class Descriptor>
00059 EntropicDynamics<T,Descriptor>::EntropicDynamics(T omega_)
00060     : IsoThermalBulkDynamics<T,Descriptor>(omega_)
00061 { }
00062 
00063 template<typename T, template<typename U> class Descriptor>
00064 EntropicDynamics<T,Descriptor>* EntropicDynamics<T,Descriptor>::clone() const {
00065     return new EntropicDynamics<T,Descriptor>(*this);
00066 }
00067  
00068 template<typename T, template<typename U> class Descriptor>
00069 int EntropicDynamics<T,Descriptor>::getId() const {
00070     return id;
00071 }
00072 
00073 template<typename T, template<typename U> class Descriptor>
00074 T EntropicDynamics<T,Descriptor>::computeEquilibrium (
00075         plint iPop, T rhoBar, Array<T,Descriptor<T>::d> const& j, T jSqr, T thetaBar ) const
00076 {
00077     T rho = Descriptor<T>::fullRho(rhoBar);
00078     T invRho = Descriptor<T>::invRho(rhoBar);
00079     Array<T,Descriptor<T>::d> u;
00080     for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00081         u[iD] = j[iD] * invRho;
00082     }
00083     return entropicLbTemplates<T,Descriptor>::equilibrium(iPop, rho, u);
00084 }
00085 
00086 template<typename T, template<typename U> class Descriptor>
00087 void EntropicDynamics<T,Descriptor>::collide (
00088         Cell<T,Descriptor>& cell,
00089         BlockStatistics& statistics )
00090 {
00091     typedef Descriptor<T> L;
00092     typedef entropicLbTemplates<T,Descriptor> eLbTempl;
00093     
00094     T rho;
00095     Array<T,Descriptor<T>::d> u;
00096     momentTemplates<T,Descriptor>::compute_rho_uLb(cell, rho, u);
00097     T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00098     
00099     Array<T,Descriptor<T>::q> f, fEq, fNeq;
00100     for (plint iPop = 0; iPop < L::q; ++iPop)
00101     {
00102         fEq[iPop]  = eLbTempl::equilibrium(iPop,rho,u);
00103         fNeq[iPop] = cell[iPop] - fEq[iPop];
00104         f[iPop]    = cell[iPop] + L::t[iPop];
00105         fEq[iPop] += L::t[iPop];
00106     }
00107     //==============================================================================//
00108     //============= Evaluation of alpha using a Newton Raphson algorithm ===========//
00109     //==============================================================================//
00110 
00111     T alpha = (T)2;
00112     bool converged = getAlpha(alpha,f,fNeq);
00113     if (!converged)
00114     {
00115         exit(1);
00116     }
00117     
00118     PLB_ASSERT(converged);
00119     
00120     T omegaTot = this->getOmega() / (T)2 * alpha;
00121     for (plint iPop=0; iPop < Descriptor<T>::q; ++iPop) 
00122     {
00123         cell[iPop] *= (T)1-omegaTot;
00124         cell[iPop] += omegaTot * (fEq[iPop]-L::t[iPop]);
00125     }
00126     
00127     if (cell.takesStatistics()) {
00128         gatherStatistics(statistics, Descriptor<T>::rhoBar(rho), uSqr);
00129     }
00130 }
00131 
00132 template<typename T, template<typename U> class Descriptor>
00133 T EntropicDynamics<T,Descriptor>::computeEntropy(Array<T,Descriptor<T>::q> const& f)
00134 {
00135     typedef Descriptor<T> L;
00136     T entropy = T();
00137     for (plint iPop = 0; iPop < L::q; ++iPop)
00138     {
00139         PLB_ASSERT(f[iPop] > T());
00140         entropy += f[iPop]*log(f[iPop]/L::t[iPop]);
00141     }
00142 
00143     return entropy;
00144 }
00145 
00146 template<typename T, template<typename U> class Descriptor>
00147 T EntropicDynamics<T,Descriptor>::computeEntropyGrowth(Array<T,Descriptor<T>::q> const& f, Array<T,Descriptor<T>::q> const& fNeq, T alpha)
00148 {
00149     typedef Descriptor<T> L;
00150     
00151     Array<T,Descriptor<T>::q> fAlphaFneq;
00152     for (plint iPop = 0; iPop < L::q; ++iPop)
00153     {
00154         fAlphaFneq[iPop] = f[iPop] - alpha*fNeq[iPop];
00155     }
00156 
00157     return computeEntropy(f) - computeEntropy(fAlphaFneq);
00158 }
00159 
00160 template<typename T, template<typename U> class Descriptor>
00161 T EntropicDynamics<T,Descriptor>::computeEntropyGrowthDerivative(Array<T,Descriptor<T>::q> const& f, Array<T,Descriptor<T>::q> const& fNeq, T alpha)
00162 {
00163     typedef Descriptor<T> L;
00164     
00165     T entropyGrowthDerivative = T();
00166     for (plint iPop = 0; iPop < L::q; ++iPop)
00167     {
00168         T tmp = f[iPop] - alpha*fNeq[iPop];
00169         PLB_ASSERT(tmp > T());
00170         entropyGrowthDerivative += fNeq[iPop]*(log(tmp/L::t[iPop]));
00171     }
00172 
00173     return entropyGrowthDerivative;
00174 }
00175 
00176 template<typename T, template<typename U> class Descriptor>
00177 bool EntropicDynamics<T,Descriptor>::getAlpha(T &alpha, Array<T,Descriptor<T>::q> const& f, Array<T,Descriptor<T>::q> const& fNeq)
00178 {
00179     const T epsilon = std::numeric_limits<T>::epsilon();
00180 
00181     T alphaGuess = T();
00182     const T var = 100.0;
00183     const T errorMax = epsilon*var;
00184     T error = 1.0;
00185     plint count = 0;
00186     for (count = 0; count < 10000; ++count)
00187     {
00188         T entGrowth = computeEntropyGrowth(f,fNeq,alpha);
00189         T entGrowthDerivative = computeEntropyGrowthDerivative(f,fNeq,alpha);
00190         if ((error < errorMax) || (fabs(entGrowth) < var*epsilon))
00191         {
00192             return true;
00193         }
00194         alphaGuess = alpha - entGrowth / entGrowthDerivative;
00195         error = fabs(alpha-alphaGuess);
00196         alpha = alphaGuess;
00197     }
00198     return false;
00199 }
00200 
00201 //====================================================================//
00203 //====================================================================//
00204 
00205 template<typename T, template<typename U> class Descriptor>
00206 int ForcedEntropicDynamics<T,Descriptor>::id =
00207     meta::registerOneParamDynamics<T,Descriptor,ForcedEntropicDynamics<T,Descriptor> >("Entropic_Forced");
00208 
00211 template<typename T, template<typename U> class Descriptor>
00212 ForcedEntropicDynamics<T,Descriptor>::ForcedEntropicDynamics(T omega_)
00213     : IsoThermalBulkDynamics<T,Descriptor>(omega_)
00214 { }
00215 
00216 template<typename T, template<typename U> class Descriptor>
00217 ForcedEntropicDynamics<T,Descriptor>* ForcedEntropicDynamics<T,Descriptor>::clone() const {
00218     return new ForcedEntropicDynamics<T,Descriptor>(*this);
00219 }
00220  
00221 template<typename T, template<typename U> class Descriptor>
00222 int ForcedEntropicDynamics<T,Descriptor>::getId() const {
00223     return id;
00224 }
00225 
00226 template<typename T, template<typename U> class Descriptor>
00227 T ForcedEntropicDynamics<T,Descriptor>::computeEquilibrium (
00228         plint iPop, T rhoBar, Array<T,Descriptor<T>::d> const& j, T jSqr, T thetaBar ) const
00229 {
00230     T rho = Descriptor<T>::fullRho(rhoBar);
00231     T invRho = Descriptor<T>::invRho(rhoBar);
00232     T uSqr = jSqr*invRho*invRho;
00233     Array<T,Descriptor<T>::d> u;
00234     for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00235         u[iD] = j[iD] * invRho;
00236     }
00237     return entropicLbTemplates<T,Descriptor>::equilibrium(iPop, rho, u);
00238 }
00239 
00240 template<typename T, template<typename U> class Descriptor>
00241 void ForcedEntropicDynamics<T,Descriptor>::collide (
00242         Cell<T,Descriptor>& cell,
00243         BlockStatistics& statistics )
00244 {
00245     typedef Descriptor<T> L;
00246     typedef entropicLbTemplates<T,Descriptor> eLbTempl;
00247 
00248     T rho;
00249     Array<T,Descriptor<T>::d> u;
00250     momentTemplates<T,Descriptor>::compute_rho_uLb(cell, rho, u);
00251     T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00252 
00253     Array<T,Descriptor<T>::q> f, fEq, fNeq;
00254     for (plint iPop = 0; iPop < L::q; ++iPop)
00255     {
00256         fEq[iPop]  = eLbTempl::equilibrium(iPop,rho,u);
00257         fNeq[iPop] = cell[iPop] - fEq[iPop];
00258         f[iPop]    = cell[iPop] + L::t[iPop];
00259         fEq[iPop] += L::t[iPop];
00260     }
00261     //==============================================================================//
00262     //============= Evaluation of alpha using a Newton Raphson algorithm ===========//
00263     //==============================================================================//
00264 
00265     T alpha = (T)2;
00266     bool converged = getAlpha(alpha,f,fNeq);
00267     if (!converged)
00268     {
00269         exit(1);
00270     }
00271 
00272     PLB_ASSERT(converged);
00273     
00274     T* force = cell.getExternal(forceBeginsAt);
00275     for (int iDim=0; iDim<Descriptor<T>::d; ++iDim)
00276     {
00277         u[iDim] += force[iDim] / (T)2.;
00278     }
00279     uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00280     T omegaTot = this->getOmega() / (T)2 * alpha;
00281     for (plint iPop=0; iPop < Descriptor<T>::q; ++iPop) 
00282     {
00283         cell[iPop] *= (T)1-omegaTot;
00284         cell[iPop] += omegaTot * eLbTempl::equilibrium(iPop,rho,u);
00285     }
00286     externalForceTemplates<T,Descriptor>::addGuoForce(cell, u, omegaTot);
00287     
00288     if (cell.takesStatistics())
00289     {
00290         gatherStatistics(statistics, Descriptor<T>::rhoBar(rho), uSqr);
00291     }
00292 }
00293 
00294 template<typename T, template<typename U> class Descriptor>
00295 T ForcedEntropicDynamics<T,Descriptor>::computeEntropy(Array<T,Descriptor<T>::q> const& f)
00296 {
00297     typedef Descriptor<T> L;
00298     T entropy = T();
00299     for (plint iPop = 0; iPop < L::q; ++iPop)
00300     {
00301         PLB_ASSERT(f[iPop] > T());
00302         entropy += f[iPop]*log(f[iPop]/L::t[iPop]);
00303     }
00304 
00305     return entropy;
00306 }
00307 
00308 template<typename T, template<typename U> class Descriptor>
00309 T ForcedEntropicDynamics<T,Descriptor>::computeEntropyGrowth(Array<T,Descriptor<T>::q> const& f, Array<T,Descriptor<T>::q> const& fNeq, T alpha)
00310 {
00311     typedef Descriptor<T> L;
00312     
00313     Array<T,Descriptor<T>::q> fAlphaFneq;
00314     for (plint iPop = 0; iPop < L::q; ++iPop)
00315     {
00316         fAlphaFneq[iPop] = f[iPop] - alpha*fNeq[iPop];
00317     }
00318 
00319     return computeEntropy(f) - computeEntropy(fAlphaFneq);
00320 }
00321 
00322 template<typename T, template<typename U> class Descriptor>
00323 T ForcedEntropicDynamics<T,Descriptor>::computeEntropyGrowthDerivative(Array<T,Descriptor<T>::q> const& f, Array<T,Descriptor<T>::q> const& fNeq, T alpha)
00324 {
00325     typedef Descriptor<T> L;
00326     
00327     T entropyGrowthDerivative = T();
00328     for (plint iPop = 0; iPop < L::q; ++iPop)
00329     {
00330         T tmp = f[iPop] - alpha*fNeq[iPop];
00331         PLB_ASSERT(tmp > T());
00332         entropyGrowthDerivative += fNeq[iPop]*log(tmp/L::t[iPop]);
00333     }
00334 
00335     return entropyGrowthDerivative;
00336 }
00337 
00338 template<typename T, template<typename U> class Descriptor>
00339 bool ForcedEntropicDynamics<T,Descriptor>::getAlpha(T& alpha, Array<T,Descriptor<T>::q> const& f, Array<T,Descriptor<T>::q> const& fNeq)
00340 {
00341     const T epsilon = std::numeric_limits<T>::epsilon();
00342 
00343     T alphaGuess = T();
00344     const T var = 100.0;
00345     const T errorMax = epsilon*var;
00346     T error = 1.0;
00347     plint count = 0;
00348     for (count = 0; count < 10000; ++count)
00349     {
00350         T entGrowth = computeEntropyGrowth(f,fNeq,alpha);
00351         T entGrowthDerivative = computeEntropyGrowthDerivative(f,fNeq,alpha);
00352         if ((error < errorMax) || (fabs(entGrowth) < var*epsilon))
00353         {
00354             return true;
00355         }
00356         alphaGuess = alpha - entGrowth / entGrowthDerivative;
00357         error = fabs(alpha-alphaGuess);
00358         alpha = alphaGuess;
00359     }
00360     return false;
00361 }
00362 
00363 }
00364 
00365 #endif