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
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "SundanceCubicHermite.hpp"
00043 #include "SundanceADReal.hpp"
00044 #include "PlayaExceptions.hpp"
00045 #include "SundanceSpatialDerivSpecifier.hpp"
00046 #include "SundancePoint.hpp"
00047 #include "SundanceObjectWithVerbosity.hpp"
00048 #include "SundanceOut.hpp"
00049
00050 using namespace Sundance;
00051 using namespace Teuchos;
00052
00053
00054
00055 bool CubicHermite::supportsCellTypePair(
00056 const CellType& maximalCellType,
00057 const CellType& cellType
00058 ) const
00059 {
00060 switch(maximalCellType)
00061 {
00062 case LineCell:
00063 switch(cellType)
00064 {
00065 case LineCell:
00066 case PointCell:
00067 return true;
00068 default:
00069 return false;
00070 }
00071 case TriangleCell:
00072 switch(cellType)
00073 {
00074 case TriangleCell:
00075 case LineCell:
00076 case PointCell:
00077 return true;
00078 default:
00079 return false;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 default:
00093 return false;
00094 }
00095 }
00096
00097 void CubicHermite::print(std::ostream& os) const
00098 {
00099 os << "CubicHermite";
00100 }
00101
00102 int CubicHermite::nReferenceDOFsWithoutFacets(
00103 const CellType& maximalCellType,
00104 const CellType& cellType
00105 ) const
00106 {
00107 switch(maximalCellType)
00108 {
00109 case LineCell:
00110 switch(cellType)
00111 {
00112 case PointCell:
00113 return 2;
00114 case LineCell:
00115 return 0;
00116 default:
00117 TEUCHOS_TEST_FOR_EXCEPTION( true , std::invalid_argument , "illegal combination of cell type and maximal cell type" );
00118 return -1;
00119 }
00120 break;
00121 case TriangleCell:
00122 switch(cellType)
00123 {
00124 case PointCell:
00125 return 3;
00126 case LineCell:
00127 return 0;
00128 case TriangleCell:
00129 return 1;
00130 default:
00131 TEUCHOS_TEST_FOR_EXCEPTION( true , std::invalid_argument , "illegal combination of cell type and maximal cell type" );
00132 return -1;
00133 }
00134 break;
00135 default:
00136 TEUCHOS_TEST_FOR_EXCEPTION( true , std::invalid_argument , "illegal combination of cell type and maximal cell type" );
00137 return -1;
00138 }
00139
00140 }
00141
00142 void CubicHermite::getReferenceDOFs(
00143 const CellType& maximalCellType,
00144 const CellType& cellType,
00145 Array<Array<Array<int> > >& dofs) const
00146 {
00147 typedef Array<int> Aint;
00148 switch(cellType)
00149 {
00150 case PointCell:
00151 {
00152 dofs.resize(1);
00153 if (maximalCellType==LineCell)
00154 dofs[0] = tuple<Aint>(tuple(0,1));
00155 else if (maximalCellType==TriangleCell)
00156 dofs[0] = tuple<Aint>(tuple(0,1,2));
00157 else TEUCHOS_TEST_FOR_EXCEPT(1);
00158 return;
00159 }
00160 break;
00161 case LineCell:
00162 {
00163 dofs.resize(2);
00164 dofs[0].resize(2);
00165 if (maximalCellType==LineCell)
00166 {
00167 dofs[0][0].resize(2);
00168 dofs[0][0][0] = 0;
00169 dofs[0][0][1] = 1;
00170 dofs[0][1].resize(2);
00171 dofs[0][1][0] = 2;
00172 dofs[0][1][1] = 3;
00173 }
00174 else if (maximalCellType==TriangleCell)
00175 {
00176 dofs[0][0].resize(3);
00177 dofs[0][0][0] = 0;
00178 dofs[0][0][1] = 1;
00179 dofs[0][0][2] = 2;
00180 dofs[0][1].resize(3);
00181 dofs[0][1][0] = 3;
00182 dofs[0][1][1] = 4;
00183 dofs[0][1][1] = 5;
00184 }
00185 else
00186 {
00187 TEUCHOS_TEST_FOR_EXCEPT(1);
00188 }
00189 dofs[1].resize(1);
00190 dofs[1][0].resize(0);
00191 return;
00192 }
00193 break;
00194 case TriangleCell:
00195 {
00196 dofs.resize(3);
00197 dofs[0].resize(3);
00198 dofs[0][0] = tuple(0,1,2);
00199 dofs[0][1] = tuple(3,4,5);
00200 dofs[0][2] = tuple(6,7,8);
00201 dofs[1].resize(3);
00202 dofs[1][0].resize(0);
00203 dofs[1][1].resize(0);
00204 dofs[1][2].resize(0);
00205 dofs[2].resize(1);
00206 dofs[2][0].resize(1);
00207 dofs[2][0][0] = 9;
00208 }
00209 break;
00210 default:
00211 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "Cell type "
00212 << cellType << " not implemented in CubicHermite basis");
00213 }
00214 }
00215
00216
00217 void CubicHermite::refEval(
00218 const CellType& cellType,
00219 const Array<Point>& pts,
00220 const SpatialDerivSpecifier& sds,
00221 Array<Array<Array<double> > >& result,
00222 int verbosity) const
00223 {
00224 TEUCHOS_TEST_FOR_EXCEPTION(!(sds.isPartial() || sds.isIdentity()),
00225 std::runtime_error,
00226 "cannot evaluate spatial derivative " << sds << " on CubicHermite basis");
00227 const MultiIndex& deriv = sds.mi();
00228 typedef Array<double> Adouble;
00229 result.resize(1);
00230 result[0].resize(pts.length());
00231
00232 switch(cellType)
00233 {
00234 case PointCell:
00235 result[0] = tuple<Adouble>(tuple(1.0));
00236 return;
00237 case LineCell:
00238 for (int i=0; i<pts.length(); i++)
00239 {
00240 evalOnLine(pts[i], deriv, result[0][i]);
00241 }
00242 return;
00243 case TriangleCell:
00244 for (int i=0; i<pts.length(); i++)
00245 {
00246 evalOnTriangle(pts[i], deriv, result[0][i]);
00247 }
00248 return;
00249 default:
00250 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
00251 "CubicHermite::refEval() unimplemented for cell type "
00252 << cellType);
00253
00254 }
00255 }
00256
00257
00258
00259 void CubicHermite::evalOnLine(const Point& pt,
00260 const MultiIndex& deriv,
00261 Array<double>& result) const
00262 {
00263 result.resize(4);
00264 ADReal x = ADReal(pt[0],0,1);
00265 Array<ADReal> tmp(4);
00266
00267 tmp[0] = 1 + x * x * ( -3 + 2 * x );
00268 tmp[1] = x * ( 1 + (x - 2 ) * x );
00269 tmp[2] = ( 3 - 2*x ) * x * x;
00270 tmp[3] = (-1+x)*x*x;
00271
00272 for (int i=0; i<tmp.length(); i++)
00273 {
00274 if (deriv.order()==0)
00275 {
00276 result[i] = tmp[i].value();
00277 }
00278 else
00279 {
00280 result[i] = tmp[i].gradient()[0];
00281 }
00282 }
00283 return;
00284 }
00285
00286 void CubicHermite::evalOnTriangle(const Point& pt,
00287 const MultiIndex& deriv,
00288 Array<double>& result) const
00289
00290 {
00291 result.resize(10);
00292 ADReal x = ADReal(pt[0], 0, 2);
00293 ADReal y = ADReal(pt[1], 1, 2);
00294 ADReal one(1.0, 2);
00295
00296 Array<ADReal> tmp(10);
00297
00298 SUNDANCE_OUT(this->verb() > 3, "x=" << x.value() << " y="
00299 << y.value());
00300
00301 tmp[0] = 1 - 3*x*x + 2 * x*x*x - 13*x*y + 13*x*x*y - 3*y*y + 13 *x*y*y + 2 *y*y*y;
00302 tmp[1] = x - 2 *x*x + x*x*x - 3*x*y + 3*x*x*y + 2*x*y*y;
00303 tmp[2] = y - 3 *x *y + 2* x*x* y - 2* y*y + 3* x*y*y + y*y*y;
00304 tmp[3] = 3 * x*x - 2* x*x*x - 7* x* y + 7* x*x *y + 7* x*y*y;
00305 tmp[4] = -x*x + x*x*x + 2*x *y - 2* x*x* y - 2* x* y*y;
00306 tmp[5] = -x* y + 2* x*x* y + x* y*y;
00307 tmp[6] = -7* x* y + 7* x*x*y + 3* y*y + 7* x* y*y - 2* y*y*y;
00308 tmp[7] = -x *y + x*x* y + 2* x* y*y;
00309 tmp[8] = 2 *x *y - 2* x*x* y - y*y - 2* x* y*y + y*y*y;
00310 tmp[9] = 27* x *y - 27* x*x* y - 27* x* y*y;
00311
00312 for (int i=0; i<tmp.length(); i++)
00313 {
00314 if (deriv.order()==0) result[i] = tmp[i].value();
00315 else
00316 result[i] = tmp[i].gradient()[deriv.firstOrderDirection()];
00317 }
00318 }
00319
00320 void CubicHermite::evalOnTet(const Point& pt,
00321 const MultiIndex& deriv,
00322 Array<double>& result) const
00323 {
00324 ADReal x = ADReal(pt[0], 0, 3);
00325 ADReal y = ADReal(pt[1], 1, 3);
00326 ADReal z = ADReal(pt[2], 2, 3);
00327 ADReal one(1.0, 3);
00328
00329 TEUCHOS_TEST_FOR_EXCEPT(true);
00330 }
00331
00332 void CubicHermite::preApplyTransformation( const CellType &maxCellType ,
00333 const Mesh &mesh,
00334 const Array<int> &cellLIDs,
00335 const CellJacobianBatch& JVol,
00336 RCP<Array<double> >& A ) const
00337 {
00338 switch(maxCellType)
00339 {
00340 case TriangleCell:
00341 preApplyTransformationTriangle( mesh , cellLIDs, JVol , A );
00342 break;
00343 default:
00344 TEUCHOS_TEST_FOR_EXCEPT(1);
00345 break;
00346 }
00347 return;
00348 }
00349
00350 void CubicHermite::postApplyTransformation( const CellType &maxCellType ,
00351 const Mesh &mesh,
00352 const Array<int> &cellLIDs,
00353 const CellJacobianBatch& JVol,
00354 RCP<Array<double> >& A ) const
00355 {
00356 switch(maxCellType)
00357 {
00358 case TriangleCell:
00359 postApplyTransformationTriangle( mesh , cellLIDs, JVol , A );
00360 break;
00361 default:
00362 TEUCHOS_TEST_FOR_EXCEPT(1);
00363 break;
00364 }
00365 return;
00366 }
00367
00368 void CubicHermite::preApplyTransformationTranspose( const CellType &maxCellType ,
00369 const Mesh &mesh,
00370 const Array<int> &cellLIDs,
00371 const CellJacobianBatch& JVol ,
00372 Array<double> & A ) const
00373 {
00374 switch(maxCellType)
00375 {
00376 case TriangleCell:
00377 preApplyTransformationTransposeTriangle( mesh , cellLIDs, JVol , A );
00378 break;
00379 default:
00380 TEUCHOS_TEST_FOR_EXCEPT(1);
00381 break;
00382 }
00383 return;
00384 }
00385
00386
00387 void CubicHermite::preApplyTransformationTriangle( const Mesh &mesh,
00388 const Array<int> &cellLIDs,
00389 const CellJacobianBatch& JVol,
00390 RCP<Array<double> >& A) const
00391 {
00392 Array<double> &Anoptr = *A;
00393
00394 Array<double> cellVertH;
00395 getVertexH( mesh , cellLIDs , cellVertH );
00396
00397
00398
00399
00400
00401 const int numCols = Anoptr.size() / JVol.numCells() / 10;
00402
00403 for (int i=0;i<JVol.numCells();i++)
00404 {
00405 const int cell_start = i * numCols * 10;
00406 const double *invJ = JVol.jVals(i);
00407
00408 for (int j=0;j<numCols;j++)
00409 {
00410 const int col_start = cell_start + 10 * j;
00411 const double a1 = Anoptr[col_start + 1];
00412 const double a2 = Anoptr[col_start + 2];
00413 const double a4 = Anoptr[col_start + 4];
00414 const double a5 = Anoptr[col_start + 5];
00415 const double a7 = Anoptr[col_start + 7];
00416 const double a8 = Anoptr[col_start + 8];
00417 Anoptr[col_start+1] = (invJ[0]*a1 + invJ[1]*a2)/cellVertH[3*i];
00418 Anoptr[col_start+2] = (invJ[2]*a1 + invJ[3]*a2)/cellVertH[3*i];
00419 Anoptr[col_start+4] = (invJ[0]*a4 + invJ[1]*a5)/cellVertH[3*i+1];
00420 Anoptr[col_start+5] = (invJ[2]*a4 + invJ[3]*a5)/cellVertH[3*i+1];
00421 Anoptr[col_start+7] = (invJ[0]*a7 + invJ[1]*a8)/cellVertH[3*i+2];
00422 Anoptr[col_start+8] = (invJ[2]*a7 + invJ[3]*a8)/cellVertH[3*i+2];
00423 }
00424 }
00425
00426 }
00427
00428 void CubicHermite::postApplyTransformationTriangle( const Mesh &mesh,
00429 const Array<int> &cellLIDs ,
00430 const CellJacobianBatch& JVol,
00431 RCP<Array<double> >& A ) const
00432 {
00433 Array<double> &Anoptr = *A;
00434
00435 Array<double> cellVertH;
00436 getVertexH( mesh , cellLIDs , cellVertH );
00437
00438
00439 const int numRows = Anoptr.size() / 10 / JVol.numCells();
00440
00441 for (int i=0;i<JVol.numCells();i++)
00442 {
00443 const double *invJ = JVol.jVals(i);
00444
00445 const int cell_start = i * numRows * 10;
00446
00447 for (int j=0;j<numRows;j++)
00448 {
00449 const double a = Anoptr[cell_start + numRows + j];
00450 const double b = Anoptr[cell_start + 2*numRows + j];
00451 Anoptr[cell_start + numRows + j] = (invJ[0] * a + invJ[1] * b)/cellVertH[3*i];
00452 Anoptr[cell_start + 2*numRows + j] = (invJ[2] * a + invJ[3] * b)/cellVertH[3*i];
00453 }
00454
00455
00456 for (int j=0;j<numRows;j++)
00457 {
00458 const double a = Anoptr[cell_start + 4*numRows + j];
00459 const double b = Anoptr[cell_start + 5*numRows + j];
00460 Anoptr[cell_start + 4*numRows + j] = (invJ[0] * a + invJ[1] * b)/cellVertH[3*i+1];
00461 Anoptr[cell_start + 5*numRows + j] = (invJ[2] * a + invJ[3] * b)/cellVertH[3*i+1];
00462 }
00463
00464
00465 for (int j=0;j<numRows;j++)
00466 {
00467 const double a = Anoptr[cell_start + 7*numRows + j];
00468 const double b = Anoptr[cell_start + 8*numRows + j];
00469 Anoptr[cell_start + 7*numRows + j] = (invJ[0] * a + invJ[1] * b)/cellVertH[3*i+2];
00470 Anoptr[cell_start + 8*numRows + j] = (invJ[2] * a + invJ[3] * b)/cellVertH[3*i+2];
00471 }
00472
00473 }
00474
00475 return;
00476 }
00477
00478 void CubicHermite::preApplyTransformationTransposeTriangle( const Mesh &mesh,
00479 const Array<int> &cellLIDs,
00480 const CellJacobianBatch& JVol,
00481 Array<double>& A ) const
00482 {
00483
00484
00485
00486 const int numCols = A.size() / JVol.numCells() / 10;
00487
00488
00489 Array<double> cellVertH;
00490 getVertexH( mesh , cellLIDs , cellVertH );
00491
00492 for (int i=0;i<JVol.numCells();i++)
00493 {
00494 const int cell_start = i * numCols * 10;
00495 const double *invJ = JVol.jVals(i);
00496
00497 for (int j=0;j<numCols;j++)
00498 {
00499 const int col_start = cell_start + 10 * j;
00500 const double a1 = A[col_start + 1];
00501 const double a2 = A[col_start + 2];
00502 const double a4 = A[col_start + 4];
00503 const double a5 = A[col_start + 5];
00504 const double a7 = A[col_start + 7];
00505 const double a8 = A[col_start + 8];
00506 A[col_start+1] = (invJ[0]*a1 + invJ[2]*a2)/cellVertH[3*i];
00507 A[col_start+2] = (invJ[1]*a1 + invJ[3]*a2)/cellVertH[3*i];
00508 A[col_start+4] = (invJ[0]*a4 + invJ[2]*a5)/cellVertH[3*i+1];
00509 A[col_start+5] = (invJ[1]*a4 + invJ[3]*a5)/cellVertH[3*i+1];
00510 A[col_start+7] = (invJ[0]*a7 + invJ[2]*a8)/cellVertH[3*i+2];
00511 A[col_start+8] = (invJ[1]*a7 + invJ[3]*a8)/cellVertH[3*i+2];
00512 }
00513 }
00514
00515 }
00516
00517
00518
00519 void CubicHermite::getVertexH( const Mesh &mesh,
00520 const Array<int> &cellLIDs ,
00521 Array<double> &cellVertexH ) const
00522 {
00523 cellVertexH.resize(3*cellLIDs.size());
00524 const int N = mesh.numCells(2);
00525 const double h = 1.0 / sqrtl( N );
00526 for (int i=0;i<cellVertexH.size();i++)
00527 {
00528 cellVertexH[i] = h;
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 return;
00587
00588 }