Cylindrical2dMesh.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 #include "Cylindrical2dMesh.hpp"
00029 
00030 
00031 Cylindrical2dMesh::Cylindrical2dMesh(double width)
00032   : MutableMesh<2,2>(),
00033     mWidth(width)
00034 {
00035     assert(width > 0.0);
00036 }
00037 
00038 
00039 Cylindrical2dMesh::Cylindrical2dMesh(double width, std::vector<Node<2>* > nodes)
00040   : MutableMesh<2,2>(),
00041     mWidth(width)
00042 {
00043     assert(width > 0.0);
00044     for (unsigned index=0; index<nodes.size(); index++)
00045     {
00046         Node<2>* temp_node = nodes[index];
00047         double x = temp_node->rGetLocation()[0];
00048         x=x; // Fix optimised build
00049         assert( 0 <= x && x < width);
00050         mNodes.push_back(temp_node);
00051     }
00052 
00053     NodeMap node_map(nodes.size());
00054     ReMesh(node_map);
00055 }
00056 
00057 
00058 void Cylindrical2dMesh::UpdateTopAndBottom()
00059 {
00060     c_vector<double,2> extremes = GetWidthExtremes(1);
00061     mBottom = extremes[0];
00062     mTop = extremes[1];
00063 }
00064 
00065 
00066 void Cylindrical2dMesh::CreateMirrorNodes()
00067 {
00068     unsigned num_nodes = GetNumAllNodes();
00069     double half_way = (mWidth)/2.0;
00070 
00071     mLeftOriginals.clear();
00072     mLeftImages.clear();
00073     mImageToLeftOriginalNodeMap.clear();
00074     mRightOriginals.clear();
00075     mRightImages.clear();
00076     mImageToRightOriginalNodeMap.clear();
00077     mLeftPeriodicBoundaryElementIndices.clear();
00078     mRightPeriodicBoundaryElementIndices.clear();
00079 
00080     for (unsigned i=0; i<num_nodes; i++)
00081     {
00082         if (!mNodes[i]->IsDeleted())
00083         {
00084             c_vector<double, 2> location = mNodes[i]->rGetLocation();
00085             unsigned this_node_index = mNodes[i]->GetIndex();
00086             double this_node_x_location = location[0];
00087 
00088             // Check the mesh currently conforms to the dimensions given
00089             assert(0.0<=location[0]);
00090             assert(location[0]<=mWidth);
00091 
00092             // Put the nodes which are to be mirrored in the relevant vectors
00093             if (this_node_x_location<half_way)
00094             {
00095                 mLeftOriginals.push_back(this_node_index);
00096             }
00097             else
00098             {
00099                 mRightOriginals.push_back(this_node_index);
00100             }
00101         }
00102     }
00103 
00104     // Go through the left original nodes and create an image node
00105     // recording its new index
00106     for (unsigned i=0; i<mLeftOriginals.size(); i++)
00107     {
00108         c_vector<double, 2> location = mNodes[mLeftOriginals[i]]->rGetLocation();
00109         location[0] = location[0] + mWidth;
00110 
00111         unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0u, location));
00112         mLeftImages.push_back(new_node_index);
00113         mImageToLeftOriginalNodeMap[new_node_index] = mLeftOriginals[i];
00114     }
00115 
00116     // Go through the right original nodes and create an image node
00117     // recording its new index
00118     for (unsigned i=0; i<mRightOriginals.size(); i++)
00119     {
00120         // Create new image nodes
00121         c_vector<double, 2> location = mNodes[mRightOriginals[i]]->rGetLocation();
00122         location[0] = location[0] - mWidth;
00123 
00124         unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0u, location));
00125         mRightImages.push_back(new_node_index);
00126         mImageToRightOriginalNodeMap[new_node_index] = mRightOriginals[i];
00127     }
00128 }
00129 
00130 
00131 void Cylindrical2dMesh::CreateHaloNodes()
00132 {
00133     UpdateTopAndBottom();
00134 
00135     mTopHaloNodes.clear();
00136     mBottomHaloNodes.clear();
00137 
00138     unsigned num_halo_nodes = (unsigned)(floor(mWidth*2.0));
00139     double halo_node_separation = mWidth/((double)(num_halo_nodes));
00140     double y_top_coordinate = mTop + halo_node_separation;
00141     double y_bottom_coordinate = mBottom - halo_node_separation;
00142 
00143     c_vector<double, 2> location;
00144     for (unsigned i=0; i< num_halo_nodes; i++)
00145     {
00146        double x_coordinate = 0.5*halo_node_separation + (double)(i)*halo_node_separation;
00147 
00148        // Inserting top halo node in mesh
00149        location[0] = x_coordinate;
00150        location[1] = y_top_coordinate;
00151        unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0u, location));
00152        mTopHaloNodes.push_back(new_node_index);
00153 
00154        location[1] = y_bottom_coordinate;
00155        new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0u, location));
00156        mBottomHaloNodes.push_back(new_node_index);
00157     }
00158 }
00159 
00160 
00161 void Cylindrical2dMesh::ReMesh(NodeMap &map)
00162 {
00163     unsigned old_num_all_nodes = GetNumAllNodes();
00164 
00165     map.Resize(old_num_all_nodes);
00166     map.ResetToIdentity();
00167 
00168     // Flag the deleted nodes as deleted in the map
00169     for (unsigned i=0; i<old_num_all_nodes; i++)
00170     {
00171         if (mNodes[i]->IsDeleted())
00172         {
00173             map.SetDeleted(i);
00174         }
00175     }
00176 
00177     CreateHaloNodes();
00178 
00179     // Create a mirrored load of nodes for the normal remesher to work with.
00180     CreateMirrorNodes();
00181 
00182     // The mesh now has messed up boundary elements, but this
00183     // doesn't matter as the ReMesh below doesn't read them in
00184     // and reconstructs the boundary elements.
00185 
00186     // Call the normal re-mesh. Note that the mesh now has lots
00187     // of extra nodes which will be deleted, hence the name 'big_map'
00188     NodeMap big_map(GetNumAllNodes());
00189     MutableMesh<2,2>::ReMesh(big_map);
00190 
00191     // If the big_map isn't the identity map, the little map ('map') needs to be
00192     // altered accordingly before being passed to the user. not sure how this all works,
00193     // so deal with this bridge when we get to it
00194     assert(big_map.IsIdentityMap());
00195 
00196     // Re-index the vectors according to the big nodemap, and set up the maps.
00197     mImageToLeftOriginalNodeMap.clear();
00198     mImageToRightOriginalNodeMap.clear();
00199 
00200     for (unsigned i=0; i<mLeftOriginals.size(); i++)
00201     {
00202         mLeftOriginals[i] = big_map.GetNewIndex(mLeftOriginals[i]);
00203         mLeftImages[i] = big_map.GetNewIndex(mLeftImages[i]);
00204         mImageToLeftOriginalNodeMap[mLeftImages[i]] = mLeftOriginals[i];
00205     }
00206 
00207     for (unsigned i=0; i<mRightOriginals.size(); i++)
00208     {
00209         mRightOriginals[i] = big_map.GetNewIndex(mRightOriginals[i]);
00210         mRightImages[i] = big_map.GetNewIndex(mRightImages[i]);
00211         mImageToRightOriginalNodeMap[mRightImages[i]] = mRightOriginals[i];
00212     }
00213 
00214     for (unsigned i=0; i<mTopHaloNodes.size(); i++)
00215     {
00216         mTopHaloNodes[i] = big_map.GetNewIndex(mTopHaloNodes[i]);
00217         mBottomHaloNodes[i] = big_map.GetNewIndex(mBottomHaloNodes[i]);
00218     }
00219 
00220     // This method checks elements crossing the periodic boundary have been meshed in the same way at each side.
00221     CorrectNonPeriodicMesh();
00222 
00223     // This method takes in the double sized mesh,
00224     // with its new boundary elements,
00225     // and removes the relevant nodes, elements and boundary elements
00226     // to leave a proper periodic mesh.
00227     ReconstructCylindricalMesh();
00228 
00229     DeleteHaloNodes();
00230 
00231     // Create a random boundary element between two nodes of the first element if it is not deleted.
00232     // This is a temporary measure to get around reindex crashing when there are no boundary elements ( J. Coopers idea )
00233     bool boundary_element_made = false;
00234     unsigned elem_index = 0;
00235     while (elem_index<GetNumAllElements() && !boundary_element_made)
00236     {
00237         Element<2,2>* p_element = GetElement(elem_index);
00238         if (!p_element->IsDeleted())
00239         {
00240             boundary_element_made = true;
00241             std::vector<Node<2>*> nodes;
00242             nodes.push_back(p_element->GetNode(0));
00243             nodes.push_back(p_element->GetNode(1));
00244             BoundaryElement<1,2>* p_boundary_element = new BoundaryElement<1,2>(0, nodes);
00245             p_boundary_element->RegisterWithNodes();
00246             mBoundaryElements.push_back(p_boundary_element);
00247             this->mBoundaryElementWeightedDirections.push_back(zero_vector<double>(2));
00248             this->mBoundaryElementJacobianDeterminants.push_back(0.0);            
00249         }
00250         elem_index++;
00251     }
00252 
00253     // Now call ReIndex to remove the temporary nodes which are marked as deleted.
00254     NodeMap reindex_map(GetNumAllNodes());
00255     ReIndex(reindex_map);
00256     assert(!reindex_map.IsIdentityMap());  // maybe don't need this
00257 
00258     // Go through the reindex map and use it to populate the original NodeMap
00259     // (the one that is returned to the user)
00260     for (unsigned i=0; i<map.Size(); i++) // only going up to be size of map, not size of reindex_map
00261     {
00262         if (reindex_map.IsDeleted(i))
00263         {
00264             // i < num_original_nodes and node is deleted, this should correspond to
00265             // a node that was labelled as before the remeshing, so should have already
00266             // been set as deleted in the map above
00267             assert(map.IsDeleted(i));
00268         }
00269         else
00270         {
00271             map.SetNewIndex(i, reindex_map.GetNewIndex(i) );
00272         }
00273     }
00274 
00275     // We can now clear the index vectors & maps; they are only used for remeshing
00276     mLeftOriginals.clear();
00277     mLeftImages.clear();
00278     mImageToLeftOriginalNodeMap.clear();
00279     mRightOriginals.clear();
00280     mRightImages.clear();
00281     mImageToRightOriginalNodeMap.clear();
00282     mLeftPeriodicBoundaryElementIndices.clear();
00283     mRightPeriodicBoundaryElementIndices.clear();
00284 }
00285 
00286 
00287 void Cylindrical2dMesh::ReconstructCylindricalMesh()
00288 {
00289     // Figure out which elements have real nodes and image nodes in them
00290     // and replace image nodes with corresponding real ones.
00291     for (unsigned elem_index = 0; elem_index<GetNumAllElements(); elem_index++)
00292     {
00293         Element<2,2>* p_element = GetElement(elem_index);
00294         if (!p_element->IsDeleted())
00295         {
00296             // Left images are on the right of the mesh
00297             unsigned number_of_left_image_nodes = 0u;
00298             unsigned number_of_right_image_nodes = 0u;
00299             for (unsigned i=0; i<3; i++)
00300             {
00301                 unsigned this_node_index = p_element->GetNodeGlobalIndex(i);
00302 
00303                 if (mImageToLeftOriginalNodeMap.find(this_node_index)
00304                     != mImageToLeftOriginalNodeMap.end())
00305                 {
00306                     number_of_left_image_nodes++;
00307                 }
00308                 else if (mImageToRightOriginalNodeMap.find(this_node_index)
00309                     != mImageToRightOriginalNodeMap.end())
00310                 {
00311                     number_of_right_image_nodes++;
00312                 }
00313             }
00314 
00315             // Delete all the elements on the left hand side (images of right)...
00316             if (number_of_right_image_nodes>=1u)
00317             {
00318                 p_element->MarkAsDeleted();
00319                 mDeletedElementIndices.push_back(p_element->GetIndex());
00320             }
00321 
00322             // Delete only purely imaginary elements on the right (images of left nodes)
00323             if (number_of_left_image_nodes==3u)
00324             {
00325                 p_element->MarkAsDeleted();
00326                 mDeletedElementIndices.push_back(p_element->GetIndex());
00327             }
00328 
00329             // If some are images then replace them with the real nodes.
00330             // There can be elements with either two image nodes on the
00331             // right (and one real) or one image node on the right
00332             // (and two real).
00333             if (number_of_left_image_nodes==1u || number_of_left_image_nodes==2u )
00334             {
00335                 for (unsigned i=0; i<3; i++)
00336                 {
00337                     unsigned this_node_index = p_element->GetNodeGlobalIndex(i);
00338                     std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
00339                     if (it != mImageToLeftOriginalNodeMap.end())
00340                     {
00341                         p_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
00342                     }
00343                 }
00344             }
00345         }
00346     } // end of loop over elements
00347 
00348     // Figure out which boundary elements have real nodes and image nodes in them
00349     // and replace image nodes with corresponding real ones.
00350     for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
00351     {
00352         BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
00353         if (!p_boundary_element->IsDeleted())
00354         {
00355             unsigned number_of_image_nodes = 0;
00356             for (unsigned i=0; i<2; i++)
00357             {
00358                 unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
00359 
00360                 if (mImageToLeftOriginalNodeMap.find(this_node_index)
00361                     != mImageToLeftOriginalNodeMap.end())
00362                 {
00363                     number_of_image_nodes++;
00364                 }
00365                 else if (mImageToRightOriginalNodeMap.find(this_node_index)
00366                     != mImageToRightOriginalNodeMap.end())
00367                 {
00368                     number_of_image_nodes++;
00369                 }
00370             }
00371 
00372             if (number_of_image_nodes==2 )
00373             {
00374                 p_boundary_element->MarkAsDeleted();
00375                 mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
00376             }
00377 
00378             // To avoid having two copies of the boundary elements on the periodic
00379             // boundaries we only deal with the elements on the left image and
00380             // delete the ones on the right image.
00381 
00382             if (number_of_image_nodes==1 )
00383             {
00384 
00385                 for (unsigned i=0; i<2; i++)
00386                 {
00387                     unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
00388                     std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
00389                     if (it != mImageToLeftOriginalNodeMap.end())
00390                     {
00391                         //std::cout << "PERIODIC \n" << std::flush;
00392                         p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
00393                         //std::cout << "Node " << this_node_index << " swapped for node " << it->second << "\n" << std::flush;
00394                     }
00395                     else
00396                     {
00397                         it = mImageToRightOriginalNodeMap.find(this_node_index);
00398                         if (it != mImageToRightOriginalNodeMap.end())
00399                         {
00400                             //std::cout << "IMAGE\n" << std::flush;
00401                             p_boundary_element->MarkAsDeleted();
00402                             mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
00403                         }
00404                     }
00405                 }
00406             }
00407         }
00408 
00409     }
00410 
00411     // Delete all image nodes unless they have already gone (halo nodes)
00412     for (unsigned i=0; i<mLeftImages.size(); i++)
00413     {
00414         mNodes[mLeftImages[i]]->MarkAsDeleted();
00415         mDeletedNodeIndices.push_back(mLeftImages[i]);
00416     }
00417 
00418     for (unsigned i=0; i<mRightImages.size(); i++)
00419     {
00420         mNodes[mRightImages[i]]->MarkAsDeleted();
00421         mDeletedNodeIndices.push_back(mRightImages[i]);
00422     }
00423 }
00424 
00425 
00426 void Cylindrical2dMesh::DeleteHaloNodes()
00427 {
00428     assert(mTopHaloNodes.size()==mBottomHaloNodes.size());
00429     for (unsigned i=0; i<mTopHaloNodes.size(); i++)
00430     {
00431         DeleteBoundaryNodeAt(mTopHaloNodes[i]);
00432         DeleteBoundaryNodeAt(mBottomHaloNodes[i]);
00433     }
00434 }
00435 
00436 
00437 c_vector<double, 2> Cylindrical2dMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
00438 {
00439     assert(mWidth > 0.0);
00440 
00441     c_vector<double, 2> location1 = rLocation1;
00442     c_vector<double, 2> location2 = rLocation2;
00443 
00444     location1[0] = fmod(location1[0], mWidth);
00445     location2[0] = fmod(location2[0], mWidth);
00446 
00447     c_vector<double, 2> vector = location2 - location1;
00448 
00449     // Handle the cylindrical condition here
00450     // if the points are more than halfway around the cylinder apart
00451     // measure the other way.
00452     if ( vector[0] > (mWidth / 2.0) )
00453     {
00454         vector[0] -= mWidth;
00455     }
00456     if ( vector[0] < -(mWidth / 2.0))
00457     {
00458         vector[0] += mWidth;
00459     }
00460     return vector;
00461 }
00462 
00463 
00464 void Cylindrical2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove)
00465 {
00466     // Perform a periodic movement if necessary
00467     if (point.rGetLocation()[0] >= mWidth)
00468     {
00469         // Move point to the left
00470         point.SetCoordinate(0u, point.rGetLocation()[0]-mWidth);
00471     }
00472     if (point.rGetLocation()[0] < 0.0)
00473     {
00474         // Move point to the right
00475         point.SetCoordinate(0u, point.rGetLocation()[0]+mWidth);
00476     }
00477 
00478     // Update the node's location
00479     MutableMesh<2,2>::SetNode(index, point, concreteMove);
00480 }
00481 
00482 
00483 bool Cylindrical2dMesh::IsThisIndexInList(const unsigned& rNodeIndex, const std::vector<unsigned>& rListOfNodes)
00484 {
00485     for (unsigned i=0; i<rListOfNodes.size(); i++)
00486     {
00487         if (rNodeIndex==rListOfNodes[i])
00488         {
00489             return true;
00490         }
00491     }
00492     return false;
00493 }
00494 
00495 
00496 double Cylindrical2dMesh::GetWidth(const unsigned& rDimension) const
00497 {
00498     double width = 0.0;
00499     assert(rDimension==0 || rDimension==1);
00500     if (rDimension==0)
00501     {
00502         width = mWidth;
00503     }
00504     else
00505     {
00506         width = MutableMesh<2,2>::GetWidth(rDimension);
00507     }
00508     return width;
00509 }
00510 
00511 
00512 unsigned Cylindrical2dMesh::AddNode(Node<2>* pNewNode)
00513 {
00514     unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode);
00515 
00516     // If necessary move it to be back on the cylinder
00517     ChastePoint<2> new_node_point = pNewNode->GetPoint();
00518     SetNode(node_index, new_node_point, false);
00519 
00520     return node_index;
00521 }
00522 
00523 
00524 void Cylindrical2dMesh::CorrectNonPeriodicMesh()
00525 {
00526     GenerateVectorsOfElementsStraddlingPeriodicBoundaries();
00527     // Copy the member variables into new vectors, which we modify
00528     // by knocking out elements which pair up on each side
00529     std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices;
00530     std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices;
00531 
00532     // Go through all of the elements on the left periodic boundary
00533     for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin();
00534          left_iter != mLeftPeriodicBoundaryElementIndices.end();
00535          ++left_iter)
00536     {
00537         unsigned elem_index = *left_iter;
00538         Element<2,2>* p_element = GetElement(elem_index);
00539 
00540         // Make lists of the nodes which the elements on the left contain
00541         // and the nodes which should be in a corresponding element on the right.
00542         c_vector<unsigned,3> original_element_node_indices;
00543         c_vector<unsigned,3> corresponding_element_node_indices;
00544         for (unsigned i=0; i<3; i++)
00545         {
00546             original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
00547             corresponding_element_node_indices[i] = GetCorrespondingNodeIndex(original_element_node_indices[i]);
00548         }
00549 
00550         // Search the right hand side elements for the corresponding element
00551         for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin();
00552              right_iter != mRightPeriodicBoundaryElementIndices.end();
00553              ++right_iter)
00554         {
00555             unsigned corresponding_elem_index = *right_iter;
00556             Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
00557 
00558             bool is_coresponding_node = true;
00559 
00560             for (unsigned i=0; i<3; i++)
00561             {
00562                 if ( !(corresponding_element_node_indices[i] == p_corresponding_element->GetNodeGlobalIndex(0)) &&
00563                     !(corresponding_element_node_indices[i] == p_corresponding_element->GetNodeGlobalIndex(1)) &&
00564                     !(corresponding_element_node_indices[i] == p_corresponding_element->GetNodeGlobalIndex(2)) )
00565                 {
00566                     is_coresponding_node = false;
00567                 }
00568             }
00569 
00570             if (is_coresponding_node)
00571             {
00572                 // Remove original and corresponding element from sets
00573                 temp_left_hand_side_elements.erase(elem_index);
00574                 temp_right_hand_side_elements.erase(corresponding_elem_index);
00575             }
00576         }
00577     }
00578 
00579     /*
00580      * If either of these ever throw you have more than one situation where the mesher has an option
00581      * of how to mesh. If it does ever throw you need to be cleverer and match up the
00582      * elements into as many pairs as possible on the left hand and right hand sides.
00583      */
00584     assert(temp_left_hand_side_elements.size()<=2u);
00585     assert(temp_right_hand_side_elements.size()<=2u);
00586 
00587     /*
00588      * Now we just have to use the first pair of elements and copy their info over to the other side.
00589      *
00590      * First we need to get hold of both elements on either side.
00591      */
00592     if (temp_left_hand_side_elements.size()==0u || temp_right_hand_side_elements.size()==0u)
00593     {
00594         assert(temp_right_hand_side_elements.size()==0u);
00595         assert(temp_left_hand_side_elements.size()==0u);
00596     }
00597     else
00598     {
00599         assert(temp_right_hand_side_elements.size()==2u && temp_left_hand_side_elements.size()==2u);
00600         if (temp_right_hand_side_elements.size()==2u)
00601         {
00602             // Use the right hand side meshing and map to left
00603             UseTheseElementsToDecideMeshing(temp_right_hand_side_elements);
00604         }
00605         else
00606         {
00607             // If you get here there are more than two mixed up elements on the periodic edge.
00608             // We need to knock the pair out and then rerun this function,
00609             // shouldn't be too hard to do but as yet unnecessary.
00610             NEVER_REACHED;
00611         }
00612     }
00613 }
00614 
00615 void Cylindrical2dMesh::UseTheseElementsToDecideMeshing(std::set<unsigned> mainSideElements)
00616 {
00617     assert(mainSideElements.size()==2u);
00618 
00619     // We find the four nodes surrounding the dodgy meshing, on each side.
00620     std::set<unsigned> main_four_nodes;
00621     for (std::set<unsigned>::iterator left_iter = mainSideElements.begin();
00622          left_iter != mainSideElements.end();
00623          ++left_iter)
00624     {
00625         unsigned elem_index = *left_iter;
00626         Element<2,2>* p_element = GetElement(elem_index);
00627         for (unsigned i=0; i<3; i++)
00628         {
00629             unsigned index = p_element->GetNodeGlobalIndex(i);
00630             main_four_nodes.insert(index);
00631         }
00632     }
00633     assert(main_four_nodes.size()==4u);
00634 
00635     std::set<unsigned> other_four_nodes;
00636     for (std::set<unsigned>::iterator iter = main_four_nodes.begin();
00637          iter != main_four_nodes.end();
00638          ++iter)
00639     {
00640         other_four_nodes.insert(GetCorrespondingNodeIndex(*iter));
00641     }
00642     assert(other_four_nodes.size()==4u);
00643 
00644     // Find the elements surrounded by the nodes on the right
00645     // and change them to match the elements on the left
00646     std::vector<unsigned> corresponding_elements;
00647 
00648     // Loop over all elements
00649     for (unsigned elem_index = 0; elem_index<GetNumAllElements(); elem_index++)
00650     {
00651         Element<2,2>* p_element = GetElement(elem_index);
00652         if (!p_element->IsDeleted())
00653         {
00654             // Loop over the nodes of the element
00655             if (!(other_four_nodes.find(p_element->GetNodeGlobalIndex(0))==other_four_nodes.end()) &&
00656                 !(other_four_nodes.find(p_element->GetNodeGlobalIndex(1))==other_four_nodes.end()) &&
00657                 !(other_four_nodes.find(p_element->GetNodeGlobalIndex(2))==other_four_nodes.end()) )
00658             {
00659                 corresponding_elements.push_back(elem_index);
00660                 p_element->MarkAsDeleted();
00661                 mDeletedElementIndices.push_back(p_element->GetIndex());
00662             }
00663         }
00664     }
00665     assert(corresponding_elements.size()==2u);
00666 
00667     // Now corresponding_elements contains the two elements which are going to be replaced by mainSideElements
00668     for (std::set<unsigned>::iterator iter = mainSideElements.begin();
00669          iter != mainSideElements.end();
00670          ++iter)
00671     {
00672         Element<2,2>* p_main_element = GetElement(*iter);
00673         std::vector<Node<2>*> nodes;
00674 
00675         // Put corresponding nodes into a std::vector
00676         for (unsigned i=0; i<3; i++)
00677         {
00678             unsigned main_node = p_main_element->GetNodeGlobalIndex(i);
00679             nodes.push_back(this->GetNode(GetCorrespondingNodeIndex(main_node)));
00680         }
00681 
00682         // Make a new element.
00683         Element<2,2>* p_new_element = new Element<2,2>(GetNumAllElements(), nodes);
00684         this->mElements.push_back(p_new_element);
00685         this->mElementJacobians.push_back(zero_matrix<double>(2,2));
00686         this->mElementInverseJacobians.push_back(zero_matrix<double>(2,2));
00687         this->mElementJacobianDeterminants.push_back(0.0);                    
00688     }
00689 
00690     // Reindex to get rid of extra elements indices
00691     NodeMap map(GetNumAllNodes());
00692     this->ReIndex(map);
00693 }
00694 
00695 
00696 void Cylindrical2dMesh::GenerateVectorsOfElementsStraddlingPeriodicBoundaries()
00697 {
00698     mLeftPeriodicBoundaryElementIndices.clear();
00699     mRightPeriodicBoundaryElementIndices.clear();
00700 
00701     for (unsigned elem_index = 0; elem_index<GetNumAllElements(); elem_index++)
00702     {
00703         Element<2,2>* p_element = GetElement(elem_index);
00704         if (!p_element->IsDeleted())
00705         {
00706             // Left images are on the right of the mesh
00707             unsigned number_of_left_image_nodes = 0u;
00708             unsigned number_of_right_image_nodes = 0u;
00709             for (unsigned i=0; i<3; i++)
00710             {
00711                 unsigned this_node_index = p_element->GetNodeGlobalIndex(i);
00712 
00713                 if (mImageToLeftOriginalNodeMap.find(this_node_index)
00714                     != mImageToLeftOriginalNodeMap.end())
00715                 {
00716                     number_of_left_image_nodes++;
00717                 }
00718                 else if (mImageToRightOriginalNodeMap.find(this_node_index)
00719                         != mImageToRightOriginalNodeMap.end())
00720                 {
00721                     number_of_right_image_nodes++;
00722                 }
00723             }
00724 
00725             // Elements on the left hand side (images of right)...
00726             if (number_of_right_image_nodes==1u || number_of_right_image_nodes==2u)
00727             {
00728                 mLeftPeriodicBoundaryElementIndices.insert(elem_index);
00729             }
00730 
00731             // Elements on the right (images of left nodes)
00732             if (number_of_left_image_nodes==1u|| number_of_left_image_nodes==2u)
00733             {
00734                 mRightPeriodicBoundaryElementIndices.insert(elem_index);
00735             }
00736         }
00737     }
00738 }
00739 
00740 
00741 unsigned Cylindrical2dMesh::GetCorrespondingNodeIndex(unsigned nodeIndex)
00742 {
00743     unsigned corresponding_node_index = UINT_MAX;
00744     bool found = false;
00745 
00746     if (IsThisIndexInList(nodeIndex, mRightOriginals))
00747     {
00748         for (unsigned i=0; i<mRightOriginals.size(); i++)
00749         {
00750             if (mRightOriginals[i]==nodeIndex)
00751             {
00752                 corresponding_node_index = mRightImages[i];
00753                 found = true;
00754             }
00755         }
00756     }
00757     if (IsThisIndexInList(nodeIndex, mRightImages))
00758     {
00759         for (unsigned i=0; i<mRightImages.size(); i++)
00760         {
00761             if (mRightImages[i]==nodeIndex)
00762             {
00763                 corresponding_node_index = mRightOriginals[i];
00764                 found = true;
00765             }
00766         }
00767     }
00768     if (IsThisIndexInList(nodeIndex, mLeftOriginals))
00769     {
00770         for (unsigned i=0; i<mLeftOriginals.size(); i++)
00771         {
00772             if (mLeftOriginals[i]==nodeIndex)
00773             {
00774                 corresponding_node_index = mLeftImages[i];
00775                 found = true;
00776             }
00777         }
00778     }
00779     if (IsThisIndexInList(nodeIndex, mLeftImages))
00780     {
00781         for (unsigned i=0; i<mLeftImages.size(); i++)
00782         {
00783             if (mLeftImages[i]==nodeIndex)
00784             {
00785                 corresponding_node_index = mLeftOriginals[i];
00786                 found = true;
00787             }
00788         }
00789     }
00790 
00791     assert(found);
00792     return corresponding_node_index;
00793 }

Generated on Wed Mar 18 12:51:49 2009 for Chaste by  doxygen 1.5.5