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

generalizedIncompressibleBoundaryTemplates.h

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 
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> &macro, 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