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 "SundanceOut.hpp"
00037 #include "PlayaTabs.hpp"
00038 #include <stack>
00039 
00040 using namespace Sundance;
00041 using namespace Teuchos;
00042 
00043 /* declare LAPACK subroutines */
00044 extern "C"
00045 {
00046 /* matrix-vector multiplication */
00047 void dgemv_(char *trans, int *m, int *n, double *alpha, double *a, int *lda,
00048     double *x, int *incx, double *beta, double *y, int *incy);
00049 }
00050 
00051 /* constructor */
00052 FeketeQuadrature::FeketeQuadrature(int order) :
00053   QuadratureFamilyBase(order)
00054 {
00055   _hasBasisCoeffs = false;
00056 }
00057 
00058 XMLObject FeketeQuadrature::toXML() const
00059 {
00060   XMLObject rtn("FeketeQuadrature");
00061   rtn.addAttribute("order", Teuchos::toString(order()));
00062   return rtn;
00063 }
00064 
00065 void FeketeQuadrature::getLineRule(Array<Point>& quadPoints,
00066     Array<double>& quadWeights) const
00067 {
00068   int p = order() + 3;
00069   p = p + (p % 2);
00070   int n = p / 2;
00071 
00072   quadPoints.resize(n);
00073   quadWeights.resize(n);
00074 
00075   GaussLobatto1D q1(n, 0.0, 1.0);
00076 
00077   for (int i = 0; i < n; i++)
00078   {
00079     quadWeights[i] = q1.weights()[i];
00080     quadPoints[i] = Point(q1.nodes()[i]);
00081   }
00082 }
00083 
00084 void FeketeQuadrature::getTriangleRule(Array<Point>& quadPoints,
00085     Array<double>& quadWeights) const
00086 {
00087   Array<double> x;
00088   Array<double> y;
00089   Array<double> w;
00090 
00091   FeketeTriangleQuadrature::getPoints(order(), w, x, y);
00092   quadPoints.resize(w.length());
00093   quadWeights.resize(w.length());
00094   for (int i = 0; i < w.length(); i++)
00095   {
00096     quadWeights[i] = 0.5 * w[i];
00097     quadPoints[i] = Point(x[i], y[i]);
00098   }
00099 }
00100 
00101 void FeketeQuadrature::getQuadRule(Array<Point>& quadPoints,
00102     Array<double>& quadWeights) const
00103 {
00104   Array<double> x;
00105   Array<double> y;
00106   Array<double> w;
00107 
00108   FeketeQuadQuadrature::getPoints(order(), w, x, y);
00109   quadPoints.resize(w.length());
00110   quadWeights.resize(w.length());
00111   for (int i = 0; i < w.length(); i++)
00112   {
00113     quadWeights[i] = w[i];
00114     quadPoints[i] = Point(x[i], y[i]);
00115   }
00116 }
00117 
00118 void FeketeQuadrature::getBrickRule(Array<Point>& quadPoints,
00119     Array<double>& quadWeights) const
00120 {
00121   Array<double> x;
00122   Array<double> y;
00123   Array<double> z;
00124   Array<double> w;
00125 
00126   FeketeBrickQuadrature::getPoints(order(), w, x, y, z);
00127   quadPoints.resize(w.length());
00128   quadWeights.resize(w.length());
00129   for (int i = 0; i < w.length(); i++)
00130   {
00131     quadWeights[i] = w[i];
00132     quadPoints[i] = Point(x[i], y[i], z[i]);
00133   }
00134 }
00135 
00136 void FeketeQuadrature::getAdaptedWeights(const CellType& cellType, int cellDim,
00137     int cellLID, int facetIndex, const Mesh& mesh, const ParametrizedCurve&
00138     globalCurve, Array<Point>& quadPoints, Array<double>& quadWeights,
00139     bool& weightsChanged) const
00140 {
00141   //int verb = 4;
00142   Tabs tabs;
00143 
00144   // Cache lookup
00145   /*if (mesh.IsSpecialWeightValid() && mesh.hasSpecialWeight(cellDim, cellLID))
00146   {
00147     weightsChanged = true;
00148     mesh.getSpecialWeight(cellDim, cellLID, quadWeights);
00149     SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedWeights Found cached weights for cell LID " << cellLID)
00150     return;
00151   }*/
00152 
00153   // Maximal cell type
00154   CellType maxCellType = mesh.cellType(mesh.spatialDim());
00155 
00156   switch (maxCellType)
00157   {
00158   // We have a triangle based mesh
00159   case TriangleCell:
00160   {
00161     switch (cellType)
00162     {
00163     case TriangleCell:
00164     {
00165       getAdaptedTriangleWeights(cellLID, mesh, globalCurve, quadPoints,
00166           quadWeights, weightsChanged);
00167       break;
00168     }
00169     default:
00170 #ifndef TRILINOS_7
00171       SUNDANCE_ERROR ("getAdaptedWeights rule for ACI(Adaptive Cell Integration) not available for submaximal cell " << maxCellType << " in a triangle mesh")
00172       ;
00173 #else
00174       SUNDANCE_ERROR7("getAdaptedWeights rule for ACI(Adaptive Cell Integration) not available for submaximal cell " << maxCellType << " in a triangle mesh");
00175 #endif
00176     }
00177     break;
00178   }
00179   case QuadCell:
00180   {
00181     switch(cellType)
00182     {
00183     case QuadCell:
00184     {
00185       getAdaptedQuadWeights(cellLID, mesh, globalCurve, quadPoints,
00186         quadWeights, weightsChanged);
00187       break;
00188     }
00189     default:
00190 #ifndef TRILINOS_7
00191     SUNDANCE_ERROR ("getAdaptedWeights rule for ACI(Adaptive Cell Integration) not available for submaximal cell " << maxCellType << " in a triangle mesh")
00192     ;
00193 #else
00194     SUNDANCE_ERROR7("getAdaptedWeights rule for ACI(Adaptive Cell Integration) not available for submaximal cell " << maxCellType << " in a triangle mesh");
00195 #endif
00196     }
00197     break;
00198   }
00199   default:
00200 #ifndef TRILINOS_7
00201     SUNDANCE_ERROR("getAdaptedWeights rule for ACI(Adaptive Cell Integration) not available for cell type " << cellType)
00202     ;
00203 #else
00204     SUNDANCE_ERROR7("getAdaptedWeights rule for ACI(Adaptive Cell Integration) not available for cell type " << cellType);
00205 #endif
00206   }
00207 }
00208 
00209 void FeketeQuadrature::getAdaptedTriangleWeights(int cellLID, const Mesh& mesh,
00210     const ParametrizedCurve& globalCurve, Array<Point>& quadPoints, Array<
00211         double>& quadWeights, bool& weightsChanged) const
00212 {
00213   int verb = 0;
00214   Tabs tabs;
00215 
00216   // ToDo: What tolerance?
00217   double tol = 1.e-8;
00218   weightsChanged = true;
00219 
00220   // For pushForward() we need the cellLID in an array
00221   Array<int> cellLIDs(1);
00222   cellLIDs[0] = cellLID;
00223 
00224   // Intersection points (parameters) with the edges of triangle
00225   Array<double> ip01, ip02, ip12;
00226   int nr_ip01, nr_ip02, nr_ip12;
00227 
00228   Array<double> originalWeights = quadWeights;
00229   ParametrizedCurve noCurve = new DummyParametrizedCurve();
00230   Array<double> integrals(originalWeights.size());
00231   for (int i = 0; i < integrals.size(); i++)
00232     integrals[i] = 0.0;
00233 
00234   // Create stack and put the initial triangle on stack
00235   std::stack<Point> s;
00236   std::stack<double> sa;
00237   s.push(Point(0.0, 0.0));
00238   s.push(Point(1.0, 0.0));
00239   s.push(Point(0.0, 1.0));
00240   sa.push(0.5);
00241   Array<Point> nodes;
00242   Array<Point> nodesref(3);
00243 
00244   // Number of investigated triangles
00245   unsigned int nTris = 0;
00246 
00247   while (s.size() >= 3)
00248   {
00249     // Increment number of triangles investigated
00250     ++nTris;
00251 
00252     SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedTriangleWeights Current number of triangles on stack: " << sa.size());
00253 
00254     // Integration results
00255     bool refine = false;
00256     Array<double> results1(originalWeights.size());
00257     Array<double> results2(originalWeights.size());
00258 
00259     // Fetch the coordinates of current triangle from stack
00260     double area = sa.top();
00261     sa.pop();
00262     for (int i = 2; i >= 0; i--)
00263     {
00264       nodesref[i] = s.top();
00265       s.pop();
00266     }
00267     mesh.pushForward(2, cellLIDs, nodesref, nodes);
00268 
00269     // Intersection points (parameters) with the edges of triangle
00270     globalCurve.returnIntersect(nodes[0], nodes[1], nr_ip01, ip01);
00271     globalCurve.returnIntersect(nodes[0], nodes[2], nr_ip02, ip02);
00272     globalCurve.returnIntersect(nodes[1], nodes[2], nr_ip12, ip12);
00273 
00274     //  Determine kind of intersection
00275     Point x, xref;
00276     Point vec1, vec1ref;
00277     Point vec2, vec2ref;
00278     bool xInOmega = false;
00279 
00280     // 'No intersection' is also handled here
00281     if ((nr_ip01 + nr_ip02 + nr_ip12 == 0) || (nr_ip01 == 0 && nr_ip02 == 0
00282         && nr_ip12 == 1) || (nr_ip01 == 1 && nr_ip02 == 1 && nr_ip12
00283         == 0))
00284     {
00285       x = nodes[0];
00286       vec1 = nodes[2] - nodes[0];
00287       vec2 = nodes[1] - nodes[0];
00288       xref = nodesref[0];
00289       vec1ref = nodesref[2] - nodesref[0];
00290       vec2ref = nodesref[1] - nodesref[0];
00291     }
00292     else if ((nr_ip01 == 0 && nr_ip02 == 1 && nr_ip12 == 0) || (nr_ip12
00293         == 1 && nr_ip01 == 1 && nr_ip02 == 0))
00294     {
00295       x = nodes[1];
00296       vec1 = nodes[0] - nodes[1];
00297       vec2 = nodes[2] - nodes[1];
00298       xref = nodesref[1];
00299       vec1ref = nodesref[0] - nodesref[1];
00300       vec2ref = nodesref[2] - nodesref[1];
00301     }
00302     else if ((nr_ip01 == 1 && nr_ip02 == 0 && nr_ip12 == 0) || (nr_ip02
00303         == 1 && nr_ip12 == 1 && nr_ip01 == 0))
00304     {
00305       x = nodes[2];
00306       vec1 = nodes[1] - nodes[2];
00307       vec2 = nodes[0] - nodes[2];
00308       xref = nodesref[2];
00309       vec1ref = nodesref[1] - nodesref[2];
00310       vec2ref = nodesref[0] - nodesref[2];
00311     }
00312     else
00313     {
00314       refine = true;
00315     }
00316 
00317     // If we found a case we can deal with, calculate the integrals
00318     if (!refine)
00319     {
00320       if (globalCurve.curveEquation(x) < 0)
00321         xInOmega = true;
00322       integrateRegion(TriangleCell, 2, order() + 1, x, xref, vec1, vec2,
00323           vec1ref, vec2ref, globalCurve, results1);
00324       if (results1.size() == 0)
00325       {
00326         SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedTriangleWeights Unknown error in integration. Refine.")
00327         refine = true;
00328       }
00329       else
00330       {
00331         integrateRegion(TriangleCell, 2, order() + 2, x, xref, vec1,
00332             vec2, vec1ref, vec2ref, globalCurve, results2);
00333 
00334         // Check results
00335         for (int i = 0; i < results1.size(); i++)
00336         {
00337           if (::fabs(results2[i] - results1[i]) > sqrt(area * tol))
00338           {
00339             SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedTriangleWeights Insufficient accuracy. Refine.")
00340             refine = true;
00341             break;
00342           }
00343         }
00344       }
00345     }
00346 
00347     // Refine (either because of lacking accuracy or strange intersections)
00348     if (refine)
00349     {
00350       // Divide triangle into 4 smaller ones (introduce new nodes at the
00351       // center of each edge)
00352       s.push(nodesref[0]);
00353       s.push((nodesref[0] + nodesref[1]) / 2);
00354       s.push((nodesref[0] + nodesref[2]) / 2);
00355       sa.push(area / 4);
00356       s.push((nodesref[0] + nodesref[1]) / 2);
00357       s.push(nodesref[1]);
00358       s.push((nodesref[1] + nodesref[2]) / 2);
00359       sa.push(area / 4);
00360       s.push((nodesref[0] + nodesref[2]) / 2);
00361       s.push((nodesref[1] + nodesref[2]) / 2);
00362       s.push(nodesref[2]);
00363       sa.push(area / 4);
00364       s.push((nodesref[0] + nodesref[2]) / 2);
00365       s.push((nodesref[0] + nodesref[1]) / 2);
00366       s.push((nodesref[1] + nodesref[2]) / 2);
00367       sa.push(area / 4);
00368       continue;
00369     }
00370 
00371     // We found an accurate solution to that part of the triangle!
00372     if (xInOmega)
00373     {
00374       for (int i = 0; i < integrals.size(); i++)
00375         integrals[i] += results2[i];
00376     }
00377     else
00378     {
00379       integrateRegion(TriangleCell, 2, order() + 1, x, xref, vec1, vec2,
00380           vec1ref, vec2ref, noCurve, results1);
00381       for (int i = 0; i < integrals.size(); i++)
00382         integrals[i] += (results1[i] - results2[i]);
00383     }
00384   } // Stack depleted here! We're done.
00385 
00386   SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedTriangleWeights Calculations in cell " << cellLID << " completed. " << nTris << " triangle(s) used.");
00387 
00388   Array<double> alphas;
00389   globalCurve.getIntegrationParams(alphas);
00390   for (int i = 0; i < quadWeights.size(); i++)
00391     quadWeights[i] = alphas[1] * integrals[i] + alphas[0]
00392         * (originalWeights[i] - integrals[i]);
00393   mesh.setSpecialWeight(2, cellLID, quadWeights);
00394 }
00395 
00396 void FeketeQuadrature::getAdaptedQuadWeights(int cellLID, const Mesh& mesh,
00397     const ParametrizedCurve& globalCurve, Array<Point>& quadPoints, Array<
00398         double>& quadWeights, bool& weightsChanged) const
00399 {
00400   // Verbosity
00401   int verb = 0;
00402   Tabs tabs;
00403 
00404   // ToDo: What tolerance?
00405   double tol = 1.e-8;
00406 
00407   // Initialization
00408   weightsChanged = true;
00409   Array<double> originalWeights = quadWeights;
00410 
00411   ParametrizedCurve noCurve = new DummyParametrizedCurve();
00412   Array<double> integrals(originalWeights.size());
00413   for (int i = 0; i < integrals.size(); i++)
00414     integrals[i] = 0.0;
00415 
00416   // For pushForward() we need the cellLID in an array
00417   Array<int> cellLIDs(1);
00418   cellLIDs[0] = cellLID;
00419   SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedQuadWeights: Current cell LID " << cellLID)
00420 
00421   //        IV
00422   //   2 __________ 3
00423   //    |          |
00424   //    |          |
00425   // II |          | III
00426   //    |__________|
00427   //   0            1
00428   //         I
00429 
00430   Array<int> nIntEdge(4);
00431   Array<Array<double> > IntEdgePars(4);
00432   int edgeIndex[4][2] = { {0,1} , {0,2} , {1,3} , {2,3} };
00433 
00434   // Create stack and put the initial quad
00435   std::stack<Point> s;
00436   std::stack<double> sa;
00437   s.push(Point(0.0, 0.0));
00438   s.push(Point(1.0, 0.0));
00439   s.push(Point(0.0, 1.0));
00440   s.push(Point(1.0, 1.0));
00441   sa.push(1.);
00442   Array<Point> nodes;
00443   Array<Point> nodesref(4);
00444 
00445   // Number of investigated quads
00446   unsigned int nQuads = 0;
00447 
00448   while (s.size() >= 4)
00449   {
00450     // Increment number of quads investigated
00451     ++nQuads;
00452     SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedQuadWeights: Current number of quads on stack: " << sa.size())
00453 
00454     // Integration results
00455     bool refine = false;
00456     bool xInOmega = false;
00457     Array<double> results1(originalWeights.size());
00458     Array<double> results2(originalWeights.size());
00459 
00460     // Fetch the coordinates of current quad from stack
00461     double area = sa.top();
00462     sa.pop();
00463     for (int i = 3; i >= 0; i--)
00464     {
00465       nodesref[i] = s.top();
00466       s.pop();
00467     }
00468     mesh.pushForward(2, cellLIDs, nodesref, nodes);
00469 
00470     // Intersection points (parameters) with the edges of triangle
00471     for (int jj = 0 ; jj < 4 ; jj++ ) {
00472       globalCurve.returnIntersect(nodes[edgeIndex[jj][0]], nodes[edgeIndex[jj][1]], nIntEdge[jj], IntEdgePars[jj] );
00473   /*    if ( nIntEdge[jj] == 0 ) {
00474         x = nodes[edgeIndex[jj][0]];
00475         vec1 =
00476         vec2 =
00477       }
00478   */  }
00479 
00480     //  Determine kind of intersection
00481     Point x, xref;
00482     Point vec1, vec1ref;
00483     Point vec2, vec2ref;
00484 
00485     // Baseline is not intersected
00486     if ( nIntEdge[0] == 0 )
00487     {
00488       x = nodes[0];
00489       vec1 = nodes[1] - nodes[0];
00490       vec2 = nodes[2] - nodes[0];
00491       xref = nodesref[0];
00492       vec1ref = nodesref[1] - nodesref[0];
00493       vec2ref = nodesref[2] - nodesref[0];
00494     }
00495     else if ( nIntEdge[1] == 0 )
00496     {
00497       x = nodes[2];
00498       vec1 = nodes[0] - nodes[2];
00499       vec2 = nodes[3] - nodes[2];
00500       xref = nodesref[2];
00501       vec1ref = nodesref[0] - nodesref[2];
00502       vec2ref = nodesref[3] - nodesref[2];
00503     }
00504     else if ( nIntEdge[2] == 0 )
00505     {
00506       x = nodes[1];
00507       vec1 = nodes[3] - nodes[1];
00508       vec2 = nodes[0] - nodes[1];
00509       xref = nodesref[1];
00510       vec1ref = nodesref[3] - nodesref[1];
00511       vec2ref = nodesref[0] - nodesref[1];
00512     }
00513     else
00514     {
00515       refine = true;
00516     }
00517 
00518     // If we found a case we can deal with, calculate the integrals
00519     if (!refine)
00520     {
00521       if (globalCurve.curveEquation(x) < 0)
00522         xInOmega = true;
00523       integrateRegion(QuadCell, 2, order() + 1, x, xref, vec1, vec2,
00524           vec1ref, vec2ref, globalCurve, results1);
00525       if (results1.size() == 0)
00526       {
00527         SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedQuadWeights Unknown error in integration. Refine.")
00528         refine = true;
00529       }
00530       else
00531       {
00532         integrateRegion(QuadCell, 2, order() + 2, x, xref, vec1,
00533             vec2, vec1ref, vec2ref, globalCurve, results2);
00534 
00535         // Check results
00536         double reltol = ::sqrt(area * tol);
00537         for (int i = 0; i < results1.size(); i++)
00538         {
00539           if (::fabs(results2[i] - results1[i]) > reltol)
00540           {
00541             SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedQuadWeights Insufficient accuracy. Refine.")
00542             refine = true;
00543             break;
00544           }
00545         }
00546       }
00547     }
00548 
00549     // Refine (either because of lacking accuracy or strange intersections)
00550     if (refine)
00551     {
00552       // Divide quad into 4 smaller ones (introduce new nodes at the
00553       // center of each edge)
00554       s.push(nodesref[0]);
00555       s.push((nodesref[0] + nodesref[1]) / 2);
00556       s.push((nodesref[0] + nodesref[2]) / 2);
00557       s.push((nodesref[0] + nodesref[3]) / 2);
00558       sa.push(area / 4);
00559       s.push((nodesref[0] + nodesref[1]) / 2);
00560       s.push(nodesref[1]);
00561       s.push((nodesref[1] + nodesref[2]) / 2);
00562       s.push((nodesref[1] + nodesref[3]) / 2);
00563       sa.push(area / 4);
00564       s.push((nodesref[0] + nodesref[2]) / 2);
00565       s.push((nodesref[1] + nodesref[2]) / 2);
00566       s.push(nodesref[2]);
00567       s.push((nodesref[2] + nodesref[3]) / 2);
00568       sa.push(area / 4);
00569       s.push((nodesref[0] + nodesref[3]) / 2);
00570       s.push((nodesref[1] + nodesref[3]) / 2);
00571       s.push((nodesref[2] + nodesref[3]) / 2);
00572       s.push(nodesref[3]);
00573       sa.push(area / 4);
00574       continue;
00575     }
00576 
00577     // We found an accurate solution to that part of the triangle!
00578     if (xInOmega)
00579     {
00580       for (int i = 0; i < integrals.size(); i++)
00581         integrals[i] += results2[i];
00582     }
00583     else
00584     {
00585       integrateRegion(QuadCell, 2, order() + 1, x, xref, vec1, vec2,
00586           vec1ref, vec2ref, noCurve, results1);
00587       for (int i = 0; i < integrals.size(); i++)
00588         integrals[i] += (results1[i] - results2[i]);
00589     }
00590   } // Stack depleted here! We're done.
00591 
00592   SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::getAdaptedQuadWeights Calculations in cell " << cellLID << " completed. " << nQuads << " quad(s) used.");
00593 
00594   Array<double> alphas;
00595   globalCurve.getIntegrationParams(alphas);
00596   for (int i = 0; i < quadWeights.size(); i++)
00597     quadWeights[i] = alphas[1] * integrals[i] + alphas[0]
00598         * (originalWeights[i] - integrals[i]);
00599   if (verb > 1 ) {
00600       writeTable(Out::os(), tabs, quadWeights, quadWeights.size());
00601   }
00602   mesh.setSpecialWeight(2, cellLID, quadWeights);
00603 }
00604 
00605 void FeketeQuadrature::integrateRegion(const CellType& cellType,
00606     const int cellDim, const int innerOrder, const Point& x,
00607     const Point& xref, const Point& vec1, const Point& vec2,
00608     const Point& vec1ref, const Point& vec2ref,
00609     const ParametrizedCurve& curve, Array<double>& integrals) const
00610 {
00611   int verb = 0;
00612   Tabs tabs;
00613 
00614   switch (cellType)
00615   {
00616   case TriangleCell:
00617   {
00618     // Prepare output array
00619     integrals.resize((order() + 1) * (order() + 2) / 2);
00620     for (int i = 0; i < integrals.size(); i++)
00621       integrals[i] = 0.0;
00622 
00623     // Get 'inner' integration points (along a line)
00624     int nrInnerQuadPts = innerOrder + 3;
00625     nrInnerQuadPts = (nrInnerQuadPts + nrInnerQuadPts % 2) / 2;
00626     GaussLobatto1D innerQuad(nrInnerQuadPts, 0.0, 1.0);
00627 
00628     Array<double> innerQuadPts(nrInnerQuadPts);
00629     Array<double> innerQuadWgts(nrInnerQuadPts);
00630     innerQuadPts = innerQuad.nodes();
00631     innerQuadWgts = innerQuad.weights();
00632 
00633     // Calculate intersection points of 'integration ray' with curve
00634     // Here one needs physical coordinates because of the curve
00635     for (int edgePos = 0; edgePos < nrInnerQuadPts; edgePos++)
00636     {
00637       // Direction of current integration
00638       Point ray = innerQuadPts[edgePos] * vec1 + (1.0
00639           - innerQuadPts[edgePos]) * vec2;
00640       Point rayref = innerQuadPts[edgePos] * vec1ref + (1.0
00641           - innerQuadPts[edgePos]) * vec2ref;
00642 
00643       int nrIntersect = 0;
00644       Array<double> t;
00645       Point rayEnd = x + ray;
00646       curve.returnIntersect(x, rayEnd, nrIntersect, t);
00647 
00648       double mu = 1.0; // w/o an intersection we integrate the whole line
00649       if (nrIntersect == 1)
00650       {
00651         mu = t[0];
00652       }
00653       else if (nrIntersect >= 2)
00654       {
00655         // More than one intersection -> We have to refine!
00656         integrals.resize(0);
00657         return;
00658       }
00659 
00660       // Array for values of basis functions at inner integration points
00661       Array<double> innerIntegrals(integrals.size());
00662       for (int i = 0; i < innerIntegrals.size(); i++)
00663         innerIntegrals[i] = 0.0;
00664 
00665       // We follow one of the rays (in reference coordinates)
00666       for (int rayPos = 0; rayPos < nrInnerQuadPts; rayPos++)
00667       {
00668         Point q = xref + mu * innerQuadPts[rayPos] * rayref;
00669 
00670         // Evaluate all basis functions at quadrature point
00671         Array<double> funcVals;
00672         evaluateAllBasisFunctions(TriangleCell, q, funcVals);
00673 
00674         // Do quadrature for all basis functions
00675         for (int i = 0; i < funcVals.size(); i++)
00676           innerIntegrals[i] += funcVals[i] * innerQuadWgts[rayPos]
00677               * innerQuadPts[rayPos];
00678       }
00679       for (int j = 0; j < integrals.size(); j++)
00680         integrals[j] += innerQuadWgts[edgePos] * mu * mu
00681             * innerIntegrals[j];
00682     }
00683 
00684     // We calculated on parts of the triangle -> Scale to right size
00685     double det = ::fabs(vec1ref[0] * vec2ref[1] - vec2ref[0] * vec1ref[1]);
00686     for (int j = 0; j < integrals.size(); j++)
00687       integrals[j] *= det;
00688   } break;
00689 
00690   case QuadCell:
00691   {
00692     // Prepare output array
00693     integrals.resize((order() + 1) * (order() + 1));
00694     for (int i = 0; i < integrals.size(); i++)
00695       integrals[i] = 0.0;
00696     SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::integrateRegion: Initializing quadrature on a QuadCell")
00697 
00698     // Get 'inner' integration points (along a line)
00699     int nrInnerQuadPts = innerOrder + 3;
00700     nrInnerQuadPts = (nrInnerQuadPts + nrInnerQuadPts % 2) / 2;
00701     GaussLobatto1D innerQuad(nrInnerQuadPts, 0.0, 1.0);
00702 
00703     Array<double> innerQuadPts(nrInnerQuadPts);
00704     Array<double> innerQuadWgts(nrInnerQuadPts);
00705     innerQuadPts = innerQuad.nodes();
00706     innerQuadWgts = innerQuad.weights();
00707 
00708     // We assume: no intersection along first axis
00709     for (int xPos = 0; xPos < nrInnerQuadPts; xPos++)
00710     {
00711       // Direction of current integration
00712       Point x_cur = x + innerQuadPts[xPos] * vec1;
00713       Point x_curref = xref + innerQuadPts[xPos] * vec1ref;
00714 
00715       SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::integrateRegion: Integrating at xPos " << xPos << " Ref point " << x_curref)
00716 
00717       // Intersection along second axis?
00718       int nrIntersect = 0;
00719       Array<double> t;
00720       Point x_curEnd = x_cur + vec2;
00721       curve.returnIntersect(x_cur, x_curEnd, nrIntersect, t);
00722       SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::integrateRegion: Nr. of intersections along y: " << t.size())
00723 
00724       double mu = 1.0; // w/o an intersection we integrate the whole line
00725       if (nrIntersect == 1)
00726       {
00727         mu = t[0];
00728         SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::integrateRegion: Intersection parameter is " << mu)
00729       }
00730       else if (nrIntersect >= 2)
00731       {
00732         // More than one intersection -> We have to refine!
00733         integrals.resize(0);
00734         SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::integrateRegion: More than one intersection -> Abort!")
00735 
00736         return;
00737       }
00738 
00739       // Array for values of basis functions at inner integration points
00740       Array<double> innerIntegrals(integrals.size());
00741       for (int jj = 0; jj < innerIntegrals.size(); jj++)
00742         innerIntegrals[jj] = 0.0;
00743 
00744       for (int yPos = 0; yPos < nrInnerQuadPts; yPos++)
00745       {
00746         Point y_curref = x_curref + mu * innerQuadPts[yPos] * vec2ref;
00747         SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::integrateRegion: Integrating at yPos " << yPos << " Ref point " << y_curref)
00748 
00749         // Evaluate all basis functions at quadrature point
00750         Array<double> funcVals;
00751         evaluateAllBasisFunctions(QuadCell, y_curref, funcVals);
00752 
00753         // Do quadrature for all basis functions
00754         for (int jj = 0; jj < funcVals.size(); jj++)
00755           innerIntegrals[jj] += funcVals[jj] * innerQuadWgts[yPos] * mu;
00756       }
00757       for (int ii = 0; ii < integrals.size(); ii++)
00758         integrals[ii] += innerQuadWgts[xPos] * innerIntegrals[ii];
00759     }
00760 
00761     // Scale to right size
00762     double det = ::fabs(vec1ref[0] * vec2ref[1] - vec2ref[0] * vec1ref[1]);
00763     for (int i = 0; i < integrals.size(); i++)
00764       integrals[i] *= det;
00765     SUNDANCE_MSG3(verb, tabs << "FeketeQuadrature::integrateRegion: Integration of region finished. Integral values " << integrals)
00766   } break;
00767 
00768   default:
00769 #ifndef TRILINOS_7
00770     SUNDANCE_ERROR("FeketeQuadrature::integrateRegion() not available for cell type " << cellType)
00771     ;
00772 #else
00773     SUNDANCE_ERROR7("FeketeQuadrature::integrateRegion() not available for cell type " << cellType);
00774 #endif
00775   }
00776 
00777 }
00778 
00779 void FeketeQuadrature::evaluateAllBasisFunctions(const CellType cellType,
00780     const Point& q, Array<double>& result) const
00781 {
00782 
00783   switch (cellType)
00784   {
00785   case TriangleCell:
00786   {
00787     // Coefficients in _basisCoeffs together with PKD polynomials form
00788     // a Lagrange basis at Fekete points
00789     if (!_hasBasisCoeffs)
00790     {
00791       FeketeTriangleQuadrature::computeBasisCoeffs(order(), _basisCoeffs);
00792       _hasBasisCoeffs = true;
00793     }
00794 
00795     // KL added explicit cast of sqrt argument to double to allow
00796     // compilation on windows.
00797     // One has nFeketePts basis functions
00798     int nFeketePts = sqrt((double) _basisCoeffs.size());
00799     result.resize(nFeketePts);
00800 
00801     // Determine values of all PKD polynomials at evaluation point q
00802     Array<double> pkdVals(nFeketePts);
00803     FeketeTriangleQuadrature::evalPKDpolynomials(order(), q[0], q[1],
00804         &(pkdVals[0]));
00805 
00806     // For each Lagrange basis function, sum up weighted PKD polynomials
00807     // (The weights are found in _basisCoeffs)
00808     char trans = 'N';
00809     double alpha = 1.;
00810     double beta = 0.;
00811     int inc = 1;
00812     ::dgemv_(&trans, &nFeketePts, &nFeketePts, &alpha, &(_basisCoeffs[0]),
00813         &nFeketePts, &(pkdVals[0]), &inc, &beta, &(result[0]), &inc);
00814     break;
00815   }
00816   case QuadCell:
00817   {
00818     // Coefficients in _basisCoeffs form a Lagrange basis at Fekete points
00819     if (!_hasBasisCoeffs)
00820     {
00821       FeketeQuadQuadrature::computeBasisCoeffs(order(), _basisCoeffs);
00822       _hasBasisCoeffs = true;
00823     }
00824 
00825     // KL added explicit cast of sqrt argument to double to allow
00826     // compilation on windows.
00827     // One has nFeketePts basis functions
00828     int nFeketePts = sqrt((double) _basisCoeffs.size());
00829     result.resize(nFeketePts);
00830 
00831     // Determine values of all polynomials at evaluation point q
00832     Array<double> polVals(nFeketePts);
00833     FeketeQuadQuadrature::evalPolynomials(nFeketePts, q[0], q[1],
00834         &(polVals[0]));
00835 
00836     // For each Lagrange basis function, sum up weighted polynomials
00837     // (The weights are found in _basisCoeffs)
00838     char trans = 'N';
00839     double alpha = 1.;
00840     double beta = 0.;
00841     int inc = 1;
00842     ::dgemv_(&trans, &nFeketePts, &nFeketePts, &alpha, &(_basisCoeffs[0]),
00843         &nFeketePts, &(polVals[0]), &inc, &beta, &(result[0]), &inc);
00844     break;
00845   }
00846   default:
00847 #ifndef TRILINOS_7
00848     SUNDANCE_ERROR("FeketeQuadrature::evaluateAllBasisFunctions() not available for cell type " << cellType)
00849     ;
00850 #else
00851     SUNDANCE_ERROR7("FeketeQuadrature::evaluateAllBasisFunctions() not available for cell type " << cellType);
00852 #endif
00853   }
00854 }

Site Contact