00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
00043 extern "C"
00044 {
00045
00046 void dgetrf_(const int* M, const int* N, double* A, const int* lda,
00047 const int* iPiv, int* info);
00048
00049
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
00147 weightsChanged = false;
00148
00149
00150 if (cellType != TriangleCell)
00151 return;
00152
00153
00154 Array<int> cellLIDs(1);
00155 cellLIDs[0] = cellLID;
00156
00157
00158
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
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
00179 if (nr_ip01 + nr_ip02 + nr_ip12 == 0)
00180 {
00181
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
00195
00196 weightsChanged = true;
00197 std::cout << "Geschnitten!" << std::endl;
00198
00199 int nTris = 1;
00200
00201
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
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
00220 ++nTris;
00221
00222 std::cout << "PunkteStack " << s.size() << " AreaStack " << sa.size()
00223 << std::endl;
00224
00225
00226 bool refine = false;
00227 Array<double> results1(originalWeights.size());
00228 Array<double> results2(originalWeights.size());
00229
00230
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
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
00246
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
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
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
00316
00317 if (refine)
00318 {
00319
00320
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
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 }
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
00383 integrals.resize((order() + 1) * (order() + 2) / 2);
00384 for (int i = 0; i < integrals.size(); i++)
00385 integrals[i] = 0.0;
00386
00387
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
00400 for (int edgePos = 0; edgePos < nrInnerQuadPts; edgePos++)
00401 {
00402
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
00409 int nrIntersect = 0;
00410 Array<double> t;
00411 Point rayEnd = x + ray;
00412 curve.returnIntersect(x, rayEnd, nrIntersect, t);
00413
00414
00415 double mu = 1.0;
00416 if (nrIntersect == 1)
00417 {
00418 mu = t[0];
00419 }
00420 else if (nrIntersect >= 2)
00421 {
00422
00423 std::cout << "Problem: Mehr als ein Schnittpunkt mit Strahl "
00424 << " fuer edgePos " << edgePos << std::endl;
00425 mu = t[1];
00426 }
00427
00428
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
00441 Array<double> funcVals;
00442 evaluateAllBasisFunctions(q[rayPos], funcVals);
00443
00444
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
00462
00463 if (!_hasBasisCoeffs)
00464 computeBasisCoeffs();
00465
00466
00467 int nFeketePts = sqrt(_basisCoeffs.size());
00468 result.resize(nFeketePts);
00469
00470
00471 Array<double> pkdVals;
00472 pkdVals.resize(nFeketePts);
00473 FeketeTriangleQuadrature::evalPKDpolynomials(order(), q[0], q[1],
00474 &(pkdVals[0]));
00475
00476
00477
00478 for (int m = 0; m < nFeketePts; m++)
00479 {
00480
00481 for (int n = 0; n < nFeketePts; n++)
00482 {
00483
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
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
00507
00508
00509 _basisCoeffs.resize(nFeketePts * nFeketePts);
00510
00511
00512
00513 for (int n = 0; n < nFeketePts; n++)
00514 {
00515
00516
00517 double* start = &(_basisCoeffs[n * nFeketePts]);
00518 FeketeTriangleQuadrature::evalPKDpolynomials(order(), feketePts[n][0],
00519 feketePts[n][1], start);
00520 }
00521
00522
00523
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
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
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
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 }