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

generalizedBoundaryDynamicsSolvers.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 
00029 #ifndef GENERALIZED_BOUNDARY_DYNAMICS_SOLVER_HH
00030 #define GENERALIZED_BOUNDARY_DYNAMICS_SOLVER_HH
00031 
00032 #include "generalizedBoundaryDynamicsSolvers.h"
00033 #include "generalizedIncompressibleBoundaryTemplates.h"
00034 #include "core/cell.h"
00035 #include "latticeBoltzmann/indexTemplates.h"
00036 #include <Eigen3/LU>
00037 #include <Eigen3/Cholesky>
00038 
00039 namespace plb {
00040 
00041 // ================ GeneralizedBoundarySolver base class =================== //
00042 template<typename T, template<typename U> class Descriptor>
00043 GeneralizedBoundarySolver<T, Descriptor>::GeneralizedBoundarySolver(const std::vector<plint> &mInd_, 
00044                                                                     const std::vector<plint> &kInd_) 
00045     : mInd(mInd_), kInd(kInd_)
00046 {  }
00047 
00048 // ============ GeneralizedLinearBoundarySolver base class ================= //
00049 template<typename T, template<typename U> class Descriptor>
00050 GeneralizedLinearBoundarySolver<T, Descriptor>::
00051 GeneralizedLinearBoundarySolver(const std::vector<plint> &mInd_, const std::vector<plint> &kInd_) 
00052     : GeneralizedBoundarySolver<T, Descriptor>(mInd_,kInd_)
00053 {  }
00054 
00055 template<typename T, template<typename U> class Descriptor>
00056 void GeneralizedLinearBoundarySolver<T, Descriptor>::apply(Cell<T,Descriptor> &cell, const Dynamics<T,Descriptor> &dyn,
00057                                                            bool replaceAll) {
00058     Eigen::MatrixXd A;    // lhs matrix
00059     Eigen::VectorXd b, x; // rhs of system of equations, unkown of the system
00060     
00061     createLinearSystem(cell, A, b);
00062     solveLinearSytem(cell, A, b, x);
00063     regularizePopulations(cell,x,dyn,replaceAll);
00064 }
00065 
00066 template<typename T, template<typename U> class Descriptor>
00067 void GeneralizedLinearBoundarySolver<T, Descriptor>::
00068         solveLinearSytem(Cell<T,Descriptor> &cell, Eigen::MatrixXd &A, Eigen::VectorXd &b, Eigen::VectorXd &x) {
00069     Eigen::MatrixXd AT = A.transpose();
00070     A = AT * A;
00071     b = AT * b;
00072     
00073     #ifdef PLB_DEBUG
00074 //     bool solutionExists = A.lu().solve(b,&x);   // using a LU factorization
00075 //     pcout << "Error in the solution = " << (A*x-b).norm()/x.norm() << std::endl;
00076 //     PLB_ASSERT(solutionExists);
00077     
00078     x = A.fullPivLu().solve(b);
00079     T relError = (A*x - b).norm() / b.norm();
00080     PLB_ASSERT(relError < 1.0e-12);
00081     
00082     #else
00083     x = A.fullPivLu().solve(b);
00084 //     A.lu().solve(b,&x);
00085     #endif
00086 }
00087 
00088 // =========== GeneralizedNonLinearBoundarySolver base class =============== //
00089 
00090 template<typename T, template<typename U> class Descriptor>
00091 GeneralizedNonLinearBoundarySolver<T, Descriptor>::
00092     GeneralizedNonLinearBoundarySolver(const std::vector<plint> &mInd_, const std::vector<plint> &kInd_,
00093                                        T epsilon_) 
00094         : GeneralizedBoundarySolver<T, Descriptor>(mInd_,kInd_), epsilon(epsilon_)
00095 {  }
00096 
00097 template<typename T, template<typename U> class Descriptor>
00098 bool GeneralizedNonLinearBoundarySolver<T, Descriptor>::converge(const Eigen::VectorXd &x, const Eigen::VectorXd &dx) {
00099     for (plint iPi = 0; iPi < x.rows(); ++iPi) {
00100         T res = (fabs(x[iPi]) > 1.0e-14 ? fabs(dx(iPi)/x(iPi)) : fabs(x(iPi)));
00101         
00102         if (res > epsilon) return false;
00103     }
00104     return true;
00105 }
00106 
00107 template<typename T, template<typename U> class Descriptor>
00108 void GeneralizedNonLinearBoundarySolver<T, Descriptor>::
00109     iterateNonLinearSystem(const Eigen::MatrixXd &Jac, const Eigen::VectorXd &f,
00110                            Eigen::VectorXd &x, Eigen::VectorXd &dx) {
00111     Eigen::MatrixXd JacT = Jac.transpose();
00112     Eigen::MatrixXd JacSqr = JacT * Jac;
00113     Eigen::VectorXd JacTf = JacT * f;
00114     
00115     #ifdef PLB_DEBUG
00116 //     bool solutionExists = JacSqr.lu().solve(JacTf,&dx);   // using a LU factorization
00117 //     PLB_ASSERT(solutionExists);
00118     x = JacSqr.fullPivLu().solve(JacT);
00119     T relError = (JacSqr*x - JacT).norm() / JacT.norm();
00120     PLB_ASSERT(relError < 1.0e-12);
00121     #else
00122     x = JacSqr.fullPivLu().solve(JacT);
00123 //     JacSqr.lu().solve(JacTf,&dx);
00124     #endif
00125     
00126     T stepMult = (T)1; // step size (step mult can only be <= 1 (usually = 1).
00127     x += stepMult*dx;  // increment solution
00128 }
00129 
00130 template<typename T, template<typename U> class Descriptor>
00131 void GeneralizedNonLinearBoundarySolver<T, Descriptor>::apply(Cell<T,Descriptor> &cell, 
00132                                                               const Dynamics<T,Descriptor> &dyn,
00133                                                               bool replaceAll) {
00134     Eigen::MatrixXd Jacobian; // lhs matrix
00135     Eigen::VectorXd f, x, dx; // rhs of system of equations, unkown of the system
00136 
00137     plint maxT = 10000;
00138     iniSystem(Jacobian, f, x, dx);
00139     fromMacroToX(x);
00140     for (plint iT = 0; iT < maxT; ++iT) {
00141         createNonLinearSystem(cell, Jacobian, f);
00142         iterateNonLinearSystem(Jacobian, f, x, dx);
00143         fromXtoMacro(x);
00144         if (converge(x,dx)) {
00145             break;
00146         }
00147     }
00148     
00149     regularizePopulations(cell,x,dyn,replaceAll);
00150     
00151 }
00152 
00153 // ========================================================================= //
00154 // ============ Different kind of Linear BCs for incompressible fluids ===== //
00155 // ========================================================================= //
00156 
00157 // ========================= Dirichlet Velocity BC ========================= //
00158 // ======================= without mass conservation ======================= //
00159 
00160 template<typename T, template<typename U> class Descriptor>
00161 DirichletVelocityBoundarySolver<T,Descriptor>::
00162     DirichletVelocityBoundarySolver(const std::vector<plint> &mInd_, const std::vector<plint> &kInd_,
00163                                     const Array<T,Descriptor<T>::d> &u_) : 
00164         GeneralizedLinearBoundarySolver<T, Descriptor>(mInd_,kInd_), u(u_)
00165 { 
00166     sysX = SymmetricTensor<T,Descriptor>::n+1;
00167     sysY = this->kInd.size()+1;
00168 }
00169 
00170 template<typename T, template<typename U> class Descriptor>
00171 void DirichletVelocityBoundarySolver<T,Descriptor>::
00172     createLinearSystem(Cell<T,Descriptor> &cell, Eigen::MatrixXd &A, Eigen::VectorXd &b) {
00173     
00174     // matrix of the system Ax=b
00175     A = Eigen::MatrixXd::Zero(sysY,sysX);
00176     // rhs of the equation Ax=b
00177     b = Eigen::VectorXd::Zero(sysY);
00178     
00179     T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00180     // f^k = A * x
00181     // A = g, 1/(2c_s^4) H^2
00182     // with g being feq/rho and H^2 the second order Hermite polynomial
00183     generalizedIncomprBoundaryTemplates<T,Descriptor>::f_to_A_ma2_contrib(this->kInd,u,uSqr,A);
00184     generalizedIncomprBoundaryTemplates<T,Descriptor>::f_to_b_contrib(cell,this->kInd,b);
00185     
00186     T rhoTmp = T();
00187     for (pluint fInd = 0; fInd < this->kInd.size(); ++fInd) {
00188         plint iPop = this->kInd[fInd];
00189         rhoTmp += fullF<T,Descriptor>(cell[iPop], iPop);
00190     }
00191     // rhoTtmp = sum_i->known f_i.
00192     b[sysY-1] = rhoTmp;
00193     
00194     // first row of the A matrix. imposing sum_i f_i = rho.
00195     Eigen::RowVectorXd e0 = Eigen::RowVectorXd::Zero(sysX); 
00196     e0[0] = 1.0;
00197     
00198     Eigen::RowVectorXd sumA = Eigen::RowVectorXd::Zero(sysX);
00199     for (pluint fInd = 0; fInd < this->mInd.size(); ++fInd) {
00200         plint iPop = this->mInd[fInd];
00201         Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(sysX);
00202         generalizedIncomprBoundaryTemplates<T,Descriptor>::f_ma2_linear(iPop, u, uSqr, lineA);
00203         for (plint iVec = 0; iVec < sysX; ++iVec) sumA(iVec) += lineA(iVec);
00204     }
00205     
00206     A.row(sysY-1) = e0-sumA;
00207 }
00208 
00209 template<typename T, template<typename U> class Descriptor>
00210 void DirichletVelocityBoundarySolver<T,Descriptor>::
00211     regularizePopulations(Cell<T,Descriptor> &cell, const Eigen::VectorXd &x,
00212                           const Dynamics<T,Descriptor> &dyn, bool replaceAll ) {
00213     
00214     T rho;
00215     Array<T,SymmetricTensor<T,Descriptor>::n> PiNeq;
00216     generalizedIncomprBoundaryTemplates<T,Descriptor>::fromXtoRhoAndPiNeq(x, rho, PiNeq);
00217     T rhoBar = Descriptor<T>::rhoBar(rho);
00218     Array<T,Descriptor<T>::d> j = rho * u;
00219     T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00220     if (replaceAll) {
00221         dyn.regularize(cell, rhoBar, j, jSqr, PiNeq);
00222     } else {
00223         Cell<T,Descriptor> tmpCell;
00224         dyn.regularize(tmpCell, rhoBar, j, jSqr, PiNeq);
00225         for (pluint fInd = 0; fInd < this->mInd.size(); ++fInd) {
00226             plint iPop = this->mInd[fInd];
00227             cell[iPop] = tmpCell[iPop];
00228         }
00229     }
00230 }
00231 
00232 // ========================= Dirichlet Velocity BC ========================= //
00233 // ======================= with  mass conservation ======================= //
00234 
00235 template<typename T, template<typename U> class Descriptor>
00236 DirichletMassConservingVelocityBoundarySolver<T,Descriptor>::
00237     DirichletMassConservingVelocityBoundarySolver(const std::vector<plint> &mInd_, 
00238                                                   const std::vector<plint> &kInd_, 
00239                                                   const std::vector<plint> &inGoingInd_,
00240                                                   const Array<T,Descriptor<T>::d> &u_ ) : 
00241         GeneralizedLinearBoundarySolver<T, Descriptor>(mInd_,kInd_),
00242         inGoingInd(inGoingInd_), u(u_)
00243 {
00244     sysX = SymmetricTensor<T,Descriptor>::n+1;
00245     sysY = this->kInd.size()+1;
00246 }
00247 
00248 template<typename T, template<typename U> class Descriptor>
00249 void DirichletMassConservingVelocityBoundarySolver<T,Descriptor>::
00250     createLinearSystem(Cell<T,Descriptor> &cell, Eigen::MatrixXd &A, Eigen::VectorXd &b) {
00251     
00252     // matrix of the system Ax=b
00253     A = Eigen::MatrixXd::Zero(sysY,sysX);
00254     // rhs of the equation Ax=b
00255     b = Eigen::VectorXd::Zero(sysY);
00256     
00257     T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00258     // f^k = A * x
00259     // A = g, 1/(2c_s^4) H^2
00260     // with g being feq/rho and H^2 the second order Hermite polynomial
00261     
00262     generalizedIncomprBoundaryTemplates<T,Descriptor>::f_to_A_ma2_contrib(this->kInd,u,uSqr,A);
00263     generalizedIncomprBoundaryTemplates<T,Descriptor>::f_to_b_contrib(cell,this->kInd,b);
00264     
00265     // computing mass incoming in the wall
00266     T rhoTmp = T();
00267     for (pluint fInd = 0; fInd < this->inGoingInd.size(); ++fInd) {
00268         plint iPop = indexTemplates::opposite<Descriptor<T> >(inGoingInd[fInd]);
00269         rhoTmp += fullF<T,Descriptor>(cell[iPop], iPop);
00270     }
00271     // rhoTtmp = sum_i->in_wall f_i.
00272     b[sysY-1] = rhoTmp;
00273     
00274     const T omega = cell.getDynamics().getOmega();
00275     Eigen::RowVectorXd sumA = Eigen::RowVectorXd::Zero(sysX);
00276     for (pluint fInd = 0; fInd < inGoingInd.size(); ++fInd) {
00277         plint iPop = inGoingInd[fInd];
00278         Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(sysX);
00279         generalizedIncomprBoundaryTemplates<T,Descriptor>::f_ma2_linear(iPop, u, uSqr, lineA, omega);
00280         for (plint iVec = 0; iVec < sysX; ++iVec) sumA(iVec) += lineA(iVec);
00281     }
00282     
00283     A.row(sysY-1) = sumA;
00284 }
00285 
00286 template<typename T, template<typename U> class Descriptor>
00287 void DirichletMassConservingVelocityBoundarySolver<T,Descriptor>::
00288     regularizePopulations(Cell<T,Descriptor> &cell, const Eigen::VectorXd &x,
00289                           const Dynamics<T,Descriptor> &dyn, bool replaceAll ) {
00290     
00291     T rho;
00292     Array<T,SymmetricTensor<T,Descriptor>::n> PiNeq;
00293     generalizedIncomprBoundaryTemplates<T,Descriptor>::fromXtoRhoAndPiNeq(x, rho, PiNeq);
00294     T rhoBar = Descriptor<T>::rhoBar(rho);
00295     Array<T,Descriptor<T>::d> j = rho * u;
00296     T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00297     dyn.regularize(cell, rhoBar, j, jSqr, PiNeq);
00298 }
00299 
00300 // ========================================================================= //
00301 // ======== Different kind of Non Linear BCs for incompressible fluids ===== //
00302 // ========================================================================= //
00303 
00304 // ========================= Dirichlet Density BC ========================= //
00305 template<typename T, template<typename U> class Descriptor, int dir>
00306 DirichletDensityBoundarySolver<T,Descriptor,dir>::
00307     DirichletDensityBoundarySolver(const std::vector<plint> &mInd_, const std::vector<plint> &kInd_,
00308                                    T &rho_, Array<T,Descriptor<T>::d> &u_,
00309                                    Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq_,
00310                                    T epsilon_) : 
00311         GeneralizedNonLinearBoundarySolver<T, Descriptor>(mInd_,kInd_, epsilon_)
00312 { 
00313     sysX = SymmetricTensor<T,Descriptor>::n+1;
00314     sysY = this->kInd.size();
00315     
00316     this->macro.push_back(rho_);
00317     for (plint iD = 0; iD < Descriptor<T>::d; ++iD) this->macro.push_back(u_[iD]);
00318     for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) this->macro.push_back(PiNeq_[iPi]);
00319 }
00320 
00321 template<typename T, template<typename U> class Descriptor, int dir>
00322 void DirichletDensityBoundarySolver<T,Descriptor,dir>::fromMacroToX(Eigen::VectorXd &x) {
00323     x[0] = this->macro[1+dir];
00324     for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00325         x[iPi+1] = this->macro[1+Descriptor<T>::d+iPi];
00326     }
00327 }
00328 
00329 template<typename T, template<typename U> class Descriptor, int dir>
00330 void DirichletDensityBoundarySolver<T,Descriptor,dir>::fromXtoMacro(const Eigen::VectorXd &x) {
00331     this->macro[1+dir] = x[0];
00332     for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00333         this->macro[1+Descriptor<T>::d+iPi] = x[iPi+1];
00334     }
00335 }
00336 
00337 template<typename T, template<typename U> class Descriptor, int dir>
00338 void DirichletDensityBoundarySolver<T,Descriptor,dir>::
00339         iniSystem(Eigen::MatrixXd &Jac, Eigen::VectorXd &f,
00340                   Eigen::VectorXd &x, Eigen::VectorXd &dx) {
00341             
00342     Jac  = Eigen::MatrixXd::Zero(sysY,sysX);
00343     f  = Eigen::VectorXd::Zero(sysY); // stores the non-linear function
00344     x  = Eigen::VectorXd::Zero(sysX); // stores the variables (u[dir] and PiNeq)
00345     dx = Eigen::VectorXd::Zero(sysX); // contains delta_u[dir], delta_PiNeq (the increments towards the solution)
00346 }
00347 
00348 template<typename T, template<typename U> class Descriptor, int dir>
00349 void DirichletDensityBoundarySolver<T,Descriptor,dir>::
00350         createNonLinearSystem(const Cell<T,Descriptor> &cell, Eigen::MatrixXd &Jac, Eigen::VectorXd &f) {
00351             
00352     // computes the non linear function F(macro) = f_i-(f^eq+f^1)
00353     T rho;
00354     Array<T,Descriptor<T>::d> j;
00355     Array<T,SymmetricTensor<T,Descriptor>::n> PiNeq;
00356     generalizedIncomprBoundaryTemplates<T,Descriptor>::
00357         from_macro_to_rho_j_pineq(this->macro, rho, j, PiNeq);
00358         
00359     T rhoBar = Descriptor<T>::rhoBar(rho);
00360     T invRho = Descriptor<T>::invRho(rhoBar);
00361     T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00362     for (pluint iPop = 0; iPop < this->kInd.size(); ++iPop) {
00363         f[iPop] = cell[this->kInd[iPop]] - (
00364             dynamicsTemplates<T,Descriptor>::bgk_ma2_equilibrium(this->kInd[iPop], rhoBar, invRho, j, jSqr) +
00365             offEquilibriumTemplates<T,Descriptor>::fromPiToFneq(this->kInd[iPop],PiNeq) );
00366     }
00367     
00368     // computes the Jacobian of F(macro)
00369     Eigen::RowVectorXd df = Eigen::RowVectorXd::Zero(sysX);
00370     for (pluint iPop = 0; iPop < this->kInd.size(); ++iPop) {
00371         generalizedIncomprBoundaryTemplates<T,Descriptor>::
00372             compute_f_diff_u_dir_and_PiNeq(this->kInd[iPop], rho, j*invRho, df, dir);
00373         Jac.row(iPop) = df;
00374     }
00375 }
00376 
00377 template<typename T, template<typename U> class Descriptor, int dir>
00378 void DirichletDensityBoundarySolver<T,Descriptor,dir>::
00379         regularizePopulations(Cell<T,Descriptor> &cell, const Eigen::VectorXd &x,
00380                               const Dynamics<T,Descriptor> &dyn, bool replaceAll ) {
00381         
00382     T rho;
00383     Array<T,Descriptor<T>::d> j;
00384     Array<T,SymmetricTensor<T,Descriptor>::n> PiNeq;
00385     generalizedIncomprBoundaryTemplates<T,Descriptor>::
00386         from_macro_to_rho_j_pineq(this->macro, rho, j, PiNeq);
00387         
00388     T rhoBar = Descriptor<T>::rhoBar(rho);
00389     T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00390     if (replaceAll) {
00391         dyn.regularize(cell, rhoBar, j, jSqr, PiNeq);
00392     }
00393     else {
00394         Cell<T,Descriptor> tmpCell;
00395         dyn.regularize(tmpCell, rhoBar, j, jSqr, PiNeq);
00396         for (pluint fInd = 0; fInd < this->mInd.size(); ++fInd) {
00397             plint iPop = this->mInd[fInd];
00398             cell[iPop] = tmpCell[iPop];
00399         }
00400     }
00401 }
00402 
00403 
00404 
00405 }  // namespace plb
00406 
00407 #endif  // GENERALIZED_BOUNDARY_DYNAMICS_HH