$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 00029 #ifndef GENERALIZED_INCOMPRESSIBLE_BOUNDARY_TEMPLATES_H 00030 #define GENERALIZED_INCOMPRESSIBLE_BOUNDARY_TEMPLATES_H 00031 00032 #include "generalizedBoundaryDynamics.h" 00033 #include "core/cell.h" 00034 #include "core/dynamicsIdentifiers.h" 00035 #include "latticeBoltzmann/indexTemplates.h" 00036 #include "latticeBoltzmann/hermitePolynomialsTemplates.h" 00037 #include <Eigen3/Core> 00038 #include <Eigen3/LU> 00039 #include <Eigen3/QR> 00040 #include <Eigen3/Cholesky> 00041 #include <Eigen3/SVD> 00042 #include <Eigen3/Dense> 00043 00044 00045 namespace plb { 00046 00047 template<typename T, template<typename U> class Descriptor> 00048 struct generalizedIncomprBoundaryTemplates { 00049 00050 static T equilibrium_ma2_over_rho(plint iPop, const Array<T,Descriptor<T>::d> &u, T uSqr) { 00051 T c_u = Descriptor<T>::c[iPop][0]*u[0]; 00052 for (int iD=1; iD < Descriptor<T>::d; ++iD) { 00053 c_u += Descriptor<T>::c[iPop][iD]*u[iD]; 00054 } 00055 return Descriptor<T>::t[iPop] * ( 00056 (T)1 + Descriptor<T>::invCs2 * c_u + 00057 Descriptor<T>::invCs2/(T)2 * ( 00058 Descriptor<T>::invCs2 * c_u*c_u - uSqr ) ); 00059 } 00060 00061 // f = w_i*rho*g_i+H2/(2*cs^4):PiNeq (rho and PiNeq unknowns) 00062 static void f_ma2_linear(plint iPop, const Array<T,Descriptor<T>::d> &u, 00063 T uSqr, Eigen::RowVectorXd &a) { 00064 T eqOverRho = equilibrium_ma2_over_rho(iPop,u,uSqr); 00065 a[0] = eqOverRho; 00066 00067 T factor = 0.5*Descriptor<T>::t[iPop]*Descriptor<T>::invCs2*Descriptor<T>::invCs2; 00068 Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop); 00069 00070 for (plint iPi=1; iPi<=SymmetricTensor<T,Descriptor>::n; ++iPi) a[iPi] = H2[iPi-1]*factor; 00071 } 00072 00073 static void f_ma2_linear(plint iPop, const Array<T,Descriptor<T>::d> &u, T uSqr, Eigen::RowVectorXd &a, 00074 T omega) { 00075 T eqOverRho = equilibrium_ma2_over_rho(iPop,u,uSqr); 00076 a(0) = eqOverRho; 00077 00078 T factor = 0.5*Descriptor<T>::t[iPop]*Descriptor<T>::invCs2*Descriptor<T>::invCs2 * ((T)1-omega); 00079 Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop); 00080 00081 for (plint iPi=1; iPi<=SymmetricTensor<T,Descriptor>::n; ++iPi) a(iPi) = H2[iPi-1]*factor; 00082 } 00083 00084 static void f_to_A_ma2_contrib(const std::vector<plint> kInd, const Array<T,Descriptor<T>::d> &u, 00085 T uSqr, Eigen::MatrixXd &A) { 00086 for (pluint fInd = 0; fInd < kInd.size(); ++fInd) { 00087 plint iPop = kInd[fInd]; 00088 Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(A.cols()); 00089 generalizedIncomprBoundaryTemplates<T,Descriptor>:: 00090 f_ma2_linear(iPop, u, uSqr, lineA); 00091 A.row(fInd) = lineA; 00092 } 00093 } 00094 00095 static void f_to_b_contrib(Cell<T,Descriptor> &cell, const std::vector<plint> kInd, Eigen::VectorXd &b) { 00096 for (pluint fInd = 0; fInd < kInd.size(); ++fInd) { 00097 plint iPop = kInd[fInd]; 00098 b[fInd] = fullF<T,Descriptor>(cell[iPop], iPop); 00099 } 00100 } 00101 00102 static void from_macro_to_rho_j_pineq(const std::vector<T> ¯o, T &rho, Array<T,Descriptor<T>::d> &j, 00103 Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq) { 00104 rho = macro[0]; 00105 for (plint iD = 0; iD < Descriptor<T>::d; ++iD) j[iD] = rho * (macro[1+iD]); 00106 for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) PiNeq[iPi] = macro[1+Descriptor<T>::d+iPi]; 00107 } 00108 00109 // generic tranformation methods 00110 static void fromRhoAndPiNeqToX(T rho, const Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq, Eigen::VectorXd &x) { 00111 x(0) = rho; 00112 for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) x(iPi+1) = PiNeq[iPi]; 00113 } 00114 00115 static void fromXtoRhoAndPiNeq(const Eigen::VectorXd &x, T &rho, Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq) { 00116 rho = x(0); 00117 for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) PiNeq[iPi] = x(iPi+1); 00118 } 00119 00120 static void fromUandPiNeqToX(const Array<T,Descriptor<T>::d> &u, 00121 const Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq, Eigen::VectorXd &x, plint dir) { 00122 x(0) = u[dir]; 00123 for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) x(iPi+1) = PiNeq[iPi]; 00124 } 00125 00126 static void fromXtoUandPiNeq(const Eigen::VectorXd &x, Array<T,Descriptor<T>::d> &u, 00127 Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq,plint dir) { 00128 u[dir] = x(0); 00129 for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) PiNeq[iPi] = x(iPi+1); 00130 } 00131 00132 // creation of the over-determined (usually) linear system 00133 // static void createLinearSystem(const Cell<T,Descriptor>& cell, const Array<T,Descriptor<T>::d> &u, 00134 // const std::vector<plint> &missingIndices, 00135 // const std::vector<plint> &knownIndices, 00136 // Eigen::MatrixXd &A,Eigen::VectorXd &b) { 00137 // 00138 // T uSqr = VectorTemplate<T,Descriptor>::normSqr(u); 00139 // 00140 // plint systSizeX = SymmetricTensor<T,Descriptor>::n+1; 00141 // plint systSizeY = knownIndices.size()+1; 00142 // 00143 // // matrix of the system Ax=b 00144 // A = Eigen::MatrixXd::Zero(systSizeY,systSizeX); 00145 // // rhs of the equation Ax=b 00146 // b = Eigen::VectorXd::Zero(systSizeY); 00147 // 00148 // // f^k = A * x 00149 // // A = g, 1/(2c_s^4) H^2 00150 // // with g being feq/rho and H^2 the second order Hermite polynomial 00151 // for (pluint fInd = 0; fInd < knownIndices.size(); ++fInd) { 00152 // plint iPop = knownIndices[fInd]; 00153 // Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX); 00154 // computeMatrixRow(iPop, u, uSqr, lineA); 00155 // A.row(fInd) = lineA; 00156 // } 00157 // 00158 // T rhoTmp = T(); 00159 // for (pluint kInd = 0; kInd < knownIndices.size(); ++kInd) { 00160 // plint iPop = knownIndices[kInd]; 00161 // rhoTmp += fullF<T,Descriptor>(cell[iPop], iPop); 00162 // b(kInd) = fullF<T,Descriptor>(cell[iPop], iPop); 00163 // } 00164 // // rhoTtmp = sum_i->known f_i. 00165 // b(knownIndices.size()) = rhoTmp; 00166 // 00167 // // first row of the A matrix. imposing sum_i f_i = rho. 00168 // Eigen::RowVectorXd e0 = Eigen::RowVectorXd::Zero(systSizeX); 00169 // e0(0) = 1.0; 00170 // 00171 // Eigen::RowVectorXd sumA = Eigen::RowVectorXd::Zero(systSizeX); 00172 // for (pluint fInd = 0; fInd < missingIndices.size(); ++fInd) { 00173 // plint iPop = missingIndices[fInd]; 00174 // Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX); 00175 // computeMatrixRow(iPop, u, uSqr, lineA); 00176 // for (plint iVec = 0; iVec < systSizeX; ++iVec) sumA(iVec) += lineA(iVec); 00177 // } 00178 // 00179 // A.row(knownIndices.size()) = e0-sumA; 00180 // 00181 // } 00182 // 00183 // static void solveLinearSystemEigen(const Cell<T,Descriptor>& cell, 00184 // const Array<T,Descriptor<T>::d> &u, 00185 // const std::vector<plint> &missingIndices, 00186 // const std::vector<plint> &knownIndices, 00187 // T &rho, 00188 // Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq) { 00189 // Eigen::MatrixXd A; 00190 // Eigen::VectorXd b; 00191 // 00192 // createLinearSystem(cell, u, missingIndices, knownIndices, A, b); 00193 // 00194 // Eigen::VectorXd x; 00195 // 00196 // Eigen::MatrixXd AT = A.transpose(); 00197 // A = AT * A; 00198 // b = AT * b; 00199 // 00200 // #ifdef PLB_DEBUG 00201 // bool solutionExists = A.lu().solve(b,&x); // using a LU factorization 00202 // PLB_ASSERT(solutionExists); 00203 // #else 00204 // A.lu().solve(b,&x); 00205 // #endif 00206 // 00207 // fromXtoRhoAndPiNeq(x,rho,PiNeq); 00208 // } 00209 00210 // ========= Methods used for the density BCs ============== // 00211 static void compute_f_diff_u_dir_and_PiNeq(plint iPop, T rho, const Array<T,Descriptor<T>::d> &u, 00212 Eigen::RowVectorXd &df, plint dir) { 00213 T tcs2 = Descriptor<T>::invCs2* Descriptor<T>::t[iPop]; 00214 T factor = 0.5 * tcs2 * Descriptor<T>::invCs2; 00215 Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop); 00216 00217 T diffFeqUmissing = T(); 00218 plint iPi = 0; 00219 for (plint iA = 0; iA < Descriptor<T>::d; ++iA) { 00220 for (plint iB = iA; iB < Descriptor<T>::d; ++iB) { 00221 if (iA == dir || iB == dir) { 00222 if (iA == iB) { 00223 diffFeqUmissing += (T)2*H2[iPi]*u[dir]; 00224 } 00225 else if (iA != dir) { 00226 diffFeqUmissing += H2[iPi]*u[iA]; 00227 } 00228 else if (iB != dir) { 00229 diffFeqUmissing += H2[iPi]*u[iB]; 00230 } 00231 } 00232 df(iPi+1) = factor*H2[iPi]; 00233 ++iPi; 00234 } 00235 } 00236 diffFeqUmissing *= factor; 00237 diffFeqUmissing += Descriptor<T>::c[iPop][dir]*tcs2; 00238 diffFeqUmissing *= rho; 00239 00240 df(0) = diffFeqUmissing; 00241 } 00242 00243 static void computeDiffF(plint iPop, T rho, const Array<T,Descriptor<T>::d> &u, plint dir, Eigen::RowVectorXd &df) { 00244 T tcs2 = Descriptor<T>::invCs2* Descriptor<T>::t[iPop]; 00245 T factor = 0.5 * tcs2 * Descriptor<T>::invCs2; 00246 Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop); 00247 00248 T diffFeqUmissing = T(); 00249 plint iPi = 0; 00250 for (plint iA = 0; iA < Descriptor<T>::d; ++iA) { 00251 for (plint iB = iA; iB < Descriptor<T>::d; ++iB) { 00252 if (iA == dir || iB == dir) { 00253 if (iA == iB) { 00254 diffFeqUmissing += (T)2*H2[iPi]*u[dir]; 00255 } 00256 else if (iA != dir) { 00257 diffFeqUmissing += H2[iPi]*u[iA]; 00258 } 00259 else if (iB != dir) { 00260 diffFeqUmissing += H2[iPi]*u[iB]; 00261 } 00262 } 00263 df(iPi+1) = factor*H2[iPi]; 00264 ++iPi; 00265 } 00266 } 00267 diffFeqUmissing *= factor; 00268 diffFeqUmissing += Descriptor<T>::c[iPop][dir]*tcs2; 00269 diffFeqUmissing *= rho; 00270 00271 df(0) = diffFeqUmissing; 00272 } 00273 00274 static void computeJacobian(T rho, 00275 const Array<T,Descriptor<T>::d> &u, 00276 const Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq, 00277 const plint dir, // direction of the unknown velocity 00278 const std::vector<plint> &knownIndices, 00279 Eigen::MatrixXd &Jac) { 00280 plint systSizeX = SymmetricTensor<T,Descriptor>::n+1; 00281 00282 Eigen::RowVectorXd df = Eigen::RowVectorXd::Zero(systSizeX); 00283 for (pluint iPop = 0; iPop < knownIndices.size(); ++iPop) { 00284 computeDiffF(knownIndices[iPop], rho, u, dir, df); 00285 Jac.row(iPop) = df; 00286 } 00287 } 00288 00289 static void computeNonLinearFunction(const Cell<T,Descriptor>& cell, 00290 T rho, 00291 const Array<T,Descriptor<T>::d> &u, 00292 const T uSqr, 00293 const Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq, 00294 const plint dir, // direction of the unknown velocity 00295 const std::vector<plint> &knownIndices, 00296 Eigen::VectorXd &f) { 00297 T rhoBar = Descriptor<T>::rhoBar(rho); 00298 T invRho = Descriptor<T>::invRho(rhoBar); 00299 Array<T,Descriptor<T>::d> j = rho * u; 00300 T jSqr = rho*rho*uSqr; 00301 for (pluint iPop = 0; iPop < knownIndices.size(); ++iPop) { 00302 f(iPop) = cell[knownIndices[iPop]] - ( 00303 dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibrium(knownIndices[iPop], rhoBar, invRho, j, jSqr) + 00304 offEquilibriumTemplates<T,Descriptor>::fromPiToFneq(knownIndices[iPop],PiNeq) ); 00305 } 00306 } 00307 00308 static bool converge(Eigen::VectorXd &x, 00309 Eigen::VectorXd &dx, 00310 T epsilon) 00311 { 00312 for (plint iPi = 0; iPi < x.rows(); ++iPi) { 00313 T res = (fabs(x[iPi]) > 1.0e-14 ? fabs(dx(iPi)/x(iPi)) : fabs(x(iPi))); 00314 00315 if (res > epsilon) return false; 00316 } 00317 return true; 00318 } 00319 00320 static void iterativelySolveSystem(const Cell<T,Descriptor>& cell, 00321 T rho, 00322 Array<T,Descriptor<T>::d> &u, 00323 Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq, 00324 const int dir, // direction of the unknown velocity 00325 const std::vector<plint> &knownIndices, 00326 T epsilon) { 00327 // u and PiNeq contain the initial guess for the solution of the system 00328 plint maxT = 10000; 00329 00330 plint systSizeX = SymmetricTensor<T,Descriptor>::n+1; 00331 plint systSizeY = knownIndices.size(); 00332 00333 Eigen::VectorXd f = Eigen::VectorXd::Zero(systSizeY); // stores the non-linear function 00334 Eigen::VectorXd x = Eigen::VectorXd::Zero(systSizeX); // stores the variables (u[dir] and PiNeq) 00335 Eigen::VectorXd dx = Eigen::VectorXd::Zero(systSizeX); // contains delta_u[dir], delta_PiNeq (the increments towards the solution) 00336 00337 fromUandPiNeqToX(u,PiNeq,x,dir); 00338 Eigen::MatrixXd Jac = Eigen::MatrixXd::Zero(systSizeY,systSizeX); 00339 Eigen::MatrixXd JacT = Jac.transpose(); 00340 for (plint iT = 0; iT < maxT; ++iT) { 00341 T uSqr = VectorTemplate<T,Descriptor>::normSqr(u); 00342 computeNonLinearFunction(cell,rho,u,uSqr,PiNeq,dir, knownIndices,f); 00343 // std::cout << iT << " " << f << std::endl << std::endl; 00344 computeJacobian(rho, u, PiNeq, dir, knownIndices, Jac); 00345 JacT = Jac.transpose(); 00346 00347 Eigen::MatrixXd JacSqr = JacT * Jac; 00348 Eigen::VectorXd JacTf = JacT * f; 00349 00350 #ifdef PLB_DEBUG 00351 // bool solutionExists = JacSqr.lu().solve(JacTf,&dx); // using a LU factorization 00352 // PLB_ASSERT(solutionExists); 00353 dx = JacSqr.fullPivLu().solve(JacTf); 00354 T relError = (JacSqr*dx - JacTf).norm() / JacTf.norm(); 00355 PLB_ASSERT(relError < 1.0e-12); 00356 #else 00357 dx = JacSqr.fullPivLu().solve(JacTf); 00358 // JacSqr.lu().solve(JacTf,&dx); 00359 // dx = JacSqr.fullPivLu().solve(JacTf); 00360 #endif 00361 00362 T stepMult = (T)1; // step size (step mult can only be <= 1 (usually = 1). 00363 x += stepMult*dx; // increment solution 00364 fromXtoUandPiNeq(x,u,PiNeq,dir); 00365 if (converge(x,dx,epsilon)) { 00366 // pcout << "Converged after " << iT << " iterations." << std::endl; 00367 // std::cout << x << std::endl << std::endl; 00368 break; 00369 } 00370 } 00371 // pcout << "NEVER CONVERGED!!!." << std::endl; 00372 } 00373 00374 }; // struct generalizedIncomprBoundaryTemplates 00375 00376 } // namespace plb 00377 00378 #endif // GENERALIZED_BOUNDARY_DYNAMICS_HH
1.6.3
1.6.3