00001
00002
00003
00004
00005
00006
00007 #include "Teuchos_TestForException.hpp"
00008 #include "Phalanx_DataLayout.hpp"
00009
00010 #include "Intrepid_FunctionSpaceTools.hpp"
00011
00012
00013
00014 namespace Aeras {
00015
00016
00017
00018 template<typename EvalT, typename Traits>
00019 ComputeBasisFunctions<EvalT, Traits>::
00020 ComputeBasisFunctions(const Teuchos::ParameterList& p,
00021 const Teuchos::RCP<Albany::Layouts>& dl) :
00022 coordVec (p.get<std::string> ("Coordinate Vector Name"), dl->node_3vector ),
00023 cubature (p.get<Teuchos::RCP <Intrepid::Cubature<RealType> > >("Cubature")),
00024 intrepidBasis (p.get<Teuchos::RCP<Intrepid::Basis<RealType, Intrepid::FieldContainer<RealType> > > > ("Intrepid Basis") ),
00025 cellType (p.get<Teuchos::RCP <shards::CellTopology> > ("Cell Type")),
00026 weighted_measure (p.get<std::string> ("Weights Name"), dl->qp_scalar ),
00027 sphere_coord (p.get<std::string> ("Spherical Coord Name"), dl->qp_gradient ),
00028 jacobian_inv (p.get<std::string> ("Jacobian Inv Name"), dl->qp_tensor ),
00029 jacobian_det (p.get<std::string> ("Jacobian Det Name"), dl->qp_scalar ),
00030 BF (p.get<std::string> ("BF Name"), dl->node_qp_scalar),
00031 wBF (p.get<std::string> ("Weighted BF Name"), dl->node_qp_scalar),
00032 GradBF (p.get<std::string> ("Gradient BF Name"), dl->node_qp_gradient),
00033 wGradBF (p.get<std::string> ("Weighted Gradient BF Name"), dl->node_qp_gradient),
00034 jacobian (p.get<std::string> ("Jacobian Name"), dl->qp_tensor )
00035 {
00036 this->addDependentField(coordVec);
00037 this->addEvaluatedField(weighted_measure);
00038 this->addEvaluatedField(sphere_coord);
00039 this->addEvaluatedField(jacobian_det);
00040 this->addEvaluatedField(jacobian_inv);
00041 this->addEvaluatedField(jacobian);
00042 this->addEvaluatedField(BF);
00043 this->addEvaluatedField(wBF);
00044 this->addEvaluatedField(GradBF);
00045 this->addEvaluatedField(wGradBF);
00046
00047
00048 std::vector<PHX::DataLayout::size_type> dim;
00049 dl->node_qp_gradient->dimensions(dim);
00050
00051 const int containerSize = dim[0];
00052 numNodes = dim[1];
00053 numQPs = dim[2];
00054 const int basisDims = 2;
00055
00056
00057
00058 val_at_cub_points .resize (numNodes, numQPs);
00059 grad_at_cub_points.resize (numNodes, numQPs, basisDims);
00060 refPoints .resize (numQPs, basisDims);
00061 refWeights .resize (numQPs);
00062
00063
00064 cubature->getCubature(refPoints, refWeights);
00065 intrepidBasis->getValues(val_at_cub_points, refPoints, Intrepid::OPERATOR_VALUE);
00066 intrepidBasis->getValues(grad_at_cub_points, refPoints, Intrepid::OPERATOR_GRAD);
00067
00068 this->setName("Aeras::ComputeBasisFunctions"+PHX::TypeString<EvalT>::value);
00069 }
00070
00071
00072 template<typename EvalT, typename Traits>
00073 void ComputeBasisFunctions<EvalT, Traits>::
00074 postRegistrationSetup(typename Traits::SetupData d,
00075 PHX::FieldManager<Traits>& fm)
00076 {
00077 this->utils.setFieldData(coordVec,fm);
00078 this->utils.setFieldData(weighted_measure,fm);
00079 this->utils.setFieldData(sphere_coord,fm);
00080 this->utils.setFieldData(jacobian_det,fm);
00081 this->utils.setFieldData(jacobian_inv,fm);
00082 this->utils.setFieldData(jacobian,fm);
00083 this->utils.setFieldData(BF,fm);
00084 this->utils.setFieldData(wBF,fm);
00085 this->utils.setFieldData(GradBF,fm);
00086 this->utils.setFieldData(wGradBF,fm);
00087 }
00088
00089
00090 template<typename EvalT, typename Traits>
00091 void ComputeBasisFunctions<EvalT, Traits>::
00092 evaluateFields(typename Traits::EvalData workset)
00093 {
00094
00103 const int numelements = coordVec.dimension(0);
00104 const int spatialDim = coordVec.dimension(2);
00105 const int basisDim = 2;
00106
00107
00108
00109
00110 if (spatialDim==basisDim) {
00111 Intrepid::CellTools<RealType>::setJacobian(jacobian, refPoints, coordVec, *cellType);
00112
00113 } else {
00114 Intrepid::FieldContainer<MeshScalarT> phi(numQPs,spatialDim);
00115 Intrepid::FieldContainer<MeshScalarT> dphi(numQPs,spatialDim,basisDim);
00116 Intrepid::FieldContainer<MeshScalarT> norm(numQPs);
00117 Intrepid::FieldContainer<MeshScalarT> sinL(numQPs);
00118 Intrepid::FieldContainer<MeshScalarT> cosL(numQPs);
00119 Intrepid::FieldContainer<MeshScalarT> sinT(numQPs);
00120 Intrepid::FieldContainer<MeshScalarT> cosT(numQPs);
00121 Intrepid::FieldContainer<MeshScalarT> D1(numQPs,basisDim,spatialDim);
00122 Intrepid::FieldContainer<MeshScalarT> D2(numQPs,spatialDim,spatialDim);
00123 Intrepid::FieldContainer<MeshScalarT> D3(numQPs,basisDim,spatialDim);
00124
00125
00126
00127
00128
00129
00130
00131 for (int e = 0; e<numelements; ++e) {
00132 phi.initialize();
00133 dphi.initialize();
00134 norm.initialize();
00135 sinL.initialize();
00136 cosL.initialize();
00137 sinT.initialize();
00138 cosT.initialize();
00139 D1.initialize();
00140 D2.initialize();
00141 D3.initialize();
00142
00143 for (int q = 0; q<numQPs; ++q)
00144 for (int b1= 0; b1<basisDim; ++b1)
00145 for (int b2= 0; b2<basisDim; ++b2)
00146 for (int d = 0; d<spatialDim;++d)
00147 jacobian(e,q,b1,b2) = 0;
00148
00149 for (int q = 0; q<numQPs; ++q)
00150 for (int d = 0; d<spatialDim; ++d)
00151 for (int v = 0; v<numNodes; ++v)
00152 phi(q,d) += coordVec(e,v,d) * val_at_cub_points(v,q);
00153
00154 for (int v = 0; v<numNodes; ++v)
00155 for (int q = 0; q<numQPs; ++q)
00156 for (int d = 0; d<spatialDim; ++d)
00157 for (int b = 0; b<basisDim; ++b)
00158 dphi(q,d,b) += coordVec(e,v,d) * grad_at_cub_points(v,q,b);
00159
00160 for (int q = 0; q<numQPs; ++q)
00161 for (int d = 0; d<spatialDim; ++d)
00162 norm(q) += phi(q,d)*phi(q,d);
00163
00164 for (int q = 0; q<numQPs; ++q)
00165 norm(q) = std::sqrt(norm(q));
00166
00167 for (int q = 0; q<numQPs; ++q)
00168 for (int d = 0; d<spatialDim; ++d)
00169 phi(q,d) /= norm(q);
00170
00171 for (int q = 0; q<numQPs; ++q) {
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 static const double pi = 3.1415926535897932385;
00185 static const double DIST_THRESHOLD = 1.0e-9;
00186 const MeshScalarT latitude = std::asin(phi(q,2));
00187
00188 MeshScalarT longitude = std::atan2(phi(q,1),phi(q,0));
00189 if (std::abs(std::abs(latitude)-pi/2) < DIST_THRESHOLD) longitude = 0;
00190 else if (longitude < 0) longitude += 2*pi;
00191
00192
00193 sphere_coord(e,q,0) = longitude;
00194 sphere_coord(e,q,1) = latitude;
00195
00196 sinT(q) = std::sin(latitude);
00197 cosT(q) = std::cos(latitude);
00198 sinL(q) = std::sin(longitude);
00199 cosL(q) = std::sin(longitude);
00200 }
00201
00202 for (int q = 0; q<numQPs; ++q) {
00203 D1(q,0,0) = -sinL(q);
00204 D1(q,0,1) = cosL(q);
00205 D1(q,1,2) = 1;
00206 }
00207
00208 for (int q = 0; q<numQPs; ++q) {
00209 D2(q,0,0) = sinL(q)*sinL(q)*cosT(q)*cosT(q) + sinT(q)*sinT(q);
00210 D2(q,0,1) = -sinL(q)*cosL(q)*cosT(q)*cosT(q);
00211 D2(q,0,2) = -cosL(q)*sinT(q)*cosT(q);
00212
00213 D2(q,1,0) = -sinL(q)*cosL(q)*cosT(q)*cosT(q);
00214 D2(q,1,1) = cosL(q)*cosL(q)*cosT(q)*cosT(q) + sinT(q)*sinT(q);
00215 D2(q,1,2) = -sinL(q)*sinT(q)*cosT(q);
00216
00217 D2(q,2,0) = -cosL(q)*sinT(q);
00218 D2(q,2,1) = -sinL(q)*sinT(q);
00219 D2(q,2,2) = cosT(q);
00220 }
00221
00222 for (int q = 0; q<numQPs; ++q)
00223 for (int b = 0; b<basisDim; ++b)
00224 for (int d = 0; d<spatialDim; ++d)
00225 for (int j = 0; j<spatialDim;++j)
00226 D3(q,b,d) += D1(q,b,j)*D2(q,j,d);
00227
00228 for (int q = 0; q<numQPs; ++q)
00229 for (int b1= 0; b1<basisDim; ++b1)
00230 for (int b2= 0; b2<basisDim; ++b2)
00231 for (int d = 0; d<spatialDim;++d)
00232 jacobian(e,q,b1,b2) += D3(q,b1,d) * dphi(q,d,b2);
00233
00234 for (int q = 0; q<numQPs; ++q)
00235 for (int b1= 0; b1<basisDim; ++b1)
00236 for (int b2= 0; b2<basisDim; ++b2)
00237 jacobian(e,q,b1,b2) /= norm(q);
00238
00239 }
00240 }
00241
00242 Intrepid::CellTools<MeshScalarT>::setJacobianInv(jacobian_inv, jacobian);
00243
00244 Intrepid::CellTools<MeshScalarT>::setJacobianDet(jacobian_det, jacobian);
00245
00246 for (int e = 0; e<numelements; ++e) {
00247 for (int q = 0; q<numQPs; ++q) {
00248 TEUCHOS_TEST_FOR_EXCEPTION(abs(jacobian_det(e,q))<.0001,
00249 std::logic_error,"Bad Jacobian Found.");
00250 }
00251 }
00252
00253 Intrepid::FunctionSpaceTools::computeCellMeasure<MeshScalarT>
00254 (weighted_measure, jacobian_det, refWeights);
00255
00256 Intrepid::FunctionSpaceTools::HGRADtransformVALUE<RealType>
00257 (BF, val_at_cub_points);
00258 Intrepid::FunctionSpaceTools::multiplyMeasure<MeshScalarT>
00259 (wBF, weighted_measure, BF);
00260 Intrepid::FunctionSpaceTools::HGRADtransformGRAD<MeshScalarT>
00261 (GradBF, jacobian_inv, grad_at_cub_points);
00262 Intrepid::FunctionSpaceTools::multiplyMeasure<MeshScalarT>
00263 (wGradBF, weighted_measure, GradBF);
00264
00265 div_check(spatialDim, numelements);
00266 }
00267
00268
00269
00270 template<typename EvalT, typename Traits>
00271 void ComputeBasisFunctions<EvalT, Traits>::
00272 initialize_grad(Intrepid::FieldContainer<RealType> &grad_at_quadrature_points) const
00273 {
00274 const unsigned N = static_cast<unsigned>(std::floor(std::sqrt(numQPs)+.1));
00275 Intrepid::FieldContainer<RealType> dLdx(N,N); dLdx.initialize();
00276
00277 for (unsigned m=0; m<N; ++m) {
00278 for (unsigned n=0; n<N; ++n) {
00279 for (unsigned i=m?0:1; i<N; (++i==m)?++i:i) {
00280 double prod = 1;
00281 for (unsigned j=0; j<N; ++j) {
00282 if (j!=m && j!=i) prod *= (refPoints(n,0)-refPoints(j,0)) /
00283 (refPoints(m,0)-refPoints(j,0));
00284 }
00285 dLdx(m,n) += prod/(refPoints(m,0)-refPoints(i,0));
00286 }
00287 }
00288 }
00289
00290 for (unsigned m=0; m<numQPs; ++m) {
00291 for (unsigned n=0; n<numQPs; ++n) {
00292 if (m/N == n/N) grad_at_quadrature_points(m,n,0) = dLdx(m%N,n%N);
00293 if (m%N == n%N) grad_at_quadrature_points(m,n,1) = dLdx(m/N,n/N);
00294 }
00295 }
00296 }
00297
00298
00299 template<typename EvalT, typename Traits>
00300 void ComputeBasisFunctions<EvalT, Traits>::
00301 spherical_divergence (Intrepid::FieldContainer<MeshScalarT> &div_v,
00302 const Intrepid::FieldContainer<MeshScalarT> &v_lambda_theta,
00303 const int e,
00304 const double rrearth) const
00305 {
00306 Intrepid::FieldContainer<RealType> grad_at_quadrature_points(numQPs,numQPs,2);
00307 static bool init_grad = true;
00308 if (init_grad) initialize_grad(grad_at_quadrature_points);
00309 init_grad = false;
00310
00311 std::vector<MeshScalarT> jac_weighted_contravarient_x(numQPs);
00312 std::vector<MeshScalarT> jac_weighted_contravarient_y(numQPs);
00313 for (int q = 0; q<numQPs; ++q) {
00314
00315 const MeshScalarT contravarient_x = jacobian_inv(e,q,0,0)*v_lambda_theta(q,0) + jacobian_inv(e,q,0,1)*v_lambda_theta(q,1);
00316 const MeshScalarT contravarient_y = jacobian_inv(e,q,1,0)*v_lambda_theta(q,0) + jacobian_inv(e,q,1,1)*v_lambda_theta(q,1);
00317 jac_weighted_contravarient_x[q] = jacobian_det(e,q) * contravarient_x;
00318 jac_weighted_contravarient_y[q] = jacobian_det(e,q) * contravarient_y;
00319 }
00320
00321 MeshScalarT dv_xi_dxi;
00322 MeshScalarT dv_eta_deta;
00323
00324 for (int q = 0; q<numQPs; ++q) {
00325 for (int v = 0; v<numQPs; ++v) {
00326 dv_xi_dxi += grad_at_quadrature_points(v,q,0)*jac_weighted_contravarient_x[v];
00327 dv_eta_deta += grad_at_quadrature_points(v,q,1)*jac_weighted_contravarient_y[v];
00328 }
00329
00330 const MeshScalarT rjacobian_det = 1/jacobian_det(e,q);
00331 const MeshScalarT div_unit = (dv_xi_dxi + dv_eta_deta)*rjacobian_det;
00332 div_v(q) = div_unit*rrearth;
00333 }
00334 }
00335
00336
00337 template<typename EvalT, typename Traits>
00338 void ComputeBasisFunctions<EvalT, Traits>::
00339 div_check(const int spatialDim, const int numelements) const
00340 {
00341
00342 const static double rearth = 6.376e06;
00343 const static double rrearth = 1;
00344
00345 for (int c = 0; c<2; ++c) {
00346 if (!c && numQPs!=16) continue;
00347 for (int e = 0; e<numelements; ++e) {
00348 static const MeshScalarT DIST_THRESHOLD = 1.0e-6;
00349
00350 Intrepid::FieldContainer<MeshScalarT> phi(numQPs,spatialDim);
00351 phi.initialize();
00352 for (int q = 0; q<numQPs; ++q)
00353 for (int d = 0; d<spatialDim; ++d)
00354 for (int v = 0; v<numNodes; ++v)
00355 phi(q,d) += coordVec(e,v,d) * val_at_cub_points(v,q);
00356
00357 std::vector<MeshScalarT> divergence_v(numQPs);
00358 Intrepid::FieldContainer<MeshScalarT> v_lambda_theta(numQPs,2);
00359 switch (c) {
00360 case 0: {
00361
00362
00363
00364
00365
00366 const static double v[16] =
00367 {7473.7470865518399, 7665.3190370095717, 7918.441032072672, 8041.3357610390449,
00368 7665.3190370095717, 7854.2794792071199, 8093.0041509498678, 8201.3952993149032,
00369 7918.4410320726756, 8093.0041509498706, 8289.0810252631491, 8360.5202251186929,
00370 8041.3357610390449, 8201.3952993149032, 8360.5202251186929, 8401.7866189014148} ;
00371 const static double s[16] =
00372 {0.000000000000000, -5.2458958075096795, -3.672098804806848, -12.19657502178409,
00373 5.245895807589972, 0.0000000000000000, 5.468563750710966, -2.68353065400852,
00374 3.672098804671908, -5.4685637506901852, 0.000000000000000, -12.88362080627209,
00375 12.196575021808101, 2.6835306540696267, 12.883620806137678, 0.00000000000000};
00376
00377 const static double d[16] =
00378 {234.2042288813096, 226.01008098131695, 215.8066813838328, 211.20330567403138,
00379 226.0100809813168, 218.35802236416407, 208.9244466731406, 204.74540616901601,
00380 215.8066813838327, 208.92444667314072, 200.6069171296133, 197.05760538656338,
00381 211.2033056740313, 204.74540616901612, 197.0576053865633, 193.87282576804154};
00382
00383
00384 bool null_test = false;
00385 for (int q = 0; q<numQPs; ++q) if (DIST_THRESHOLD<std::abs(jacobian_det(e,q)-d[q])) null_test=true;
00386 if (null_test) {
00387 for (int q = 0; q<numQPs; ++q) {
00388 v_lambda_theta(q,0) = 0;
00389 divergence_v[q] = 0;
00390 v_lambda_theta(q,1) = 0;
00391 }
00392 } else {
00393 for (int q = 0; q<numQPs; ++q) {
00394 v_lambda_theta(q,0) = v[q];
00395 divergence_v[q] = s[q];
00396 v_lambda_theta(q,1) = 0;
00397 }
00398 }
00399 }
00400 break;
00401 case 1: {
00402
00403
00404
00405
00406
00407 for (int q = 0; q<numQPs; ++q) {
00408 v_lambda_theta(q,0) =
00409 (val_at_cub_points(0,q)*jacobian(e,q,0,0)+val_at_cub_points(1,q)*jacobian(e,q,0,1))/jacobian_det(e,q);
00410 v_lambda_theta(q,1) =
00411 (val_at_cub_points(2,q)*jacobian(e,q,1,0)+val_at_cub_points(3,q)*jacobian(e,q,1,1))/jacobian_det(e,q);
00412 divergence_v[q] = 0;
00413 }
00414 }
00415 break;
00416 case 2: {
00417
00418
00419
00420
00421 for (int q = 0; q<numQPs; ++q) {
00422 const MeshScalarT R = std::sqrt(phi(q,0)*phi(q,0)+phi(q,1)*phi(q,1)+phi(q,2)*phi(q,2));
00423 const MeshScalarT X = phi(q,0)/R;
00424 const MeshScalarT Y = phi(q,1)/R;
00425 const MeshScalarT Z = phi(q,2)/R;
00426 const MeshScalarT cos_theta = Z;
00427 const MeshScalarT sin_theta = 1-Z*Z;
00428 const MeshScalarT theta = std::acos (Z);
00429 const MeshScalarT lambda = std::atan2(Y,X);
00430 v_lambda_theta(q,0) = -lambda*lambda*(cos_theta*cos_theta - sin_theta*sin_theta)/2;
00431 v_lambda_theta(q,1) = lambda * cos_theta;
00432 divergence_v[q] = 0;
00433 }
00434 }
00435 break;
00436 case 3: {
00437
00438
00439
00440
00441 for (int q = 0; q<numQPs; ++q) {
00442 const MeshScalarT R = std::sqrt(phi(q,0)*phi(q,0)+phi(q,1)*phi(q,1)+phi(q,2)*phi(q,2));
00443 const MeshScalarT X = phi(q,0)/R;
00444 const MeshScalarT Y = phi(q,1)/R;
00445 const MeshScalarT Z = phi(q,2)/R;
00446 const MeshScalarT cos_theta = Z;
00447 const MeshScalarT sin_theta = 1-Z*Z;
00448 const MeshScalarT theta = std::acos (Z);
00449 const MeshScalarT lambda = std::atan2(Y,X);
00450 v_lambda_theta(q,0) = lambda*lambda*cos_theta;
00451 v_lambda_theta(q,1) = theta * theta;
00452 divergence_v[q] = 2*theta*sin_theta + theta*theta*cos_theta + 2*lambda*cos_theta;
00453 }
00454 }
00455 break;
00456 }
00457
00458
00459 Intrepid::FieldContainer<MeshScalarT> div_v(numQPs);
00460 spherical_divergence(div_v, v_lambda_theta, e, rrearth);
00461 for (int q = 0; q<numQPs; ++q) {
00462 if (DIST_THRESHOLD<std::abs(div_v(q)/rrearth - divergence_v[q]))
00463 std::cout <<"Aeras_ComputeBasisFunctions_Def"<<":"<<__LINE__
00464 <<" case, element, quadpoint:("<<c<<","<<e<<","<<q
00465 <<") divergence_v, div_v:("<<divergence_v[q] <<","<<div_v(q)/rrearth
00466 <<")" <<std::endl;
00467 }
00468 if (!c) e==numelements;
00469 }
00470 }
00471 }
00472
00473
00474 }