$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 /* 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
1.6.3
1.6.3