$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_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
1.6.3
1.6.3