$extrastylesheet
cell_tet4.C
Go to the documentation of this file.
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 // C++ includes
00020 
00021 // Local includes
00022 #include "libmesh/side.h"
00023 #include "libmesh/cell_tet4.h"
00024 #include "libmesh/edge_edge2.h"
00025 #include "libmesh/face_tri3.h"
00026 
00027 namespace libMesh
00028 {
00029 
00030 
00031 
00032 // ------------------------------------------------------------
00033 // Tet4 class static member initializations
00034 const unsigned int Tet4::side_nodes_map[4][3] =
00035   {
00036     {0, 2, 1}, // Side 0
00037     {0, 1, 3}, // Side 1
00038     {1, 2, 3}, // Side 2
00039     {2, 0, 3}  // Side 3
00040   };
00041 
00042 const unsigned int Tet4::edge_nodes_map[6][2] =
00043   {
00044     {0, 1}, // Side 0
00045     {1, 2}, // Side 1
00046     {0, 2}, // Side 2
00047     {0, 3}, // Side 3
00048     {1, 3}, // Side 4
00049     {2, 3}  // Side 5
00050   };
00051 
00052 
00053 // ------------------------------------------------------------
00054 // Tet4 class member functions
00055 
00056 bool Tet4::is_vertex(const unsigned int) const
00057 {
00058   return true;
00059 }
00060 
00061 bool Tet4::is_edge(const unsigned int) const
00062 {
00063   return false;
00064 }
00065 
00066 bool Tet4::is_face(const unsigned int) const
00067 {
00068   return false;
00069 }
00070 
00071 bool Tet4::is_node_on_edge(const unsigned int n,
00072                            const unsigned int e) const
00073 {
00074   libmesh_assert_less (e, n_edges());
00075   for (unsigned int i = 0; i != 2; ++i)
00076     if (edge_nodes_map[e][i] == n)
00077       return true;
00078   return false;
00079 }
00080 
00081 
00082 
00083 
00084 #ifdef LIBMESH_ENABLE_AMR
00085 
00086 // This function only works if LIBMESH_ENABLE_AMR...
00087 bool Tet4::is_child_on_side(const unsigned int c,
00088                             const unsigned int s) const
00089 {
00090   // OK, for the Tet4, this is pretty obvious... it is sets of nodes
00091   // not equal to the current node.  But if we want this algorithm to
00092   // be generic and work for Tet10 also it helps to do it this way.
00093   const unsigned int nodes_opposite[4][3] =
00094     {
00095       {1,2,3}, // nodes opposite node 0
00096       {0,2,3}, // nodes opposite node 1
00097       {0,1,3}, // nodes opposite node 2
00098       {0,1,2}  // nodes opposite node 3
00099     };
00100 
00101   // Call the base class helper function
00102   return Tet::is_child_on_side_helper(c, s, nodes_opposite);
00103 }
00104 
00105 #else
00106 
00107 bool Tet4::is_child_on_side(const unsigned int /*c*/,
00108                             const unsigned int /*s*/) const
00109 {
00110   libmesh_not_implemented();
00111   return false;
00112 }
00113 
00114 #endif //LIBMESH_ENABLE_AMR
00115 
00116 
00117 
00118 
00119 bool Tet4::is_node_on_side(const unsigned int n,
00120                            const unsigned int s) const
00121 {
00122   libmesh_assert_less (s, n_sides());
00123   for (unsigned int i = 0; i != 3; ++i)
00124     if (side_nodes_map[s][i] == n)
00125       return true;
00126   return false;
00127 }
00128 
00129 UniquePtr<Elem> Tet4::build_side (const unsigned int i,
00130                                   bool proxy) const
00131 {
00132   libmesh_assert_less (i, this->n_sides());
00133 
00134   if (proxy)
00135     return UniquePtr<Elem>(new Side<Tri3,Tet4>(this,i));
00136 
00137   else
00138     {
00139       Elem* face = new Tri3;
00140       face->subdomain_id() = this->subdomain_id();
00141 
00142       switch (i)
00143         {
00144         case 0:
00145           {
00146             face->set_node(0) = this->get_node(0);
00147             face->set_node(1) = this->get_node(2);
00148             face->set_node(2) = this->get_node(1);
00149             break;
00150           }
00151         case 1:
00152           {
00153             face->set_node(0) = this->get_node(0);
00154             face->set_node(1) = this->get_node(1);
00155             face->set_node(2) = this->get_node(3);
00156             break;
00157           }
00158         case 2:
00159           {
00160             face->set_node(0) = this->get_node(1);
00161             face->set_node(1) = this->get_node(2);
00162             face->set_node(2) = this->get_node(3);
00163             break;
00164           }
00165         case 3:
00166           {
00167             face->set_node(0) = this->get_node(2);
00168             face->set_node(1) = this->get_node(0);
00169             face->set_node(2) = this->get_node(3);
00170             break;
00171           }
00172         default:
00173           libmesh_error_msg("Invalid side i = " << i);
00174         }
00175 
00176       return UniquePtr<Elem>(face);
00177     }
00178 
00179   libmesh_error_msg("We'll never get here!");
00180   return UniquePtr<Elem>();
00181 }
00182 
00183 
00184 UniquePtr<Elem> Tet4::build_edge (const unsigned int i) const
00185 {
00186   libmesh_assert_less (i, this->n_edges());
00187 
00188   return UniquePtr<Elem>(new SideEdge<Edge2,Tet4>(this,i));
00189 }
00190 
00191 
00192 void Tet4::connectivity(const unsigned int libmesh_dbg_var(sc),
00193                         const IOPackage iop,
00194                         std::vector<dof_id_type>& conn) const
00195 {
00196   libmesh_assert(_nodes);
00197   libmesh_assert_less (sc, this->n_sub_elem());
00198   libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
00199 
00200 
00201   switch (iop)
00202     {
00203     case TECPLOT:
00204       {
00205         conn.resize(8);
00206         conn[0] = this->node(0)+1;
00207         conn[1] = this->node(1)+1;
00208         conn[2] = this->node(2)+1;
00209         conn[3] = this->node(2)+1;
00210         conn[4] = this->node(3)+1;
00211         conn[5] = this->node(3)+1;
00212         conn[6] = this->node(3)+1;
00213         conn[7] = this->node(3)+1;
00214         return;
00215       }
00216 
00217     case VTK:
00218       {
00219         conn.resize(4);
00220         conn[0] = this->node(0);
00221         conn[1] = this->node(1);
00222         conn[2] = this->node(2);
00223         conn[3] = this->node(3);
00224         return;
00225       }
00226 
00227     default:
00228       libmesh_error_msg("Unsupported IO package " << iop);
00229     }
00230 }
00231 
00232 
00233 
00234 #ifdef LIBMESH_ENABLE_AMR
00235 
00236 const float Tet4::_embedding_matrix[8][4][4] =
00237   {
00238     // embedding matrix for child 0
00239     {
00240       // 0    1    2    3
00241       {1.0, 0.0, 0.0, 0.0}, // 0
00242       {0.5, 0.5, 0.0, 0.0}, // 1
00243       {0.5, 0.0, 0.5, 0.0}, // 2
00244       {0.5, 0.0, 0.0, 0.5}  // 3
00245     },
00246 
00247     // embedding matrix for child 1
00248     {
00249       // 0    1    2    3
00250       {0.5, 0.5, 0.0, 0.0}, // 0
00251       {0.0, 1.0, 0.0, 0.0}, // 1
00252       {0.0, 0.5, 0.5, 0.0}, // 2
00253       {0.0, 0.5, 0.0, 0.5}  // 3
00254     },
00255 
00256     // embedding matrix for child 2
00257     {
00258       // 0    1    2    3
00259       {0.5, 0.0, 0.5, 0.0}, // 0
00260       {0.0, 0.5, 0.5, 0.0}, // 1
00261       {0.0, 0.0, 1.0, 0.0}, // 2
00262       {0.0, 0.0, 0.5, 0.5}  // 3
00263     },
00264 
00265     // embedding matrix for child 3
00266     {
00267       // 0    1    2    3
00268       {0.5, 0.0, 0.0, 0.5}, // 0
00269       {0.0, 0.5, 0.0, 0.5}, // 1
00270       {0.0, 0.0, 0.5, 0.5}, // 2
00271       {0.0, 0.0, 0.0, 1.0}  // 3
00272     },
00273 
00274     // embedding matrix for child 4
00275     {
00276       // 0    1    2    3
00277       {0.5, 0.5, 0.0, 0.0}, // 0
00278       {0.0, 0.5, 0.0, 0.5}, // 1
00279       {0.5, 0.0, 0.5, 0.0}, // 2
00280       {0.5, 0.0, 0.0, 0.5}  // 3
00281     },
00282 
00283     // embedding matrix for child 5
00284     {
00285       // 0    1    2    3
00286       {0.5, 0.5, 0.0, 0.0}, // 0
00287       {0.0, 0.5, 0.5, 0.0}, // 1
00288       {0.5, 0.0, 0.5, 0.0}, // 2
00289       {0.0, 0.5, 0.0, 0.5}  // 3
00290     },
00291 
00292     // embedding matrix for child 6
00293     {
00294       // 0    1    2    3
00295       {0.5, 0.0, 0.5, 0.0}, // 0
00296       {0.0, 0.5, 0.5, 0.0}, // 1
00297       {0.0, 0.0, 0.5, 0.5}, // 2
00298       {0.0, 0.5, 0.0, 0.5}  // 3
00299     },
00300 
00301     // embedding matrix for child 7
00302     {
00303       // 0    1    2    3
00304       {0.5, 0.0, 0.5, 0.0}, // 0
00305       {0.0, 0.5, 0.0, 0.5}, // 1
00306       {0.0, 0.0, 0.5, 0.5}, // 2
00307       {0.5, 0.0, 0.0, 0.5}  // 3
00308     }
00309   };
00310 
00311 #endif // #ifdef LIBMESH_ENABLE_AMR
00312 
00313 
00314 
00315 
00316 
00317 Real Tet4::volume () const
00318 {
00319   // The volume of a tetrahedron is 1/6 the box product formed
00320   // by its base and apex vectors
00321   Point a ( *this->get_node(3) - *this->get_node(0) );
00322 
00323   // b is the vector pointing from 0 to 1
00324   Point b ( *this->get_node(1) - *this->get_node(0) );
00325 
00326   // c is the vector pointing from 0 to 2
00327   Point c ( *this->get_node(2) - *this->get_node(0) );
00328 
00329   return (1.0 / 6.0) * (a * (b.cross(c)));
00330 }
00331 
00332 
00333 
00334 
00335 std::pair<Real, Real> Tet4::min_and_max_angle() const
00336 {
00337   Point n[4];
00338 
00339   // Compute the outward normal vectors on each face
00340   n[0] = (this->point(2) - this->point(0)).cross(this->point(1) - this->point(0));
00341   n[1] = (this->point(1) - this->point(0)).cross(this->point(3) - this->point(0));
00342   n[2] = (this->point(2) - this->point(1)).cross(this->point(3) - this->point(1));
00343   n[3] = (this->point(0) - this->point(2)).cross(this->point(3) - this->point(2));
00344 
00345   Real dihedral_angles[6]; // 01, 02, 03, 12, 13, 23
00346 
00347   // Compute dihedral angles
00348   for (unsigned int k=0,i=0; i<4; ++i)
00349     for (unsigned int j=i+1; j<4; ++j,k+=1)
00350       dihedral_angles[k] = std::acos(n[i]*n[j] / n[i].size() / n[j].size()); // return value is between 0 and PI
00351 
00352   // Return max/min dihedral angles
00353   return std::make_pair(*std::min_element(dihedral_angles, dihedral_angles+6),
00354                         *std::max_element(dihedral_angles, dihedral_angles+6));
00355 
00356 }
00357 
00358 
00359 
00360 #ifdef LIBMESH_ENABLE_AMR
00361 float Tet4::embedding_matrix (const unsigned int i,
00362                               const unsigned int j,
00363                               const unsigned int k) const
00364 {
00365   // Choose an optimal diagonal, if one has not already been selected
00366   this->choose_diagonal();
00367 
00368   // Permuted j and k indices
00369   unsigned int
00370     jp=j,
00371     kp=k;
00372 
00373   if ((i>3) && (this->_diagonal_selection!=DIAG_02_13))
00374     {
00375       // Just the enum value cast to an unsigned int...
00376       const unsigned ds = static_cast<unsigned int>(this->_diagonal_selection);
00377 
00378       // Permute j, k:
00379       // ds==1      ds==2
00380       // 0 -> 1     0 -> 2
00381       // 1 -> 2     1 -> 0
00382       // 2 -> 0     2 -> 1
00383       if (jp != 3)
00384         jp = (jp+ds)%3;
00385 
00386       if (kp != 3)
00387         kp = (kp+ds)%3;
00388     }
00389 
00390   // Debugging
00391   // libMesh::err << "Selected diagonal " << _diagonal_selection << std::endl;
00392   // libMesh::err << "j=" << j << std::endl;
00393   // libMesh::err << "k=" << k << std::endl;
00394   // libMesh::err << "jp=" << jp << std::endl;
00395   // libMesh::err << "kp=" << kp << std::endl;
00396 
00397   // Call embedding matrx with permuted indices
00398   return this->_embedding_matrix[i][jp][kp];
00399 }
00400 
00401 
00402 
00403 
00404 
00405 
00406 // void Tet4::reselect_diagonal (const Diagonal diag)
00407 // {
00408 //   /* Make sure that the element has just been refined.  */
00409 //   libmesh_assert(_children);
00410 //   libmesh_assert_equal_to (n_children(), 8);
00411 //   libmesh_assert_equal_to (_children[0]->refinement_flag(), JUST_REFINED);
00412 //   libmesh_assert_equal_to (_children[1]->refinement_flag(), JUST_REFINED);
00413 //   libmesh_assert_equal_to (_children[2]->refinement_flag(), JUST_REFINED);
00414 //   libmesh_assert_equal_to (_children[3]->refinement_flag(), JUST_REFINED);
00415 //   libmesh_assert_equal_to (_children[4]->refinement_flag(), JUST_REFINED);
00416 //   libmesh_assert_equal_to (_children[5]->refinement_flag(), JUST_REFINED);
00417 //   libmesh_assert_equal_to (_children[6]->refinement_flag(), JUST_REFINED);
00418 //   libmesh_assert_equal_to (_children[7]->refinement_flag(), JUST_REFINED);
00419 //
00420 //   /* Check whether anything has to be changed.  */
00421 //   if (_diagonal_selection!=diag)
00422 //     {
00423 //       /* Set new diagonal selection.  */
00424 //       _diagonal_selection = diag;
00425 //
00426 //       /* The first four children do not have to be changed.  For the
00427 //  others, only the nodes have to be changed.  Note that we have
00428 //  to keep track of the nodes ourselves since there is no \p
00429 //  MeshRefinement object with a valid \p _new_nodes_map
00430 //  available.  */
00431 //       for (unsigned int c=4; c<this->n_children(); c++)
00432 // {
00433 //   Elem *child = this->child(c);
00434 //   for (unsigned int nc=0; nc<child->n_nodes(); nc++)
00435 //     {
00436 //       /* Unassign the current node.  */
00437 //       child->set_node(nc) = NULL;
00438 //
00439 //       /* We have to find the correct new node now.  We know
00440 //  that it exists somewhere.  We make use of the fact
00441 //  that the embedding matrix for these children consists
00442 //  of entries 0.0 and 0.5 only.  Also, we make use of
00443 //  the properties of the embedding matrix for the first
00444 //  (unchanged) four children, which allow us to use a
00445 //  simple mechanism to find the required node.  */
00446 //
00447 //
00448 //       unsigned int first_05_in_embedding_matrix = libMesh::invalid_uint;
00449 //       for (unsigned int n=0; n<this->n_nodes(); n++)
00450 // {
00451 //   if (this->embedding_matrix(c,nc,n) != 0.0)
00452 //     {
00453 //       /* It must be 0.5 then.  Check whether it's the
00454 //  first or second time that we get a 0.5
00455 //  value.  */
00456 //       if (first_05_in_embedding_matrix==libMesh::invalid_uint)
00457 // {
00458 //   /* First time, so just remeber this position.  */
00459 //   first_05_in_embedding_matrix = n;
00460 // }
00461 //       else
00462 // {
00463 //   /* Second time, so we know now which node to
00464 //      use.  */
00465 //   child->set_node(nc) = this->child(n)->get_node(first_05_in_embedding_matrix);
00466 // }
00467 //
00468 //     }
00469 // }
00470 //
00471 //       /* Make sure that a node has been found.  */
00472 //       libmesh_assert(child->get_node(nc));
00473 //     }
00474 // }
00475 //     }
00476 // }
00477 
00478 
00479 
00480 // void Tet4::reselect_optimal_diagonal (const Diagonal exclude_this)
00481 // {
00482 //   Real diag_01_23 = (this->point(0)+this->point(1)-this->point(2)-this->point(3)).size_sq();
00483 //   Real diag_02_13 = (this->point(0)-this->point(1)+this->point(2)-this->point(3)).size_sq();
00484 //   Real diag_03_12 = (this->point(0)-this->point(1)-this->point(2)+this->point(3)).size_sq();
00485 //
00486 //   Diagonal use_this = INVALID_DIAG;
00487 //   switch (exclude_this)
00488 //     {
00489 //     case DIAG_01_23:
00490 //       use_this = DIAG_02_13;
00491 //       if (diag_03_12 < diag_02_13)
00492 // {
00493 //   use_this = DIAG_03_12;
00494 // }
00495 //       break;
00496 //
00497 //     case DIAG_02_13:
00498 //       use_this = DIAG_03_12;
00499 //       if (diag_01_23 < diag_03_12)
00500 // {
00501 //   use_this = DIAG_01_23;
00502 // }
00503 //       break;
00504 //
00505 //     case DIAG_03_12:
00506 //       use_this = DIAG_02_13;
00507 //       if (diag_01_23 < diag_02_13)
00508 // {
00509 //   use_this = DIAG_01_23;
00510 // }
00511 //       break;
00512 //
00513 //     default:
00514 //       use_this = DIAG_02_13;
00515 //       if (diag_01_23 < diag_02_13 || diag_03_12 < diag_02_13)
00516 // {
00517 //   if (diag_01_23 < diag_03_12)
00518 //     {
00519 //       use_this = DIAG_01_23;
00520 //     }
00521 //   else
00522 //     {
00523 //       use_this = DIAG_03_12;
00524 //     }
00525 // }
00526 //       break;
00527 //     }
00528 //
00529 //   reselect_diagonal (use_this);
00530 // }
00531 #endif // #ifdef LIBMESH_ENABLE_AMR
00532 
00533 } // namespace libMesh