Chaste Release::3.1
Cylindrical2dMesh.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #include <map>
00037 
00038 /* These lines are very useful for debugging (visualize with 'showme').
00039 #include "TrianglesMeshWriter.hpp"
00040 TrianglesMeshWriter<2,2> mesh_writer("Cylindrical2dMeshDebug", "mesh", false);
00041 mesh_writer.WriteFilesUsingMesh(*this);
00042 */
00043 #include "Cylindrical2dMesh.hpp"
00044 #include "Exception.hpp"
00045 
00046 Cylindrical2dMesh::Cylindrical2dMesh(double width)
00047   : MutableMesh<2,2>(),
00048     mWidth(width)
00049 {
00050     assert(width > 0.0);
00051 }
00052 
00053 Cylindrical2dMesh::~Cylindrical2dMesh()
00054 {
00055 }
00056 
00057 Cylindrical2dMesh::Cylindrical2dMesh(double width, std::vector<Node<2>* > nodes)
00058   : MutableMesh<2,2>(),
00059     mWidth(width)
00060 {
00061     assert(width > 0.0);
00062 //    mMismatchedBoundaryElements = false;
00063     for (unsigned index=0; index<nodes.size(); index++)
00064     {
00065         Node<2>* p_temp_node = nodes[index];
00066         double x = p_temp_node->rGetLocation()[0];
00067         x = x; // Fix optimised build
00068         assert( 0 <= x && x < width);
00069         mNodes.push_back(p_temp_node);
00070     }
00071 
00072     NodeMap node_map(nodes.size());
00073     ReMesh(node_map);
00074 }
00075 
00076 //bool Cylindrical2dMesh::GetInstanceOfMismatchedBoundaryNodes()
00077 //{
00078 //    return mMismatchedBoundaryElements;
00079 //}
00080 
00081 void Cylindrical2dMesh::UpdateTopAndBottom()
00082 {
00083     ChasteCuboid<2> bounding_box = CalculateBoundingBox();
00084     mBottom = bounding_box.rGetLowerCorner()[1];
00085     mTop = bounding_box.rGetUpperCorner()[1];
00086 }
00087 
00088 void Cylindrical2dMesh::CreateMirrorNodes()
00089 {
00090     double half_way = 0.5*mWidth;
00091 
00092     mLeftOriginals.clear();
00093     mLeftImages.clear();
00094     mImageToLeftOriginalNodeMap.clear();
00095     mRightOriginals.clear();
00096     mRightImages.clear();
00097     mImageToRightOriginalNodeMap.clear();
00098     mLeftPeriodicBoundaryElementIndices.clear();
00099     mRightPeriodicBoundaryElementIndices.clear();
00100 
00101     for (AbstractMesh<2,2>::NodeIterator node_iter = GetNodeIteratorBegin();
00102          node_iter != GetNodeIteratorEnd();
00103          ++node_iter)
00104     {
00105         c_vector<double, 2> location = node_iter->rGetLocation();
00106         unsigned this_node_index = node_iter->GetIndex();
00107         double this_node_x_location = location[0];
00108 
00109         // Check the mesh currently conforms to the dimensions given
00110         assert(0.0 <= location[0]);
00111         assert(location[0] <= mWidth);
00112 
00113         // Put the nodes which are to be mirrored in the relevant vectors
00114         if (this_node_x_location < half_way)
00115         {
00116             mLeftOriginals.push_back(this_node_index);
00117         }
00118         else
00119         {
00120             mRightOriginals.push_back(this_node_index);
00121         }
00122     }
00123 
00124     // For each left original node, create an image node and record its new index
00125     for (unsigned i=0; i<mLeftOriginals.size(); i++)
00126     {
00127         c_vector<double, 2> location = mNodes[mLeftOriginals[i]]->rGetLocation();
00128         location[0] = location[0] + mWidth;
00129 
00130         unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
00131         mLeftImages.push_back(new_node_index);
00132         mImageToLeftOriginalNodeMap[new_node_index] = mLeftOriginals[i];
00133     }
00134 
00135     // For each right original node, create an image node and record its new index
00136     for (unsigned i=0; i<mRightOriginals.size(); i++)
00137     {
00138         c_vector<double, 2> location = mNodes[mRightOriginals[i]]->rGetLocation();
00139         location[0] = location[0] - mWidth;
00140 
00141         unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
00142         mRightImages.push_back(new_node_index);
00143         mImageToRightOriginalNodeMap[new_node_index] = mRightOriginals[i];
00144     }
00145 
00146     assert(mRightOriginals.size() == mRightImages.size());
00147     assert(mLeftOriginals.size() == mLeftImages.size());
00148     assert(mImageToLeftOriginalNodeMap.size() == mLeftOriginals.size());
00149     assert(mImageToRightOriginalNodeMap.size() == mRightOriginals.size());
00150 }
00151 
00152 void Cylindrical2dMesh::CreateHaloNodes()
00153 {
00154     UpdateTopAndBottom();
00155 
00156     mTopHaloNodes.clear();
00157     mBottomHaloNodes.clear();
00158 
00159     unsigned num_halo_nodes = (unsigned)(floor(mWidth*2.0));
00160     double halo_node_separation = mWidth/((double)(num_halo_nodes));
00161     double y_top_coordinate = mTop + halo_node_separation;
00162     double y_bottom_coordinate = mBottom - halo_node_separation;
00163 
00164     c_vector<double, 2> location;
00165     for (unsigned i=0; i<num_halo_nodes; i++)
00166     {
00167        double x_coordinate = 0.5*halo_node_separation + (double)(i)*halo_node_separation;
00168 
00169        // Inserting top halo node in mesh
00170        location[0] = x_coordinate;
00171        location[1] = y_top_coordinate;
00172        unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
00173        mTopHaloNodes.push_back(new_node_index);
00174 
00175        location[1] = y_bottom_coordinate;
00176        new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location));
00177        mBottomHaloNodes.push_back(new_node_index);
00178     }
00179 }
00180 
00181 void Cylindrical2dMesh::ReMesh(NodeMap& rMap)
00182 {
00183     unsigned old_num_all_nodes = GetNumAllNodes();
00184 
00185     rMap.Resize(old_num_all_nodes);
00186     rMap.ResetToIdentity();
00187 
00188     // Flag the deleted nodes as deleted in the map
00189     for (unsigned i=0; i<old_num_all_nodes; i++)
00190     {
00191         if (mNodes[i]->IsDeleted())
00192         {
00193             rMap.SetDeleted(i);
00194         }
00195     }
00196 
00197     CreateHaloNodes();
00198 
00199     // Create mirrored nodes for the normal remesher to work with
00200     CreateMirrorNodes();
00201 
00202     /*
00203      * The mesh now has messed up boundary elements, but this
00204      * doesn't matter as the ReMesh() below doesn't read them in
00205      * and reconstructs the boundary elements.
00206      *
00207      * Call ReMesh() on the parent class. Note that the mesh now has lots
00208      * of extra nodes which will be deleted, hence the name 'big_map'.
00209      */
00210     NodeMap big_map(GetNumAllNodes());
00211     MutableMesh<2,2>::ReMesh(big_map);
00212 
00213     /*
00214      * If the big_map isn't the identity map, the little map ('map') needs to be
00215      * altered accordingly before being passed to the user. Not sure how this all
00216      * works, so deal with this bridge when we get to it.
00217      */
00218     assert(big_map.IsIdentityMap());
00219 
00220     // Re-index the vectors according to the big nodemap, and set up the maps.
00221     mImageToLeftOriginalNodeMap.clear();
00222     mImageToRightOriginalNodeMap.clear();
00223 
00224     assert(mLeftOriginals.size() == mLeftImages.size());
00225     assert(mRightOriginals.size() == mRightImages.size());
00226 
00227     for (unsigned i=0; i<mLeftOriginals.size(); i++)
00228     {
00229         mLeftOriginals[i] = big_map.GetNewIndex(mLeftOriginals[i]);
00230         mLeftImages[i] = big_map.GetNewIndex(mLeftImages[i]);
00231         mImageToLeftOriginalNodeMap[mLeftImages[i]] = mLeftOriginals[i];
00232     }
00233 
00234     for (unsigned i=0; i<mRightOriginals.size(); i++)
00235     {
00236         mRightOriginals[i] = big_map.GetNewIndex(mRightOriginals[i]);
00237         mRightImages[i] = big_map.GetNewIndex(mRightImages[i]);
00238         mImageToRightOriginalNodeMap[mRightImages[i]] = mRightOriginals[i];
00239     }
00240 
00241     for (unsigned i=0; i<mTopHaloNodes.size(); i++)
00242     {
00243         mTopHaloNodes[i] = big_map.GetNewIndex(mTopHaloNodes[i]);
00244         mBottomHaloNodes[i] = big_map.GetNewIndex(mBottomHaloNodes[i]);
00245     }
00246 
00247     /*
00248      * Check that elements crossing the periodic boundary have been meshed
00249      * in the same way at each side.
00250      */
00251     CorrectNonPeriodicMesh();
00252 
00253     /*
00254      * Take the double-sized mesh, with its new boundary elements, and
00255      * remove the relevant nodes, elements and boundary elements to leave
00256      * a proper periodic mesh.
00257      */
00258     ReconstructCylindricalMesh();
00259 
00260     DeleteHaloNodes();
00261 
00262     /*
00263      * Create a random boundary element between two nodes of the first
00264      * element if it is not deleted. This is a temporary measure to get
00265      * around re-index crashing when there are no boundary elements.
00266      */
00267     unsigned num_elements = GetNumAllElements();
00268     bool boundary_element_made = false;
00269     unsigned elem_index = 0;
00270 
00271     while (elem_index<num_elements && !boundary_element_made)
00272     {
00273         Element<2,2>* p_element = GetElement(elem_index);
00274         if (!p_element->IsDeleted())
00275         {
00276             boundary_element_made = true;
00277             std::vector<Node<2>*> nodes;
00278             nodes.push_back(p_element->GetNode(0));
00279             nodes.push_back(p_element->GetNode(1));
00280             BoundaryElement<1,2>* p_boundary_element = new BoundaryElement<1,2>(0, nodes);
00281             p_boundary_element->RegisterWithNodes();
00282             mBoundaryElements.push_back(p_boundary_element);
00283             this->mBoundaryElementWeightedDirections.push_back(zero_vector<double>(2));
00284             this->mBoundaryElementJacobianDeterminants.push_back(0.0);
00285         }
00286         elem_index++;
00287     }
00288 
00289     // Now call ReIndex() to remove the temporary nodes which are marked as deleted
00290     NodeMap reindex_map(GetNumAllNodes());
00291     ReIndex(reindex_map);
00292     assert(!reindex_map.IsIdentityMap());  // maybe don't need this
00293 
00294     /*
00295      * Go through the reindex map and use it to populate the original NodeMap
00296      * (the one that is returned to the user).
00297      */
00298     for (unsigned i=0; i<rMap.Size(); i++) // only going up to be size of map, not size of reindex_map
00299     {
00300         if (reindex_map.IsDeleted(i))
00301         {
00302             /*
00303              * i < num_original_nodes and node is deleted, this should correspond to
00304              * a node that was labelled as before the remeshing, so should have already
00305              * been set as deleted in the map above.
00306              */
00307             assert(rMap.IsDeleted(i));
00308         }
00309         else
00310         {
00311             rMap.SetNewIndex(i, reindex_map.GetNewIndex(i));
00312         }
00313     }
00314 
00315     // We can now clear the index vectors and maps; they are only used for remeshing
00316     mLeftOriginals.clear();
00317     mLeftImages.clear();
00318     mImageToLeftOriginalNodeMap.clear();
00319     mRightOriginals.clear();
00320     mRightImages.clear();
00321     mImageToRightOriginalNodeMap.clear();
00322     mLeftPeriodicBoundaryElementIndices.clear();
00323     mRightPeriodicBoundaryElementIndices.clear();
00324 }
00325 
00326 void Cylindrical2dMesh::ReconstructCylindricalMesh()
00327 {
00328     /*
00329      * Figure out which elements have real nodes and image nodes in them
00330      * and replace image nodes with corresponding real ones.
00331      */
00332     for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin();
00333          elem_iter != GetElementIteratorEnd();
00334          ++elem_iter)
00335     {
00336         // Left images are on the right of the mesh
00337         unsigned number_of_left_image_nodes = 0;
00338         unsigned number_of_right_image_nodes = 0;
00339 
00340         for (unsigned i=0; i<3; i++)
00341         {
00342             unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
00343 
00344             if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
00345             {
00346                 number_of_left_image_nodes++;
00347             }
00348             else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
00349             {
00350                 number_of_right_image_nodes++;
00351             }
00352         }
00353 
00354         // Delete all the elements on the left hand side (images of right)...
00355         if (number_of_right_image_nodes >= 1)
00356         {
00357             elem_iter->MarkAsDeleted();
00358             mDeletedElementIndices.push_back(elem_iter->GetIndex());
00359         }
00360 
00361         // Delete only purely imaginary elements on the right (images of left nodes)
00362         if (number_of_left_image_nodes == 3)
00363         {
00364             elem_iter->MarkAsDeleted();
00365             mDeletedElementIndices.push_back(elem_iter->GetIndex());
00366         }
00367 
00368         /*
00369          * If some are images then replace them with the real nodes. There
00370          * can be elements with either two image nodes on the right (and one
00371          * real) or one image node on the right (and two real).
00372          */
00373         if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
00374         {
00375             for (unsigned i=0; i<3; i++)
00376             {
00377                 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
00378                 std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
00379                 if (it != mImageToLeftOriginalNodeMap.end())
00380                 {
00381                     elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
00382                 }
00383             }
00384         }
00385     }
00386 
00387     /*
00388      * Figure out which boundary elements have real nodes and image nodes in them
00389      * and replace image nodes with corresponding real ones.
00390      */
00391     for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++)
00392     {
00393         BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index);
00394         if (!p_boundary_element->IsDeleted())
00395         {
00396             unsigned number_of_image_nodes = 0;
00397             for (unsigned i=0; i<2; i++)
00398             {
00399                 unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
00400 
00401                 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
00402                 {
00403                     number_of_image_nodes++;
00404                 }
00405                 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
00406                 {
00407                     number_of_image_nodes++;
00408                 }
00409             }
00410 
00411             if (number_of_image_nodes == 2)
00412             {
00413                 p_boundary_element->MarkAsDeleted();
00414                 mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
00415             }
00416 
00417             /*
00418              * To avoid having two copies of the boundary elements on the periodic
00419              * boundaries we only deal with the elements on the left image and
00420              * delete the ones on the right image.
00421              */
00422             if (number_of_image_nodes == 1)
00423             {
00424                 for (unsigned i=0; i<2; i++)
00425                 {
00426                     unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i);
00427                     std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index);
00428                     if (it != mImageToLeftOriginalNodeMap.end())
00429                     {
00430                         p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]);
00431                     }
00432                     else
00433                     {
00434                         it = mImageToRightOriginalNodeMap.find(this_node_index);
00435                         if (it != mImageToRightOriginalNodeMap.end())
00436                         {
00437                             p_boundary_element->MarkAsDeleted();
00438                             mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex());
00439                         }
00440                     }
00441                 }
00442             }
00443         }
00444     }
00445 
00446     // Delete all image nodes unless they have already gone (halo nodes)
00447     for (unsigned i=0; i<mLeftImages.size(); i++)
00448     {
00449         mNodes[mLeftImages[i]]->MarkAsDeleted();
00450         mDeletedNodeIndices.push_back(mLeftImages[i]);
00451     }
00452 
00453     for (unsigned i=0; i<mRightImages.size(); i++)
00454     {
00455         mNodes[mRightImages[i]]->MarkAsDeleted();
00456         mDeletedNodeIndices.push_back(mRightImages[i]);
00457     }
00458 }
00459 
00460 void Cylindrical2dMesh::DeleteHaloNodes()
00461 {
00462     assert(mTopHaloNodes.size() == mBottomHaloNodes.size());
00463     for (unsigned i=0; i<mTopHaloNodes.size(); i++)
00464     {
00465         DeleteBoundaryNodeAt(mTopHaloNodes[i]);
00466         DeleteBoundaryNodeAt(mBottomHaloNodes[i]);
00467     }
00468 }
00469 
00470 c_vector<double, 2> Cylindrical2dMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
00471 {
00472     assert(mWidth > 0.0);
00473 
00474     c_vector<double, 2> location1 = rLocation1;
00475     c_vector<double, 2> location2 = rLocation2;
00476 
00477     location1[0] = fmod(location1[0], mWidth);
00478     location2[0] = fmod(location2[0], mWidth);
00479 
00480     c_vector<double, 2> vector = location2 - location1;
00481 
00482     /*
00483      * Handle the cylindrical condition here: if the points are more
00484      * than halfway around the cylinder apart, measure the other way.
00485      */
00486     if (vector[0] > 0.5*mWidth)
00487     {
00488         vector[0] -= mWidth;
00489     }
00490     else if (vector[0] < -0.5*mWidth)
00491     {
00492         vector[0] += mWidth;
00493     }
00494     return vector;
00495 }
00496 
00497 void Cylindrical2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove)
00498 {
00499     // Perform a periodic movement if necessary
00500     if (point.rGetLocation()[0] >= mWidth)
00501     {
00502         // Move point to the left
00503         point.SetCoordinate(0, point.rGetLocation()[0] - mWidth);
00504     }
00505     else if (point.rGetLocation()[0] < 0.0)
00506     {
00507         // Move point to the right
00508         point.SetCoordinate(0, point.rGetLocation()[0] + mWidth);
00509     }
00510 
00511     // Update the node's location
00512     MutableMesh<2,2>::SetNode(index, point, concreteMove);
00513 }
00514 
00515 double Cylindrical2dMesh::GetWidth(const unsigned& rDimension) const
00516 {
00517     double width = 0.0;
00518     assert(rDimension==0 || rDimension==1);
00519     if (rDimension==0)
00520     {
00521         width = mWidth;
00522     }
00523     else
00524     {
00525         width = MutableMesh<2,2>::GetWidth(rDimension);
00526     }
00527     return width;
00528 }
00529 
00530 unsigned Cylindrical2dMesh::AddNode(Node<2>* pNewNode)
00531 {
00532     unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode);
00533 
00534     // If necessary move it to be back on the cylinder
00535     ChastePoint<2> new_node_point = pNewNode->GetPoint();
00536     SetNode(node_index, new_node_point, false);
00537 
00538     return node_index;
00539 }
00540 
00541 void Cylindrical2dMesh::CorrectNonPeriodicMesh()
00542 {
00543     GenerateVectorsOfElementsStraddlingPeriodicBoundaries();
00544 
00545     /*
00546      * Copy the member variables into new vectors, which we modify
00547      * by knocking out elements which pair up on each side.
00548      */
00549     std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices;
00550     std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices;
00551 
00552 //    if ( (mLeftPeriodicBoundaryElementIndices.size()!=mRightPeriodicBoundaryElementIndices.size())
00553 //            || (temp_left_hand_side_elements.size() <= 2)
00554 //            || (temp_right_hand_side_elements.size() <= 2) )
00555 //    {
00556 //        mMismatchedBoundaryElements = true;
00557 //    }
00558     assert(mLeftPeriodicBoundaryElementIndices.size()==mRightPeriodicBoundaryElementIndices.size());
00559 
00560     // Go through all of the elements on the left periodic boundary
00561     for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin();
00562          left_iter != mLeftPeriodicBoundaryElementIndices.end();
00563          ++left_iter)
00564     {
00565         unsigned elem_index = *left_iter;
00566 
00567         Element<2,2>* p_element = GetElement(elem_index);
00568 
00569         /*
00570          * Make lists of the nodes which the elements on the left contain and
00571          * the nodes which should be in a corresponding element on the right.
00572          */
00573         c_vector<unsigned,3> original_element_node_indices;
00574         c_vector<unsigned,3> corresponding_element_node_indices;
00575         for (unsigned i=0; i<3; i++)
00576         {
00577             original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
00578             corresponding_element_node_indices[i] = GetCorrespondingNodeIndex(original_element_node_indices[i]);
00579         }
00580 
00581         // Search the right hand side elements for the corresponding element
00582         for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin();
00583              right_iter != mRightPeriodicBoundaryElementIndices.end();
00584              ++right_iter)
00585         {
00586             unsigned corresponding_elem_index = *right_iter;
00587 
00588             Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
00589 
00590             bool is_corresponding_node = true;
00591 
00592             for (unsigned i=0; i<3; i++)
00593             {
00594                 if ( (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
00595                      (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
00596                      (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
00597                 {
00598                     is_corresponding_node = false;
00599                     break;
00600                 }
00601             }
00602 
00603             if (is_corresponding_node)
00604             {
00605                 // Remove original and corresponding element from sets
00606                 temp_left_hand_side_elements.erase(elem_index);
00607                 temp_right_hand_side_elements.erase(corresponding_elem_index);
00608             }
00609         }
00610     }
00611 
00612     /*
00613      * If either of these ever throw you have more than one situation where the mesher has an option
00614      * of how to mesh. If it does ever throw you need to be cleverer and match up the
00615      * elements into as many pairs as possible on the left hand and right hand sides.
00616      */
00617 //    assert(temp_left_hand_side_elements.size() <= 2);
00618 //    assert(temp_right_hand_side_elements.size() <= 2);
00619 
00620     /*
00621      * Now we just have to use the first pair of elements and copy their info over to the other side.
00622      * First we need to get hold of both elements on either side.
00623      */
00624     if (temp_left_hand_side_elements.empty() || temp_right_hand_side_elements.empty())
00625     {
00626         assert(temp_right_hand_side_elements.empty());
00627         assert(temp_left_hand_side_elements.empty());
00628     }
00629     else
00630     {
00631         if (temp_right_hand_side_elements.size() == 2 && temp_left_hand_side_elements.size() == 2)
00632         {
00633 
00634             if (temp_right_hand_side_elements.size() == 2)
00635             {
00636                 // Use the right hand side meshing and map to left
00637                 UseTheseElementsToDecideMeshing(temp_right_hand_side_elements);
00638             }
00639             else
00640             {
00641                 /*
00642                  * If you get here there are more than two mixed up elements on the periodic edge.
00643                  * We need to knock the pair out and then rerun this function. This shouldn't be
00644                  * too hard to do but is as yet unnecessary.
00645                  */
00646                 NEVER_REACHED;
00647             }
00648         }
00649     }
00650 }
00651 
00652 void Cylindrical2dMesh::UseTheseElementsToDecideMeshing(std::set<unsigned>& rMainSideElements)
00653 {
00654     assert(rMainSideElements.size() == 2);
00655 
00656     // We find the four nodes surrounding the dodgy meshing, on each side.
00657     std::set<unsigned> main_four_nodes;
00658     for (std::set<unsigned>::iterator left_iter = rMainSideElements.begin();
00659          left_iter != rMainSideElements.end();
00660          ++left_iter)
00661     {
00662         unsigned elem_index = *left_iter;
00663         Element<2,2>* p_element = GetElement(elem_index);
00664         for (unsigned i=0; i<3; i++)
00665         {
00666             unsigned index = p_element->GetNodeGlobalIndex(i);
00667             main_four_nodes.insert(index);
00668         }
00669     }
00670     assert(main_four_nodes.size() == 4);
00671 
00672     std::set<unsigned> other_four_nodes;
00673     for (std::set<unsigned>::iterator iter = main_four_nodes.begin();
00674          iter != main_four_nodes.end();
00675          ++iter)
00676     {
00677         other_four_nodes.insert(GetCorrespondingNodeIndex(*iter));
00678     }
00679     assert(other_four_nodes.size() == 4);
00680 
00681     /*
00682      * Find the elements surrounded by the nodes on the right
00683      * and change them to match the elements on the left.
00684      */
00685     std::vector<unsigned> corresponding_elements;
00686 
00687     // Loop over all elements
00688     for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin();
00689          elem_iter != GetElementIteratorEnd();
00690          ++elem_iter)
00691     {
00692         // Loop over the nodes of the element
00693         if (!(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(0))==other_four_nodes.end()) &&
00694             !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(1))==other_four_nodes.end()) &&
00695             !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(2))==other_four_nodes.end()) )
00696         {
00697             corresponding_elements.push_back(elem_iter->GetIndex());
00698             elem_iter->MarkAsDeleted();
00699             mDeletedElementIndices.push_back(elem_iter->GetIndex());
00700         }
00701     }
00702     assert(corresponding_elements.size() == 2);
00703 
00704     // Now corresponding_elements contains the two elements which are going to be replaced by rMainSideElements
00705     unsigned num_elements = GetNumAllElements();
00706     for (std::set<unsigned>::iterator iter = rMainSideElements.begin();
00707          iter != rMainSideElements.end();
00708          ++iter)
00709     {
00710         Element<2,2>* p_main_element = GetElement(*iter);
00711         std::vector<Node<2>*> nodes;
00712 
00713         // Put corresponding nodes into a std::vector
00714         for (unsigned i=0; i<3; i++)
00715         {
00716             unsigned main_node = p_main_element->GetNodeGlobalIndex(i);
00717             nodes.push_back(this->GetNode(GetCorrespondingNodeIndex(main_node)));
00718         }
00719 
00720         // Make a new element
00721         Element<2,2>* p_new_element = new Element<2,2>(num_elements, nodes);
00722         this->mElements.push_back(p_new_element);
00723         this->mElementJacobians.push_back(zero_matrix<double>(2,2));
00724         this->mElementInverseJacobians.push_back(zero_matrix<double>(2,2));
00725         this->mElementJacobianDeterminants.push_back(0.0);
00726         num_elements++;
00727     }
00728 
00729     // Reindex to get rid of extra elements indices
00730     NodeMap map(GetNumAllNodes());
00731     this->ReIndex(map);
00732 }
00733 
00734 void Cylindrical2dMesh::GenerateVectorsOfElementsStraddlingPeriodicBoundaries()
00735 {
00736     mLeftPeriodicBoundaryElementIndices.clear();
00737     mRightPeriodicBoundaryElementIndices.clear();
00738 
00739     unsigned incidences_of_zero_left_image_nodes = 0;
00740     unsigned incidences_of_zero_right_image_nodes = 0;
00741 
00742     for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin();
00743          elem_iter != GetElementIteratorEnd();
00744          ++elem_iter)
00745     {
00746         // Left images are on the right of the mesh
00747         unsigned number_of_left_image_nodes = 0;
00748         unsigned number_of_right_image_nodes = 0;
00749 
00750         for (unsigned i=0; i<3; i++)
00751         {
00752             unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
00753 
00754             if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
00755             {
00756                 number_of_left_image_nodes++;
00757             }
00758             else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
00759             {
00760                 number_of_right_image_nodes++;
00761             }
00762         }
00763 
00764         if ( (number_of_left_image_nodes == 0) && (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2) )
00765         {
00766             incidences_of_zero_left_image_nodes++;
00767         }
00768         if ( (number_of_right_image_nodes == 0) && (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2) )
00769         {
00770             incidences_of_zero_right_image_nodes++;
00771         }
00772 
00773         /* SJ - Have checked the following:
00774          * - It is never the case that number_of_left_image_nodes + number_of_right_image_nodes > 3
00775          * - There are 1264 incidences of zero left image nodes, and 1252 incidences of zero right image nodes
00776          * - There are 450 incidences of zero left image nodes and non-zero right image nodes; 438 incidences of zero right image nodes and non-zero left
00777          *   image nodes
00778          * - There are 40 incidences of 0 left image nodes, and 1/2 right image nodes; 39 incidences of 0 right image nodes and 1/2 left image nodes
00779          * As this corresponds to 40 left-hand boundary elements and 39 right-hand boundary elements, then it is this extra occurrence of a 0 left
00780          * image node with 1/2 right image nodes that is responsible for the extra element.
00781          */
00782 
00783         // Elements on the left hand side (images of right nodes)
00784         if (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2)
00785         {
00786             mLeftPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
00787         }
00788 
00789         // Elements on the right (images of left nodes)
00790         if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
00791         {
00792             mRightPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
00793         }
00794     }
00795 
00796 //    if (mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
00797 //    {
00798 //        mMismatchedBoundaryElements = true;
00799 //        // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
00800 //
00801 //    }
00802 
00803     // Every boundary element on the left must have a corresponding element on the right
00804     assert(mLeftPeriodicBoundaryElementIndices.size() == mRightPeriodicBoundaryElementIndices.size());
00805 }
00806 
00807 unsigned Cylindrical2dMesh::GetCorrespondingNodeIndex(unsigned nodeIndex)
00808 {
00809     unsigned corresponding_node_index = UINT_MAX;
00810 
00811     // If nodeIndex is a member of mRightOriginals, then find the corresponding node index in mRightImages
00812     std::vector<unsigned>::iterator right_orig_iter = std::find(mRightOriginals.begin(), mRightOriginals.end(), nodeIndex);
00813     if (right_orig_iter != mRightOriginals.end())
00814     {
00815         corresponding_node_index = mRightImages[right_orig_iter - mRightOriginals.begin()];
00816     }
00817     else
00818     {
00819         // If nodeIndex is a member of mRightImages, then find the corresponding node index in mRightOriginals
00820         std::vector<unsigned>::iterator right_im_iter = std::find(mRightImages.begin(), mRightImages.end(), nodeIndex);
00821         if (right_im_iter != mRightImages.end())
00822         {
00823             corresponding_node_index = mRightOriginals[right_im_iter - mRightImages.begin()];
00824         }
00825         else
00826         {
00827             // If nodeIndex is a member of mLeftOriginals, then find the corresponding node index in mLeftImages
00828             std::vector<unsigned>::iterator left_orig_iter = std::find(mLeftOriginals.begin(), mLeftOriginals.end(), nodeIndex);
00829             if (left_orig_iter != mLeftOriginals.end())
00830             {
00831                 corresponding_node_index = mLeftImages[left_orig_iter - mLeftOriginals.begin()];
00832             }
00833             else
00834             {
00835                 // If nodeIndex is a member of mLeftImages, then find the corresponding node index in mLeftOriginals
00836                 std::vector<unsigned>::iterator left_im_iter = std::find(mLeftImages.begin(), mLeftImages.end(), nodeIndex);
00837                 if (left_im_iter != mLeftImages.end())
00838                 {
00839                     corresponding_node_index = mLeftOriginals[left_im_iter - mLeftImages.begin()];
00840                 }
00841             }
00842         }
00843     }
00844 
00845     // We must have found the corresponding node index
00846     assert(corresponding_node_index != UINT_MAX);
00847     return corresponding_node_index;
00848 }
00849 
00850 // Serialization for Boost >= 1.36
00851 #include "SerializationExportWrapperForCpp.hpp"
00852 CHASTE_CLASS_EXPORT(Cylindrical2dMesh)