$extrastylesheet
reference_elem.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2013 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/node.h"
00022 #include "libmesh/elem.h"
00023 #include "libmesh/reference_elem.h"
00024 #include "libmesh/libmesh_singleton.h"
00025 #include "libmesh/threads.h"
00026 
00027 // C++ includes
00028 #include <map>
00029 #include <sstream>
00030 
00031 
00032 
00033 //-----------------------------------------------
00034 // anonymous namespace for implementation details
00035 namespace
00036 {
00037 using namespace libMesh;
00038 
00039 namespace ElemDataStrings
00040 {
00041 #include "reference_elem.data"
00042 }
00043 
00044 typedef Threads::spin_mutex InitMutex;
00045 
00046 // Mutex for thread safety.
00047 InitMutex init_mtx;
00048 
00049 // map from ElemType to reference element file system object name
00050 typedef std::map<ElemType, const char*> FileMapType;
00051 FileMapType ref_elem_file;
00052 Elem* ref_elem_map[INVALID_ELEM];
00053 
00054 
00055 
00056 class SingletonCache : public libMesh::Singleton
00057 {
00058 public:
00059   ~SingletonCache()
00060   {
00061     for (unsigned int e=0; e<elem_list.size(); e++)
00062       {
00063         delete elem_list[e];
00064         elem_list[e] = NULL;
00065       }
00066 
00067     elem_list.clear();
00068 
00069     for (unsigned int n=0; n<node_list.size(); n++)
00070       {
00071         delete node_list[n];
00072         node_list[n] = NULL;
00073       }
00074 
00075     node_list.clear();
00076   }
00077 
00078   std::vector<Node*> node_list;
00079   std::vector<Elem*> elem_list;
00080 };
00081 
00082 // singleton object, dynamically created and then
00083 // removed at program exit
00084 SingletonCache *singleton_cache = NULL;
00085 
00086 
00087 
00088 Elem* read_ref_elem (const ElemType Type,
00089                      std::istream &in)
00090 {
00091   libmesh_assert (singleton_cache != NULL);
00092 
00093   static const unsigned int comm_len = 1024;
00094   char comm[comm_len];
00095 
00096   std::string foo;
00097   unsigned int n_elem, n_nodes, elem_type, nn;
00098   double x, y, z;
00099 
00100   in >> foo;
00101   in >> n_elem;   in.getline (comm, comm_len); libmesh_assert_equal_to (n_elem, 1);
00102   in >> n_nodes;  in.getline (comm, comm_len);
00103   in >> foo;      in.getline (comm, comm_len);
00104   in >> foo;      in.getline (comm, comm_len);
00105   in >> foo;      in.getline (comm, comm_len);
00106   in >> foo;      in.getline (comm, comm_len);
00107   in >> n_elem;   in.getline (comm, comm_len); libmesh_assert_equal_to (n_elem, 1);
00108 
00109   in >> elem_type;
00110 
00111   libmesh_assert_less (elem_type, INVALID_ELEM);
00112   libmesh_assert_equal_to (elem_type, static_cast<unsigned int>(Type));
00113   libmesh_assert_equal_to (n_nodes, Elem::type_to_n_nodes_map[elem_type]);
00114 
00115   // Construct the elem
00116   Elem *elem = Elem::build(static_cast<ElemType>(elem_type)).release();
00117 
00118   // We are expecing an identity map, so assert it!
00119   for (unsigned int n=0; n<n_nodes; n++)
00120     {
00121       in >> nn;
00122       libmesh_assert_equal_to (n,nn);
00123     }
00124 
00125   for (unsigned int n=0; n<n_nodes; n++)
00126     {
00127       in >> x >> y >> z;
00128 
00129       Node *node = new Node(x,y,z,n);
00130       singleton_cache->node_list.push_back(node);
00131 
00132       elem->set_node(n) = node;
00133     }
00134 
00135 
00136   // it is entirely possible we ran out of file or encountered
00137   // another error.  If so, cleanly abort.
00138   if (!in)
00139     {
00140       delete elem;
00141       elem = NULL;
00142       libmesh_error_msg("ERROR while creating element singleton!");
00143     }
00144 
00145   else
00146     singleton_cache->elem_list.push_back (elem);
00147 
00148   ref_elem_map[Type] = elem;
00149 
00150   return elem;
00151 }
00152 
00153 
00154 
00155 void init_ref_elem_table()
00156 {
00157   // ouside mutex - if this pointer is set, we can trust it.
00158   if (singleton_cache != NULL) return;
00159 
00160   // playing with fire here - lock before touching shared
00161   // data structures
00162   InitMutex::scoped_lock lock(init_mtx);
00163 
00164   // inside mutex - pointer may have changed while waiting
00165   // for the lock to acquire, check it again.
00166   if (singleton_cache != NULL) return;
00167 
00168   // OK, if we get here we have the lock and we are not
00169   // initialized.  populate singleton.
00170   singleton_cache = new SingletonCache;
00171 
00172   // initialize the reference file table
00173   {
00174     ref_elem_file.clear();
00175 
00176     // // 1D elements
00177     ref_elem_file[EDGE2]    = ElemDataStrings::one_edge;
00178     ref_elem_file[EDGE3]    = ElemDataStrings::one_edge3;
00179     ref_elem_file[EDGE4]    = ElemDataStrings::one_edge4;
00180 
00181     // 2D elements
00182     ref_elem_file[TRI3]     = ElemDataStrings::one_tri;
00183     ref_elem_file[TRI6]     = ElemDataStrings::one_tri6;
00184 
00185     ref_elem_file[QUAD4]    = ElemDataStrings::one_quad;
00186     ref_elem_file[QUAD8]    = ElemDataStrings::one_quad8;
00187     ref_elem_file[QUAD9]    = ElemDataStrings::one_quad9;
00188 
00189     // 3D elements
00190     ref_elem_file[HEX8]     = ElemDataStrings::one_hex;
00191     ref_elem_file[HEX20]    = ElemDataStrings::one_hex20;
00192     ref_elem_file[HEX27]    = ElemDataStrings::one_hex27;
00193 
00194     ref_elem_file[TET4]     = ElemDataStrings::one_tet;
00195     ref_elem_file[TET10]    = ElemDataStrings::one_tet10;
00196 
00197     ref_elem_file[PRISM6]   = ElemDataStrings::one_prism;
00198     ref_elem_file[PRISM15]  = ElemDataStrings::one_prism15;
00199     ref_elem_file[PRISM18]  = ElemDataStrings::one_prism18;
00200 
00201     ref_elem_file[PYRAMID5] = ElemDataStrings::one_pyramid;
00202     ref_elem_file[PYRAMID13] = ElemDataStrings::one_pyramid13;
00203     ref_elem_file[PYRAMID14] = ElemDataStrings::one_pyramid14;
00204   }
00205 
00206   // Read'em
00207   for (FileMapType::const_iterator it=ref_elem_file.begin();
00208        it != ref_elem_file.end(); ++it)
00209     {
00210       std::istringstream stream(it->second);
00211 
00212       read_ref_elem(it->first,
00213                     stream);
00214     }
00215 }
00216 
00217 
00218 // no reason to do this at startup -
00219 // data structures will get initialized *if*
00220 // ReferenceElem::get() is ever called.
00221 // // Class to setup singleton data
00222 // class ReferenceElemSetup : public Singleton::Setup
00223 // {
00224 //   void setup ()
00225 //   {
00226 //     init_ref_elem_table();
00227 //   }
00228 // } reference_elem_setup;
00229 
00230 } // anonymous namespace
00231 
00232 
00233 
00234 //----------------------------------------------------------------------------
00235 // external API Implementation
00236 namespace libMesh
00237 {
00238 namespace ReferenceElem
00239 {
00240 const Elem & get (const ElemType Type)
00241 {
00242   libmesh_assert_less (Type, INVALID_ELEM);
00243 
00244   init_ref_elem_table();
00245 
00246   libmesh_assert (ref_elem_map[Type] != NULL);
00247 
00248   return *ref_elem_map[Type];
00249 }
00250 } // namespace ReferenceElem
00251 } // namespace libMesh