Cylindrical2dMesh.cpp

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

Generated by  doxygen 1.6.2