Cylindrical2dMesh.cpp

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

Generated on Tue Aug 4 16:10:21 2009 for Chaste by  doxygen 1.5.5