SundanceFeketeQuadrature.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                              Sundance
00005 //                 Copyright (2005) Sandia Corporation
00006 // 
00007 // Copyright (year first published) Sandia Corporation.  Under the terms 
00008 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 
00009 // retains certain rights in this software.
00010 // 
00011 // This library is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Lesser General Public License as
00013 // published by the Free Software Foundation; either version 2.1 of the
00014 // License, or (at your option) any later version.
00015 //  
00016 // This library is distributed in the hope that it will be useful, but
00017 // WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 //                                                                                 
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA                                                                                
00025 // Questions? Contact Kevin Long (krlong@sandia.gov), 
00026 // Sandia National Laboratories, Livermore, California, USA
00027 // 
00028 // ************************************************************************
00029 /* @HEADER@ */
00030 
00031 #include "SundanceFeketeBrickQuadrature.hpp"
00032 #include "SundanceFeketeQuadQuadrature.hpp"
00033 #include "SundanceFeketeQuadrature.hpp"
00034 #include "SundanceFeketeTriangleQuadrature.hpp"
00035 #include "SundanceGaussLobatto1D.hpp"
00036 #include "SundanceTabs.hpp"
00037 #include <stack>
00038 
00039 using namespace Sundance;
00040 using namespace Teuchos;
00041 
00042 /* declare LAPACK subroutines */
00043 extern "C"
00044 {
00045 /* LAPACK factorization */
00046 void dgetrf_(const int* M, const int* N, double* A, const int* lda,
00047     const int* iPiv, int* info);
00048 
00049 /* LAPACK inversion of factorized matrix */
00050 void dgetri_(const int* n, double* a, const int* lda, const int* iPiv,
00051     double* work, const int* lwork, int* info);
00052 }
00053 
00054 FeketeQuadrature::FeketeQuadrature(int order) :
00055   QuadratureFamilyBase(order)
00056 {
00057   _hasBasisCoeffs = false;
00058 }
00059 
00060 XMLObject FeketeQuadrature::toXML() const
00061 {
00062   XMLObject rtn("FeketeQuadrature");
00063   rtn.addAttribute("order", Teuchos::toString(order()));
00064   return rtn;
00065 }
00066 
00067 void FeketeQuadrature::getLineRule(Array<Point>& quadPoints,
00068     Array<double>& quadWeights) const
00069 {
00070   int p = order() + 3;
00071   p = p + (p % 2);
00072   int n = p / 2;
00073 
00074   quadPoints.resize(n);
00075   quadWeights.resize(n);
00076 
00077   GaussLobatto1D q1(n, 0.0, 1.0);
00078 
00079   for (int i = 0; i < n; i++)
00080   {
00081     quadWeights[i] = q1.weights()[i];
00082     quadPoints[i] = Point(q1.nodes()[i]);
00083   }
00084 }
00085 
00086 void FeketeQuadrature::getTriangleRule(Array<Point>& quadPoints,
00087     Array<double>& quadWeights) const
00088 {
00089   Array<double> x;
00090   Array<double> y;
00091   Array<double> w;
00092 
00093   FeketeTriangleQuadrature::getPoints(order(), w, x, y);
00094   quadPoints.resize(w.length());
00095   quadWeights.resize(w.length());
00096   for (int i = 0; i < w.length(); i++)
00097   {
00098     quadWeights[i] = 0.5 * w[i];
00099     quadPoints[i] = Point(x[i], y[i]);
00100   }
00101 }
00102 
00103 void FeketeQuadrature::getQuadRule(Array<Point>& quadPoints,
00104     Array<double>& quadWeights) const
00105 {
00106   Array<double> x;
00107   Array<double> y;
00108   Array<double> w;
00109 
00110   FeketeQuadQuadrature::getPoints(order(), w, x, y);
00111   quadPoints.resize(w.length());
00112   quadWeights.resize(w.length());
00113   for (int i = 0; i < w.length(); i++)
00114   {
00115     quadWeights[i] = w[i];
00116     quadPoints[i] = Point(x[i], y[i]);
00117   }
00118 }
00119 
00120 void FeketeQuadrature::getBrickRule(Array<Point>& quadPoints,
00121     Array<double>& quadWeights) const
00122 {
00123   Array<double> x;
00124   Array<double> y;
00125   Array<double> z;
00126   Array<double> w;
00127 
00128   FeketeBrickQuadrature::getPoints(order(), w, x, y, z);
00129   quadPoints.resize(w.length());
00130   quadWeights.resize(w.length());
00131   for (int i = 0; i < w.length(); i++)
00132   {
00133     quadWeights[i] = w[i];
00134     quadPoints[i] = Point(x[i], y[i], z[i]);
00135   }
00136 }
00137 
00138 void FeketeQuadrature::getAdaptedWeights(const CellType& cellType, int cellDim,
00139     int cellLID, int facetIndex, const Mesh& mesh,
00140     const ParametrizedCurve& globalCurve,
00141     Array<Point>& quadPoints, Array<double>& quadWeights,
00142     bool &weightsChanged) const
00143 {
00144   double tol = 1.e-10;
00145 
00146   // Flag, if we have changed the values of the weights
00147   weightsChanged = false;
00148 
00149   // ToDo: Other cell types!
00150   if (cellType != TriangleCell)
00151     return;
00152 
00153   // pushForward likes cellLID in an array
00154   Array<int> cellLIDs(1);
00155   cellLIDs[0] = cellLID;
00156 
00157   //
00158   // First, let's see, if we can do it the quick way...
00159   //
00160   Array<Point> nodes;
00161   Array<Point> nodesref(3);
00162   nodesref[0] = Point(0.0, 0.0);
00163   nodesref[1] = Point(1.0, 0.0);
00164   nodesref[2] = Point(0.0, 1.0);
00165   mesh.pushForward(cellDim, cellLIDs, nodesref, nodes);
00166 
00167   // Intersection points (parameters) with the edges of triangle
00168   Array<double> ip01;
00169   Array<double> ip02;
00170   Array<double> ip12;
00171   int nr_ip01;
00172   int nr_ip02;
00173   int nr_ip12;
00174   globalCurve.returnIntersect(nodes[0], nodes[1], nr_ip01, ip01);
00175   globalCurve.returnIntersect(nodes[0], nodes[2], nr_ip02, ip02);
00176   globalCurve.returnIntersect(nodes[1], nodes[2], nr_ip12, ip12);
00177 
00178   // Cell is _not intersected_ by curve
00179   if (nr_ip01 + nr_ip02 + nr_ip12 == 0)
00180   {
00181     // ToDo: further intersection tests? (curve totally inside this cell...)
00182     double alpha = globalCurve.integrationParameter(nodes[0]);
00183     if (alpha != 1.0)
00184     {
00185       weightsChanged = true;
00186       for (int i = 0; i < quadWeights.size(); i++)
00187         quadWeights[i] *= alpha;
00188     }
00189     std::cout << "Nicht geschnitten!" << std::endl;
00190     return;
00191   }
00192 
00193   //
00194   // If we are here, it is an intersected cell and we have to do the big thing...
00195   //
00196   weightsChanged = true;
00197   std::cout << "Geschnitten!" << std::endl;
00198   // Number of investigated triangles
00199   int nTris = 1;
00200 
00201   // Create stack
00202   std::stack<Point> s;
00203   std::stack<double> sa;
00204 
00205   Array<double> originalWeights = quadWeights;
00206   ParametrizedCurve noCurve = new DummyParametrizedCurve();
00207   Array<double> integrals(originalWeights.size());
00208   for (int i = 0; i < integrals.size(); i++)
00209     integrals[i] = 0.0;
00210 
00211   // Put the whole triangle on stack
00212   s.push(Point(0.0, 0.0));
00213   s.push(Point(1.0, 0.0));
00214   s.push(Point(0.0, 1.0));
00215   sa.push(1.0);
00216 
00217   while (s.size() >= 3)
00218   {
00219     // Number of triangles investigated
00220     ++nTris;
00221 
00222     std::cout << "PunkteStack " << s.size() << " AreaStack " << sa.size()
00223         << std::endl;
00224 
00225     // Integration results
00226     bool refine = false;
00227     Array<double> results1(originalWeights.size());
00228     Array<double> results2(originalWeights.size());
00229 
00230     // Fetch the coordinates of current triangle
00231     double area = sa.top();
00232     sa.pop();
00233     for (int i = 2; i > -1; i--)
00234     {
00235       nodesref[i] = s.top();
00236       s.pop();
00237     }
00238     mesh.pushForward(cellDim, cellLIDs, nodesref, nodes);
00239 
00240     // Intersection points (parameters) with the edges of triangle
00241     globalCurve.returnIntersect(nodes[0], nodes[1], nr_ip01, ip01);
00242     globalCurve.returnIntersect(nodes[0], nodes[2], nr_ip02, ip02);
00243     globalCurve.returnIntersect(nodes[1], nodes[2], nr_ip12, ip12);
00244 
00245     //  Determine kind of intersection
00246     // 'No intersection' is handled also in first case
00247     Point x, xref;
00248     Point vec1, vec1ref;
00249     Point vec2, vec2ref;
00250     bool xInOmega = false;
00251     if ((nr_ip01 + nr_ip02 + nr_ip12 == 0) || (nr_ip01 == 1 && nr_ip02 == 1
00252         && nr_ip12 == 0))
00253     {
00254       x = nodes[0];
00255       vec1 = nodes[2] - nodes[0];
00256       vec2 = nodes[1] - nodes[0];
00257       xref = nodesref[0];
00258       vec1ref = nodesref[2] - nodesref[0];
00259       vec2ref = nodesref[1] - nodesref[0];
00260       std::cout << "Fall 0" << std::endl;
00261     }
00262     else if (nr_ip12 == 1 && nr_ip01 == 1 && nr_ip02 == 0)
00263     {
00264       x = nodes[1];
00265       vec1 = nodes[0] - nodes[1];
00266       vec2 = nodes[2] - nodes[1];
00267       xref = nodesref[1];
00268       vec1ref = nodesref[0] - nodesref[1];
00269       vec2ref = nodesref[2] - nodesref[1];
00270       std::cout << "Fall 1" << std::endl;
00271     }
00272     else if (nr_ip02 == 1 && nr_ip12 == 1 && nr_ip01 == 0)
00273     {
00274       x = nodes[2];
00275       vec1 = nodes[1] - nodes[2];
00276       vec2 = nodes[0] - nodes[2];
00277       xref = nodesref[2];
00278       vec1ref = nodesref[1] - nodesref[2];
00279       vec2ref = nodesref[0] - nodesref[2];
00280       std::cout << "Fall 2" << std::endl;
00281     }
00282     else
00283     {
00284       std::cout << "Komische Schnitte: Verfeinern! Area: " << area
00285           << std::endl;
00286       std::cout << "Schnitte: 01: " << nr_ip01 << " 02: " << nr_ip02
00287           << " 12: " << nr_ip12 << std::endl;
00288       refine = true;
00289     }
00290 
00291 
00292     // If we found a case we can deal with, calculate integrals
00293     if (!refine)
00294     {
00295       if (globalCurve.curveEquation(x) < 0)
00296         xInOmega = true;
00297       integrateRegion(cellType, cellDim, order(), x, xref, vec1, vec2,
00298           vec1ref, vec2ref, globalCurve, results1);
00299       integrateRegion(cellType, cellDim, order() + 1, x, xref, vec1,
00300           vec2, vec1ref, vec2ref, globalCurve, results2);
00301 
00302       // Check results
00303       for (int i = 0; i < results2.size(); i++)
00304       {
00305         if (::fabs(results2[i] - results1[i]) > sqrt(0.5 * area * tol))
00306         {
00307           std::cout << "Zu ungenau: Verfeinern! Area: " << area
00308               << std::endl;
00309           refine = true;
00310           break;
00311         }
00312       }
00313     }
00314 
00315     // If we had not found a case we can deal with or we are unsatisfied
00316     // with accuracy -> refinement
00317     if (refine)
00318     {
00319       // Divide triangle into 4 smaller ones (introduce new nodes at the
00320       // center of each edge
00321       s.push(nodesref[0]);
00322       s.push((nodesref[0] + nodesref[1]) / 2);
00323       s.push((nodesref[0] + nodesref[2]) / 2);
00324       sa.push(area / 4);
00325       s.push((nodesref[0] + nodesref[1]) / 2);
00326       s.push(nodesref[1]);
00327       s.push((nodesref[1] + nodesref[2]) / 2);
00328       sa.push(area / 4);
00329       s.push((nodesref[0] + nodesref[2]) / 2);
00330       s.push((nodesref[1] + nodesref[2]) / 2);
00331       s.push(nodesref[2]);
00332       sa.push(area / 4);
00333       s.push((nodesref[0] + nodesref[2]) / 2);
00334       s.push((nodesref[0] + nodesref[1]) / 2);
00335       s.push((nodesref[1] + nodesref[2]) / 2);
00336       sa.push(area / 4);
00337     }
00338 
00339     // We found an accurate solution to that part of the triangle!
00340     else
00341     {
00342       if (xInOmega)
00343       {
00344         for (int i = 0; i < integrals.size(); i++)
00345           integrals[i] += results2[i];
00346         std::cout << "x in Omega!" << std::endl;
00347       }
00348       else
00349       {
00350         integrateRegion(cellType, cellDim, order() + 1, x, xref, vec1,
00351             vec2, vec1ref, vec2ref, noCurve, results1);
00352         for (int i = 0; i < integrals.size(); i++)
00353           integrals[i] += (results1[i] - results2[i]);
00354       }
00355     }
00356   } // Stack depleted here!
00357 
00358   if (s.size() != 0)
00359   {
00360     std::cout << "Problem mit stack size!" << std::endl;
00361   }
00362   std::cout << "Anzahl behandelter Teildreiecke: " << nTris << std::endl;
00363 
00364   Array<double> alphas;
00365   globalCurve.getIntegrationParams(alphas);
00366   for (int i = 0; i < quadWeights.size(); i++)
00367     quadWeights[i] = alphas[1] * integrals[i] + alphas[0]
00368         * (originalWeights[i] - integrals[i]);
00369 
00370   std::cout << "Gewichte: ";
00371   for (int i = 0; i < quadWeights.size(); i++)
00372     std::cout << quadWeights[i] << " ";
00373   std::cout << std::endl;
00374 }
00375 
00376 void FeketeQuadrature::integrateRegion(const CellType& cellType,
00377     const int cellDim, const int innerOrder, const Point& x,
00378     const Point& xref, const Point& vec1, const Point& vec2,
00379     const Point& vec1ref, const Point& vec2ref,
00380     const ParametrizedCurve& curve, Array<double>& integrals) const
00381 {
00382   // Prepare output array
00383   integrals.resize((order() + 1) * (order() + 2) / 2); // ToDo: This is triangle-specific!
00384   for (int i = 0; i < integrals.size(); i++)
00385     integrals[i] = 0.0;
00386 
00387   // Get 'inner integration' points
00388   Array<double> innerQuadPts;
00389   Array<double> innerQuadWgts;
00390   int nrInnerQuadPts = innerOrder + 3;
00391   nrInnerQuadPts = (nrInnerQuadPts + nrInnerQuadPts % 2) / 2;
00392   GaussLobatto1D innerQuad(nrInnerQuadPts, 0.0, 1.0);
00393 
00394   innerQuadPts.resize(nrInnerQuadPts);
00395   innerQuadWgts.resize(nrInnerQuadPts);
00396   innerQuadPts = innerQuad.nodes();
00397   innerQuadWgts = innerQuad.weights();
00398 
00399   // Calculate intersection points
00400   for (int edgePos = 0; edgePos < nrInnerQuadPts; edgePos++)
00401   {
00402     // Direction of current integration
00403     Point ray = innerQuadPts[edgePos] * vec1
00404         + (1.0 - innerQuadPts[edgePos]) * vec2;
00405     Point rayref = innerQuadPts[edgePos] * vec1ref + (1.0
00406         - innerQuadPts[edgePos]) * vec2ref;
00407 
00408     // Calculate intersection along ray
00409     int nrIntersect = 0;
00410     Array<double> t;
00411     Point rayEnd = x + ray;
00412     curve.returnIntersect(x, rayEnd, nrIntersect, t);
00413 
00414     // Without an intersection we integrate from x to the opposing edge
00415     double mu = 1.0;
00416     if (nrIntersect == 1)
00417     {
00418       mu = t[0];
00419     }
00420     else if (nrIntersect >= 2)
00421     {
00422       // ToDo: Verfeinern
00423       std::cout << "Problem: Mehr als ein Schnittpunkt mit Strahl "
00424           << " fuer edgePos " << edgePos << std::endl;
00425       mu = t[1]; // ToDo: Falsch! Nur damit es weitergeht...
00426     }
00427 
00428     // Array for values of basis functions at inner integration points
00429     Array<double> innerIntegrals;
00430     innerIntegrals.resize(integrals.size());
00431     for (int i = 0; i < innerIntegrals.size(); i++)
00432       innerIntegrals[i] = 0.0;
00433 
00434     Array<Point> q;
00435     q.resize(nrInnerQuadPts);
00436     for (int rayPos = 0; rayPos < nrInnerQuadPts; rayPos++)
00437     {
00438       q[rayPos] = xref + mu * innerQuadPts[rayPos] * rayref;
00439 
00440       // Evaluate all basis functions at quadrature point
00441       Array<double> funcVals;
00442       evaluateAllBasisFunctions(q[rayPos], funcVals);
00443 
00444       // Do quadrature for all basis functions
00445       for (int j = 0; j < funcVals.size(); j++)
00446         innerIntegrals[j] += funcVals[j] * innerQuadWgts[rayPos]
00447             * innerQuadPts[rayPos];
00448     }
00449     for (int j = 0; j < integrals.size(); j++)
00450       integrals[j] += innerQuadWgts[edgePos] * mu * mu
00451           * innerIntegrals[j];
00452   }
00453   double det = ::fabs(vec1ref[0] * vec2ref[1] - vec2ref[0] * vec1ref[1]);
00454   for (int j = 0; j < integrals.size(); j++)
00455     integrals[j] *= det;
00456 }
00457 
00458 void FeketeQuadrature::evaluateAllBasisFunctions(const Point& q,
00459     Array<double>& result) const
00460 {
00461   // Coefficients in _basisCoeffs together with PKD polynomials form
00462   // a Lagrange basis at Fekete points
00463   if (!_hasBasisCoeffs)
00464     computeBasisCoeffs();
00465 
00466   // We have nFeketePts basis functions
00467   int nFeketePts = sqrt(_basisCoeffs.size());
00468   result.resize(nFeketePts);
00469 
00470   // Determine values of all PKD polynomials at q
00471   Array<double> pkdVals;
00472   pkdVals.resize(nFeketePts);
00473   FeketeTriangleQuadrature::evalPKDpolynomials(order(), q[0], q[1],
00474       &(pkdVals[0]));
00475 
00476   // ToDo: BLAS dgemv (with matrix transposed) ?
00477   // For each Lagrange basis function
00478   for (int m = 0; m < nFeketePts; m++)
00479   {
00480     // Sum up weighted PKD polynomials
00481     for (int n = 0; n < nFeketePts; n++)
00482     {
00483       // Coefficients of m-th basis function are in m-th column
00484       result[m] += _basisCoeffs[m + n * nFeketePts] * pkdVals[n];
00485     }
00486   }
00487 }
00488 
00489 void FeketeQuadrature::computeBasisCoeffs() const
00490 {
00491   if (_hasBasisCoeffs)
00492     return;
00493 
00494   // Get Fekete points of chosen order
00495   Array<Point> feketePts;
00496 
00497   Array<double> x;
00498   Array<double> y;
00499   Array<double> w;
00500   FeketeTriangleQuadrature::getPoints(order(), w, x, y);
00501   int nFeketePts = w.length();
00502   feketePts.resize(nFeketePts);
00503   for (int i = 0; i < nFeketePts; i++)
00504     feketePts[i] = Point(x[i], y[i]);
00505 
00506   // We construct a Lagrange basis at feketePts (there are nFeketePts of them)
00507   // Each basis polynomial itself is given by a linear combination of
00508   // nFeketePts PKD polynomials and their coefficients
00509   _basisCoeffs.resize(nFeketePts * nFeketePts);
00510 
00511   // Let's compute the coefficients:
00512   // Build Vandermonde matrix of PKD basis at Fekete points
00513   for (int n = 0; n < nFeketePts; n++)
00514   {
00515     // Set pointer to beginning of n-th row and determine values of
00516     // PKD polynomials at n-th Fekete point
00517     double* start = &(_basisCoeffs[n * nFeketePts]);
00518     FeketeTriangleQuadrature::evalPKDpolynomials(order(), feketePts[n][0],
00519         feketePts[n][1], start);
00520   }
00521 
00522   // Invert Vandermonde matrix to obtain basis coefficients:
00523   // LAPACK error flag, array for switched rows, work array
00524   int lapack_err = 0;
00525   Array<int> pivot;
00526   pivot.resize(nFeketePts);
00527   Array<double> work;
00528   work.resize(1);
00529   int lwork = -1;
00530 
00531   // LU factorization
00532 	::dgetrf_(&nFeketePts, &nFeketePts, &(_basisCoeffs[0]), &nFeketePts,
00533       &(pivot[0]), &lapack_err);
00534 
00535   TEST_FOR_EXCEPTION(
00536       lapack_err != 0,
00537       RuntimeError,
00538       "FeketeQuadrature::computeBasisCoeffs(): factorization of generalized Vandermonde failed");
00539 
00540   // Determine work array size
00541 	::dgetri_(&nFeketePts, &(_basisCoeffs[0]), &nFeketePts, &(pivot[0]),
00542       &(work[0]), &lwork, &lapack_err);
00543   lwork = (int) work[0];
00544   work.resize(lwork);
00545 
00546   // Inversion of factorized matrix
00547 	::dgetri_(&nFeketePts, &(_basisCoeffs[0]), &nFeketePts, &(pivot[0]),
00548       &(work[0]), &lwork, &lapack_err);
00549 
00550   TEST_FOR_EXCEPTION(
00551       lapack_err != 0,
00552       RuntimeError,
00553       "FeketeQuadrature::computeBasisCoeffs(): inversion of generalized Vandermonde failed");
00554 
00555   _hasBasisCoeffs = true;
00556 }

Site Contact