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

generalizedCompressibleBoundaryTemplates.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_COMPRESSIBLE_BOUNDARY_TEMPLATES_H
00030 #define GENERALIZED_COMPRESSIBLE_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 
00043 namespace plb {
00044 
00045 template<typename T, template<typename U> class Descriptor>
00046 struct generalizedComprTempBoundaryTemplates {
00047     
00048     static T equilibriumOverRho(plint iPop, const Array<T,Descriptor<T>::d> &u, T uSqr, T thetaBar) {
00049         typedef Descriptor<T> L;
00050         T c_u = Descriptor<T>::c[iPop][0]*u[0];
00051         for (int iD=1; iD < Descriptor<T>::d; ++iD) {
00052             c_u += Descriptor<T>::c[iPop][iD]*u[iD];
00053         }
00054         
00055         return L::t[iPop] * (
00056             (T)1 + L::invCs2 * c_u +
00057             L::invCs2/(T)2 * ((L::invCs2 * c_u*c_u - uSqr )
00058                                         + thetaBar * (L::cNormSqr[iPop]-L::cs2*L::d))
00059             + L::invCs2*L::invCs2*L::invCs2/(T)6 * c_u * (
00060                 c_u*c_u-(T)3*L::cs2*uSqr+(T)3*L::cs2*thetaBar*(L::cNormSqr[iPop]-L::cs2*(L::d+2))
00061             )
00062             + L::invCs2*L::invCs2*L::invCs2*L::invCs2/(T)24 * (
00063                 c_u*c_u*c_u*c_u - (T)6*L::cs2*uSqr*c_u*c_u + (T)3*L::cs2*L::cs2*uSqr*uSqr
00064                 + (T)6*L::cs2*thetaBar*(c_u*c_u*(L::cNormSqr[iPop]-L::cs2*(L::d+4))+L::cs2*uSqr*(L::cs2*(L::d+2)-L::cNormSqr[iPop]))
00065                 + (T)3*L::cs2*L::cs2*thetaBar*thetaBar*(
00066                     L::cNormSqr[iPop]*L::cNormSqr[iPop]-(T)2*L::cs2*(L::d+2)*L::cNormSqr[iPop]+L::cs2*L::cs2*L::d*(L::d+2)
00067                 )
00068             )
00069         );
00070     }
00071     
00072 // ================================================================================== //
00073 // ================================================================================== //
00074 // = Methods used for boundary celles located "far" from the wall (not on the wall) = //
00075 // ================================= Non-Linear case ================================ //
00076 // ================================================================================== //
00077 // ================================================================================== //
00078     static void computeDiffF(plint iPop, T rho, const Array<T,Descriptor<T>::d> &u, T uSqr,
00079                              T thetaBar, Eigen::RowVectorXd &df) {
00080         df(0) = equilibriumOverRho(iPop, u, uSqr, thetaBar); // df/drho
00081         
00082         Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::order2(iPop);
00083         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> H3 = HermiteTemplate<T,Descriptor>::order3(iPop);
00084         Array<T,SymmetricRankFourTensor<T,Descriptor>::n> H4 = HermiteTemplate<T,Descriptor>::order4(iPop);
00085         
00086         Array<T,Descriptor<T>::d> H3contracted, H2_u, H3_u2, H4_u, H4_u3;
00087         SymmetricRankThreeTensor<T,Descriptor>::contractLastTwoIndexes(H3,H3contracted);
00088         
00089         Array<T,SymmetricTensor<T,Descriptor>::n> H4contracted;
00090         SymmetricRankFourTensor<T,Descriptor>::contractLastTwoIndexes(H4,H4contracted);
00091         
00092         Array<T,SymmetricTensor<T,Descriptor>::n> u2;
00093         VectorTemplate<T,Descriptor>::symTensorProduct(u,u,u2);
00094         SymmetricTensor<T,Descriptor>::matVectMult(H2, u, H2_u);
00095         SymmetricRankThreeTensor<T,Descriptor>::multWithRankTwoSymTensor(H3, u2, H3_u2);
00096         
00097         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> u3;
00098         VectorTemplate<T,Descriptor>::symTensorProduct(u,u,u,u3);
00099         SymmetricRankFourTensor<T,Descriptor>::multWithRankThreeSymTensor(H4, u3, H4_u3);
00100         SymmetricTensor<T,Descriptor>::matVectMult(H4contracted, u, H4_u);
00101         
00102         
00103         T tcs2 = Descriptor<T>::invCs2* Descriptor<T>::t[iPop];
00104         T tcs4 = tcs2 * Descriptor<T>::invCs2;
00105         T tcs6_2 = 0.5 * tcs4 * Descriptor<T>::invCs2;
00106         T cs2_thetaBar = Descriptor<T>::cs2*thetaBar;
00107         T tcs8_6 = tcs6_2 * Descriptor<T>::invCs2 / (T)3;
00108         T cs2_thetaBar_3 = cs2_thetaBar * (T)3;
00109         for (plint iD = 0; iD < Descriptor<T>::d; ++iD) {
00110             df(1+iD) = tcs2 * Descriptor<T>::c[iPop][iD];
00111             df(1+iD) += tcs4 * H2_u[iD];
00112             df(1+iD) += tcs6_2 * (H3_u2[iD] + cs2_thetaBar*H3contracted[iD]);
00113             df(1+iD) += tcs8_6 * (H4_u3[iD] + cs2_thetaBar_3*H4_u[iD]);
00114             
00115             df(1+iD) *= rho;
00116         }
00117         df(1+Descriptor<T>::d) = tcs2*SymmetricTensor<T,Descriptor>::trace(H2);
00118         df(1+Descriptor<T>::d) += tcs4/(T)6 * VectorTemplate<T,Descriptor>::scalarProduct(H3contracted, u);
00119         df(1+Descriptor<T>::d) += tcs6_2/(T)2 * (SymmetricTensor<T,Descriptor>::contractIndexes(H4contracted, u2)
00120                                                + cs2_thetaBar * SymmetricTensor<T,Descriptor>::trace(H4contracted));
00121         
00122         H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop);
00123         for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00124             df(1+Descriptor<T>::d+1+iPi) = H2[iPi]*tcs4/(T)2;
00125         }
00126         H3 = HermiteTemplate<T,Descriptor>::contractedOrder3(iPop);
00127         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00128             df(1+Descriptor<T>::d+1+SymmetricTensor<T,Descriptor>::n+iPi) = H3[iPi]*tcs6_2/(T)3;
00129         }
00130 
00131     }
00132     
00133     static void computeDiffFtrLessPiNeq(plint iPop, T rho, const Array<T,Descriptor<T>::d> &u, T uSqr,
00134                                         T thetaBar, Eigen::RowVectorXd &df) {
00135         df(0) = equilibriumOverRho(iPop, u, uSqr, thetaBar); // df/drho
00136         
00137         Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::order2(iPop);
00138         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> H3 = HermiteTemplate<T,Descriptor>::order3(iPop);
00139         Array<T,SymmetricRankFourTensor<T,Descriptor>::n> H4 = HermiteTemplate<T,Descriptor>::order4(iPop);
00140         
00141         Array<T,Descriptor<T>::d> H3contracted, H2_u, H3_u2, H4_u, H4_u3;
00142         SymmetricRankThreeTensor<T,Descriptor>::contractLastTwoIndexes(H3,H3contracted);
00143         
00144         Array<T,SymmetricTensor<T,Descriptor>::n> H4contracted;
00145         SymmetricRankFourTensor<T,Descriptor>::contractLastTwoIndexes(H4,H4contracted);
00146         
00147         Array<T,SymmetricTensor<T,Descriptor>::n> u2;
00148         VectorTemplate<T,Descriptor>::symTensorProduct(u,u,u2);
00149         SymmetricTensor<T,Descriptor>::matVectMult(H2, u, H2_u);
00150         SymmetricRankThreeTensor<T,Descriptor>::multWithRankTwoSymTensor(H3, u2, H3_u2);
00151             
00152         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> u3;
00153         VectorTemplate<T,Descriptor>::symTensorProduct(u,u,u,u3);
00154         SymmetricRankFourTensor<T,Descriptor>::multWithRankThreeSymTensor(H4, u3, H4_u3);
00155         SymmetricTensor<T,Descriptor>::matVectMult(H4contracted, u, H4_u);
00156         
00157         T tcs2 = Descriptor<T>::invCs2* Descriptor<T>::t[iPop];
00158         T tcs4 = tcs2 * Descriptor<T>::invCs2;
00159         T tcs6_2 = 0.5 * tcs4 * Descriptor<T>::invCs2;
00160         T cs2_thetaBar = Descriptor<T>::cs2*thetaBar;
00161         T tcs8_6 = tcs6_2 * Descriptor<T>::invCs2 / (T)3;
00162         T cs2_thetaBar_3 = cs2_thetaBar * (T)3;
00163         for (plint iD = 0; iD < Descriptor<T>::d; ++iD) {
00164             df(1+iD) = tcs2 * Descriptor<T>::c[iPop][iD];
00165             df(1+iD) += tcs4 * H2_u[iD];
00166             df(1+iD) += tcs6_2 * (H3_u2[iD] + cs2_thetaBar*H3contracted[iD]);
00167             df(1+iD) += tcs8_6 * (H4_u3[iD] + cs2_thetaBar_3*H4_u[iD]);
00168             
00169             df(1+iD) *= rho;
00170         }
00171         df(1+Descriptor<T>::d) = tcs2*SymmetricTensor<T,Descriptor>::trace(H2);
00172         df(1+Descriptor<T>::d) += tcs4/(T)6 * VectorTemplate<T,Descriptor>::scalarProduct(H3contracted, u);
00173         df(1+Descriptor<T>::d) += tcs6_2/(T)2 * (SymmetricTensor<T,Descriptor>::contractIndexes(H4contracted, u2)
00174                                                + cs2_thetaBar * SymmetricTensor<T,Descriptor>::trace(H4contracted));
00175         
00176         H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop);
00177         df(2+Descriptor<T>::d) = (H2[SymmetricTensorImpl<T,2>::xx]-H2[SymmetricTensorImpl<T,2>::yy])*tcs4/(T)2;
00178         df(2+Descriptor<T>::d+1) = H2[SymmetricTensorImpl<T,2>::xy]*tcs4/(T)2;
00179         H3 = HermiteTemplate<T,Descriptor>::contractedOrder3(iPop);
00180         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00181             df(1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n+iPi) = H3[iPi]*tcs6_2/(T)3;
00182         }
00183 
00184     }
00185 
00186     static void computeJacobian(T rho, const Array<T,Descriptor<T>::d> &u,
00187                                 T thetaBar, const std::vector<plint> &knownIndices, Eigen::MatrixXd &Jac) {
00188         plint systSizeX =  SymmetricRankThreeTensor<T,Descriptor>::n
00189                            + SymmetricTensor<T,Descriptor>::n
00190                            + 1 + Descriptor<T>::d + 1;
00191         
00192         plint systSizeY = knownIndices.size();
00193         
00194         Jac = Eigen::MatrixXd::Zero(systSizeY,systSizeX);
00195         T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00196 
00197         Eigen::RowVectorXd df = Eigen::RowVectorXd::Zero(systSizeX);
00198         for (pluint iPop = 0; iPop < knownIndices.size(); ++iPop) {
00199             computeDiffF(knownIndices[iPop], rho, u, uSqr, thetaBar, df);
00200             //             Jac.row(iPop+1) = df;
00201             Jac.row(iPop) = df;
00202         }
00203     }
00204     
00205     static void computeJacobianTrLessPiNeq(T rho, const Array<T,Descriptor<T>::d> &u,
00206                                            T thetaBar, const std::vector<plint> &knownIndices, Eigen::MatrixXd &Jac) {
00207         plint systSizeX =  SymmetricRankThreeTensor<T,Descriptor>::n
00208                            + SymmetricTensor<T,Descriptor>::n
00209                            + 1 + Descriptor<T>::d;
00210         
00211         plint systSizeY = knownIndices.size();
00212         
00213         Jac = Eigen::MatrixXd::Zero(systSizeY,systSizeX);
00214         T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00215 
00216         Eigen::RowVectorXd df = Eigen::RowVectorXd::Zero(systSizeX);
00217         for (pluint iPop = 0; iPop < knownIndices.size(); ++iPop) {
00218             computeDiffFtrLessPiNeq(knownIndices[iPop], rho, u, uSqr, thetaBar, df);
00219             //             Jac.row(iPop+1) = df;
00220             Jac.row(iPop) = df;
00221         }
00222     }
00223     
00224     static void computeNonLinearFunction(const Cell<T,Descriptor>& cell, 
00225                                          T rho,
00226                                          const Array<T,Descriptor<T>::d> &u,
00227                                          const T uSqr,
00228                                          T thetaBar,
00229                                          const Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq,
00230                                          const Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> &Qneq,
00231                                          const std::vector<plint> &knownIndices,
00232                                          const std::vector<plint> &missingIndices,
00233                                          Eigen::VectorXd &f) {
00234         plint systSizeY = knownIndices.size();
00235         
00236         f = Eigen::VectorXd::Zero(systSizeY);
00237 
00238         T rhoBar = Descriptor<T>::rhoBar(rho);
00239         T invRho = Descriptor<T>::invRho(rhoBar);
00240         Array<T,Descriptor<T>::d> j = rho * u;
00241         T jSqr = rho*rho*uSqr;
00242         for (pluint iPop = 0; iPop < knownIndices.size(); ++iPop) {
00243             f(iPop) = cell[knownIndices[iPop]] - (
00244                 dynamicsTemplates<T,Descriptor>::bgk_ma4_equilibrium(knownIndices[iPop], rhoBar, invRho, j, jSqr, thetaBar) +
00245                 offEquilibriumTemplates<T,Descriptor>::fromPiAndQtoFneq(knownIndices[iPop],PiNeq, Qneq) );
00246 //             pcout << ", f[" << iPop << "] = " << f(iPop+1);
00247         }
00248 //         pcout << std::endl;
00249     }
00250     
00251     static bool converge(Eigen::VectorXd &x,
00252                          const T rho,
00253                          const Array<T,Descriptor<T>::d> &u, 
00254                          const T thetaBar,
00255                          const Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq,
00256                          const Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> &Qneq,
00257                          T epsilon,
00258                          T &sumRes)
00259     {
00260         
00261 //         pcout << "x = ";
00262         T threshold = 1.0e-13;
00263         Array<T,SymmetricTensor<T,Descriptor>::n+2+Descriptor<T>::d+SymmetricRankThreeTensor<T,Descriptor>::n> res;
00264         if (fabs(rho) > threshold) {
00265             res[0] = fabs(x(0)/rho);
00266         }
00267         else res[0] = fabs(x(0));
00268 //         pcout << x(0) << ", ";
00269 
00270         for (plint iD = 0; iD < Descriptor<T>::d; ++iD) {
00271 //             pcout << x(iD+1) << ", ";
00272             if (fabs(u[iD])  > threshold) {
00273                 res[iD+1] = fabs(x(iD+1)/u[iD]);
00274             }
00275             else res[iD+1] = fabs(x(iD+1));
00276         }
00277 //         pcout << std::endl;
00278         if (fabs(thetaBar) > threshold) {
00279             res[1+Descriptor<T>::d] = fabs(x(1+Descriptor<T>::d)/thetaBar);
00280         }
00281         else res[1+Descriptor<T>::d] = fabs(x(1+Descriptor<T>::d));
00282         
00283         for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00284 //             pcout << x(iPi+1) << ", ";
00285             if (fabs(PiNeq[iPi]) > threshold) {
00286                 res[iPi+2+Descriptor<T>::d] = fabs(x(iPi+2+Descriptor<T>::d)/PiNeq[iPi]);
00287             }
00288             else res[iPi+2+Descriptor<T>::d] = fabs(x(iPi+2+Descriptor<T>::d));
00289         }
00290 //         pcout << std::endl;
00291         
00292 //         pcout << u[dir] << ", " << PiNeq[0] << ", " << PiNeq[1] << ", " << PiNeq[2] << std::endl;
00293         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00294 //             pcout << x(iPi+1) << ", ";
00295             if (fabs(Qneq[iPi]) > threshold) {
00296                 res[iPi+2+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n] = 
00297                     fabs(x(iPi+2+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n)/Qneq[iPi]);
00298             }
00299             else res[iPi+2+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n] =
00300                 fabs(x(iPi+2+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n));
00301         }
00302         
00303 //         pcout << "res = ";
00304         sumRes = T();
00305         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n+SymmetricTensor<T,Descriptor>::n+2+Descriptor<T>::d; ++iPi) {
00306             sumRes += fabs(res[iPi]);
00307 //             pcout << res[iPi] << ", ";
00308             if (res[iPi] > epsilon) {
00309                 return false;
00310             }
00311         }
00312 //         pcout << std::endl;
00313 //         pcout << "num = " << u[dir] << ", " << PiNeq[0] << ", " << PiNeq[1] << ", " << PiNeq[2] << std::endl;
00314         return true;
00315     }
00316     
00317     static bool convergeTrLessPiNeq(Eigen::VectorXd &x,
00318                          const T rho,
00319                          const Array<T,Descriptor<T>::d> &u, 
00320                          const T thetaBar,
00321                          const Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq,
00322                          const Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> &Qneq,
00323                          T epsilon,
00324                          T &sumRes)
00325     {
00326         
00327 //         pcout << "x = ";
00328         T threshold = 1.0e-13;
00329         Array<T,SymmetricTensor<T,Descriptor>::n+2+Descriptor<T>::d+SymmetricRankThreeTensor<T,Descriptor>::n> res;
00330         if (fabs(rho) > threshold) {
00331             res[0] = fabs(x(0)/rho);
00332         }
00333         else res[0] = fabs(x(0));
00334 //         pcout << x(0) << ", ";
00335 
00336         for (plint iD = 0; iD < Descriptor<T>::d; ++iD) {
00337 //             pcout << x(iD+1) << ", ";
00338             if (fabs(u[iD])  > threshold) {
00339                 res[iD+1] = fabs(x(iD+1)/u[iD]);
00340             }
00341             else res[iD+1] = fabs(x(iD+1));
00342         }
00343 //         pcout << std::endl;
00344         if (fabs(thetaBar) > threshold) {
00345             res[1+Descriptor<T>::d] = fabs(x(1+Descriptor<T>::d)/thetaBar);
00346         }
00347         else res[1+Descriptor<T>::d] = fabs(x(1+Descriptor<T>::d));
00348         
00349         for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n-1; ++iPi) {
00350 //             pcout << x(iPi+1) << ", ";
00351             if (fabs(PiNeq[iPi]) > threshold) {
00352                 res[iPi+2+Descriptor<T>::d] = fabs(x(iPi+2+Descriptor<T>::d)/PiNeq[iPi]);
00353             }
00354             else res[iPi+2+Descriptor<T>::d] = fabs(x(iPi+2+Descriptor<T>::d));
00355         }
00356 //         pcout << std::endl;
00357         
00358 //         pcout << u[dir] << ", " << PiNeq[0] << ", " << PiNeq[1] << ", " << PiNeq[2] << std::endl;
00359         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00360 //             pcout << x(iPi+1) << ", ";
00361             if (fabs(Qneq[iPi]) > threshold) {
00362                 res[iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n] = 
00363                     fabs(x(iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n)/Qneq[iPi]);
00364             }
00365             else res[iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n] =
00366                 fabs(x(iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n));
00367         }
00368         
00369 //         pcout << "res = ";
00370         sumRes = T();
00371         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n+SymmetricTensor<T,Descriptor>::n+1+Descriptor<T>::d; ++iPi) {
00372             sumRes += fabs(res[iPi]);
00373 //             pcout << res[iPi] << ", ";
00374             if (res[iPi] > epsilon) {
00375                 return false;
00376             }
00377         }
00378 //         pcout << std::endl;
00379 //         pcout << "num = " << u[dir] << ", " << PiNeq[0] << ", " << PiNeq[1] << ", " << PiNeq[2] << std::endl;
00380         return true;
00381     }
00382     
00383     static bool iterativelySolveSystem(const Cell<T,Descriptor>& cell, 
00384                                        T &rho,
00385                                        Array<T,Descriptor<T>::d> &u,
00386                                        T &thetaBar,
00387                                        Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq,
00388                                        Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> &Qneq,
00389                                        const std::vector<plint> &knownIndices,
00390                                        const std::vector<plint> &missingIndices,
00391                                        T epsilon, T &resSum) {
00392         // rho, u, PiNeq contain the initial guess for the solution of the system
00393         plint maxT = 10000;
00394         Eigen::VectorXd f = Eigen::VectorXd::Zero(knownIndices.size());
00395         Eigen::VectorXd x;
00396         
00397         Eigen::MatrixXd Jac;
00398         for (plint iT = 0; iT < maxT; ++iT) {
00399             T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00400             computeNonLinearFunction(cell,rho,u,uSqr,thetaBar,PiNeq,Qneq,knownIndices,missingIndices,f);
00401             computeJacobian(rho, u, thetaBar, knownIndices, Jac);
00402             Eigen::MatrixXd JacT = Jac.transpose();
00403             
00404             Jac = JacT * Jac;
00405             f = JacT * f;
00406             
00407             #ifdef PLB_DEBUG
00408 //             bool solutionExists = Jac.lu().solve(f,&x);   // using a LU factorization
00409 //             PLB_ASSERT(solutionExists);
00410             x = Jac.fullPivLu().solve(f);
00411             T relError = (Jac*x - f).norm() / f.norm();
00412             PLB_ASSERT(relError < 1.0e-12);
00413             #else
00414 //             Jac.lu().solve(f,&x);
00415             x = Jac.fullPivLu().solve(f);
00416             #endif
00417             
00418             T stepMult = (T)1;
00419             rho += stepMult*x(0);
00420             for (plint iD = 0; iD < Descriptor<T>::d; ++iD) {
00421                 u[iD] += stepMult*x(iD+1);
00422             }
00423             thetaBar +=  stepMult*x(Descriptor<T>::d+1);
00424             for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00425                 PiNeq[iPi] += stepMult*x(iPi+2+Descriptor<T>::d);
00426             }
00427             for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00428                 Qneq[iPi] += stepMult*x(iPi+2+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n);
00429             }
00430             if (converge(x,rho,u,thetaBar,PiNeq,Qneq,epsilon,resSum)) {
00431 //                 pcout << "Res Sum = " << resSum << std::endl;
00432 //                 pcout << "Converged after " << iT << " iterations." << std::endl;
00433                 return true;
00434             }
00435 //             pcout << "Res Sum = " << resSum << std::endl;
00436         }
00437 //         pcout << "NEVER CONVERGED!!!." << std::endl;
00438         return false;
00439     }
00440     
00441     static bool iterativelySolveSystemTrLessPiNeq(const Cell<T,Descriptor>& cell, 
00442                                        T &rho,
00443                                        Array<T,Descriptor<T>::d> &u,
00444                                        T &thetaBar,
00445                                        Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq,
00446                                        Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> &Qneq,
00447                                        const std::vector<plint> &knownIndices,
00448                                        const std::vector<plint> &missingIndices,
00449                                        T epsilon, T &resSum) {
00450         // rho, u, PiNeq contain the initial guess for the solution of the system
00451         plint maxT = 10000;
00452         Eigen::VectorXd f = Eigen::VectorXd::Zero(knownIndices.size());
00453         Eigen::VectorXd x;
00454         
00455         Eigen::MatrixXd Jac;
00456         for (plint iT = 0; iT < maxT; ++iT) {
00457             T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00458             computeNonLinearFunction(cell,rho,u,uSqr,thetaBar,PiNeq,Qneq,knownIndices,missingIndices,f);
00459             computeJacobianTrLessPiNeq(rho, u, thetaBar, knownIndices, Jac);
00460             Eigen::MatrixXd JacT = Jac.transpose();
00461             
00462             Jac = JacT * Jac;
00463             f = JacT * f;
00464             
00465             #ifdef PLB_DEBUG
00466 //             bool solutionExists = Jac.lu().solve(f,&x);   // using a LU factorization
00467 //             PLB_ASSERT(solutionExists);
00468             x = Jac.fullPivLu().solve(f);
00469             T relError = (Jac*x - f).norm() / f.norm();
00470             PLB_ASSERT(relError < 1.0e-12);
00471             #else
00472 //             Jac.lu().solve(f,&x);
00473             x = Jac.fullPivLu().solve(f);
00474             #endif
00475             
00476             T stepMult = (T)1;
00477             rho += stepMult*x(0);
00478             for (plint iD = 0; iD < Descriptor<T>::d; ++iD) {
00479                 u[iD] += stepMult*x(iD+1);
00480             }
00481             thetaBar +=  stepMult*x(Descriptor<T>::d+1);
00482             for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n-1; ++iPi) {
00483                 PiNeq[iPi] += stepMult*x(iPi+2+Descriptor<T>::d);
00484             }
00485             PiNeq[2] += -stepMult*x(2+Descriptor<T>::d);
00486             for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00487                 Qneq[iPi] += stepMult*x(iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n);
00488             }
00489             if (convergeTrLessPiNeq(x,rho,u,thetaBar,PiNeq,Qneq,epsilon,resSum)) {
00490 //                 pcout << "Res Sum = " << resSum << std::endl;
00491 //                 pcout << "Converged after " << iT << " iterations." << std::endl;
00492                 return true;
00493             }
00494 //             pcout << "Res Sum = " << resSum << std::endl;
00495         }
00496 //         pcout << "NEVER CONVERGED!!!." << std::endl;
00497         return false;
00498     }
00499     
00500     // ==================================================================== //
00501     // ==================================================================== //
00502     // ============= Methods used for ON-WALL boundary nodes ============================ //
00503     // ==================================================================== //
00504     // ==================================================================== //
00505     
00506     // = matrix row computation for the decomposition of f_i=rho*t_i*g_i+H2:piNeq+H3:qNeq= //
00507     // = it also imposes tha mass conservation============================================ // 
00508     static void computeMatrixRow(
00509         plint iPop, const Array<T,Descriptor<T>::d> &u, T uSqr, 
00510         T thetaBar, T omega, Eigen::RowVectorXd &a) {
00511         
00512         T eqOverRho = equilibriumOverRho(iPop,u,uSqr,thetaBar);
00513         a(0) = eqOverRho;
00514         
00515         T oneMinusOmega = (T)1-omega;
00516         T factor = oneMinusOmega * Descriptor<T>::t[iPop]*Descriptor<T>::invCs2*Descriptor<T>::invCs2 / (T)2;
00517         Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop);
00518         for (plint iPi=0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00519             a(iPi+1) = H2[iPi]*factor;
00520         }
00521         
00522         factor *= Descriptor<T>::invCs2 / (T)3;
00523         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> H3 = HermiteTemplate<T,Descriptor>::contractedOrder3(iPop);
00524         for (plint iPi=0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00525             a(iPi+1+SymmetricTensor<T,Descriptor>::n) = H3[iPi]*factor;
00526         }
00527     }
00528     
00529     // = matrix row computation for the decomposition of f_i=rho*t_i*g_i+H2:piNeq+H3:qNeq =//
00530     // = it also imposes tha mass conservation============================================ // 
00531     // In this case the assumption that PiNeq is traceless is done.========================//
00532     static void computeMatrixRowTrLessPiNeq(
00533             plint iPop, const Array<T,Descriptor<T>::d> &u, T uSqr, 
00534             T thetaBar, T omega, Eigen::RowVectorXd &a) {
00535         
00536         typedef SymmetricTensorImpl<T,Descriptor<T>::d> S;
00537         T eqOverRho = equilibriumOverRho(iPop,u,uSqr,thetaBar);
00538         a(0) = eqOverRho;
00539         
00540         T oneMinusOmega = (T)1-omega;
00541         T factor = oneMinusOmega * Descriptor<T>::t[iPop]*Descriptor<T>::invCs2*Descriptor<T>::invCs2 / (T)2;
00542         Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop);
00543         
00544         PLB_ASSERT(Descriptor<T>::d == 2);
00545         //TODO generalize for 2 and 3d cases....
00546         if (Descriptor<T>::d == 2)
00547         {
00548             a(1) = (H2[S::xx]-H2[S::yy])*factor;
00549             a(2) = H2[S::xy]*factor;
00550         }
00551         
00552         factor *= Descriptor<T>::invCs2 / (T)3;
00553         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> H3 = HermiteTemplate<T,Descriptor>::contractedOrder3(iPop);
00554         for (plint iPi=0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00555             a(iPi+SymmetricTensor<T,Descriptor>::n) = H3[iPi]*factor;
00556         }
00557     }
00558     
00559     // = matrix row computation for the decomposition of f_i=rho*t_i*g_i+H2:piNeq+H3:qNeq= //
00560     static void computeMatrixRow(
00561             plint iPop, const Array<T,Descriptor<T>::d> &u, T uSqr, 
00562             T thetaBar, Eigen::RowVectorXd &a) {
00563         
00564         T eqOverRho = equilibriumOverRho(iPop,u,uSqr,thetaBar);
00565         a(0) = eqOverRho;
00566         T factor = Descriptor<T>::t[iPop]*Descriptor<T>::invCs2*Descriptor<T>::invCs2 / (T)2;
00567         Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop);
00568         
00569         for (plint iPi=0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00570             a(iPi+1) = H2[iPi]*factor;
00571         }
00572         
00573         factor *= Descriptor<T>::invCs2 / (T)3;
00574         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> H3 = HermiteTemplate<T,Descriptor>::contractedOrder3(iPop);
00575         
00576         for (plint iPi=0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00577             a(iPi+1+SymmetricTensor<T,Descriptor>::n) = H3[iPi]*factor;
00578         }
00579     }
00580     
00581     // = matrix row computation for the decomposition of f_i=rho*t_i*g_i+H2:piNeq+H3:qNeq =//
00582     // In this case the assumption that PiNeq is traceless is done.========================//
00583     static void computeMatrixRowTrLessPiNeq(
00584             plint iPop, const Array<T,Descriptor<T>::d> &u, T uSqr, 
00585             T thetaBar, Eigen::RowVectorXd &a) {
00586         
00587         typedef SymmetricTensorImpl<T,Descriptor<T>::d> S;
00588         
00589         T eqOverRho = equilibriumOverRho(iPop,u,uSqr,thetaBar);
00590         a(0) = eqOverRho;
00591         T factor = Descriptor<T>::t[iPop]*Descriptor<T>::invCs2*Descriptor<T>::invCs2 / (T)2;
00592         Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop);
00593         
00594         PLB_ASSERT(Descriptor<T>::d == 2);
00595         //TODO generalize for 2 and 3d cases....
00596         if (Descriptor<T>::d == 2)
00597         {
00598             a(1) = (H2[S::xx]-H2[S::yy])*factor;
00599             a(2) = H2[S::xy]*factor;
00600         }
00601         
00602         factor *= Descriptor<T>::invCs2 / (T)3;
00603         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> H3 = HermiteTemplate<T,Descriptor>::contractedOrder3(iPop);
00604         
00605         for (plint iPi=0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00606             a(iPi+SymmetricTensor<T,Descriptor>::n) = H3[iPi]*factor;
00607         }
00608     }
00609     
00610     // creation of the over-determined (usually) linear system
00611     // for an on-wall boundary node
00612     static void createLinearSystem(
00613             const Cell<T,Descriptor>& cell, const Array<T,Descriptor<T>::d> &u, T thetaBar,
00614             const std::vector<plint> &missingIndices,const std::vector<plint> &knownIndices,
00615             Eigen::MatrixXd &A,Eigen::VectorXd &b, bool massConservation) {
00616         
00617         T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00618         T omega = cell.getDynamics().getOmega();
00619         
00620         plint systSizeX = SymmetricRankThreeTensor<T,Descriptor>::n+SymmetricTensor<T,Descriptor>::n+1;
00621 //         plint systSizeX = SymmetricRankThreeTensor<T,Descriptor>::n+SymmetricTensor<T,Descriptor>::n; // PiNeq is traceless...
00622         plint systSizeY = knownIndices.size()+1;
00623         
00624         // matrix of the system Ax=b
00625         A = Eigen::MatrixXd::Zero(systSizeY,systSizeX);
00626         // rhs of the equation Ax=b
00627         b = Eigen::VectorXd::Zero(systSizeY);
00628         
00629         if (massConservation) {
00630             T rhoIn = T();
00631 //             T rhoTest = T();
00632             for (pluint mInd = 0; mInd < missingIndices.size(); ++mInd) {
00633                 plint iPop = missingIndices[mInd];
00634                 plint opp = indexTemplates::opposite<Descriptor<T> >(iPop);
00635                 rhoIn += fullF<T,Descriptor>(cell[opp], opp);
00636                 
00637 //                 rhoTest += Descriptor<T>::t[iPop];
00638             }
00639 //             pcout << ", rhoTest = " << rhoTest << ", ";
00640             b(knownIndices.size()) = rhoIn;
00641             Eigen::RowVectorXd sumA = Eigen::RowVectorXd::Zero(systSizeX);
00642 //             pcout << ", uSqr = " << uSqr << ", thetaBar = " << thetaBar << ", omega = " << omega;
00643             for (pluint fInd = 0; fInd < missingIndices.size(); ++fInd) {
00644                 plint iPop = missingIndices[fInd];
00645                 Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX);
00646                 computeMatrixRow(iPop, u, uSqr, thetaBar, omega, lineA);
00647                 for (plint iVec = 0; iVec < systSizeX; ++iVec) sumA(iVec) += lineA(iVec);
00648             }
00649             A.row(knownIndices.size()) = sumA;
00650 //             pcout << ", rhoTest2 = " << sumA(0) << ", ";
00651             
00652         } else {
00653             
00654             T rhoTmp = T();
00655             for (pluint kInd = 0; kInd < knownIndices.size(); ++kInd) {
00656                 plint iPop = knownIndices[kInd];
00657                 rhoTmp += fullF<T,Descriptor>(cell[iPop], iPop);
00658             }
00659             // rhoTtmp = sum_i->known f_i.
00660             b(knownIndices.size()) = rhoTmp;
00661             
00662             // first row of the A matrix. imposing sum_i f_i = rho.
00663             Eigen::RowVectorXd e0 = Eigen::RowVectorXd::Zero(systSizeX); 
00664             e0(0) = 1.0;
00665             
00666             Eigen::RowVectorXd sumA = Eigen::RowVectorXd::Zero(systSizeX);
00667             for (pluint fInd = 0; fInd < missingIndices.size(); ++fInd) {
00668                 plint iPop = missingIndices[fInd];
00669                 Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX);
00670                 computeMatrixRow(iPop, u, uSqr, thetaBar, lineA);
00671                 for (plint iVec = 0; iVec < systSizeX; ++iVec) sumA(iVec) += lineA(iVec);
00672             }
00673             
00674             A.row(knownIndices.size()) = e0-sumA;
00675         }
00676 //         pcout << "rhoIn = " << b(0) << ", ";
00677         
00678         for (pluint fInd = 0; fInd < knownIndices.size(); ++fInd) {
00679             plint iPop = knownIndices[fInd];
00680             b(fInd) = fullF<T,Descriptor>(cell[iPop], iPop);
00681             Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX);
00682             computeMatrixRow(iPop, u, uSqr, thetaBar, lineA);
00683             A.row(fInd) = lineA;
00684         }
00685     }
00686     
00687     // We impose tr(PiNeq) = 0 in this case
00688     // creation of the over-determined (usually) linear system
00689     static void createLinearSystemTrLessPiNeq(
00690             const Cell<T,Descriptor>& cell, const Array<T,Descriptor<T>::d> &u, T thetaBar,
00691             const std::vector<plint> &missingIndices,const std::vector<plint> &knownIndices,
00692             Eigen::MatrixXd &A,Eigen::VectorXd &b, bool massConservation) {
00693         
00694         T uSqr = VectorTemplate<T,Descriptor>::normSqr(u);
00695         T omega = cell.getDynamics().getOmega();
00696         
00697         plint systSizeX = SymmetricRankThreeTensor<T,Descriptor>::n+SymmetricTensor<T,Descriptor>::n; // PiNeq is traceless...
00698         plint systSizeY = knownIndices.size()+1;
00699         
00700         // matrix of the system Ax=b
00701         A = Eigen::MatrixXd::Zero(systSizeY,systSizeX);
00702         // rhs of the equation Ax=b
00703         b = Eigen::VectorXd::Zero(systSizeY);
00704         
00705         if (massConservation) {
00706             T rhoIn = T();
00707 //             T rhoTest = T();
00708             for (pluint mInd = 0; mInd < missingIndices.size(); ++mInd) {
00709                 plint iPop = missingIndices[mInd];
00710                 plint opp = indexTemplates::opposite<Descriptor<T> >(iPop);
00711                 rhoIn += fullF<T,Descriptor>(cell[opp], opp);
00712                 
00713 //                 rhoTest += Descriptor<T>::t[iPop];
00714             }
00715 //             pcout << ", rhoTest = " << rhoTest << ", ";
00716             b(knownIndices.size()) = rhoIn;
00717             Eigen::RowVectorXd sumA = Eigen::RowVectorXd::Zero(systSizeX);
00718 //             pcout << ", uSqr = " << uSqr << ", thetaBar = " << thetaBar << ", omega = " << omega;
00719             for (pluint fInd = 0; fInd < missingIndices.size(); ++fInd) {
00720                 plint iPop = missingIndices[fInd];
00721                 Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX);
00722                 computeMatrixRowTrLessPiNeq(iPop, u, uSqr, thetaBar, omega, lineA);
00723                 for (plint iVec = 0; iVec < systSizeX; ++iVec) sumA(iVec) += lineA(iVec);
00724             }
00725             A.row(knownIndices.size()) = sumA;
00726 //             pcout << ", rhoTest2 = " << sumA(0) << ", ";
00727             
00728         } else {
00729             
00730             T rhoTmp = T();
00731             for (pluint kInd = 0; kInd < knownIndices.size(); ++kInd) {
00732                 plint iPop = knownIndices[kInd];
00733                 rhoTmp += fullF<T,Descriptor>(cell[iPop], iPop);
00734             }
00735             // rhoTtmp = sum_i->known f_i.
00736             b(knownIndices.size()) = rhoTmp;
00737             
00738             // first row of the A matrix. imposing sum_i f_i = rho.
00739             Eigen::RowVectorXd e0 = Eigen::RowVectorXd::Zero(systSizeX); 
00740             e0(0) = 1.0;
00741             
00742             Eigen::RowVectorXd sumA = Eigen::RowVectorXd::Zero(systSizeX);
00743             for (pluint fInd = 0; fInd < missingIndices.size(); ++fInd) {
00744                 plint iPop = missingIndices[fInd];
00745                 Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX);
00746                 computeMatrixRowTrLessPiNeq(iPop, u, uSqr, thetaBar, lineA);
00747                 for (plint iVec = 0; iVec < systSizeX; ++iVec) sumA(iVec) += lineA(iVec);
00748             }
00749             
00750             A.row(knownIndices.size()) = e0-sumA;
00751         }
00752 //         pcout << "rhoIn = " << b(0) << ", ";
00753         
00754 //         pcout << ", rhoIn = " << rhoIn << std::endl;
00755         for (pluint fInd = 0; fInd < knownIndices.size(); ++fInd) {
00756             plint iPop = knownIndices[fInd];
00757             b(fInd) = fullF<T,Descriptor>(cell[iPop], iPop);
00758             Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX);
00759             computeMatrixRowTrLessPiNeq(iPop, u, uSqr, thetaBar, lineA);
00760             A.row(fInd) = lineA;
00761         }
00762     }
00763     
00764     static void solveLinearSystem(const Cell<T,Descriptor>& cell, 
00765                                   const Array<T,Descriptor<T>::d> &u,
00766                                   T thetaBar,
00767                                   const std::vector<plint> &missingIndices,
00768                                   const std::vector<plint> &knownIndices,
00769                                   T &rho, 
00770                                   Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq,
00771                                   Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> &qNeq,
00772                                   bool massConservation) {
00773         Eigen::MatrixXd A;
00774         Eigen::VectorXd b;
00775         
00776         createLinearSystem(cell, u, thetaBar, missingIndices, knownIndices, A, b, massConservation);
00777         
00778         Eigen::VectorXd x;
00779         
00780         Eigen::MatrixXd AT = A.transpose();
00781         A = AT * A;
00782         b = AT * b;
00783         
00784         #ifdef PLB_DEBUG
00785 //         bool solutionExists = A.lu().solve(b,&x);   // using a LU factorization
00786 //         PLB_ASSERT(solutionExists);
00787         x = A.fullPivLu().solve(b);
00788         T relError = (A*x - b).norm() / b.norm();
00789         PLB_ASSERT(relError < 1.0e-12);
00790         #else
00791 //         A.lu().solve(b,&x);
00792         x = A.fullPivLu().solve(b);
00793         #endif
00794         
00795         
00796         rho = x(0);
00797 //         pcout << "rho = " << rho << ", ";
00798         for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00799             PiNeq[iPi] = x(iPi+1);
00800 //             pcout << "piNeq = " << x(iPi+1) << ", ";
00801         }
00802 //         PiNeq[2] = -PiNeq[0];
00803         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00804             qNeq[iPi] = x(iPi+1+SymmetricTensor<T,Descriptor>::n);
00805 //             pcout << "qNeq = " << x(iPi+1+SymmetricTensor<T,Descriptor>::n) << ", ";
00806         }
00807         
00808 //         pcout << "TrPiNeq = " << PiNeq[0] - PiNeq[2] << ", PiNeq[xx] = " << PiNeq[0] << ", PiNeq[xy] = " << PiNeq[1] << ", PiNeq[yy] = " << PiNeq[2] << std::endl;
00809     }
00810     
00811     
00812     // ======================================================================= //
00813     // We impose tr(PiNeq) = 0 in this case
00814     // creation of the over-determined (usually) linear system
00815     // ======================================================================= //
00816     static void solveLinearSystemTrLessPiNeq(
00817             const Cell<T,Descriptor>& cell, const Array<T,Descriptor<T>::d> &u, T thetaBar,
00818             const std::vector<plint> &missingIndices, const std::vector<plint> &knownIndices,
00819             T &rho, Array<T,SymmetricTensor<T,Descriptor>::n> &PiNeq, 
00820             Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> &qNeq,bool massConservation) {
00821         Eigen::MatrixXd A;
00822         Eigen::VectorXd b;
00823         
00824         createLinearSystemTrLessPiNeq(cell, u, thetaBar, missingIndices, knownIndices, A, b, massConservation);
00825         
00826         Eigen::VectorXd x;
00827         
00828         Eigen::MatrixXd AT = A.transpose();
00829         A = AT * A;
00830         b = AT * b;
00831         
00832         #ifdef PLB_DEBUG
00833 //         bool solutionExists = A.lu().solve(b,&x);   // using a LU factorization
00834 //         PLB_ASSERT(solutionExists);
00835         x = A.fullPivLu().solve(b);
00836         T relError = (A*x - b).norm() / b.norm();
00837         PLB_ASSERT(relError < 1.0e-12);
00838         #else
00839         x = A.fullPivLu().solve(b);
00840 //         A.lu().solve(b,&x);
00841         #endif
00842         
00843         
00844         rho = x(0);
00845 //         pcout << "rho = " << rho << ", ";
00846         for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n-1; ++iPi) {
00847             PiNeq[iPi] = x(iPi+1);
00848 //             pcout << "piNeq = " << x(iPi+1) << ", ";
00849         }
00850         PiNeq[2] = -PiNeq[0];
00851         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00852             qNeq[iPi] = x(iPi+SymmetricTensor<T,Descriptor>::n);
00853 //             pcout << "qNeq = " << x(iPi+1+SymmetricTensor<T,Descriptor>::n) << ", ";
00854         }
00855         
00856 //         pcout << "TrPiNeq = " << PiNeq[0] - PiNeq[2] << ", PiNeq[xx] = " << PiNeq[0] << ", PiNeq[xy] = " << PiNeq[1] << ", PiNeq[yy] = " << PiNeq[2] << std::endl;
00857     }
00858 
00859 
00860     // ================================================================================== //
00861     // ================================================================================== //
00862     // = Methods used for boundary celles located "far" from the wall (not on the wall) = //
00863     // ================================= Linear case ==================================== //
00864     // ================================================================================== //
00865     // ================================================================================== //
00866 
00867     // Matrix row corespond to the factors in front of each Hermite coefficient (the Hermite polynomials times the weights).
00868     // a(0) = w_i H0, a(1,..,d) = w_i/c_s^ 2*H1_ii, a(d+1,..,SymRank2::n)=w_i/(2c_s^4)Q_i
00869     // a(SymRank2::n+1,..,SymRank3::n) = w_i, a(1,..,d) = w_i/(6c_s^6)*H3_i
00870     // a(SmyRank3::n+1,...,SmyRank4::n)=w_i/(24c_s^8)H4_i
00871     static void computeMatrixRow(plint iPop, Eigen::RowVectorXd &a) {
00872         T factor = Descriptor<T>::t[iPop];
00873         a(0) = (T)1*factor;
00874 
00875         factor *= Descriptor<T>::invCs2;
00876         for (plint iPi=0; iPi < Descriptor<T>::d; ++iPi) a(iPi+1) = Descriptor<T>::c[iPop][iPi] * factor;
00877 
00878         factor *= Descriptor<T>::invCs2 / (T)2;
00879         Array<T,SymmetricTensor<T,Descriptor>::n> H2 = HermiteTemplate<T,Descriptor>::contractedOrder2(iPop);
00880         for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) a(iPi+1+Descriptor<T>::d) = H2[iPi]*factor;
00881 
00882         factor *= Descriptor<T>::invCs2 / (T)3;
00883         Array<T,SymmetricRankThreeTensor<T,Descriptor>::n> H3 = HermiteTemplate<T,Descriptor>::contractedOrder3(iPop);
00884         for (plint iPi=0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00885             a(iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n) = H3[iPi]*factor;
00886         }
00887 
00888         factor *= Descriptor<T>::invCs2 / (T)4;
00889         Array<T,SymmetricRankFourTensor<T,Descriptor>::n> H4 = HermiteTemplate<T,Descriptor>::contractedOrder4(iPop);
00890 
00891         for (plint iPi=0; iPi < SymmetricRankFourTensor<T,Descriptor>::n; ++iPi) {
00892             a(iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n+SymmetricRankThreeTensor<T,Descriptor>::n)
00893                 = H4[iPi]*factor;
00894         }
00895     }
00896 
00897     // creation of the over-determined (usually) linear system
00898     // In this case the matrix is composed by the Hermite polynomials and the corresponding weights
00899     // while the unknowns are the Hermite coefficients.
00900     static void createLinearSystem(const Cell<T,Descriptor>& cell,
00901                                    const std::vector<plint> &missingIndices,
00902                                    const std::vector<plint> &knownIndices,
00903                                    Eigen::MatrixXd &A,Eigen::VectorXd &b) {
00904         plint systSizeX =  SymmetricRankFourTensor<T,Descriptor>::n
00905                          + SymmetricRankThreeTensor<T,Descriptor>::n
00906                          + SymmetricTensor<T,Descriptor>::n
00907                          + Descriptor<T>::d + 1;
00908 
00909         plint systSizeY = knownIndices.size();
00910         // matrix of the system Ax=b
00911         A = Eigen::MatrixXd::Zero(systSizeY,systSizeX);
00912         // rhs of the equation Ax=b
00913         b = Eigen::VectorXd::Zero(systSizeY);
00914 
00915         for (pluint fInd = 0; fInd < knownIndices.size(); ++fInd) {
00916             plint iPop = knownIndices[fInd];
00917             Eigen::RowVectorXd lineA = Eigen::RowVectorXd::Zero(systSizeX);
00918             computeMatrixRow(iPop, lineA);
00919             b(fInd) = fullF<T,Descriptor>(cell[iPop], iPop);
00920 //             std::cout << lineA << std::endl << std::endl;
00921             A.row(fInd) = lineA;
00922         }
00923     }
00924 
00925     // The linear system composed used to compute explicitely the Hermite coefficients (not directly
00926     // the macroscopic moments : density, velocity , temperature, ...)
00927     static void solveLinearSystem(const Cell<T,Descriptor>& cell,
00928                                   const std::vector<plint> &missingIndices,
00929                                   const std::vector<plint> &knownIndices,
00930                                   std::vector<T> &coeffs) {
00931         Eigen::MatrixXd A;
00932         Eigen::VectorXd b;
00933 
00934         createLinearSystem(cell,missingIndices,knownIndices, A, b);
00935 
00936         Eigen::VectorXd x;
00937 
00938         Eigen::MatrixXd AT = A.transpose();
00939 
00940         A = AT * A;
00941         b = AT * b;
00942 
00943         #ifdef PLB_DEBUG
00944 //         bool solutionExists = A.lu().solve(b,&x);   // using a LU factorization
00945 //         PLB_ASSERT(solutionExists);
00946         x = A.fullPivLu().solve(b);
00947         T relError = (A*x - b).norm() / b.norm();
00948         PLB_ASSERT(relError < 1.0e-12);
00949         #else
00950         x = A.fullPivLu().solve(b);
00951 //         A.lu().solve(b,&x);
00952         #endif
00953 
00954         coeffs.push_back(x(0));
00955 //         pcout << "a0 = " << coeffs[0] << ", ";
00956         for (plint iPi = 0; iPi < Descriptor<T>::d; ++iPi) {
00957             coeffs.push_back(x(iPi+1));
00958 //             pcout << "a1 = " << coeffs[iPi+1] << ", ";
00959         }
00960         for (plint iPi = 0; iPi < SymmetricTensor<T,Descriptor>::n; ++iPi) {
00961             coeffs.push_back(x(iPi+1+Descriptor<T>::d));
00962 //             pcout << "a2 = " << coeffs[iPi+1+Descriptor<T>::d] << ", ";
00963         }
00964         for (plint iPi = 0; iPi < SymmetricRankThreeTensor<T,Descriptor>::n; ++iPi) {
00965             coeffs.push_back(x(iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n));
00966 //             pcout << "a3 = " << coeffs[iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n] << ", ";
00967         }
00968         for (plint iPi = 0; iPi < SymmetricRankFourTensor<T,Descriptor>::n; ++iPi) {
00969             coeffs.push_back(x(iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n+SymmetricRankThreeTensor<T,Descriptor>::n));
00970 //             pcout << "a4 = " << coeffs[iPi+1+Descriptor<T>::d+SymmetricTensor<T,Descriptor>::n+SymmetricRankThreeTensor<T,Descriptor>::n] << ", ";
00971         }
00972 //         pcout << std::endl;
00973     }
00974     
00975     
00976 
00977 };  // struct generalizedIncomprBoundaryTemplates
00978 
00979 }  // namespace plb
00980 
00981 #endif  // GENERALIZED_BOUNDARY_DYNAMICS_HH