$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // Local includes 00021 #include "libmesh/fe.h" 00022 #include "libmesh/inf_fe.h" 00023 #include "libmesh/libmesh_logging.h" 00024 // For projection code: 00025 #include "libmesh/boundary_info.h" 00026 #include "libmesh/mesh_base.h" 00027 #include "libmesh/dense_matrix.h" 00028 #include "libmesh/dense_vector.h" 00029 #include "libmesh/dof_map.h" 00030 #include "libmesh/elem.h" 00031 #include "libmesh/fe_interface.h" 00032 #include "libmesh/numeric_vector.h" 00033 #include "libmesh/periodic_boundary_base.h" 00034 #include "libmesh/periodic_boundaries.h" 00035 #include "libmesh/quadrature.h" 00036 #include "libmesh/quadrature_gauss.h" 00037 #include "libmesh/tensor_value.h" 00038 #include "libmesh/threads.h" 00039 00040 // Anonymous namespace, for a helper function for periodic boundary 00041 // constraint calculations 00042 namespace 00043 { 00044 using namespace libMesh; 00045 00046 // Find the "primary" element around a boundary point: 00047 const Elem* primary_boundary_point_neighbor 00048 (const Elem* elem, 00049 const Point& p, 00050 const BoundaryInfo& boundary_info, 00051 const std::set<boundary_id_type>& boundary_ids) 00052 { 00053 // If we don't find a better alternative, the user will have 00054 // provided the primary element 00055 const Elem *primary = elem; 00056 00057 std::set<const Elem*> point_neighbors; 00058 elem->find_point_neighbors(p, point_neighbors); 00059 for (std::set<const Elem*>::const_iterator point_neighbors_iter = 00060 point_neighbors.begin(); 00061 point_neighbors_iter != point_neighbors.end(); ++point_neighbors_iter) 00062 { 00063 const Elem* pt_neighbor = *point_neighbors_iter; 00064 00065 // If this point neighbor isn't at least 00066 // as coarse as the current primary elem, or if it is at 00067 // the same level but has a lower id, then 00068 // we won't defer to it. 00069 if ((pt_neighbor->level() > primary->level()) || 00070 (pt_neighbor->level() == primary->level() && 00071 pt_neighbor->id() < primary->id())) 00072 continue; 00073 00074 // Otherwise, we will defer to the point neighbor, but only if 00075 // one of its sides is on a relevant boundary and that side 00076 // contains this vertex 00077 bool vertex_on_periodic_side = false; 00078 for (unsigned short int ns = 0; 00079 ns != pt_neighbor->n_sides(); ++ns) 00080 { 00081 const std::vector<boundary_id_type> bc_ids = 00082 boundary_info.boundary_ids (pt_neighbor, ns); 00083 00084 bool on_relevant_boundary = false; 00085 for (std::set<boundary_id_type>::const_iterator i = 00086 boundary_ids.begin(); i != boundary_ids.end(); ++i) 00087 if (std::find(bc_ids.begin(), bc_ids.end(), *i) 00088 != bc_ids.end()) 00089 on_relevant_boundary = true; 00090 00091 if (!on_relevant_boundary) 00092 continue; 00093 00094 if (!pt_neighbor->build_side(ns)->contains_point(p)) 00095 continue; 00096 00097 vertex_on_periodic_side = true; 00098 break; 00099 } 00100 00101 if (vertex_on_periodic_side) 00102 primary = pt_neighbor; 00103 } 00104 00105 return primary; 00106 } 00107 00108 // Find the "primary" element around a boundary edge: 00109 const Elem* primary_boundary_edge_neighbor 00110 (const Elem* elem, 00111 const Point& p1, 00112 const Point& p2, 00113 const BoundaryInfo& boundary_info, 00114 const std::set<boundary_id_type>& boundary_ids) 00115 { 00116 // If we don't find a better alternative, the user will have 00117 // provided the primary element 00118 const Elem *primary = elem; 00119 00120 std::set<const Elem*> edge_neighbors; 00121 elem->find_edge_neighbors(p1, p2, edge_neighbors); 00122 for (std::set<const Elem*>::const_iterator edge_neighbors_iter = 00123 edge_neighbors.begin(); 00124 edge_neighbors_iter != edge_neighbors.end(); ++edge_neighbors_iter) 00125 { 00126 const Elem* e_neighbor = *edge_neighbors_iter; 00127 00128 // If this edge neighbor isn't at least 00129 // as coarse as the current primary elem, or if it is at 00130 // the same level but has a lower id, then 00131 // we won't defer to it. 00132 if ((e_neighbor->level() > primary->level()) || 00133 (e_neighbor->level() == primary->level() && 00134 e_neighbor->id() < primary->id())) 00135 continue; 00136 00137 // Otherwise, we will defer to the edge neighbor, but only if 00138 // one of its sides is on this periodic boundary and that 00139 // side contains this edge 00140 bool vertex_on_periodic_side = false; 00141 for (unsigned short int ns = 0; 00142 ns != e_neighbor->n_sides(); ++ns) 00143 { 00144 const std::vector<boundary_id_type>& bc_ids = 00145 boundary_info.boundary_ids (e_neighbor, ns); 00146 00147 bool on_relevant_boundary = false; 00148 for (std::set<boundary_id_type>::const_iterator i = 00149 boundary_ids.begin(); i != boundary_ids.end(); ++i) 00150 if (std::find(bc_ids.begin(), bc_ids.end(), *i) 00151 != bc_ids.end()) 00152 on_relevant_boundary = true; 00153 00154 if (!on_relevant_boundary) 00155 continue; 00156 00157 UniquePtr<Elem> periodic_side = e_neighbor->build_side(ns); 00158 if (!(periodic_side->contains_point(p1) && 00159 periodic_side->contains_point(p2))) 00160 continue; 00161 00162 vertex_on_periodic_side = true; 00163 break; 00164 } 00165 00166 if (vertex_on_periodic_side) 00167 primary = e_neighbor; 00168 } 00169 00170 return primary; 00171 } 00172 00173 } 00174 00175 namespace libMesh 00176 { 00177 00178 00179 00180 // ------------------------------------------------------------ 00181 // FEBase class members 00182 template <> 00183 UniquePtr<FEGenericBase<Real> > 00184 FEGenericBase<Real>::build (const unsigned int dim, 00185 const FEType& fet) 00186 { 00187 switch (dim) 00188 { 00189 // 0D 00190 case 0: 00191 { 00192 switch (fet.family) 00193 { 00194 case CLOUGH: 00195 return UniquePtr<FEBase>(new FE<0,CLOUGH>(fet)); 00196 00197 case HERMITE: 00198 return UniquePtr<FEBase>(new FE<0,HERMITE>(fet)); 00199 00200 case LAGRANGE: 00201 return UniquePtr<FEBase>(new FE<0,LAGRANGE>(fet)); 00202 00203 case L2_LAGRANGE: 00204 return UniquePtr<FEBase>(new FE<0,L2_LAGRANGE>(fet)); 00205 00206 case HIERARCHIC: 00207 return UniquePtr<FEBase>(new FE<0,HIERARCHIC>(fet)); 00208 00209 case L2_HIERARCHIC: 00210 return UniquePtr<FEBase>(new FE<0,L2_HIERARCHIC>(fet)); 00211 00212 case MONOMIAL: 00213 return UniquePtr<FEBase>(new FE<0,MONOMIAL>(fet)); 00214 00215 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00216 case SZABAB: 00217 return UniquePtr<FEBase>(new FE<0,SZABAB>(fet)); 00218 00219 case BERNSTEIN: 00220 return UniquePtr<FEBase>(new FE<0,BERNSTEIN>(fet)); 00221 #endif 00222 00223 case XYZ: 00224 return UniquePtr<FEBase>(new FEXYZ<0>(fet)); 00225 00226 case SCALAR: 00227 return UniquePtr<FEBase>(new FEScalar<0>(fet)); 00228 00229 default: 00230 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00231 } 00232 } 00233 // 1D 00234 case 1: 00235 { 00236 switch (fet.family) 00237 { 00238 case CLOUGH: 00239 return UniquePtr<FEBase>(new FE<1,CLOUGH>(fet)); 00240 00241 case HERMITE: 00242 return UniquePtr<FEBase>(new FE<1,HERMITE>(fet)); 00243 00244 case LAGRANGE: 00245 return UniquePtr<FEBase>(new FE<1,LAGRANGE>(fet)); 00246 00247 case L2_LAGRANGE: 00248 return UniquePtr<FEBase>(new FE<1,L2_LAGRANGE>(fet)); 00249 00250 case HIERARCHIC: 00251 return UniquePtr<FEBase>(new FE<1,HIERARCHIC>(fet)); 00252 00253 case L2_HIERARCHIC: 00254 return UniquePtr<FEBase>(new FE<1,L2_HIERARCHIC>(fet)); 00255 00256 case MONOMIAL: 00257 return UniquePtr<FEBase>(new FE<1,MONOMIAL>(fet)); 00258 00259 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00260 case SZABAB: 00261 return UniquePtr<FEBase>(new FE<1,SZABAB>(fet)); 00262 00263 case BERNSTEIN: 00264 return UniquePtr<FEBase>(new FE<1,BERNSTEIN>(fet)); 00265 #endif 00266 00267 case XYZ: 00268 return UniquePtr<FEBase>(new FEXYZ<1>(fet)); 00269 00270 case SCALAR: 00271 return UniquePtr<FEBase>(new FEScalar<1>(fet)); 00272 00273 default: 00274 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00275 } 00276 } 00277 00278 00279 // 2D 00280 case 2: 00281 { 00282 switch (fet.family) 00283 { 00284 case CLOUGH: 00285 return UniquePtr<FEBase>(new FE<2,CLOUGH>(fet)); 00286 00287 case HERMITE: 00288 return UniquePtr<FEBase>(new FE<2,HERMITE>(fet)); 00289 00290 case LAGRANGE: 00291 return UniquePtr<FEBase>(new FE<2,LAGRANGE>(fet)); 00292 00293 case L2_LAGRANGE: 00294 return UniquePtr<FEBase>(new FE<2,L2_LAGRANGE>(fet)); 00295 00296 case HIERARCHIC: 00297 return UniquePtr<FEBase>(new FE<2,HIERARCHIC>(fet)); 00298 00299 case L2_HIERARCHIC: 00300 return UniquePtr<FEBase>(new FE<2,L2_HIERARCHIC>(fet)); 00301 00302 case MONOMIAL: 00303 return UniquePtr<FEBase>(new FE<2,MONOMIAL>(fet)); 00304 00305 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00306 case SZABAB: 00307 return UniquePtr<FEBase>(new FE<2,SZABAB>(fet)); 00308 00309 case BERNSTEIN: 00310 return UniquePtr<FEBase>(new FE<2,BERNSTEIN>(fet)); 00311 #endif 00312 00313 case XYZ: 00314 return UniquePtr<FEBase>(new FEXYZ<2>(fet)); 00315 00316 case SCALAR: 00317 return UniquePtr<FEBase>(new FEScalar<2>(fet)); 00318 00319 case SUBDIVISION: 00320 return UniquePtr<FEBase>(new FESubdivision(fet)); 00321 00322 default: 00323 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00324 } 00325 } 00326 00327 00328 // 3D 00329 case 3: 00330 { 00331 switch (fet.family) 00332 { 00333 case CLOUGH: 00334 libmesh_error_msg("ERROR: Clough-Tocher elements currently only support 1D and 2D"); 00335 00336 case HERMITE: 00337 return UniquePtr<FEBase>(new FE<3,HERMITE>(fet)); 00338 00339 case LAGRANGE: 00340 return UniquePtr<FEBase>(new FE<3,LAGRANGE>(fet)); 00341 00342 case L2_LAGRANGE: 00343 return UniquePtr<FEBase>(new FE<3,L2_LAGRANGE>(fet)); 00344 00345 case HIERARCHIC: 00346 return UniquePtr<FEBase>(new FE<3,HIERARCHIC>(fet)); 00347 00348 case L2_HIERARCHIC: 00349 return UniquePtr<FEBase>(new FE<3,L2_HIERARCHIC>(fet)); 00350 00351 case MONOMIAL: 00352 return UniquePtr<FEBase>(new FE<3,MONOMIAL>(fet)); 00353 00354 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00355 case SZABAB: 00356 return UniquePtr<FEBase>(new FE<3,SZABAB>(fet)); 00357 00358 case BERNSTEIN: 00359 return UniquePtr<FEBase>(new FE<3,BERNSTEIN>(fet)); 00360 #endif 00361 00362 case XYZ: 00363 return UniquePtr<FEBase>(new FEXYZ<3>(fet)); 00364 00365 case SCALAR: 00366 return UniquePtr<FEBase>(new FEScalar<3>(fet)); 00367 00368 default: 00369 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00370 } 00371 } 00372 00373 default: 00374 libmesh_error_msg("Invalid dimension dim = " << dim); 00375 } 00376 00377 libmesh_error_msg("We'll never get here!"); 00378 return UniquePtr<FEBase>(); 00379 } 00380 00381 00382 00383 template <> 00384 UniquePtr<FEGenericBase<RealGradient> > 00385 FEGenericBase<RealGradient>::build (const unsigned int dim, 00386 const FEType& fet) 00387 { 00388 switch (dim) 00389 { 00390 // 0D 00391 case 0: 00392 { 00393 switch (fet.family) 00394 { 00395 case LAGRANGE_VEC: 00396 return UniquePtr<FEVectorBase>(new FELagrangeVec<0>(fet)); 00397 00398 default: 00399 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00400 } 00401 } 00402 case 1: 00403 { 00404 switch (fet.family) 00405 { 00406 case LAGRANGE_VEC: 00407 return UniquePtr<FEVectorBase>(new FELagrangeVec<1>(fet)); 00408 00409 default: 00410 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00411 } 00412 } 00413 case 2: 00414 { 00415 switch (fet.family) 00416 { 00417 case LAGRANGE_VEC: 00418 return UniquePtr<FEVectorBase>(new FELagrangeVec<2>(fet)); 00419 00420 case NEDELEC_ONE: 00421 return UniquePtr<FEVectorBase>(new FENedelecOne<2>(fet)); 00422 00423 default: 00424 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00425 } 00426 } 00427 case 3: 00428 { 00429 switch (fet.family) 00430 { 00431 case LAGRANGE_VEC: 00432 return UniquePtr<FEVectorBase>(new FELagrangeVec<3>(fet)); 00433 00434 case NEDELEC_ONE: 00435 return UniquePtr<FEVectorBase>(new FENedelecOne<3>(fet)); 00436 00437 default: 00438 libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family); 00439 } 00440 } 00441 00442 default: 00443 libmesh_error_msg("Invalid dimension dim = " << dim); 00444 } // switch(dim) 00445 00446 libmesh_error_msg("We'll never get here!"); 00447 return UniquePtr<FEVectorBase>(); 00448 } 00449 00450 00451 00452 00453 00454 00455 00456 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00457 00458 00459 template <> 00460 UniquePtr<FEGenericBase<Real> > 00461 FEGenericBase<Real>::build_InfFE (const unsigned int dim, 00462 const FEType& fet) 00463 { 00464 switch (dim) 00465 { 00466 00467 // 1D 00468 case 1: 00469 { 00470 switch (fet.radial_family) 00471 { 00472 case INFINITE_MAP: 00473 libmesh_error_msg("ERROR: Can't build an infinite element with FEFamily = " << fet.radial_family); 00474 00475 case JACOBI_20_00: 00476 { 00477 switch (fet.inf_map) 00478 { 00479 case CARTESIAN: 00480 return UniquePtr<FEBase>(new InfFE<1,JACOBI_20_00,CARTESIAN>(fet)); 00481 00482 default: 00483 libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map); 00484 } 00485 } 00486 00487 case JACOBI_30_00: 00488 { 00489 switch (fet.inf_map) 00490 { 00491 case CARTESIAN: 00492 return UniquePtr<FEBase>(new InfFE<1,JACOBI_30_00,CARTESIAN>(fet)); 00493 00494 default: 00495 libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map); 00496 } 00497 } 00498 00499 case LEGENDRE: 00500 { 00501 switch (fet.inf_map) 00502 { 00503 case CARTESIAN: 00504 return UniquePtr<FEBase>(new InfFE<1,LEGENDRE,CARTESIAN>(fet)); 00505 00506 default: 00507 libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map); 00508 } 00509 } 00510 00511 case LAGRANGE: 00512 { 00513 switch (fet.inf_map) 00514 { 00515 case CARTESIAN: 00516 return UniquePtr<FEBase>(new InfFE<1,LAGRANGE,CARTESIAN>(fet)); 00517 00518 default: 00519 libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map); 00520 } 00521 } 00522 00523 default: 00524 libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family); 00525 } 00526 } 00527 00528 00529 00530 00531 // 2D 00532 case 2: 00533 { 00534 switch (fet.radial_family) 00535 { 00536 case INFINITE_MAP: 00537 libmesh_error_msg("ERROR: Can't build an infinite element with FEFamily = " << fet.radial_family); 00538 00539 case JACOBI_20_00: 00540 { 00541 switch (fet.inf_map) 00542 { 00543 case CARTESIAN: 00544 return UniquePtr<FEBase>(new InfFE<2,JACOBI_20_00,CARTESIAN>(fet)); 00545 00546 default: 00547 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00548 } 00549 } 00550 00551 case JACOBI_30_00: 00552 { 00553 switch (fet.inf_map) 00554 { 00555 case CARTESIAN: 00556 return UniquePtr<FEBase>(new InfFE<2,JACOBI_30_00,CARTESIAN>(fet)); 00557 00558 default: 00559 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00560 } 00561 } 00562 00563 case LEGENDRE: 00564 { 00565 switch (fet.inf_map) 00566 { 00567 case CARTESIAN: 00568 return UniquePtr<FEBase>(new InfFE<2,LEGENDRE,CARTESIAN>(fet)); 00569 00570 default: 00571 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00572 } 00573 } 00574 00575 case LAGRANGE: 00576 { 00577 switch (fet.inf_map) 00578 { 00579 case CARTESIAN: 00580 return UniquePtr<FEBase>(new InfFE<2,LAGRANGE,CARTESIAN>(fet)); 00581 00582 default: 00583 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00584 } 00585 } 00586 00587 default: 00588 libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family); 00589 } 00590 } 00591 00592 00593 00594 00595 // 3D 00596 case 3: 00597 { 00598 switch (fet.radial_family) 00599 { 00600 case INFINITE_MAP: 00601 libmesh_error_msg("ERROR: Don't build an infinite element with FEFamily = " << fet.radial_family); 00602 00603 case JACOBI_20_00: 00604 { 00605 switch (fet.inf_map) 00606 { 00607 case CARTESIAN: 00608 return UniquePtr<FEBase>(new InfFE<3,JACOBI_20_00,CARTESIAN>(fet)); 00609 00610 default: 00611 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00612 } 00613 } 00614 00615 case JACOBI_30_00: 00616 { 00617 switch (fet.inf_map) 00618 { 00619 case CARTESIAN: 00620 return UniquePtr<FEBase>(new InfFE<3,JACOBI_30_00,CARTESIAN>(fet)); 00621 00622 default: 00623 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00624 } 00625 } 00626 00627 case LEGENDRE: 00628 { 00629 switch (fet.inf_map) 00630 { 00631 case CARTESIAN: 00632 return UniquePtr<FEBase>(new InfFE<3,LEGENDRE,CARTESIAN>(fet)); 00633 00634 default: 00635 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00636 } 00637 } 00638 00639 case LAGRANGE: 00640 { 00641 switch (fet.inf_map) 00642 { 00643 case CARTESIAN: 00644 return UniquePtr<FEBase>(new InfFE<3,LAGRANGE,CARTESIAN>(fet)); 00645 00646 default: 00647 libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map); 00648 } 00649 } 00650 00651 default: 00652 libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family); 00653 } 00654 } 00655 00656 default: 00657 libmesh_error_msg("Invalid dimension dim = " << dim); 00658 } 00659 00660 libmesh_error_msg("We'll never get here!"); 00661 return UniquePtr<FEBase>(); 00662 } 00663 00664 00665 00666 template <> 00667 UniquePtr<FEGenericBase<RealGradient> > 00668 FEGenericBase<RealGradient>::build_InfFE (const unsigned int, 00669 const FEType& ) 00670 { 00671 // No vector types defined... YET. 00672 libmesh_not_implemented(); 00673 return UniquePtr<FEVectorBase>(); 00674 } 00675 00676 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00677 00678 00679 template <typename OutputType> 00680 void FEGenericBase<OutputType> ::compute_shape_functions (const Elem* elem, 00681 const std::vector<Point>& qp) 00682 { 00683 //------------------------------------------------------------------------- 00684 // Compute the shape function values (and derivatives) 00685 // at the Quadrature points. Note that the actual values 00686 // have already been computed via init_shape_functions 00687 00688 // Start logging the shape function computation 00689 START_LOG("compute_shape_functions()", "FE"); 00690 00691 calculations_started = true; 00692 00693 // If the user forgot to request anything, we'll be safe and 00694 // calculate everything: 00695 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00696 if (!calculate_phi && !calculate_dphi && !calculate_d2phi && !calculate_curl_phi && !calculate_div_phi) 00697 { 00698 calculate_phi = calculate_dphi = calculate_d2phi = true; 00699 // Only compute curl, div for vector-valued elements 00700 if( TypesEqual<OutputType,RealGradient>::value ) 00701 { 00702 calculate_curl_phi = true; 00703 calculate_div_phi = true; 00704 } 00705 } 00706 #else 00707 if (!calculate_phi && !calculate_dphi && !calculate_curl_phi && !calculate_div_phi) 00708 { 00709 calculate_phi = calculate_dphi = true; 00710 // Only compute curl for vector-valued elements 00711 if( TypesEqual<OutputType,RealGradient>::value ) 00712 { 00713 calculate_curl_phi = true; 00714 calculate_div_phi = true; 00715 } 00716 } 00717 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES 00718 00719 00720 if( calculate_phi ) 00721 this->_fe_trans->map_phi( this->dim, elem, qp, (*this), this->phi ); 00722 00723 if( calculate_dphi ) 00724 this->_fe_trans->map_dphi( this->dim, elem, qp, (*this), this->dphi, 00725 this->dphidx, this->dphidy, this->dphidz ); 00726 00727 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00728 if( calculate_d2phi ) 00729 this->_fe_trans->map_d2phi( this->dim, elem, qp, (*this), this->d2phi, 00730 this->d2phidx2, this->d2phidxdy, this->d2phidxdz, 00731 this->d2phidy2, this->d2phidydz, this->d2phidz2 ); 00732 #endif //LIBMESH_ENABLE_SECOND_DERIVATIVES 00733 00734 // Only compute curl for vector-valued elements 00735 if( calculate_curl_phi && TypesEqual<OutputType,RealGradient>::value ) 00736 this->_fe_trans->map_curl( this->dim, elem, qp, (*this), this->curl_phi ); 00737 00738 // Only compute div for vector-valued elements 00739 if( calculate_div_phi && TypesEqual<OutputType,RealGradient>::value ) 00740 this->_fe_trans->map_div( this->dim, elem, qp, (*this), this->div_phi ); 00741 00742 // Stop logging the shape function computation 00743 STOP_LOG("compute_shape_functions()", "FE"); 00744 } 00745 00746 00747 template <typename OutputType> 00748 void FEGenericBase<OutputType>::print_phi(std::ostream& os) const 00749 { 00750 for (unsigned int i=0; i<phi.size(); ++i) 00751 for (unsigned int j=0; j<phi[i].size(); ++j) 00752 os << " phi[" << i << "][" << j << "]=" << phi[i][j] << std::endl; 00753 } 00754 00755 00756 00757 00758 template <typename OutputType> 00759 void FEGenericBase<OutputType>::print_dphi(std::ostream& os) const 00760 { 00761 for (unsigned int i=0; i<dphi.size(); ++i) 00762 for (unsigned int j=0; j<dphi[i].size(); ++j) 00763 os << " dphi[" << i << "][" << j << "]=" << dphi[i][j]; 00764 } 00765 00766 00767 00768 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00769 00770 00771 template <typename OutputType> 00772 void FEGenericBase<OutputType>::print_d2phi(std::ostream& os) const 00773 { 00774 for (unsigned int i=0; i<dphi.size(); ++i) 00775 for (unsigned int j=0; j<dphi[i].size(); ++j) 00776 os << " d2phi[" << i << "][" << j << "]=" << d2phi[i][j]; 00777 } 00778 00779 #endif 00780 00781 00782 00783 #ifdef LIBMESH_ENABLE_AMR 00784 00785 template <typename OutputType> 00786 void 00787 FEGenericBase<OutputType>::coarsened_dof_values(const NumericVector<Number> &old_vector, 00788 const DofMap &dof_map, 00789 const Elem *elem, 00790 DenseVector<Number> &Ue, 00791 const unsigned int var, 00792 const bool use_old_dof_indices) 00793 { 00794 // Side/edge local DOF indices 00795 std::vector<unsigned int> new_side_dofs, old_side_dofs; 00796 00797 // FIXME: what about 2D shells in 3D space? 00798 unsigned int dim = elem->dim(); 00799 00800 // We use local FE objects for now 00801 // FIXME: we should use more, external objects instead for efficiency 00802 const FEType& base_fe_type = dof_map.variable_type(var); 00803 UniquePtr<FEGenericBase<OutputShape> > fe 00804 (FEGenericBase<OutputShape>::build(dim, base_fe_type)); 00805 UniquePtr<FEGenericBase<OutputShape> > fe_coarse 00806 (FEGenericBase<OutputShape>::build(dim, base_fe_type)); 00807 00808 UniquePtr<QBase> qrule (base_fe_type.default_quadrature_rule(dim)); 00809 UniquePtr<QBase> qedgerule (base_fe_type.default_quadrature_rule(1)); 00810 UniquePtr<QBase> qsiderule (base_fe_type.default_quadrature_rule(dim-1)); 00811 std::vector<Point> coarse_qpoints; 00812 00813 // The values of the shape functions at the quadrature 00814 // points 00815 const std::vector<std::vector<OutputShape> >& phi_values = 00816 fe->get_phi(); 00817 const std::vector<std::vector<OutputShape> >& phi_coarse = 00818 fe_coarse->get_phi(); 00819 00820 // The gradients of the shape functions at the quadrature 00821 // points on the child element. 00822 const std::vector<std::vector<OutputGradient> > *dphi_values = 00823 NULL; 00824 const std::vector<std::vector<OutputGradient> > *dphi_coarse = 00825 NULL; 00826 00827 const FEContinuity cont = fe->get_continuity(); 00828 00829 if (cont == C_ONE) 00830 { 00831 const std::vector<std::vector<OutputGradient> >& 00832 ref_dphi_values = fe->get_dphi(); 00833 dphi_values = &ref_dphi_values; 00834 const std::vector<std::vector<OutputGradient> >& 00835 ref_dphi_coarse = fe_coarse->get_dphi(); 00836 dphi_coarse = &ref_dphi_coarse; 00837 } 00838 00839 // The Jacobian * quadrature weight at the quadrature points 00840 const std::vector<Real>& JxW = 00841 fe->get_JxW(); 00842 00843 // The XYZ locations of the quadrature points on the 00844 // child element 00845 const std::vector<Point>& xyz_values = 00846 fe->get_xyz(); 00847 00848 00849 00850 FEType fe_type = base_fe_type, temp_fe_type; 00851 const ElemType elem_type = elem->type(); 00852 fe_type.order = static_cast<Order>(fe_type.order + 00853 elem->max_descendant_p_level()); 00854 00855 // Number of nodes on parent element 00856 const unsigned int n_nodes = elem->n_nodes(); 00857 00858 // Number of dofs on parent element 00859 const unsigned int new_n_dofs = 00860 FEInterface::n_dofs(dim, fe_type, elem_type); 00861 00862 // Fixed vs. free DoFs on edge/face projections 00863 std::vector<char> dof_is_fixed(new_n_dofs, false); // bools 00864 std::vector<int> free_dof(new_n_dofs, 0); 00865 00866 DenseMatrix<Real> Ke; 00867 DenseVector<Number> Fe; 00868 Ue.resize(new_n_dofs); Ue.zero(); 00869 00870 00871 // When coarsening, in general, we need a series of 00872 // projections to ensure a unique and continuous 00873 // solution. We start by interpolating nodes, then 00874 // hold those fixed and project edges, then 00875 // hold those fixed and project faces, then 00876 // hold those fixed and project interiors 00877 00878 // Copy node values first 00879 { 00880 std::vector<dof_id_type> node_dof_indices; 00881 if (use_old_dof_indices) 00882 dof_map.old_dof_indices (elem, node_dof_indices, var); 00883 else 00884 dof_map.dof_indices (elem, node_dof_indices, var); 00885 00886 unsigned int current_dof = 0; 00887 for (unsigned int n=0; n!= n_nodes; ++n) 00888 { 00889 // FIXME: this should go through the DofMap, 00890 // not duplicate dof_indices code badly! 00891 const unsigned int my_nc = 00892 FEInterface::n_dofs_at_node (dim, fe_type, 00893 elem_type, n); 00894 if (!elem->is_vertex(n)) 00895 { 00896 current_dof += my_nc; 00897 continue; 00898 } 00899 00900 temp_fe_type = base_fe_type; 00901 // We're assuming here that child n shares vertex n, 00902 // which is wrong on non-simplices right now 00903 // ... but this code isn't necessary except on elements 00904 // where p refinement creates more vertex dofs; we have 00905 // no such elements yet. 00906 /* 00907 if (elem->child(n)->p_level() < elem->p_level()) 00908 { 00909 temp_fe_type.order = 00910 static_cast<Order>(temp_fe_type.order + 00911 elem->child(n)->p_level()); 00912 } 00913 */ 00914 const unsigned int nc = 00915 FEInterface::n_dofs_at_node (dim, temp_fe_type, 00916 elem_type, n); 00917 for (unsigned int i=0; i!= nc; ++i) 00918 { 00919 Ue(current_dof) = 00920 old_vector(node_dof_indices[current_dof]); 00921 dof_is_fixed[current_dof] = true; 00922 current_dof++; 00923 } 00924 } 00925 } 00926 00927 // In 3D, project any edge values next 00928 if (dim > 2 && cont != DISCONTINUOUS) 00929 for (unsigned int e=0; e != elem->n_edges(); ++e) 00930 { 00931 FEInterface::dofs_on_edge(elem, dim, fe_type, 00932 e, new_side_dofs); 00933 00934 // Some edge dofs are on nodes and already 00935 // fixed, others are free to calculate 00936 unsigned int free_dofs = 0; 00937 for (unsigned int i=0; i != 00938 new_side_dofs.size(); ++i) 00939 if (!dof_is_fixed[new_side_dofs[i]]) 00940 free_dof[free_dofs++] = i; 00941 Ke.resize (free_dofs, free_dofs); Ke.zero(); 00942 Fe.resize (free_dofs); Fe.zero(); 00943 // The new edge coefficients 00944 DenseVector<Number> Uedge(free_dofs); 00945 00946 // Add projection terms from each child sharing 00947 // this edge 00948 for (unsigned int c=0; c != elem->n_children(); 00949 ++c) 00950 { 00951 if (!elem->is_child_on_edge(c,e)) 00952 continue; 00953 Elem *child = elem->child(c); 00954 00955 std::vector<dof_id_type> child_dof_indices; 00956 if (use_old_dof_indices) 00957 dof_map.old_dof_indices (child, 00958 child_dof_indices, var); 00959 else 00960 dof_map.dof_indices (child, 00961 child_dof_indices, var); 00962 const unsigned int child_n_dofs = 00963 cast_int<unsigned int> 00964 (child_dof_indices.size()); 00965 00966 temp_fe_type = base_fe_type; 00967 temp_fe_type.order = 00968 static_cast<Order>(temp_fe_type.order + 00969 child->p_level()); 00970 00971 FEInterface::dofs_on_edge(child, dim, 00972 temp_fe_type, e, old_side_dofs); 00973 00974 // Initialize both child and parent FE data 00975 // on the child's edge 00976 fe->attach_quadrature_rule (qedgerule.get()); 00977 fe->edge_reinit (child, e); 00978 const unsigned int n_qp = qedgerule->n_points(); 00979 00980 FEInterface::inverse_map (dim, fe_type, elem, 00981 xyz_values, coarse_qpoints); 00982 00983 fe_coarse->reinit(elem, &coarse_qpoints); 00984 00985 // Loop over the quadrature points 00986 for (unsigned int qp=0; qp<n_qp; qp++) 00987 { 00988 // solution value at the quadrature point 00989 OutputNumber fineval = libMesh::zero; 00990 // solution grad at the quadrature point 00991 OutputNumberGradient finegrad; 00992 00993 // Sum the solution values * the DOF 00994 // values at the quadrature point to 00995 // get the solution value and gradient. 00996 for (unsigned int i=0; i<child_n_dofs; 00997 i++) 00998 { 00999 fineval += 01000 (old_vector(child_dof_indices[i])* 01001 phi_values[i][qp]); 01002 if (cont == C_ONE) 01003 finegrad += (*dphi_values)[i][qp] * 01004 old_vector(child_dof_indices[i]); 01005 } 01006 01007 // Form edge projection matrix 01008 for (unsigned int sidei=0, freei=0; 01009 sidei != new_side_dofs.size(); 01010 ++sidei) 01011 { 01012 unsigned int i = new_side_dofs[sidei]; 01013 // fixed DoFs aren't test functions 01014 if (dof_is_fixed[i]) 01015 continue; 01016 for (unsigned int sidej=0, freej=0; 01017 sidej != new_side_dofs.size(); 01018 ++sidej) 01019 { 01020 unsigned int j = 01021 new_side_dofs[sidej]; 01022 if (dof_is_fixed[j]) 01023 Fe(freei) -= 01024 TensorTools::inner_product(phi_coarse[i][qp], 01025 phi_coarse[j][qp]) * 01026 JxW[qp] * Ue(j); 01027 else 01028 Ke(freei,freej) += 01029 TensorTools::inner_product(phi_coarse[i][qp], 01030 phi_coarse[j][qp]) * 01031 JxW[qp]; 01032 if (cont == C_ONE) 01033 { 01034 if (dof_is_fixed[j]) 01035 Fe(freei) -= 01036 TensorTools::inner_product((*dphi_coarse)[i][qp], 01037 (*dphi_coarse)[j][qp]) * 01038 JxW[qp] * Ue(j); 01039 else 01040 Ke(freei,freej) += 01041 TensorTools::inner_product((*dphi_coarse)[i][qp], 01042 (*dphi_coarse)[j][qp]) * 01043 JxW[qp]; 01044 } 01045 if (!dof_is_fixed[j]) 01046 freej++; 01047 } 01048 Fe(freei) += TensorTools::inner_product(phi_coarse[i][qp], 01049 fineval) * JxW[qp]; 01050 if (cont == C_ONE) 01051 Fe(freei) += 01052 TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp]; 01053 freei++; 01054 } 01055 } 01056 } 01057 Ke.cholesky_solve(Fe, Uedge); 01058 01059 // Transfer new edge solutions to element 01060 for (unsigned int i=0; i != free_dofs; ++i) 01061 { 01062 Number &ui = Ue(new_side_dofs[free_dof[i]]); 01063 libmesh_assert(std::abs(ui) < TOLERANCE || 01064 std::abs(ui - Uedge(i)) < TOLERANCE); 01065 ui = Uedge(i); 01066 dof_is_fixed[new_side_dofs[free_dof[i]]] = 01067 true; 01068 } 01069 } 01070 01071 // Project any side values (edges in 2D, faces in 3D) 01072 if (dim > 1 && cont != DISCONTINUOUS) 01073 for (unsigned int s=0; s != elem->n_sides(); ++s) 01074 { 01075 FEInterface::dofs_on_side(elem, dim, fe_type, 01076 s, new_side_dofs); 01077 01078 // Some side dofs are on nodes/edges and already 01079 // fixed, others are free to calculate 01080 unsigned int free_dofs = 0; 01081 for (unsigned int i=0; i != 01082 new_side_dofs.size(); ++i) 01083 if (!dof_is_fixed[new_side_dofs[i]]) 01084 free_dof[free_dofs++] = i; 01085 Ke.resize (free_dofs, free_dofs); Ke.zero(); 01086 Fe.resize (free_dofs); Fe.zero(); 01087 // The new side coefficients 01088 DenseVector<Number> Uside(free_dofs); 01089 01090 // Add projection terms from each child sharing 01091 // this side 01092 for (unsigned int c=0; c != elem->n_children(); 01093 ++c) 01094 { 01095 if (!elem->is_child_on_side(c,s)) 01096 continue; 01097 Elem *child = elem->child(c); 01098 01099 std::vector<dof_id_type> child_dof_indices; 01100 if (use_old_dof_indices) 01101 dof_map.old_dof_indices (child, 01102 child_dof_indices, var); 01103 else 01104 dof_map.dof_indices (child, 01105 child_dof_indices, var); 01106 const unsigned int child_n_dofs = 01107 cast_int<unsigned int> 01108 (child_dof_indices.size()); 01109 01110 temp_fe_type = base_fe_type; 01111 temp_fe_type.order = 01112 static_cast<Order>(temp_fe_type.order + 01113 child->p_level()); 01114 01115 FEInterface::dofs_on_side(child, dim, 01116 temp_fe_type, s, old_side_dofs); 01117 01118 // Initialize both child and parent FE data 01119 // on the child's side 01120 fe->attach_quadrature_rule (qsiderule.get()); 01121 fe->reinit (child, s); 01122 const unsigned int n_qp = qsiderule->n_points(); 01123 01124 FEInterface::inverse_map (dim, fe_type, elem, 01125 xyz_values, coarse_qpoints); 01126 01127 fe_coarse->reinit(elem, &coarse_qpoints); 01128 01129 // Loop over the quadrature points 01130 for (unsigned int qp=0; qp<n_qp; qp++) 01131 { 01132 // solution value at the quadrature point 01133 OutputNumber fineval = libMesh::zero; 01134 // solution grad at the quadrature point 01135 OutputNumberGradient finegrad; 01136 01137 // Sum the solution values * the DOF 01138 // values at the quadrature point to 01139 // get the solution value and gradient. 01140 for (unsigned int i=0; i<child_n_dofs; 01141 i++) 01142 { 01143 fineval += 01144 old_vector(child_dof_indices[i]) * 01145 phi_values[i][qp]; 01146 if (cont == C_ONE) 01147 finegrad += (*dphi_values)[i][qp] * 01148 old_vector(child_dof_indices[i]); 01149 } 01150 01151 // Form side projection matrix 01152 for (unsigned int sidei=0, freei=0; 01153 sidei != new_side_dofs.size(); 01154 ++sidei) 01155 { 01156 unsigned int i = new_side_dofs[sidei]; 01157 // fixed DoFs aren't test functions 01158 if (dof_is_fixed[i]) 01159 continue; 01160 for (unsigned int sidej=0, freej=0; 01161 sidej != new_side_dofs.size(); 01162 ++sidej) 01163 { 01164 unsigned int j = 01165 new_side_dofs[sidej]; 01166 if (dof_is_fixed[j]) 01167 Fe(freei) -= 01168 TensorTools::inner_product(phi_coarse[i][qp], 01169 phi_coarse[j][qp]) * 01170 JxW[qp] * Ue(j); 01171 else 01172 Ke(freei,freej) += 01173 TensorTools::inner_product(phi_coarse[i][qp], 01174 phi_coarse[j][qp]) * 01175 JxW[qp]; 01176 if (cont == C_ONE) 01177 { 01178 if (dof_is_fixed[j]) 01179 Fe(freei) -= 01180 TensorTools::inner_product((*dphi_coarse)[i][qp], 01181 (*dphi_coarse)[j][qp]) * 01182 JxW[qp] * Ue(j); 01183 else 01184 Ke(freei,freej) += 01185 TensorTools::inner_product((*dphi_coarse)[i][qp], 01186 (*dphi_coarse)[j][qp]) * 01187 JxW[qp]; 01188 } 01189 if (!dof_is_fixed[j]) 01190 freej++; 01191 } 01192 Fe(freei) += TensorTools::inner_product(fineval, phi_coarse[i][qp]) * JxW[qp]; 01193 if (cont == C_ONE) 01194 Fe(freei) += 01195 TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp]; 01196 freei++; 01197 } 01198 } 01199 } 01200 Ke.cholesky_solve(Fe, Uside); 01201 01202 // Transfer new side solutions to element 01203 for (unsigned int i=0; i != free_dofs; ++i) 01204 { 01205 Number &ui = Ue(new_side_dofs[free_dof[i]]); 01206 libmesh_assert(std::abs(ui) < TOLERANCE || 01207 std::abs(ui - Uside(i)) < TOLERANCE); 01208 ui = Uside(i); 01209 dof_is_fixed[new_side_dofs[free_dof[i]]] = 01210 true; 01211 } 01212 } 01213 01214 // Project the interior values, finally 01215 01216 // Some interior dofs are on nodes/edges/sides and 01217 // already fixed, others are free to calculate 01218 unsigned int free_dofs = 0; 01219 for (unsigned int i=0; i != new_n_dofs; ++i) 01220 if (!dof_is_fixed[i]) 01221 free_dof[free_dofs++] = i; 01222 Ke.resize (free_dofs, free_dofs); Ke.zero(); 01223 Fe.resize (free_dofs); Fe.zero(); 01224 // The new interior coefficients 01225 DenseVector<Number> Uint(free_dofs); 01226 01227 // Add projection terms from each child 01228 for (unsigned int c=0; c != elem->n_children(); ++c) 01229 { 01230 Elem *child = elem->child(c); 01231 01232 std::vector<dof_id_type> child_dof_indices; 01233 if (use_old_dof_indices) 01234 dof_map.old_dof_indices (child, 01235 child_dof_indices, var); 01236 else 01237 dof_map.dof_indices (child, 01238 child_dof_indices, var); 01239 const unsigned int child_n_dofs = 01240 cast_int<unsigned int> 01241 (child_dof_indices.size()); 01242 01243 // Initialize both child and parent FE data 01244 // on the child's quadrature points 01245 fe->attach_quadrature_rule (qrule.get()); 01246 fe->reinit (child); 01247 const unsigned int n_qp = qrule->n_points(); 01248 01249 FEInterface::inverse_map (dim, fe_type, elem, 01250 xyz_values, coarse_qpoints); 01251 01252 fe_coarse->reinit(elem, &coarse_qpoints); 01253 01254 // Loop over the quadrature points 01255 for (unsigned int qp=0; qp<n_qp; qp++) 01256 { 01257 // solution value at the quadrature point 01258 OutputNumber fineval = libMesh::zero; 01259 // solution grad at the quadrature point 01260 OutputNumberGradient finegrad; 01261 01262 // Sum the solution values * the DOF 01263 // values at the quadrature point to 01264 // get the solution value and gradient. 01265 for (unsigned int i=0; i<child_n_dofs; i++) 01266 { 01267 fineval += 01268 (old_vector(child_dof_indices[i]) * 01269 phi_values[i][qp]); 01270 if (cont == C_ONE) 01271 finegrad += (*dphi_values)[i][qp] * 01272 old_vector(child_dof_indices[i]); 01273 } 01274 01275 // Form interior projection matrix 01276 for (unsigned int i=0, freei=0; 01277 i != new_n_dofs; ++i) 01278 { 01279 // fixed DoFs aren't test functions 01280 if (dof_is_fixed[i]) 01281 continue; 01282 for (unsigned int j=0, freej=0; j != 01283 new_n_dofs; ++j) 01284 { 01285 if (dof_is_fixed[j]) 01286 Fe(freei) -= 01287 TensorTools::inner_product(phi_coarse[i][qp], 01288 phi_coarse[j][qp]) * 01289 JxW[qp] * Ue(j); 01290 else 01291 Ke(freei,freej) += 01292 TensorTools::inner_product(phi_coarse[i][qp], 01293 phi_coarse[j][qp]) * 01294 JxW[qp]; 01295 if (cont == C_ONE) 01296 { 01297 if (dof_is_fixed[j]) 01298 Fe(freei) -= 01299 TensorTools::inner_product((*dphi_coarse)[i][qp], 01300 (*dphi_coarse)[j][qp]) * 01301 JxW[qp] * Ue(j); 01302 else 01303 Ke(freei,freej) += 01304 TensorTools::inner_product((*dphi_coarse)[i][qp], 01305 (*dphi_coarse)[j][qp]) * 01306 JxW[qp]; 01307 } 01308 if (!dof_is_fixed[j]) 01309 freej++; 01310 } 01311 Fe(freei) += TensorTools::inner_product(phi_coarse[i][qp], fineval) * 01312 JxW[qp]; 01313 if (cont == C_ONE) 01314 Fe(freei) += TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp]; 01315 freei++; 01316 } 01317 } 01318 } 01319 Ke.cholesky_solve(Fe, Uint); 01320 01321 // Transfer new interior solutions to element 01322 for (unsigned int i=0; i != free_dofs; ++i) 01323 { 01324 Number &ui = Ue(free_dof[i]); 01325 libmesh_assert(std::abs(ui) < TOLERANCE || 01326 std::abs(ui - Uint(i)) < TOLERANCE); 01327 ui = Uint(i); 01328 // We should be fixing all dofs by now; no need to keep track of 01329 // that unless we're debugging 01330 #ifndef NDEBUG 01331 dof_is_fixed[free_dof[i]] = true; 01332 #endif 01333 } 01334 01335 #ifndef NDEBUG 01336 // Make sure every DoF got reached! 01337 for (unsigned int i=0; i != new_n_dofs; ++i) 01338 libmesh_assert(dof_is_fixed[i]); 01339 #endif 01340 } 01341 01342 01343 01344 template <typename OutputType> 01345 void 01346 FEGenericBase<OutputType>::compute_proj_constraints (DofConstraints &constraints, 01347 DofMap &dof_map, 01348 const unsigned int variable_number, 01349 const Elem* elem) 01350 { 01351 libmesh_assert(elem); 01352 01353 const unsigned int Dim = elem->dim(); 01354 01355 // Only constrain elements in 2,3D. 01356 if (Dim == 1) 01357 return; 01358 01359 // Only constrain active elements with this method 01360 if (!elem->active()) 01361 return; 01362 01363 const FEType& base_fe_type = dof_map.variable_type(variable_number); 01364 01365 // Construct FE objects for this element and its neighbors. 01366 UniquePtr<FEGenericBase<OutputShape> > my_fe 01367 (FEGenericBase<OutputShape>::build(Dim, base_fe_type)); 01368 const FEContinuity cont = my_fe->get_continuity(); 01369 01370 // We don't need to constrain discontinuous elements 01371 if (cont == DISCONTINUOUS) 01372 return; 01373 libmesh_assert (cont == C_ZERO || cont == C_ONE); 01374 01375 UniquePtr<FEGenericBase<OutputShape> > neigh_fe 01376 (FEGenericBase<OutputShape>::build(Dim, base_fe_type)); 01377 01378 QGauss my_qface(Dim-1, base_fe_type.default_quadrature_order()); 01379 my_fe->attach_quadrature_rule (&my_qface); 01380 std::vector<Point> neigh_qface; 01381 01382 const std::vector<Real>& JxW = my_fe->get_JxW(); 01383 const std::vector<Point>& q_point = my_fe->get_xyz(); 01384 const std::vector<std::vector<OutputShape> >& phi = my_fe->get_phi(); 01385 const std::vector<std::vector<OutputShape> >& neigh_phi = 01386 neigh_fe->get_phi(); 01387 const std::vector<Point> *face_normals = NULL; 01388 const std::vector<std::vector<OutputGradient> > *dphi = NULL; 01389 const std::vector<std::vector<OutputGradient> > *neigh_dphi = NULL; 01390 01391 std::vector<dof_id_type> my_dof_indices, neigh_dof_indices; 01392 std::vector<unsigned int> my_side_dofs, neigh_side_dofs; 01393 01394 if (cont != C_ZERO) 01395 { 01396 const std::vector<Point>& ref_face_normals = 01397 my_fe->get_normals(); 01398 face_normals = &ref_face_normals; 01399 const std::vector<std::vector<OutputGradient> >& ref_dphi = 01400 my_fe->get_dphi(); 01401 dphi = &ref_dphi; 01402 const std::vector<std::vector<OutputGradient> >& ref_neigh_dphi = 01403 neigh_fe->get_dphi(); 01404 neigh_dphi = &ref_neigh_dphi; 01405 } 01406 01407 DenseMatrix<Real> Ke; 01408 DenseVector<Real> Fe; 01409 std::vector<DenseVector<Real> > Ue; 01410 01411 // Look at the element faces. Check to see if we need to 01412 // build constraints. 01413 for (unsigned int s=0; s<elem->n_sides(); s++) 01414 if (elem->neighbor(s) != NULL) 01415 { 01416 // Get pointers to the element's neighbor. 01417 const Elem* neigh = elem->neighbor(s); 01418 01419 // h refinement constraints: 01420 // constrain dofs shared between 01421 // this element and ones coarser 01422 // than this element. 01423 if (neigh->level() < elem->level()) 01424 { 01425 unsigned int s_neigh = neigh->which_neighbor_am_i(elem); 01426 libmesh_assert_less (s_neigh, neigh->n_neighbors()); 01427 01428 // Find the minimum p level; we build the h constraint 01429 // matrix with this and then constrain away all higher p 01430 // DoFs. 01431 libmesh_assert(neigh->active()); 01432 const unsigned int min_p_level = 01433 std::min(elem->p_level(), neigh->p_level()); 01434 01435 // we may need to make the FE objects reinit with the 01436 // minimum shared p_level 01437 // FIXME - I hate using const_cast<> and avoiding 01438 // accessor functions; there's got to be a 01439 // better way to do this! 01440 const unsigned int old_elem_level = elem->p_level(); 01441 if (old_elem_level != min_p_level) 01442 (const_cast<Elem *>(elem))->hack_p_level(min_p_level); 01443 const unsigned int old_neigh_level = neigh->p_level(); 01444 if (old_neigh_level != min_p_level) 01445 (const_cast<Elem *>(neigh))->hack_p_level(min_p_level); 01446 01447 my_fe->reinit(elem, s); 01448 01449 // This function gets called element-by-element, so there 01450 // will be a lot of memory allocation going on. We can 01451 // at least minimize this for the case of the dof indices 01452 // by efficiently preallocating the requisite storage. 01453 // n_nodes is not necessarily n_dofs, but it is better 01454 // than nothing! 01455 my_dof_indices.reserve (elem->n_nodes()); 01456 neigh_dof_indices.reserve (neigh->n_nodes()); 01457 01458 dof_map.dof_indices (elem, my_dof_indices, 01459 variable_number); 01460 dof_map.dof_indices (neigh, neigh_dof_indices, 01461 variable_number); 01462 01463 const unsigned int n_qp = my_qface.n_points(); 01464 01465 FEInterface::inverse_map (Dim, base_fe_type, neigh, 01466 q_point, neigh_qface); 01467 01468 neigh_fe->reinit(neigh, &neigh_qface); 01469 01470 // We're only concerned with DOFs whose values (and/or first 01471 // derivatives for C1 elements) are supported on side nodes 01472 FEInterface::dofs_on_side(elem, Dim, base_fe_type, s, my_side_dofs); 01473 FEInterface::dofs_on_side(neigh, Dim, base_fe_type, s_neigh, neigh_side_dofs); 01474 01475 // We're done with functions that examine Elem::p_level(), 01476 // so let's unhack those levels 01477 if (elem->p_level() != old_elem_level) 01478 (const_cast<Elem *>(elem))->hack_p_level(old_elem_level); 01479 if (neigh->p_level() != old_neigh_level) 01480 (const_cast<Elem *>(neigh))->hack_p_level(old_neigh_level); 01481 01482 const unsigned int n_side_dofs = 01483 cast_int<unsigned int>(my_side_dofs.size()); 01484 libmesh_assert_equal_to (n_side_dofs, neigh_side_dofs.size()); 01485 01486 Ke.resize (n_side_dofs, n_side_dofs); 01487 Ue.resize(n_side_dofs); 01488 01489 // Form the projection matrix, (inner product of fine basis 01490 // functions against fine test functions) 01491 for (unsigned int is = 0; is != n_side_dofs; ++is) 01492 { 01493 const unsigned int i = my_side_dofs[is]; 01494 for (unsigned int js = 0; js != n_side_dofs; ++js) 01495 { 01496 const unsigned int j = my_side_dofs[js]; 01497 for (unsigned int qp = 0; qp != n_qp; ++qp) 01498 { 01499 Ke(is,js) += JxW[qp] * TensorTools::inner_product(phi[i][qp], phi[j][qp]); 01500 if (cont != C_ZERO) 01501 Ke(is,js) += JxW[qp] * 01502 TensorTools::inner_product((*dphi)[i][qp] * 01503 (*face_normals)[qp], 01504 (*dphi)[j][qp] * 01505 (*face_normals)[qp]); 01506 } 01507 } 01508 } 01509 01510 // Form the right hand sides, (inner product of coarse basis 01511 // functions against fine test functions) 01512 for (unsigned int is = 0; is != n_side_dofs; ++is) 01513 { 01514 const unsigned int i = neigh_side_dofs[is]; 01515 Fe.resize (n_side_dofs); 01516 for (unsigned int js = 0; js != n_side_dofs; ++js) 01517 { 01518 const unsigned int j = my_side_dofs[js]; 01519 for (unsigned int qp = 0; qp != n_qp; ++qp) 01520 { 01521 Fe(js) += JxW[qp] * 01522 TensorTools::inner_product(neigh_phi[i][qp], 01523 phi[j][qp]); 01524 if (cont != C_ZERO) 01525 Fe(js) += JxW[qp] * 01526 TensorTools::inner_product((*neigh_dphi)[i][qp] * 01527 (*face_normals)[qp], 01528 (*dphi)[j][qp] * 01529 (*face_normals)[qp]); 01530 } 01531 } 01532 Ke.cholesky_solve(Fe, Ue[is]); 01533 } 01534 01535 for (unsigned int js = 0; js != n_side_dofs; ++js) 01536 { 01537 const unsigned int j = my_side_dofs[js]; 01538 const dof_id_type my_dof_g = my_dof_indices[j]; 01539 libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id); 01540 01541 // Hunt for "constraining against myself" cases before 01542 // we bother creating a constraint row 01543 bool self_constraint = false; 01544 for (unsigned int is = 0; is != n_side_dofs; ++is) 01545 { 01546 const unsigned int i = neigh_side_dofs[is]; 01547 const dof_id_type their_dof_g = neigh_dof_indices[i]; 01548 libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id); 01549 01550 if (their_dof_g == my_dof_g) 01551 { 01552 #ifndef NDEBUG 01553 const Real their_dof_value = Ue[is](js); 01554 libmesh_assert_less (std::abs(their_dof_value-1.), 01555 10*TOLERANCE); 01556 01557 for (unsigned int k = 0; k != n_side_dofs; ++k) 01558 libmesh_assert(k == is || 01559 std::abs(Ue[k](js)) < 01560 10*TOLERANCE); 01561 #endif 01562 01563 self_constraint = true; 01564 break; 01565 } 01566 } 01567 01568 if (self_constraint) 01569 continue; 01570 01571 DofConstraintRow* constraint_row; 01572 01573 // we may be running constraint methods concurrently 01574 // on multiple threads, so we need a lock to 01575 // ensure that this constraint is "ours" 01576 { 01577 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 01578 01579 if (dof_map.is_constrained_dof(my_dof_g)) 01580 continue; 01581 01582 constraint_row = &(constraints[my_dof_g]); 01583 libmesh_assert(constraint_row->empty()); 01584 } 01585 01586 for (unsigned int is = 0; is != n_side_dofs; ++is) 01587 { 01588 const unsigned int i = neigh_side_dofs[is]; 01589 const dof_id_type their_dof_g = neigh_dof_indices[i]; 01590 libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id); 01591 libmesh_assert_not_equal_to (their_dof_g, my_dof_g); 01592 01593 const Real their_dof_value = Ue[is](js); 01594 01595 if (std::abs(their_dof_value) < 10*TOLERANCE) 01596 continue; 01597 01598 constraint_row->insert(std::make_pair(their_dof_g, 01599 their_dof_value)); 01600 } 01601 } 01602 } 01603 // p refinement constraints: 01604 // constrain dofs shared between 01605 // active elements and neighbors with 01606 // lower polynomial degrees 01607 const unsigned int min_p_level = 01608 neigh->min_p_level_by_neighbor(elem, elem->p_level()); 01609 if (min_p_level < elem->p_level()) 01610 { 01611 // Adaptive p refinement of non-hierarchic bases will 01612 // require more coding 01613 libmesh_assert(my_fe->is_hierarchic()); 01614 dof_map.constrain_p_dofs(variable_number, elem, 01615 s, min_p_level); 01616 } 01617 } 01618 } 01619 01620 #endif // #ifdef LIBMESH_ENABLE_AMR 01621 01622 01623 01624 #ifdef LIBMESH_ENABLE_PERIODIC 01625 template <typename OutputType> 01626 void 01627 FEGenericBase<OutputType>:: 01628 compute_periodic_constraints (DofConstraints &constraints, 01629 DofMap &dof_map, 01630 const PeriodicBoundaries &boundaries, 01631 const MeshBase &mesh, 01632 const PointLocatorBase *point_locator, 01633 const unsigned int variable_number, 01634 const Elem* elem) 01635 { 01636 // Only bother if we truly have periodic boundaries 01637 if (boundaries.empty()) 01638 return; 01639 01640 libmesh_assert(elem); 01641 01642 // Only constrain active elements with this method 01643 if (!elem->active()) 01644 return; 01645 01646 const unsigned int Dim = elem->dim(); 01647 01648 // We need sys_number and variable_number for DofObject methods 01649 // later 01650 const unsigned int sys_number = dof_map.sys_number(); 01651 01652 const FEType& base_fe_type = dof_map.variable_type(variable_number); 01653 01654 // Construct FE objects for this element and its pseudo-neighbors. 01655 UniquePtr<FEGenericBase<OutputShape> > my_fe 01656 (FEGenericBase<OutputShape>::build(Dim, base_fe_type)); 01657 const FEContinuity cont = my_fe->get_continuity(); 01658 01659 // We don't need to constrain discontinuous elements 01660 if (cont == DISCONTINUOUS) 01661 return; 01662 libmesh_assert (cont == C_ZERO || cont == C_ONE); 01663 01664 // We'll use element size to generate relative tolerances later 01665 const Real primary_hmin = elem->hmin(); 01666 01667 UniquePtr<FEGenericBase<OutputShape> > neigh_fe 01668 (FEGenericBase<OutputShape>::build(Dim, base_fe_type)); 01669 01670 QGauss my_qface(Dim-1, base_fe_type.default_quadrature_order()); 01671 my_fe->attach_quadrature_rule (&my_qface); 01672 std::vector<Point> neigh_qface; 01673 01674 const std::vector<Real>& JxW = my_fe->get_JxW(); 01675 const std::vector<Point>& q_point = my_fe->get_xyz(); 01676 const std::vector<std::vector<OutputShape> >& phi = my_fe->get_phi(); 01677 const std::vector<std::vector<OutputShape> >& neigh_phi = 01678 neigh_fe->get_phi(); 01679 const std::vector<Point> *face_normals = NULL; 01680 const std::vector<std::vector<OutputGradient> > *dphi = NULL; 01681 const std::vector<std::vector<OutputGradient> > *neigh_dphi = NULL; 01682 std::vector<dof_id_type> my_dof_indices, neigh_dof_indices; 01683 std::vector<unsigned int> my_side_dofs, neigh_side_dofs; 01684 01685 if (cont != C_ZERO) 01686 { 01687 const std::vector<Point>& ref_face_normals = 01688 my_fe->get_normals(); 01689 face_normals = &ref_face_normals; 01690 const std::vector<std::vector<OutputGradient> >& ref_dphi = 01691 my_fe->get_dphi(); 01692 dphi = &ref_dphi; 01693 const std::vector<std::vector<OutputGradient> >& ref_neigh_dphi = 01694 neigh_fe->get_dphi(); 01695 neigh_dphi = &ref_neigh_dphi; 01696 } 01697 01698 DenseMatrix<Real> Ke; 01699 DenseVector<Real> Fe; 01700 std::vector<DenseVector<Real> > Ue; 01701 01702 // Look at the element faces. Check to see if we need to 01703 // build constraints. 01704 for (unsigned short int s=0; s<elem->n_sides(); s++) 01705 { 01706 if (elem->neighbor(s)) 01707 continue; 01708 01709 const std::vector<boundary_id_type>& bc_ids = 01710 mesh.get_boundary_info().boundary_ids (elem, s); 01711 for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it) 01712 { 01713 const boundary_id_type boundary_id = *id_it; 01714 const PeriodicBoundaryBase *periodic = boundaries.boundary(boundary_id); 01715 if (periodic && periodic->is_my_variable(variable_number)) 01716 { 01717 libmesh_assert(point_locator); 01718 01719 // Get pointers to the element's neighbor. 01720 const Elem* neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s); 01721 01722 if (neigh == NULL) 01723 libmesh_error_msg("PeriodicBoundaries point locator object returned NULL!"); 01724 01725 // periodic (and possibly h refinement) constraints: 01726 // constrain dofs shared between 01727 // this element and ones as coarse 01728 // as or coarser than this element. 01729 if (neigh->level() <= elem->level()) 01730 { 01731 unsigned int s_neigh = 01732 mesh.get_boundary_info().side_with_boundary_id(neigh, periodic->pairedboundary); 01733 libmesh_assert_not_equal_to (s_neigh, libMesh::invalid_uint); 01734 01735 #ifdef LIBMESH_ENABLE_AMR 01736 // Find the minimum p level; we build the h constraint 01737 // matrix with this and then constrain away all higher p 01738 // DoFs. 01739 libmesh_assert(neigh->active()); 01740 const unsigned int min_p_level = 01741 std::min(elem->p_level(), neigh->p_level()); 01742 01743 // we may need to make the FE objects reinit with the 01744 // minimum shared p_level 01745 // FIXME - I hate using const_cast<> and avoiding 01746 // accessor functions; there's got to be a 01747 // better way to do this! 01748 const unsigned int old_elem_level = elem->p_level(); 01749 if (old_elem_level != min_p_level) 01750 (const_cast<Elem *>(elem))->hack_p_level(min_p_level); 01751 const unsigned int old_neigh_level = neigh->p_level(); 01752 if (old_neigh_level != min_p_level) 01753 (const_cast<Elem *>(neigh))->hack_p_level(min_p_level); 01754 #endif // #ifdef LIBMESH_ENABLE_AMR 01755 01756 // We can do a projection with a single integration, 01757 // due to the assumption of nested finite element 01758 // subspaces. 01759 // FIXME: it might be more efficient to do nodes, 01760 // then edges, then side, to reduce the size of the 01761 // Cholesky factorization(s) 01762 my_fe->reinit(elem, s); 01763 01764 dof_map.dof_indices (elem, my_dof_indices, 01765 variable_number); 01766 dof_map.dof_indices (neigh, neigh_dof_indices, 01767 variable_number); 01768 01769 const unsigned int n_qp = my_qface.n_points(); 01770 01771 // Translate the quadrature points over to the 01772 // neighbor's boundary 01773 std::vector<Point> neigh_point(q_point.size()); 01774 for (unsigned int i=0; i != neigh_point.size(); ++i) 01775 neigh_point[i] = periodic->get_corresponding_pos(q_point[i]); 01776 01777 FEInterface::inverse_map (Dim, base_fe_type, neigh, 01778 neigh_point, neigh_qface); 01779 01780 neigh_fe->reinit(neigh, &neigh_qface); 01781 01782 // We're only concerned with DOFs whose values (and/or first 01783 // derivatives for C1 elements) are supported on side nodes 01784 FEInterface::dofs_on_side(elem, Dim, base_fe_type, s, my_side_dofs); 01785 FEInterface::dofs_on_side(neigh, Dim, base_fe_type, s_neigh, neigh_side_dofs); 01786 01787 // We're done with functions that examine Elem::p_level(), 01788 // so let's unhack those levels 01789 #ifdef LIBMESH_ENABLE_AMR 01790 if (elem->p_level() != old_elem_level) 01791 (const_cast<Elem *>(elem))->hack_p_level(old_elem_level); 01792 if (neigh->p_level() != old_neigh_level) 01793 (const_cast<Elem *>(neigh))->hack_p_level(old_neigh_level); 01794 #endif // #ifdef LIBMESH_ENABLE_AMR 01795 01796 const unsigned int n_side_dofs = 01797 cast_int<unsigned int> 01798 (my_side_dofs.size()); 01799 libmesh_assert_equal_to (n_side_dofs, neigh_side_dofs.size()); 01800 01801 Ke.resize (n_side_dofs, n_side_dofs); 01802 Ue.resize(n_side_dofs); 01803 01804 // Form the projection matrix, (inner product of fine basis 01805 // functions against fine test functions) 01806 for (unsigned int is = 0; is != n_side_dofs; ++is) 01807 { 01808 const unsigned int i = my_side_dofs[is]; 01809 for (unsigned int js = 0; js != n_side_dofs; ++js) 01810 { 01811 const unsigned int j = my_side_dofs[js]; 01812 for (unsigned int qp = 0; qp != n_qp; ++qp) 01813 { 01814 Ke(is,js) += JxW[qp] * 01815 TensorTools::inner_product(phi[i][qp], 01816 phi[j][qp]); 01817 if (cont != C_ZERO) 01818 Ke(is,js) += JxW[qp] * 01819 TensorTools::inner_product((*dphi)[i][qp] * 01820 (*face_normals)[qp], 01821 (*dphi)[j][qp] * 01822 (*face_normals)[qp]); 01823 } 01824 } 01825 } 01826 01827 // Form the right hand sides, (inner product of coarse basis 01828 // functions against fine test functions) 01829 for (unsigned int is = 0; is != n_side_dofs; ++is) 01830 { 01831 const unsigned int i = neigh_side_dofs[is]; 01832 Fe.resize (n_side_dofs); 01833 for (unsigned int js = 0; js != n_side_dofs; ++js) 01834 { 01835 const unsigned int j = my_side_dofs[js]; 01836 for (unsigned int qp = 0; qp != n_qp; ++qp) 01837 { 01838 Fe(js) += JxW[qp] * 01839 TensorTools::inner_product(neigh_phi[i][qp], 01840 phi[j][qp]); 01841 if (cont != C_ZERO) 01842 Fe(js) += JxW[qp] * 01843 TensorTools::inner_product((*neigh_dphi)[i][qp] * 01844 (*face_normals)[qp], 01845 (*dphi)[j][qp] * 01846 (*face_normals)[qp]); 01847 } 01848 } 01849 Ke.cholesky_solve(Fe, Ue[is]); 01850 } 01851 01852 // Make sure we're not adding recursive constraints 01853 // due to the redundancy in the way we add periodic 01854 // boundary constraints 01855 // 01856 // In order for this to work while threaded or on 01857 // distributed meshes, we need a rigorous way to 01858 // avoid recursive constraints. Here it is: 01859 // 01860 // For vertex DoFs, if there is a "prior" element 01861 // (i.e. a coarser element or an equally refined 01862 // element with a lower id) on this boundary which 01863 // contains the vertex point, then we will avoid 01864 // generating constraints; the prior element (or 01865 // something prior to it) may do so. If we are the 01866 // most prior (or "primary") element on this 01867 // boundary sharing this point, then we look at the 01868 // boundary periodic to us, we find the primary 01869 // element there, and if that primary is coarser or 01870 // equal-but-lower-id, then our vertex dofs are 01871 // constrained in terms of that element. 01872 // 01873 // For edge DoFs, if there is a coarser element 01874 // on this boundary sharing this edge, then we will 01875 // avoid generating constraints (we will be 01876 // constrained indirectly via AMR constraints 01877 // connecting us to the coarser element's DoFs). If 01878 // we are the coarsest element sharing this edge, 01879 // then we generate constraints if and only if we 01880 // are finer than the coarsest element on the 01881 // boundary periodic to us sharing the corresponding 01882 // periodic edge, or if we are at equal level but 01883 // our edge nodes have higher ids than the periodic 01884 // edge nodes (sorted from highest to lowest, then 01885 // compared lexicographically) 01886 // 01887 // For face DoFs, we generate constraints if we are 01888 // finer than our periodic neighbor, or if we are at 01889 // equal level but our element id is higher than its 01890 // element id. 01891 // 01892 // If the primary neighbor is also the current elem 01893 // (a 1-element-thick mesh) then we choose which 01894 // vertex dofs to constrain via lexicographic 01895 // ordering on point locations 01896 01897 // FIXME: This code doesn't yet properly handle 01898 // cases where multiple different periodic BCs 01899 // intersect. 01900 std::set<dof_id_type> my_constrained_dofs; 01901 01902 for (unsigned int n = 0; n != elem->n_nodes(); ++n) 01903 { 01904 if (!elem->is_node_on_side(n,s)) 01905 continue; 01906 01907 const Node* my_node = elem->get_node(n); 01908 01909 if (elem->is_vertex(n)) 01910 { 01911 // Find all boundary ids that include this 01912 // point and have periodic boundary 01913 // conditions for this variable 01914 std::set<boundary_id_type> point_bcids; 01915 01916 for (unsigned int new_s = 0; new_s != 01917 elem->n_sides(); ++new_s) 01918 { 01919 if (!elem->is_node_on_side(n,new_s)) 01920 continue; 01921 01922 const std::vector<boundary_id_type> new_bc_ids = 01923 mesh.get_boundary_info().boundary_ids (elem, s); 01924 for (std::vector<boundary_id_type>::const_iterator 01925 new_id_it=new_bc_ids.begin(); new_id_it!=new_bc_ids.end(); ++new_id_it) 01926 { 01927 const boundary_id_type new_boundary_id = *new_id_it; 01928 const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id); 01929 if (new_periodic && new_periodic->is_my_variable(variable_number)) 01930 { 01931 point_bcids.insert(new_boundary_id); 01932 } 01933 } 01934 } 01935 01936 // See if this vertex has point neighbors to 01937 // defer to 01938 if (primary_boundary_point_neighbor 01939 (elem, *my_node, mesh.get_boundary_info(), point_bcids) 01940 != elem) 01941 continue; 01942 01943 // Find the complementary boundary id set 01944 std::set<boundary_id_type> point_pairedids; 01945 for (std::set<boundary_id_type>::const_iterator i = 01946 point_bcids.begin(); i != point_bcids.end(); ++i) 01947 { 01948 const boundary_id_type new_boundary_id = *i; 01949 const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id); 01950 point_pairedids.insert(new_periodic->pairedboundary); 01951 } 01952 01953 // What do we want to constrain against? 01954 const Elem* primary_elem = NULL; 01955 const Elem* main_neigh = NULL; 01956 Point main_pt = *my_node, 01957 primary_pt = *my_node; 01958 01959 for (std::set<boundary_id_type>::const_iterator i = 01960 point_bcids.begin(); i != point_bcids.end(); ++i) 01961 { 01962 // Find the corresponding periodic point and 01963 // its primary neighbor 01964 const boundary_id_type new_boundary_id = *i; 01965 const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id); 01966 01967 const Point neigh_pt = 01968 new_periodic->get_corresponding_pos(*my_node); 01969 01970 // If the point is getting constrained 01971 // to itself by this PBC then we don't 01972 // generate any constraints 01973 if (neigh_pt.absolute_fuzzy_equals 01974 (*my_node, primary_hmin*TOLERANCE)) 01975 continue; 01976 01977 // Otherwise we'll have a constraint in 01978 // one direction or another 01979 if (!primary_elem) 01980 primary_elem = elem; 01981 01982 const Elem *primary_neigh = 01983 primary_boundary_point_neighbor(neigh, neigh_pt, 01984 mesh.get_boundary_info(), 01985 point_pairedids); 01986 01987 libmesh_assert(primary_neigh); 01988 01989 if (new_boundary_id == boundary_id) 01990 { 01991 main_neigh = primary_neigh; 01992 main_pt = neigh_pt; 01993 } 01994 01995 // Finer elements will get constrained in 01996 // terms of coarser neighbors, not the 01997 // other way around 01998 if ((primary_neigh->level() > primary_elem->level()) || 01999 02000 // For equal-level elements, the one with 02001 // higher id gets constrained in terms of 02002 // the one with lower id 02003 (primary_neigh->level() == primary_elem->level() && 02004 primary_neigh->id() > primary_elem->id()) || 02005 02006 // On a one-element-thick mesh, we compare 02007 // points to see what side gets constrained 02008 (primary_neigh == primary_elem && 02009 (neigh_pt > primary_pt))) 02010 continue; 02011 02012 primary_elem = primary_neigh; 02013 primary_pt = neigh_pt; 02014 } 02015 02016 if (!primary_elem || 02017 primary_elem != main_neigh || 02018 primary_pt != main_pt) 02019 continue; 02020 } 02021 else if (elem->is_edge(n)) 02022 { 02023 // Find which edge we're on 02024 unsigned int e=0; 02025 for (; e != elem->n_edges(); ++e) 02026 { 02027 if (elem->is_node_on_edge(n,e)) 02028 break; 02029 } 02030 libmesh_assert_less (e, elem->n_edges()); 02031 02032 // Find the edge end nodes 02033 Node *e1 = NULL, 02034 *e2 = NULL; 02035 for (unsigned int nn = 0; nn != elem->n_nodes(); ++nn) 02036 { 02037 if (nn == n) 02038 continue; 02039 02040 if (elem->is_node_on_edge(nn, e)) 02041 { 02042 if (e1 == NULL) 02043 { 02044 e1 = elem->get_node(nn); 02045 } 02046 else 02047 { 02048 e2 = elem->get_node(nn); 02049 break; 02050 } 02051 } 02052 } 02053 libmesh_assert (e1 && e2); 02054 02055 // Find all boundary ids that include this 02056 // edge and have periodic boundary 02057 // conditions for this variable 02058 std::set<boundary_id_type> edge_bcids; 02059 02060 for (unsigned int new_s = 0; new_s != 02061 elem->n_sides(); ++new_s) 02062 { 02063 if (!elem->is_node_on_side(n,new_s)) 02064 continue; 02065 02066 const std::vector<boundary_id_type>& new_bc_ids = 02067 mesh.get_boundary_info().boundary_ids (elem, s); 02068 for (std::vector<boundary_id_type>::const_iterator 02069 new_id_it=new_bc_ids.begin(); new_id_it!=new_bc_ids.end(); ++new_id_it) 02070 { 02071 const boundary_id_type new_boundary_id = *new_id_it; 02072 const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id); 02073 if (new_periodic && new_periodic->is_my_variable(variable_number)) 02074 { 02075 edge_bcids.insert(new_boundary_id); 02076 } 02077 } 02078 } 02079 02080 02081 // See if this edge has neighbors to defer to 02082 if (primary_boundary_edge_neighbor 02083 (elem, *e1, *e2, mesh.get_boundary_info(), edge_bcids) 02084 != elem) 02085 continue; 02086 02087 // Find the complementary boundary id set 02088 std::set<boundary_id_type> edge_pairedids; 02089 for (std::set<boundary_id_type>::const_iterator i = 02090 edge_bcids.begin(); i != edge_bcids.end(); ++i) 02091 { 02092 const boundary_id_type new_boundary_id = *i; 02093 const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id); 02094 edge_pairedids.insert(new_periodic->pairedboundary); 02095 } 02096 02097 // What do we want to constrain against? 02098 const Elem* primary_elem = NULL; 02099 const Elem* main_neigh = NULL; 02100 Point main_pt1 = *e1, 02101 main_pt2 = *e2, 02102 primary_pt1 = *e1, 02103 primary_pt2 = *e2; 02104 02105 for (std::set<boundary_id_type>::const_iterator i = 02106 edge_bcids.begin(); i != edge_bcids.end(); ++i) 02107 { 02108 // Find the corresponding periodic edge and 02109 // its primary neighbor 02110 const boundary_id_type new_boundary_id = *i; 02111 const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id); 02112 02113 Point neigh_pt1 = new_periodic->get_corresponding_pos(*e1), 02114 neigh_pt2 = new_periodic->get_corresponding_pos(*e2); 02115 02116 // If the edge is getting constrained 02117 // to itself by this PBC then we don't 02118 // generate any constraints 02119 if (neigh_pt1.absolute_fuzzy_equals 02120 (*e1, primary_hmin*TOLERANCE) && 02121 neigh_pt2.absolute_fuzzy_equals 02122 (*e2, primary_hmin*TOLERANCE)) 02123 continue; 02124 02125 // Otherwise we'll have a constraint in 02126 // one direction or another 02127 if (!primary_elem) 02128 primary_elem = elem; 02129 02130 const Elem *primary_neigh = primary_boundary_edge_neighbor 02131 (neigh, neigh_pt1, neigh_pt2, 02132 mesh.get_boundary_info(), edge_pairedids); 02133 02134 libmesh_assert(primary_neigh); 02135 02136 if (new_boundary_id == boundary_id) 02137 { 02138 main_neigh = primary_neigh; 02139 main_pt1 = neigh_pt1; 02140 main_pt2 = neigh_pt2; 02141 } 02142 02143 // If we have a one-element thick mesh, 02144 // we'll need to sort our points to get a 02145 // consistent ordering rule 02146 // 02147 // Use >= in this test to make sure that, 02148 // for angular constraints, no node gets 02149 // constrained to itself. 02150 if (primary_neigh == primary_elem) 02151 { 02152 if (primary_pt1 > primary_pt2) 02153 std::swap(primary_pt1, primary_pt2); 02154 if (neigh_pt1 > neigh_pt2) 02155 std::swap(neigh_pt1, neigh_pt2); 02156 02157 if (neigh_pt2 >= primary_pt2) 02158 continue; 02159 } 02160 02161 // Otherwise: 02162 // Finer elements will get constrained in 02163 // terms of coarser ones, not the other way 02164 // around 02165 if ((primary_neigh->level() > primary_elem->level()) || 02166 02167 // For equal-level elements, the one with 02168 // higher id gets constrained in terms of 02169 // the one with lower id 02170 (primary_neigh->level() == primary_elem->level() && 02171 primary_neigh->id() > primary_elem->id())) 02172 continue; 02173 02174 primary_elem = primary_neigh; 02175 primary_pt1 = neigh_pt1; 02176 primary_pt2 = neigh_pt2; 02177 } 02178 02179 if (!primary_elem || 02180 primary_elem != main_neigh || 02181 primary_pt1 != main_pt1 || 02182 primary_pt2 != main_pt2) 02183 continue; 02184 } 02185 else if (elem->is_face(n)) 02186 { 02187 // If we have a one-element thick mesh, 02188 // use the ordering of the face node and its 02189 // periodic counterpart to determine what 02190 // gets constrained 02191 if (neigh == elem) 02192 { 02193 const Point neigh_pt = 02194 periodic->get_corresponding_pos(*my_node); 02195 if (neigh_pt > *my_node) 02196 continue; 02197 } 02198 02199 // Otherwise: 02200 // Finer elements will get constrained in 02201 // terms of coarser ones, not the other way 02202 // around 02203 if ((neigh->level() > elem->level()) || 02204 02205 // For equal-level elements, the one with 02206 // higher id gets constrained in terms of 02207 // the one with lower id 02208 (neigh->level() == elem->level() && 02209 neigh->id() > elem->id())) 02210 continue; 02211 } 02212 02213 // If we made it here without hitting a continue 02214 // statement, then we're at a node whose dofs 02215 // should be constrained by this element's 02216 // calculations. 02217 const unsigned int n_comp = 02218 my_node->n_comp(sys_number, variable_number); 02219 02220 for (unsigned int i=0; i != n_comp; ++i) 02221 my_constrained_dofs.insert 02222 (my_node->dof_number 02223 (sys_number, variable_number, i)); 02224 } 02225 02226 // FIXME: old code for disambiguating periodic BCs: 02227 // this is not threadsafe nor safe to run on a 02228 // non-serialized mesh. 02229 /* 02230 std::vector<bool> recursive_constraint(n_side_dofs, false); 02231 02232 for (unsigned int is = 0; is != n_side_dofs; ++is) 02233 { 02234 const unsigned int i = neigh_side_dofs[is]; 02235 const dof_id_type their_dof_g = neigh_dof_indices[i]; 02236 libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id); 02237 02238 { 02239 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 02240 02241 if (!dof_map.is_constrained_dof(their_dof_g)) 02242 continue; 02243 } 02244 02245 DofConstraintRow& their_constraint_row = 02246 constraints[their_dof_g].first; 02247 02248 for (unsigned int js = 0; js != n_side_dofs; ++js) 02249 { 02250 const unsigned int j = my_side_dofs[js]; 02251 const dof_id_type my_dof_g = my_dof_indices[j]; 02252 libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id); 02253 02254 if (their_constraint_row.count(my_dof_g)) 02255 recursive_constraint[js] = true; 02256 } 02257 } 02258 */ 02259 02260 for (unsigned int js = 0; js != n_side_dofs; ++js) 02261 { 02262 // FIXME: old code path 02263 // if (recursive_constraint[js]) 02264 // continue; 02265 02266 const unsigned int j = my_side_dofs[js]; 02267 const dof_id_type my_dof_g = my_dof_indices[j]; 02268 libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id); 02269 02270 // FIXME: new code path 02271 if (!my_constrained_dofs.count(my_dof_g)) 02272 continue; 02273 02274 DofConstraintRow* constraint_row; 02275 02276 // we may be running constraint methods concurretly 02277 // on multiple threads, so we need a lock to 02278 // ensure that this constraint is "ours" 02279 { 02280 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 02281 02282 if (dof_map.is_constrained_dof(my_dof_g)) 02283 continue; 02284 02285 constraint_row = &(constraints[my_dof_g]); 02286 libmesh_assert(constraint_row->empty()); 02287 } 02288 02289 for (unsigned int is = 0; is != n_side_dofs; ++is) 02290 { 02291 const unsigned int i = neigh_side_dofs[is]; 02292 const dof_id_type their_dof_g = neigh_dof_indices[i]; 02293 libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id); 02294 02295 // Periodic constraints should never be 02296 // self-constraints 02297 // libmesh_assert_not_equal_to (their_dof_g, my_dof_g); 02298 02299 const Real their_dof_value = Ue[is](js); 02300 02301 if (their_dof_g == my_dof_g) 02302 { 02303 libmesh_assert_less (std::abs(their_dof_value-1.), 1.e-5); 02304 for (unsigned int k = 0; k != n_side_dofs; ++k) 02305 libmesh_assert(k == is || std::abs(Ue[k](js)) < 1.e-5); 02306 continue; 02307 } 02308 02309 if (std::abs(their_dof_value) < 10*TOLERANCE) 02310 continue; 02311 02312 constraint_row->insert(std::make_pair(their_dof_g, 02313 their_dof_value)); 02314 } 02315 } 02316 } 02317 // p refinement constraints: 02318 // constrain dofs shared between 02319 // active elements and neighbors with 02320 // lower polynomial degrees 02321 #ifdef LIBMESH_ENABLE_AMR 02322 const unsigned int min_p_level = 02323 neigh->min_p_level_by_neighbor(elem, elem->p_level()); 02324 if (min_p_level < elem->p_level()) 02325 { 02326 // Adaptive p refinement of non-hierarchic bases will 02327 // require more coding 02328 libmesh_assert(my_fe->is_hierarchic()); 02329 dof_map.constrain_p_dofs(variable_number, elem, 02330 s, min_p_level); 02331 } 02332 #endif // #ifdef LIBMESH_ENABLE_AMR 02333 } 02334 } 02335 } 02336 } 02337 02338 #endif // LIBMESH_ENABLE_PERIODIC 02339 02340 // ------------------------------------------------------------ 02341 // Explicit instantiations 02342 template class FEGenericBase<Real>; 02343 template class FEGenericBase<RealGradient>; 02344 02345 } // namespace libMesh