Cylindrical2dMesh.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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         UNUSED_OPT(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.GetSize(); 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> vector = rLocation2 - rLocation1;
00475     vector[0] = fmod(vector[0], mWidth);
00476 
00477     /*
00478      * Handle the cylindrical condition here: if the points are more
00479      * than halfway around the cylinder apart, measure the other way.
00480      */
00481     if (vector[0] > 0.5*mWidth)
00482     {
00483         vector[0] -= mWidth;
00484     }
00485     else if (vector[0] < -0.5*mWidth)
00486     {
00487         vector[0] += mWidth;
00488     }
00489     return vector;
00490 }
00491 
00492 void Cylindrical2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove)
00493 {
00494     // Perform a periodic movement if necessary
00495     if (point.rGetLocation()[0] >= mWidth)
00496     {
00497         // Move point to the left
00498         point.SetCoordinate(0, point.rGetLocation()[0] - mWidth);
00499     }
00500     else if (point.rGetLocation()[0] < 0.0)
00501     {
00502         // Move point to the right
00503         point.SetCoordinate(0, point.rGetLocation()[0] + mWidth);
00504     }
00505 
00506     // Update the node's location
00507     MutableMesh<2,2>::SetNode(index, point, concreteMove);
00508 }
00509 
00510 double Cylindrical2dMesh::GetWidth(const unsigned& rDimension) const
00511 {
00512     double width = 0.0;
00513     assert(rDimension==0 || rDimension==1);
00514     if (rDimension==0)
00515     {
00516         width = mWidth;
00517     }
00518     else
00519     {
00520         width = MutableMesh<2,2>::GetWidth(rDimension);
00521     }
00522     return width;
00523 }
00524 
00525 unsigned Cylindrical2dMesh::AddNode(Node<2>* pNewNode)
00526 {
00527     unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode);
00528 
00529     // If necessary move it to be back on the cylinder
00530     ChastePoint<2> new_node_point = pNewNode->GetPoint();
00531     SetNode(node_index, new_node_point, false);
00532 
00533     return node_index;
00534 }
00535 
00536 void Cylindrical2dMesh::CorrectNonPeriodicMesh()
00537 {
00538     GenerateVectorsOfElementsStraddlingPeriodicBoundaries();
00539 
00540     /*
00541      * Copy the member variables into new vectors, which we modify
00542      * by knocking out elements which pair up on each side.
00543      */
00544     std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices;
00545     std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices;
00546 
00547 //    if ( (mLeftPeriodicBoundaryElementIndices.size()!=mRightPeriodicBoundaryElementIndices.size())
00548 //            || (temp_left_hand_side_elements.size() <= 2)
00549 //            || (temp_right_hand_side_elements.size() <= 2) )
00550 //    {
00551 //        mMismatchedBoundaryElements = true;
00552 //    }
00553     assert(mLeftPeriodicBoundaryElementIndices.size()==mRightPeriodicBoundaryElementIndices.size());
00554 
00555     // Go through all of the elements on the left periodic boundary
00556     for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin();
00557          left_iter != mLeftPeriodicBoundaryElementIndices.end();
00558          ++left_iter)
00559     {
00560         unsigned elem_index = *left_iter;
00561 
00562         Element<2,2>* p_element = GetElement(elem_index);
00563 
00564         /*
00565          * Make lists of the nodes which the elements on the left contain and
00566          * the nodes which should be in a corresponding element on the right.
00567          */
00568         c_vector<unsigned,3> original_element_node_indices;
00569         c_vector<unsigned,3> corresponding_element_node_indices;
00570         for (unsigned i=0; i<3; i++)
00571         {
00572             original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i);
00573             corresponding_element_node_indices[i] = GetCorrespondingNodeIndex(original_element_node_indices[i]);
00574         }
00575 
00576         // Search the right hand side elements for the corresponding element
00577         for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin();
00578              right_iter != mRightPeriodicBoundaryElementIndices.end();
00579              ++right_iter)
00580         {
00581             unsigned corresponding_elem_index = *right_iter;
00582 
00583             Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index);
00584 
00585             bool is_corresponding_node = true;
00586 
00587             for (unsigned i=0; i<3; i++)
00588             {
00589                 if ( (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) &&
00590                      (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) &&
00591                      (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) )
00592                 {
00593                     is_corresponding_node = false;
00594                     break;
00595                 }
00596             }
00597 
00598             if (is_corresponding_node)
00599             {
00600                 // Remove original and corresponding element from sets
00601                 temp_left_hand_side_elements.erase(elem_index);
00602                 temp_right_hand_side_elements.erase(corresponding_elem_index);
00603             }
00604         }
00605     }
00606 
00607     /*
00608      * If either of these ever throw you have more than one situation where the mesher has an option
00609      * of how to mesh. If it does ever throw you need to be cleverer and match up the
00610      * elements into as many pairs as possible on the left hand and right hand sides.
00611      */
00612 //    assert(temp_left_hand_side_elements.size() <= 2);
00613 //    assert(temp_right_hand_side_elements.size() <= 2);
00614 
00615     /*
00616      * Now we just have to use the first pair of elements and copy their info over to the other side.
00617      * First we need to get hold of both elements on either side.
00618      */
00619     if (temp_left_hand_side_elements.empty() || temp_right_hand_side_elements.empty())
00620     {
00621         assert(temp_right_hand_side_elements.empty());
00622         assert(temp_left_hand_side_elements.empty());
00623     }
00624     else
00625     {
00626         if (temp_right_hand_side_elements.size() == 2 && temp_left_hand_side_elements.size() == 2)
00627         {
00628             if (temp_right_hand_side_elements.size() == 2)
00629             {
00630                 // Use the right hand side meshing and map to left
00631                 UseTheseElementsToDecideMeshing(temp_right_hand_side_elements);
00632             }
00633             else
00634             {
00635                 /*
00636                  * If you get here there are more than two mixed up elements on the periodic edge.
00637                  * We need to knock the pair out and then rerun this function. This shouldn't be
00638                  * too hard to do but is as yet unnecessary.
00639                  */
00640                 NEVER_REACHED;
00641             }
00642         }
00643     }
00644 }
00645 
00646 void Cylindrical2dMesh::UseTheseElementsToDecideMeshing(std::set<unsigned>& rMainSideElements)
00647 {
00648     assert(rMainSideElements.size() == 2);
00649 
00650     // We find the four nodes surrounding the dodgy meshing, on each side.
00651     std::set<unsigned> main_four_nodes;
00652     for (std::set<unsigned>::iterator left_iter = rMainSideElements.begin();
00653          left_iter != rMainSideElements.end();
00654          ++left_iter)
00655     {
00656         unsigned elem_index = *left_iter;
00657         Element<2,2>* p_element = GetElement(elem_index);
00658         for (unsigned i=0; i<3; i++)
00659         {
00660             unsigned index = p_element->GetNodeGlobalIndex(i);
00661             main_four_nodes.insert(index);
00662         }
00663     }
00664     assert(main_four_nodes.size() == 4);
00665 
00666     std::set<unsigned> other_four_nodes;
00667     for (std::set<unsigned>::iterator iter = main_four_nodes.begin();
00668          iter != main_four_nodes.end();
00669          ++iter)
00670     {
00671         other_four_nodes.insert(GetCorrespondingNodeIndex(*iter));
00672     }
00673     assert(other_four_nodes.size() == 4);
00674 
00675     /*
00676      * Find the elements surrounded by the nodes on the right
00677      * and change them to match the elements on the left.
00678      */
00679     std::vector<unsigned> corresponding_elements;
00680 
00681     // Loop over all elements
00682     for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin();
00683          elem_iter != GetElementIteratorEnd();
00684          ++elem_iter)
00685     {
00686         // Loop over the nodes of the element
00687         if (!(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(0))==other_four_nodes.end()) &&
00688             !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(1))==other_four_nodes.end()) &&
00689             !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(2))==other_four_nodes.end()) )
00690         {
00691             corresponding_elements.push_back(elem_iter->GetIndex());
00692             elem_iter->MarkAsDeleted();
00693             mDeletedElementIndices.push_back(elem_iter->GetIndex());
00694         }
00695     }
00696     assert(corresponding_elements.size() == 2);
00697 
00698     // Now corresponding_elements contains the two elements which are going to be replaced by rMainSideElements
00699     unsigned num_elements = GetNumAllElements();
00700     for (std::set<unsigned>::iterator iter = rMainSideElements.begin();
00701          iter != rMainSideElements.end();
00702          ++iter)
00703     {
00704         Element<2,2>* p_main_element = GetElement(*iter);
00705         std::vector<Node<2>*> nodes;
00706 
00707         // Put corresponding nodes into a std::vector
00708         for (unsigned i=0; i<3; i++)
00709         {
00710             unsigned main_node = p_main_element->GetNodeGlobalIndex(i);
00711             nodes.push_back(this->GetNode(GetCorrespondingNodeIndex(main_node)));
00712         }
00713 
00714         // Make a new element
00715         Element<2,2>* p_new_element = new Element<2,2>(num_elements, nodes);
00716         this->mElements.push_back(p_new_element);
00717         this->mElementJacobians.push_back(zero_matrix<double>(2,2));
00718         this->mElementInverseJacobians.push_back(zero_matrix<double>(2,2));
00719         this->mElementJacobianDeterminants.push_back(0.0);
00720         num_elements++;
00721     }
00722 
00723     // Reindex to get rid of extra elements indices
00724     NodeMap map(GetNumAllNodes());
00725     this->ReIndex(map);
00726 }
00727 
00728 void Cylindrical2dMesh::GenerateVectorsOfElementsStraddlingPeriodicBoundaries()
00729 {
00730     mLeftPeriodicBoundaryElementIndices.clear();
00731     mRightPeriodicBoundaryElementIndices.clear();
00732 
00733     unsigned incidences_of_zero_left_image_nodes = 0;
00734     unsigned incidences_of_zero_right_image_nodes = 0;
00735 
00736     for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin();
00737          elem_iter != GetElementIteratorEnd();
00738          ++elem_iter)
00739     {
00740         // Left images are on the right of the mesh
00741         unsigned number_of_left_image_nodes = 0;
00742         unsigned number_of_right_image_nodes = 0;
00743 
00744         for (unsigned i=0; i<3; i++)
00745         {
00746             unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i);
00747 
00748             if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end())
00749             {
00750                 number_of_left_image_nodes++;
00751             }
00752             else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end())
00753             {
00754                 number_of_right_image_nodes++;
00755             }
00756         }
00757 
00758         if ( (number_of_left_image_nodes == 0) && (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2) )
00759         {
00760             incidences_of_zero_left_image_nodes++;
00761         }
00762         if ( (number_of_right_image_nodes == 0) && (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2) )
00763         {
00764             incidences_of_zero_right_image_nodes++;
00765         }
00766 
00767         /* SJ - Have checked the following:
00768          * - It is never the case that number_of_left_image_nodes + number_of_right_image_nodes > 3
00769          * - There are 1264 incidences of zero left image nodes, and 1252 incidences of zero right image nodes
00770          * - 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
00771          *   image nodes
00772          * - 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
00773          * 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
00774          * image node with 1/2 right image nodes that is responsible for the extra element.
00775          */
00776 
00777         // Elements on the left hand side (images of right nodes)
00778         if (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2)
00779         {
00780             mLeftPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
00781         }
00782 
00783         // Elements on the right (images of left nodes)
00784         if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2)
00785         {
00786             mRightPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex());
00787         }
00788     }
00789 
00790 //    if (mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size())
00791 //    {
00792 //        mMismatchedBoundaryElements = true;
00793 //        // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event
00794 //
00795 //    }
00796 
00797     // Every boundary element on the left must have a corresponding element on the right
00798     assert(mLeftPeriodicBoundaryElementIndices.size() == mRightPeriodicBoundaryElementIndices.size());
00799 }
00800 
00801 unsigned Cylindrical2dMesh::GetCorrespondingNodeIndex(unsigned nodeIndex)
00802 {
00803     unsigned corresponding_node_index = UINT_MAX;
00804 
00805     // If nodeIndex is a member of mRightOriginals, then find the corresponding node index in mRightImages
00806     std::vector<unsigned>::iterator right_orig_iter = std::find(mRightOriginals.begin(), mRightOriginals.end(), nodeIndex);
00807     if (right_orig_iter != mRightOriginals.end())
00808     {
00809         corresponding_node_index = mRightImages[right_orig_iter - mRightOriginals.begin()];
00810     }
00811     else
00812     {
00813         // If nodeIndex is a member of mRightImages, then find the corresponding node index in mRightOriginals
00814         std::vector<unsigned>::iterator right_im_iter = std::find(mRightImages.begin(), mRightImages.end(), nodeIndex);
00815         if (right_im_iter != mRightImages.end())
00816         {
00817             corresponding_node_index = mRightOriginals[right_im_iter - mRightImages.begin()];
00818         }
00819         else
00820         {
00821             // If nodeIndex is a member of mLeftOriginals, then find the corresponding node index in mLeftImages
00822             std::vector<unsigned>::iterator left_orig_iter = std::find(mLeftOriginals.begin(), mLeftOriginals.end(), nodeIndex);
00823             if (left_orig_iter != mLeftOriginals.end())
00824             {
00825                 corresponding_node_index = mLeftImages[left_orig_iter - mLeftOriginals.begin()];
00826             }
00827             else
00828             {
00829                 // If nodeIndex is a member of mLeftImages, then find the corresponding node index in mLeftOriginals
00830                 std::vector<unsigned>::iterator left_im_iter = std::find(mLeftImages.begin(), mLeftImages.end(), nodeIndex);
00831                 if (left_im_iter != mLeftImages.end())
00832                 {
00833                     corresponding_node_index = mLeftOriginals[left_im_iter - mLeftImages.begin()];
00834                 }
00835             }
00836         }
00837     }
00838 
00839     // We must have found the corresponding node index
00840     assert(corresponding_node_index != UINT_MAX);
00841     return corresponding_node_index;
00842 }
00843 
00844 // Serialization for Boost >= 1.36
00845 #include "SerializationExportWrapperForCpp.hpp"
00846 CHASTE_CLASS_EXPORT(Cylindrical2dMesh)

Generated by  doxygen 1.6.2