00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "QuadraticMeshHelper.hpp"
00037
00038 #define SEEK_TO_CONTENT(methNameDirect, methNameIncrement, index) \
00039 if (index > 0u) { \
00040 if (rMeshReader.IsFileFormatBinary()) { \
00041 rMeshReader.methNameDirect(index - 1u); \
00042 } else { \
00043 for (unsigned i=0; i<index-1u; ++i) { \
00044 rMeshReader.methNameIncrement(); \
00045 } } }
00046
00047 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00048 void SeekToBoundaryElement(AbstractMeshReader<ELEMENT_DIM, SPACE_DIM>& rMeshReader,
00049 unsigned boundaryElementIndex)
00050 {
00051 SEEK_TO_CONTENT(GetFaceData, GetNextFaceData, boundaryElementIndex);
00052 }
00053
00054 template<unsigned DIM>
00055 void QuadraticMeshHelper<DIM>::AddInternalNodesToElements(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00056 AbstractMeshReader<DIM,DIM>* pMeshReader)
00057 {
00058 assert(pMesh);
00059 assert(pMeshReader);
00060
00061 if (pMesh->GetNumLocalElements() > 0u)
00062 {
00063 pMeshReader->Reset();
00064
00065
00066 std::set<unsigned> owned_element_indices;
00067 for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = pMesh->GetElementIteratorBegin();
00068 iter != pMesh->GetElementIteratorEnd();
00069 ++iter)
00070 {
00071 owned_element_indices.insert(iter->GetIndex());
00072 }
00073
00074 const std::vector<unsigned>& r_node_perm = pMesh->rGetNodePermutation();
00075
00076
00077 for (typename AbstractMeshReader<DIM,DIM>::ElementIterator iter = pMeshReader->GetElementIteratorBegin(owned_element_indices);
00078 iter != pMeshReader->GetElementIteratorEnd();
00079 ++iter)
00080 {
00081 std::vector<unsigned> nodes = iter->NodeIndices;
00082 assert(nodes.size()==(DIM+1)*(DIM+2)/2);
00083 Element<DIM,DIM>* p_element = pMesh->GetElement(iter.GetIndex());
00084 assert(p_element->GetNumNodes()==DIM+1);
00085
00086
00087 for (unsigned j=DIM+1; j<(DIM+1)*(DIM+2)/2; j++)
00088 {
00089 unsigned node_index = nodes[j];
00090 if (!r_node_perm.empty())
00091 {
00092 node_index = r_node_perm[node_index];
00093 }
00094 Node<DIM>* p_node = pMesh->GetNodeOrHaloNode(node_index);
00095 p_element->AddNode(p_node);
00096 p_node->AddElement(p_element->GetIndex());
00097 p_node->MarkAsInternal();
00098 }
00099 }
00100 }
00101 }
00102
00103 template<unsigned DIM>
00104 void QuadraticMeshHelper<DIM>::AddInternalNodesToBoundaryElements(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00105 AbstractMeshReader<DIM,DIM>* pMeshReader)
00106 {
00107 assert(pMesh);
00108 assert(pMeshReader);
00109
00110 if (DIM > 1 && pMesh->GetNumLocalBoundaryElements() > 0u)
00111 {
00112
00113 if (pMeshReader->GetOrderOfBoundaryElements() == 2u)
00114 {
00115
00116
00117 assert((*pMesh->GetBoundaryElementIteratorBegin())->GetNumNodes()==DIM*(DIM+1)/2);
00118 return;
00119 }
00120 else
00121 {
00122 AddNodesToBoundaryElements(pMesh, pMeshReader);
00123 }
00124 }
00125 }
00126
00127 template<unsigned DIM>
00128 void QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00129 AbstractMeshReader<DIM,DIM>* pMeshReader)
00130 {
00131
00132
00133 bool boundary_element_file_has_containing_element_info = false;
00134
00135 if (pMeshReader)
00136 {
00137 boundary_element_file_has_containing_element_info = pMeshReader->GetReadContainingElementOfBoundaryElement();
00138 }
00139
00140 if (DIM > 1)
00141 {
00142 if (boundary_element_file_has_containing_element_info)
00143 {
00144 pMeshReader->Reset();
00145 }
00146
00148
00149
00150 unsigned next_face_on_file = 0u;
00151
00152 for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00153 = pMesh->GetBoundaryElementIteratorBegin();
00154 iter != pMesh->GetBoundaryElementIteratorEnd();
00155 ++iter)
00156 {
00157
00158
00159 std::set<unsigned> boundary_element_node_indices;
00160 for (unsigned i=0; i<DIM; i++)
00161 {
00162 boundary_element_node_indices.insert( (*iter)->GetNodeGlobalIndex(i) );
00163 }
00164
00165 bool found_this_boundary_element = false;
00166
00167
00168
00169
00170
00171 Node<DIM>* p_representative_node = (*iter)->GetNode(0);
00172 for (typename Node<DIM>::ContainingElementIterator element_iter = p_representative_node->ContainingElementsBegin();
00173 element_iter != p_representative_node->ContainingElementsEnd();
00174 ++element_iter)
00175 {
00176 unsigned elem_index = *element_iter;
00177
00178
00179 if (boundary_element_file_has_containing_element_info)
00180 {
00181 unsigned face_index = (*iter)->GetIndex();
00183 do
00184 {
00185 elem_index = pMeshReader->GetNextFaceData().ContainingElement;
00186 next_face_on_file++;
00187 }
00188 while (face_index >= next_face_on_file);
00189 }
00190
00191 Element<DIM,DIM>* p_element = pMesh->GetElement(elem_index);
00192
00193
00194 for (unsigned face=0; face<DIM+1; face++)
00195 {
00196
00197 std::set<unsigned> node_indices;
00198 for (unsigned local_node_index=0; local_node_index<DIM+1; local_node_index++)
00199 {
00200 if (local_node_index != face)
00201 {
00202 node_indices.insert( p_element->GetNodeGlobalIndex(local_node_index) );
00203 }
00204 }
00205
00206 assert(node_indices.size()==DIM);
00207
00208
00209 if (node_indices == boundary_element_node_indices)
00210 {
00211 QuadraticMeshHelper<DIM>::AddExtraBoundaryNodes(pMesh, *iter, p_element, face);
00212
00213 found_this_boundary_element = true;
00214 break;
00215 }
00216 }
00217
00218
00219 if (boundary_element_file_has_containing_element_info && !found_this_boundary_element)
00220 {
00221 #define COVERAGE_IGNORE
00222
00223 EXCEPTION("Boundary element " << (*iter)->GetIndex()
00224 << "wasn't found in the containing element given for it "
00225 << elem_index);
00226 #undef COVERAGE_IGNORE
00227 }
00228
00229 if (found_this_boundary_element)
00230 {
00231 break;
00232 }
00233 }
00234
00235 if (!found_this_boundary_element)
00236 {
00237 #define COVERAGE_IGNORE
00238 EXCEPTION("Unable to find a face of an element which matches one of the boundary elements");
00239 #undef COVERAGE_IGNORE
00240 }
00241 }
00242 }
00243 }
00244
00245 template<unsigned DIM>
00246 void QuadraticMeshHelper<DIM>::CheckBoundaryElements(AbstractTetrahedralMesh<DIM, DIM>* pMesh)
00247 {
00248 #ifndef NDEBUG
00249 unsigned expected_num_nodes = DIM*(DIM+1)/2;
00250 for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00251 = pMesh->GetBoundaryElementIteratorBegin();
00252 iter != pMesh->GetBoundaryElementIteratorEnd();
00253 ++iter)
00254 {
00255 assert((*iter)->GetNumNodes() == expected_num_nodes);
00256 }
00257 #endif
00258 }
00259
00260 template<unsigned DIM>
00261 void QuadraticMeshHelper<DIM>::AddNodeToBoundaryElement(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00262 BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00263 Node<DIM>* pNode)
00264 {
00265 assert(DIM > 1);
00266
00267
00268 if (!pNode->IsBoundaryNode())
00269 {
00270 pNode->SetAsBoundaryNode();
00271 pMesh->mBoundaryNodes.push_back(pNode);
00272 }
00273
00274 pBoundaryElement->AddNode(pNode);
00275 }
00276
00277 template<unsigned DIM>
00278 void QuadraticMeshHelper<DIM>::AddNodeToBoundaryElement(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00279 BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00280 Element<DIM,DIM>* pElement,
00281 unsigned internalNode)
00282 {
00283 assert(DIM > 1);
00284 assert(internalNode >= DIM+1);
00285 assert(internalNode < (DIM+1)*(DIM+2)/2);
00286 Node<DIM>* p_internal_node = pElement->GetNode(internalNode);
00287 AddNodeToBoundaryElement(pMesh, pBoundaryElement, p_internal_node);
00288 }
00289
00290 template<unsigned DIM>
00291 void QuadraticMeshHelper<DIM>::AddExtraBoundaryNodes(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00292 BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00293 Element<DIM,DIM>* pElement,
00294 unsigned nodeIndexOppositeToFace)
00295 {
00296 assert(DIM!=1);
00297 if (DIM==2)
00298 {
00299 assert(nodeIndexOppositeToFace<3);
00300
00301 AddNodeToBoundaryElement(pMesh, pBoundaryElement, pElement, nodeIndexOppositeToFace+3);
00302 }
00303 else
00304 {
00305 assert(DIM==3);
00306
00307 unsigned b_elem_n0 = pBoundaryElement->GetNodeGlobalIndex(0);
00308 unsigned b_elem_n1 = pBoundaryElement->GetNodeGlobalIndex(1);
00309
00310 unsigned offset;
00311 bool reverse;
00312
00313 if (nodeIndexOppositeToFace==0)
00314 {
00315
00316 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 1, 2, 3, offset, reverse);
00317 HelperMethod2(pMesh, pBoundaryElement, pElement, 9, 8, 5, offset, reverse);
00318 }
00319 else if (nodeIndexOppositeToFace==1)
00320 {
00321
00322 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 2, 0, 3, offset, reverse);
00323 HelperMethod2(pMesh, pBoundaryElement, pElement, 7, 9, 6, offset, reverse);
00324 }
00325 else if (nodeIndexOppositeToFace==2)
00326 {
00327
00328 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 3, offset, reverse);
00329 HelperMethod2(pMesh, pBoundaryElement, pElement, 8, 7, 4, offset, reverse);
00330 }
00331 else
00332 {
00333 assert(nodeIndexOppositeToFace==3);
00334
00335 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 2, offset, reverse);
00336 HelperMethod2(pMesh, pBoundaryElement, pElement, 5, 6, 4, offset, reverse);
00337 }
00338 }
00339 }
00340
00342
00344
00345 #define COVERAGE_IGNORE
00346 template<unsigned DIM>
00347 void QuadraticMeshHelper<DIM>::HelperMethod1(unsigned boundaryElemNode0, unsigned boundaryElemNode1,
00348 Element<DIM,DIM>* pElement,
00349 unsigned node0, unsigned node1, unsigned node2,
00350 unsigned& rOffset,
00351 bool& rReverse)
00352 {
00353 if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode0)
00354 {
00355 rOffset = 0;
00356 if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1)
00357 {
00358 rReverse = false;
00359 }
00360 else
00361 {
00362 assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1);
00363 rReverse = true;
00364 }
00365 }
00366 else if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode0)
00367 {
00368 rOffset = 1;
00369 if (pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1)
00370 {
00371 rReverse = false;
00372 }
00373 else
00374 {
00375 assert(pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1);
00376 rReverse = true;
00377 }
00378 }
00379 else
00380 {
00381 assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode0);
00382 rOffset = 2;
00383 if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1)
00384 {
00385 rReverse = false;
00386 }
00387 else
00388 {
00389 assert(pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1);
00390 rReverse = true;
00391 }
00392 }
00393 }
00394 #undef COVERAGE_IGNORE
00395
00396
00397 #define COVERAGE_IGNORE
00398 template<unsigned DIM>
00399 void QuadraticMeshHelper<DIM>::HelperMethod2(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00400 BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00401 Element<DIM,DIM>* pElement,
00402 unsigned internalNode0, unsigned internalNode1, unsigned internalNode2,
00403 unsigned offset,
00404 bool reverse)
00405 {
00406 if (offset==1)
00407 {
00408 unsigned temp = internalNode0;
00409 internalNode0 = internalNode1;
00410 internalNode1 = internalNode2;
00411 internalNode2 = temp;
00412 }
00413 else if (offset == 2)
00414 {
00415 unsigned temp = internalNode0;
00416 internalNode0 = internalNode2;
00417 internalNode2 = internalNode1;
00418 internalNode1 = temp;
00419 }
00420
00421 if (reverse)
00422 {
00423 unsigned temp = internalNode1;
00424 internalNode1 = internalNode2;
00425 internalNode2 = temp;
00426 }
00427
00428 AddNodeToBoundaryElement(pMesh, pBoundaryElement, pElement, internalNode0);
00429 AddNodeToBoundaryElement(pMesh, pBoundaryElement, pElement, internalNode1);
00430 AddNodeToBoundaryElement(pMesh, pBoundaryElement, pElement, internalNode2);
00431 }
00432 #undef COVERAGE_IGNORE
00433
00435 // Explicit instantiation
00437
00438 template class QuadraticMeshHelper<1>;
00439 template class QuadraticMeshHelper<2>;
00440 template class QuadraticMeshHelper<3>;