MutableMesh.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 "MutableMesh.hpp"
00030 
00031 
00032 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00033 MutableMesh<ELEMENT_DIM, SPACE_DIM>::MutableMesh()
00034 {
00035     mAddedNodes = false;
00036 }
00037 
00038 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00039 MutableMesh<ELEMENT_DIM, SPACE_DIM>::MutableMesh(std::vector<Node<SPACE_DIM> *> nodes)
00040 {
00041     Clear();
00042     for (unsigned index=0; index<nodes.size(); index++)
00043     {
00044         Node<SPACE_DIM>* temp_node = nodes[index];
00045         this->mNodes.push_back(temp_node);
00046     }
00047     mAddedNodes = true;
00048     NodeMap node_map(nodes.size());
00049     ReMesh(node_map);
00050 }
00051 
00052 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00053 MutableMesh<ELEMENT_DIM, SPACE_DIM>::~MutableMesh()
00054 {
00055     Clear();
00056 }
00057 
00058 
00059 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00060 unsigned MutableMesh<ELEMENT_DIM, SPACE_DIM>::AddNode(Node<SPACE_DIM> *pNewNode)
00061 {
00062 
00063     if (mDeletedNodeIndices.empty())
00064     {
00065         pNewNode->SetIndex(this->mNodes.size());
00066         this->mNodes.push_back(pNewNode);
00067     }
00068     else
00069     {
00070         unsigned index=mDeletedNodeIndices.back();
00071         pNewNode->SetIndex(index);
00072         mDeletedNodeIndices.pop_back();
00073         delete this->mNodes[index];
00074         this->mNodes[index] = pNewNode;
00075     }
00076     mAddedNodes = true;
00077     return pNewNode->GetIndex();
00078 }
00079 
00080 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00081 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::Clear()
00082 {
00083     mDeletedElementIndices.clear();
00084     mDeletedBoundaryElementIndices.clear();
00085     mDeletedNodeIndices.clear();
00086     mAddedNodes = false;
00087 
00088     TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Clear();        
00089 }
00090 
00091 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00092 unsigned MutableMesh<ELEMENT_DIM, SPACE_DIM>::GetNumBoundaryElements() const
00093 {
00094     return this->mBoundaryElements.size() - mDeletedBoundaryElementIndices.size();
00095 }
00096 
00097 
00098 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00099 unsigned MutableMesh<ELEMENT_DIM, SPACE_DIM>::GetNumElements() const
00100 {
00101     return this->mElements.size() - mDeletedElementIndices.size();
00102 }
00103 
00104 
00106 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00107 unsigned MutableMesh<ELEMENT_DIM, SPACE_DIM>::GetNumNodes() const
00108 {
00109     return this->mNodes.size() - mDeletedNodeIndices.size();
00110 }
00111 
00112 template<>
00113 void MutableMesh<1, 1>::RescaleMeshFromBoundaryNode(ChastePoint<1> updatedPoint, unsigned boundaryNodeIndex)
00114 {
00115     assert(this->GetNode(boundaryNodeIndex)->IsBoundaryNode());
00116     double scaleFactor = updatedPoint[0] / this->GetNode(boundaryNodeIndex)->GetPoint()[0];
00117     double temp;
00118     for (unsigned i=0; i < boundaryNodeIndex+1; i++)
00119     {
00120         temp = scaleFactor * this->mNodes[i]->GetPoint()[0];
00121         ChastePoint<1> newPoint(temp);
00122         this->mNodes[i]->SetPoint(newPoint);
00123     }
00124     this->RefreshMesh();
00125 }
00126 
00134 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00135 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::SetNode(unsigned index,
00136         ChastePoint<SPACE_DIM> point,
00137         bool concreteMove)
00138 {    
00139     this->mNodes[index]->SetPoint(point);
00140     
00141     if (concreteMove)
00142     {
00143         for (typename Node<SPACE_DIM>::ContainingElementIterator it = this->mNodes[index]->ContainingElementsBegin();
00144              it != this->mNodes[index]->ContainingElementsEnd();
00145              ++it)
00146         {
00147             if (ELEMENT_DIM == SPACE_DIM)
00148             {
00149                 try
00150                 {
00151                     GetElement(*it)->CalculateInverseJacobian(this->mElementJacobians[ (*it) ],
00152                                                               this->mElementJacobianDeterminants[ (*it) ],
00153                                                               this->mElementInverseJacobians[ (*it) ]);
00154                 }
00155                 catch (Exception e)
00156                 {
00157                         EXCEPTION("Moving node caused an element to have a non-positive Jacobian determinant");
00158                 }
00159             }
00160             else
00161             {
00162                 c_vector<double,SPACE_DIM> previous_direction = this->mElementWeightedDirections[ (*it) ];
00163                 
00164                 GetElement(*it)->CalculateWeightedDirection(this->mElementWeightedDirections[ (*it) ],
00165                                                             this->mElementJacobianDeterminants[ (*it) ]);
00166                 
00167                 if ( inner_prod(previous_direction, this->mElementWeightedDirections[ (*it) ]) < 0)
00168                 {
00169                     EXCEPTION("Moving node caused an subspace element to change direction");
00170                 }
00171                                                                                   
00172             }
00173         }
00174         for (typename Node<SPACE_DIM>::ContainingBoundaryElementIterator it = this->mNodes[index]->ContainingBoundaryElementsBegin();
00175              it != this->mNodes[index]->ContainingBoundaryElementsEnd();
00176              ++it)
00177         {
00178             try
00179             {
00180                 GetBoundaryElement(*it)->CalculateWeightedDirection(this->mBoundaryElementWeightedDirections[ (*it) ],
00181                                                                     this->mBoundaryElementJacobianDeterminants[ (*it) ]);                    
00182             }
00183             catch (Exception e)
00184             {
00185                 EXCEPTION("Moving node caused a boundary element to have a non-positive Jacobian determinant");
00186             }
00187         }
00188     }
00189 }
00190 
00198 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00199 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::DeleteNode(unsigned index)
00200 {
00201     if (this->mNodes[index]->IsDeleted())
00202     {
00203         EXCEPTION("Trying to delete a deleted node");
00204     }
00205     unsigned target_index = (unsigned)(-1);
00206     bool found_target=false;
00207     for (typename Node<SPACE_DIM>::ContainingElementIterator it = this->mNodes[index]->ContainingElementsBegin();
00208          !found_target && it != this->mNodes[index]->ContainingElementsEnd();
00209          ++it)
00210     {
00211         Element <ELEMENT_DIM,SPACE_DIM> *p_element = GetElement(*it);
00212         for (unsigned i=0; i<=ELEMENT_DIM && !found_target; i++)
00213         {
00214             target_index = p_element->GetNodeGlobalIndex(i);
00215             try
00216             {
00217                 MoveMergeNode(index, target_index, false);
00218                 found_target = true;
00219             }
00220             catch (Exception e)
00221             {
00222                 // Just try the next node
00223             }
00224         }
00225     }
00226     if (!found_target)
00227     {
00228         EXCEPTION("Failure to delete node");
00229     }
00230 
00231     MoveMergeNode(index, target_index);
00232 }
00233 
00242 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00243 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::DeleteNodePriorToReMesh(unsigned index)
00244 {
00245 #define COVERAGE_IGNORE
00246     // A ReMesh can only happen in 2D or 3D so
00247     assert(SPACE_DIM==2 || SPACE_DIM==3);
00248 #undef COVERAGE_IGNORE
00249     this->mNodes[index]->MarkAsDeleted();
00250     mDeletedNodeIndices.push_back(index);
00251 }
00252 
00262 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00263 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::MoveMergeNode(unsigned index,
00264         unsigned targetIndex,
00265         bool concreteMove)
00266 {
00267     if (this->mNodes[index]->IsDeleted())
00268     {
00269         EXCEPTION("Trying to move a deleted node");
00270     }
00271 
00272     if (index == targetIndex)
00273     {
00274         EXCEPTION("Trying to merge a node with itself");
00275     }
00276     if (this->mNodes[index]->IsBoundaryNode())
00277     {
00278         if (!this->mNodes[targetIndex]->IsBoundaryNode())
00279         {
00280             EXCEPTION("A boundary node can only be moved on to another boundary node");
00281         }
00282     }
00283     std::set<unsigned> unshared_element_indices;
00284     std::set_difference(this->mNodes[index]->rGetContainingElementIndices().begin(),
00285                         this->mNodes[index]->rGetContainingElementIndices().end(),
00286                         this->mNodes[targetIndex]->rGetContainingElementIndices().begin(),
00287                         this->mNodes[targetIndex]->rGetContainingElementIndices().end(),
00288                         std::inserter(unshared_element_indices, unshared_element_indices.begin()));
00289 
00290 
00291     if (unshared_element_indices.size() == this->mNodes[index]->rGetContainingElementIndices().size())
00292     {
00293         EXCEPTION("These nodes cannot be merged since they are not neighbours");
00294     }
00295 
00296     std::set<unsigned> unshared_boundary_element_indices;
00297     std::set_difference(this->mNodes[index]->rGetContainingBoundaryElementIndices().begin(),
00298                         this->mNodes[index]->rGetContainingBoundaryElementIndices().end(),
00299                         this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().begin(),
00300                         this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().end(),
00301                         std::inserter(unshared_boundary_element_indices, unshared_boundary_element_indices.begin()));
00302 
00303 
00304     if (this->mNodes[index]->IsBoundaryNode())
00305     {
00306         if (unshared_boundary_element_indices.size()
00307             == this->mNodes[index]->rGetContainingBoundaryElementIndices().size())
00308         {
00309             //May be redundant (only thrown in 1D tests)
00310             EXCEPTION("These nodes cannot be merged since they are not neighbours on the boundary");
00311         }
00312     }
00313 
00314     this->mNodes[index]->rGetModifiableLocation() = this->mNodes[targetIndex]->rGetLocation();
00315 
00316     for (std::set<unsigned>::const_iterator element_iter=unshared_element_indices.begin();
00317              element_iter != unshared_element_indices.end();
00318              element_iter++)
00319     {
00320         try
00321         {
00322             if (SPACE_DIM == ELEMENT_DIM)
00323             {            
00324                 this->GetElement(*element_iter)->CalculateInverseJacobian(this->mElementJacobians[(*element_iter)], 
00325                                                                           this->mElementJacobianDeterminants[(*element_iter)], 
00326                                                                           this->mElementInverseJacobians[ (*element_iter) ]);
00327             }
00328             else
00329             {
00330                 this->GetElement(*element_iter)->CalculateWeightedDirection(this->mElementWeightedDirections[(*element_iter)], 
00331                                                                             this->mElementJacobianDeterminants[(*element_iter)]);                
00332             }
00333             
00334             if (concreteMove)
00335             {
00336                 this->GetElement(*element_iter)->ReplaceNode(this->mNodes[index], this->mNodes[targetIndex]);
00337             }
00338 
00339         }
00340         catch (Exception e)
00341         {
00342             EXCEPTION("Moving node caused an element to have a non-positive Jacobian determinant");
00343         }
00344     }
00345 
00346     for (std::set<unsigned>::const_iterator boundary_element_iter=
00347                  unshared_boundary_element_indices.begin();
00348              boundary_element_iter != unshared_boundary_element_indices.end();
00349              boundary_element_iter++)
00350     {
00351 
00352 // remove 767
00353 //        this->GetBoundaryElement(*boundary_element_iter)->RefreshJacobianDeterminant(concreteMove); // to be removed
00354 //        this->mBoundaryElementJacobianDeterminants[ (*boundary_element_iter) ] = this->GetBoundaryElement(*boundary_element_iter)->CalculateJacobianDeterminant();
00355 
00356         this->GetBoundaryElement(*boundary_element_iter)->CalculateWeightedDirection(this->mBoundaryElementWeightedDirections[(*boundary_element_iter)],
00357                                                                                      this->mBoundaryElementJacobianDeterminants[(*boundary_element_iter)]);
00358 
00359         if (concreteMove)
00360         {
00361             this->GetBoundaryElement(*boundary_element_iter)->ReplaceNode(this->mNodes[index], this->mNodes[targetIndex]);
00362         }
00363     }
00364 
00365     std::set<unsigned> shared_element_indices;
00366     std::set_intersection(this->mNodes[index]->rGetContainingElementIndices().begin(),
00367                           this->mNodes[index]->rGetContainingElementIndices().end(),
00368                           this->mNodes[targetIndex]->rGetContainingElementIndices().begin(),
00369                           this->mNodes[targetIndex]->rGetContainingElementIndices().end(),
00370                           std::inserter(shared_element_indices, shared_element_indices.begin()));
00371 
00372     for (std::set<unsigned>::const_iterator element_iter=shared_element_indices.begin();
00373              element_iter != shared_element_indices.end();
00374              element_iter++)
00375     {
00376         if (concreteMove)
00377         {
00378             this->GetElement(*element_iter)->MarkAsDeleted();
00379             this->mElementJacobianDeterminants[ (*element_iter) ] = 0.0; //This used to be done in MarkAsDeleted
00380             mDeletedElementIndices.push_back(*element_iter);
00381         }
00382         else
00383         {
00384 // remove 767            
00385 //            this->GetElement(*element_iter)->ZeroJacobianDeterminant();  // to be removed
00386             this->mElementJacobianDeterminants[ (*element_iter) ] = 0.0;
00387         }
00388     }
00389 
00390 
00391     std::set<unsigned> shared_boundary_element_indices;
00392     std::set_intersection(this->mNodes[index]->rGetContainingBoundaryElementIndices().begin(),
00393                           this->mNodes[index]->rGetContainingBoundaryElementIndices().end(),
00394                           this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().begin(),
00395                           this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().end(),
00396                           std::inserter(shared_boundary_element_indices, shared_boundary_element_indices.begin()));
00397 
00398     for (std::set<unsigned>::const_iterator boundary_element_iter=shared_boundary_element_indices.begin();
00399              boundary_element_iter != shared_boundary_element_indices.end();
00400              boundary_element_iter++)
00401     {
00402         if (concreteMove)
00403         {
00404             this->GetBoundaryElement(*boundary_element_iter)->MarkAsDeleted();
00405             this->mBoundaryElementJacobianDeterminants[ (*boundary_element_iter) ] = 0.0; //This used to be done in MarkAsDeleted
00406             mDeletedBoundaryElementIndices.push_back(*boundary_element_iter);
00407         }
00408         else
00409         {
00410 // remove 767            
00411 //            this->GetBoundaryElement(*boundary_element_iter)->ZeroJacobianDeterminant();  // to be removed
00412             this->mBoundaryElementJacobianDeterminants[ (*boundary_element_iter) ] = 0.0;
00413 // remove 767
00414 //            this->GetBoundaryElement(*boundary_element_iter)->ZeroWeightedDirection();
00415             this->mBoundaryElementWeightedDirections[ (*boundary_element_iter) ] = zero_vector<double>(SPACE_DIM);
00416         }
00417     }
00418 
00419     if (concreteMove)
00420     {
00421         this->mNodes[index]->MarkAsDeleted();
00422         mDeletedNodeIndices.push_back(index);        
00423     }
00424 }
00425 
00426 
00427 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00428 unsigned MutableMesh<ELEMENT_DIM, SPACE_DIM>::RefineElement(
00429     Element<ELEMENT_DIM,SPACE_DIM>* pElement,
00430     ChastePoint<SPACE_DIM> point)
00431 {
00432 
00433     //Check that the point is in the element
00434     if (pElement->IncludesPoint(point, true) == false)
00435     {
00436         EXCEPTION("RefineElement could not be started (point is not in element)");
00437     }
00438 
00439     // Add a new node from the point that is passed to RefineElement
00440     unsigned new_node_index = AddNode(new Node<SPACE_DIM>(0, point.rGetLocation()));
00441     // Note: the first argument is the index of the node, which is going to be
00442     //       overriden by AddNode, so it can safely be ignored
00443 
00444     //This loop constructs the extra elements which are going to fill the space
00445     for (unsigned i = 0; i < ELEMENT_DIM; i++)
00446     {
00447 
00448         // First, make a copy of the current element making sure we update its index
00449         unsigned new_elt_index;
00450         if (mDeletedElementIndices.empty())
00451         {
00452             new_elt_index = this->mElements.size();
00453         }
00454         else
00455         {
00456             new_elt_index = mDeletedElementIndices.back();
00457             mDeletedElementIndices.pop_back();
00458         }
00459 
00460         Element<ELEMENT_DIM,SPACE_DIM>* p_new_element=
00461             new Element<ELEMENT_DIM,SPACE_DIM>(*pElement, new_elt_index);
00462 
00463         // Second, update the node in the element with the new one
00464         p_new_element->UpdateNode(ELEMENT_DIM-1-i, this->mNodes[new_node_index]);
00465 
00466 // remove 767
00467 //        p_new_element->RefreshJacobianDeterminant();
00468 
00469         // Third, add the new element to the set
00470         if ((unsigned) new_elt_index == this->mElements.size())
00471         {
00472             this->mElements.push_back(p_new_element);
00473         }
00474         else
00475         {
00476             delete this->mElements[new_elt_index];
00477             this->mElements[new_elt_index] = p_new_element;
00478         }
00479 
00480     }
00481 
00482     // Lastly, update the last node in the element to be refined
00483     pElement->UpdateNode(ELEMENT_DIM, this->mNodes[new_node_index]);
00484 // remove 767
00485 //    pElement->RefreshJacobianDeterminant();
00486 
00487     return new_node_index;
00488 }
00489 
00490 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00491 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::DeleteBoundaryNodeAt(unsigned index)
00492 {
00493     if (!this->mNodes[index]->IsBoundaryNode() )
00494     {
00495         EXCEPTION(" You may only delete a boundary node ");
00496     }
00497 
00498     this->mNodes[index]->MarkAsDeleted();
00499     mDeletedNodeIndices.push_back(index);
00500     // Update the boundary node vector
00501     typename std::vector<Node<SPACE_DIM>*>::iterator b_node_iter
00502     = std::find(this->mBoundaryNodes.begin(), this->mBoundaryNodes.end(), this->mNodes[index]);
00503     this->mBoundaryNodes.erase(b_node_iter);
00504 
00505     // Remove boundary elements containing this node
00506     std::set<unsigned> boundary_element_indices = this->mNodes[index]->rGetContainingBoundaryElementIndices();
00507     std::set<unsigned>::const_iterator boundary_element_indices_iterator = boundary_element_indices.begin();
00508     while (boundary_element_indices_iterator != boundary_element_indices.end())
00509     {
00510         BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* p_boundary_element = this->GetBoundaryElement(*boundary_element_indices_iterator);
00511         p_boundary_element->MarkAsDeleted();
00512         mDeletedBoundaryElementIndices.push_back(*boundary_element_indices_iterator);
00513         boundary_element_indices_iterator++;
00514     }
00515 
00516     // Remove elements containing this node
00517     std::set<unsigned> element_indices = this->mNodes[index]->rGetContainingElementIndices();
00518     std::set<unsigned>::const_iterator element_indices_iterator = element_indices.begin();
00519     while (element_indices_iterator != element_indices.end())
00520     {
00521         Element<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(*element_indices_iterator);
00522         for (unsigned i=0; i< p_element->GetNumNodes();i++)
00523         {
00524             Node<SPACE_DIM>* p_node = p_element->GetNode(i);
00525             if (!p_node->IsDeleted())
00526             {
00527                 p_node->SetAsBoundaryNode();
00528                 // Update the boundary node vector
00529                 this->mBoundaryNodes.push_back(p_node);
00530             }
00531         }
00532         p_element->MarkAsDeleted();
00533         mDeletedElementIndices.push_back(p_element->GetIndex());
00534         element_indices_iterator++;
00535     }
00536 }
00537 
00538 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00539 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::ReIndex(NodeMap& map)
00540 {
00541     assert(!mAddedNodes);
00542     map.Resize(this->GetNumAllNodes());
00543 
00544     std::vector<Element<ELEMENT_DIM, SPACE_DIM> *> live_elements;
00545     
00546     for (unsigned i=0; i<this->mElements.size(); i++)
00547     {
00548         assert(i==this->mElements[i]->GetIndex()); // We need this to be true to be able to reindex the jacobian cache
00549         if (this->mElements[i]->IsDeleted())
00550         {
00551             delete this->mElements[i];
00552         }
00553         else
00554         {
00555             live_elements.push_back(this->mElements[i]);
00556             
00557             if (SPACE_DIM == ELEMENT_DIM)
00558             {            
00559                 this->mElementJacobians[live_elements.size()-1] = this->mElementJacobians[this->mElements[i]->GetIndex()];    
00560                 this->mElementInverseJacobians[live_elements.size()-1] = this->mElementInverseJacobians[this->mElements[i]->GetIndex()];
00561             }
00562             else
00563             {        
00564                 this->mElementWeightedDirections[live_elements.size()-1] = this->mElementWeightedDirections[this->mElements[i]->GetIndex()]; 
00565             }
00566             this->mElementJacobianDeterminants[live_elements.size()-1] = this->mElementJacobianDeterminants[this->mElements[i]->GetIndex()];            
00567         }
00568     }
00569 
00570     assert (mDeletedElementIndices.size() == this->mElements.size()-live_elements.size());
00571     mDeletedElementIndices.clear();
00572     this->mElements = live_elements;
00573     unsigned num_elements = this->mElements.size();
00574 
00575     if (SPACE_DIM == ELEMENT_DIM)
00576     {            
00577         this->mElementJacobians.resize(num_elements);    
00578         this->mElementInverseJacobians.resize(num_elements);
00579     }
00580     else
00581     {        
00582         this->mElementWeightedDirections.resize(num_elements); 
00583     }
00584     this->mElementJacobianDeterminants.resize(num_elements);    
00585 
00586     std::vector<Node<SPACE_DIM> *> live_nodes;
00587     for (unsigned i=0; i<this->mNodes.size(); i++)
00588     {
00589         if (this->mNodes[i]->IsDeleted())
00590         {
00591             delete this->mNodes[i];
00592             map.SetDeleted(i);
00593         }
00594         else
00595         {
00596             live_nodes.push_back(this->mNodes[i]);
00597             // the nodes will have their index set to be the index into the live_nodes
00598             // vector further down
00599             map.SetNewIndex(i, (unsigned)(live_nodes.size()-1));
00600         }
00601     }
00602 
00603     assert (mDeletedNodeIndices.size() == this->mNodes.size()-live_nodes.size());
00604     this->mNodes = live_nodes;
00605     mDeletedNodeIndices.clear();
00606 
00607     std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *> live_boundary_elements;
00608     for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
00609     {
00610         if (this->mBoundaryElements[i]->IsDeleted())
00611         {
00612             delete this->mBoundaryElements[i];
00613         }
00614         else
00615         {
00616             live_boundary_elements.push_back(this->mBoundaryElements[i]);
00617             
00618             this->mBoundaryElementWeightedDirections[live_boundary_elements.size()-1] = this->mBoundaryElementWeightedDirections[this->mBoundaryElements[i]->GetIndex()];
00619             this->mBoundaryElementJacobianDeterminants[live_boundary_elements.size()-1] = this->mBoundaryElementJacobianDeterminants[this->mBoundaryElements[i]->GetIndex()];
00620         }
00621     }
00622 
00623     assert (mDeletedBoundaryElementIndices.size() == this->mBoundaryElements.size()-live_boundary_elements.size());
00624     this->mBoundaryElements = live_boundary_elements;
00625     mDeletedBoundaryElementIndices.clear();
00626 
00627     unsigned num_boundary_elements = this->mBoundaryElements.size();
00628 
00629     this->mBoundaryElementWeightedDirections.resize(num_boundary_elements); 
00630     this->mBoundaryElementJacobianDeterminants.resize(num_boundary_elements);    
00631 
00632 
00633     for (unsigned i=0; i<this->mNodes.size();i++)
00634     {
00635         this->mNodes[i]->SetIndex(i);
00636     }
00637     for (unsigned i=0; i<this->mElements.size();i++)
00638     {
00639         
00640         this->mElements[i]->ResetIndex(i);
00641     }
00642     for (unsigned i=0; i<this->mBoundaryElements.size();i++)
00643     {
00644         this->mBoundaryElements[i]->ResetIndex(i);
00645     }
00646 }
00647 
00648 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00649 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::ReMesh(NodeMap& map)
00650 {
00651     // Make sure that we are in the correct dimension - this code will be eliminated at compile time
00652     #define COVERAGE_IGNORE
00653     assert( SPACE_DIM==2 || SPACE_DIM==3 );
00654     assert( ELEMENT_DIM == SPACE_DIM );
00655     #undef COVERAGE_IGNORE
00656     
00657     // Avoid some triangle/tetgen errors: need at least four 
00658     // nodes for tetgen, and at least three for triangle
00659     if (GetNumNodes() <= SPACE_DIM)
00660     {
00661         EXCEPTION("The number of nodes must exceed the spatial dimension.");   
00662     }
00663 
00664 // I think the following dramatically slows down the simulations, as with a 
00665 // decent sized mesh we nearly always do need to remesh somewhere.
00666 
00667 //    // If there are no nodes waiting to be deleted,
00668 //    // and the current mesh is Voronoi, then we don't
00669 //    // need to call triangle/tetgen
00670 //    if (mDeletedNodeIndices.size()==0 && !mAddedNodes)
00671 //    {        
00672 //        if (CheckVoronoi())
00673 //        {
00674 //            map.ResetToIdentity();
00675 //            return;
00676 //        }
00677 //    }
00678     
00679     // Make sure the map is big enough
00680     map.Resize(this->GetNumAllNodes());
00681     
00682     if (SPACE_DIM==2)  // In 2D, remesh using triangle via library calls
00683     {
00684         struct triangulateio triangle_input;
00685         triangle_input.pointlist = (double *) malloc(GetNumNodes() * 2 * sizeof(double));
00686         triangle_input.numberofpoints = GetNumNodes();
00687         triangle_input.numberofpointattributes = 0;
00688         triangle_input.pointmarkerlist = NULL;
00689         triangle_input.numberofsegments = 0;
00690         triangle_input.numberofholes = 0;
00691         triangle_input.numberofregions = 0;
00692     
00693         unsigned new_index = 0;
00694         for (unsigned i=0; i<this->GetNumAllNodes(); i++)
00695         {
00696             if (this->mNodes[i]->IsDeleted())
00697             {
00698                 map.SetDeleted(i);
00699             }
00700             else
00701             {
00702                 map.SetNewIndex(i, new_index);
00703                 triangle_input.pointlist[2*new_index] = this->mNodes[i]->rGetLocation()[0];
00704                 triangle_input.pointlist[2*new_index + 1] = this->mNodes[i]->rGetLocation()[1];
00705                 new_index++;
00706             }
00707         }
00708     
00709         // Make structure for output
00710         struct triangulateio triangle_output;
00711         triangle_output.pointlist = NULL;
00712         triangle_output.pointattributelist = (double *) NULL;
00713         triangle_output.pointmarkerlist = (int *) NULL;
00714         triangle_output.trianglelist = (int *) NULL;
00715         triangle_output.triangleattributelist = (double *) NULL;
00716         triangle_output.edgelist = (int *) NULL;
00717         triangle_output.edgemarkerlist = (int *) NULL;
00718     
00719         // Library call
00720         triangulate((char*)"Qze", &triangle_input, &triangle_output, NULL);
00721     
00722         assert(triangle_output.numberofcorners == 3);
00723     
00724         // Remove current data
00725         Clear();
00726     
00727         // Construct the nodes
00728         for (unsigned node_index=0; node_index<(unsigned)triangle_output.numberofpoints; node_index++)
00729         {
00730             if (triangle_output.pointmarkerlist[node_index] == 1)
00731             {
00732                 // Boundary node
00733                 Node<SPACE_DIM> *p_node = new Node<SPACE_DIM>(node_index, true,
00734                   triangle_output.pointlist[node_index * 2],
00735                   triangle_output.pointlist[node_index * 2+1]);
00736                 this->mNodes.push_back(p_node);
00737                 this->mBoundaryNodes.push_back(p_node);
00738             }
00739             else
00740             {
00741                 this->mNodes.push_back(new Node<SPACE_DIM>(node_index, false,
00742                   triangle_output.pointlist[node_index * 2],
00743                   triangle_output.pointlist[node_index * 2+1]));
00744             }
00745         }
00746     
00747         // Construct the elements
00748         this->mElements.reserve(triangle_output.numberoftriangles);
00749         for (unsigned element_index=0; element_index<(unsigned)triangle_output.numberoftriangles; element_index++)
00750         {
00751             std::vector<Node<SPACE_DIM>*> nodes;
00752             for (unsigned j=0; j<3; j++)
00753             {
00754                 unsigned global_node_index = triangle_output.trianglelist[element_index*3 + j];
00755                 assert(global_node_index < this->mNodes.size());
00756                 nodes.push_back(this->mNodes[global_node_index]);
00757             }
00758             this->mElements.push_back(new Element<ELEMENT_DIM, SPACE_DIM>(element_index, nodes));
00759         }
00760     
00761         // Construct the edges
00762         // too big mBoundaryElements.reserve(triangle_output.numberoftriangles);
00763         unsigned next_boundary_element_index = 0;
00764         for (unsigned boundary_element_index=0; boundary_element_index<(unsigned)triangle_output.numberofedges; boundary_element_index++)
00765         {
00766             if (triangle_output.edgemarkerlist[boundary_element_index] == 1)
00767             {
00768                 std::vector<Node<SPACE_DIM>*> nodes;
00769                 for (unsigned j=0; j<2; j++)
00770                 {
00771                     unsigned global_node_index=triangle_output.edgelist[boundary_element_index*2 + j];
00772                     assert(global_node_index < this->mNodes.size());
00773                     nodes.push_back(this->mNodes[global_node_index]);
00774                 }
00775                 this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>(next_boundary_element_index++, nodes));
00776             }
00777         }
00778     
00779         free(triangle_input.pointlist);
00780     
00781         free(triangle_output.pointlist);
00782         free(triangle_output.pointattributelist);
00783         free(triangle_output.pointmarkerlist);
00784         free(triangle_output.trianglelist);
00785         free(triangle_output.triangleattributelist);
00786         free(triangle_output.edgelist);
00787         free(triangle_output.edgemarkerlist);
00788         
00789         this->RefreshJacobianCachedData();
00790     }
00791     else // in 3D, remesh using tetgen
00792     {
00793         std::stringstream pid;
00794         pid << getpid();
00795     
00796         OutputFileHandler handler("");
00797         std::string full_name = handler.GetOutputDirectoryFullPath("") + "temp_" + pid.str() + ".";
00798     
00799         // Only the master process should do IO and call the mesher
00800         if (handler.IsMaster())
00801         {
00802             std::string node_file_name = "temp_" + pid.str() + ".node";
00803             {
00804                 out_stream node_file = handler.OpenOutputFile(node_file_name);
00805     
00806                 (*node_file) << GetNumNodes() << "\t" << SPACE_DIM << "\t0\t0\n";
00807     
00808                 unsigned new_index = 0;
00809     
00810                 for (unsigned i=0; i<this->GetNumAllNodes(); i++)
00811                 {
00812                     if (this->mNodes[i]->IsDeleted())
00813                     {
00814                         map.SetDeleted(i);
00815                     }
00816                     else
00817                     {
00818                         map.SetNewIndex(i, new_index);
00819                         new_index++;
00820                         const c_vector<double, SPACE_DIM> node_loc = this->mNodes[i]->rGetLocation();
00821                         (*node_file) << i << "\t" << node_loc[0] << "\t" << node_loc[1] << "\t" << node_loc[2] << "\n";
00822                     }
00823                 }
00824                 node_file->close();
00825             }
00826     
00827             std::string binary_name;
00828 //            if(sizeof(long)==4)
00829 //            {
00830 //                // 32-bit machine
00831 //                binary_name = "./bin/tetgen";
00832 //            }
00833 //            else
00834 //            {
00835 //                //64-bit machine
00836 //                binary_name = "./bin/tetgen_64";
00837 //                
00838 //            }
00839             binary_name="tetgen"; //Assume it's in the path
00840             std::string command = binary_name + " -Q " + full_name + "node";
00841     
00842             // Tetgen's quiet mode isn't as quiet as Triangle's
00843             command += " > /dev/null";
00844             
00845             int return_value = system(command.c_str());
00846             if (return_value != 0)
00847             {
00848 #define COVERAGE_IGNORE                    
00849                 EXCEPTION("The tetgen mesher did not succeed in remeshing.  This functionality relies on tetgen.  Do you have tetgen from http://tetgen.berlios.de/ in your path?");
00850 #undef COVERAGE_IGNORE
00851             }
00852         }
00853         // Wait for the new mesh to be available and communicate its name
00854     #ifndef SPECIAL_SERIAL
00855         if (!PetscTools::IsSequential())
00856         {
00857             char full_name_comm[200]; 
00858             strcpy(full_name_comm, full_name.c_str());
00859             MPI_Bcast(full_name_comm, 200, MPI_CHAR, 0, MPI_COMM_WORLD);
00860             full_name = full_name_comm;
00861         }
00862     #endif //SPECIAL_SERIAL
00863     
00864         // Clear all current data
00865         Clear();
00866     
00867         // Read the new mesh back from file
00868         TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM> mesh_reader(full_name+"1");
00869         ConstructFromMeshReader(mesh_reader);
00870     
00871         // Make sure the file is not deleted before all the processors have read it
00872         PetscTools::Barrier();
00873     
00874         if (handler.IsMaster())
00875         {
00876             std::string remove_command = "rm " + full_name + "*";
00877             //system(remove_command.c_str());
00878         }
00879     }    
00880 }
00881 
00882 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00883 void MutableMesh<ELEMENT_DIM, SPACE_DIM>::ReMesh()
00884 {
00885     NodeMap map(GetNumNodes());
00886     ReMesh(map);
00887 }
00888 
00889 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00890 bool MutableMesh<ELEMENT_DIM, SPACE_DIM>::CheckVoronoi(Element<ELEMENT_DIM, SPACE_DIM> *pElement, double maxPenetration)
00891 {
00892     assert(ELEMENT_DIM == SPACE_DIM);
00893     unsigned num_nodes = pElement->GetNumNodes();
00894     std::set<unsigned> neighbouring_elements_indices;
00895     std::set< Element<ELEMENT_DIM,SPACE_DIM> *> neighbouring_elements;
00896     std::set<unsigned> neighbouring_nodes_indices;
00897 
00898     //Form a set of neighbouring elements via the nodes
00899     for (unsigned i = 0; i < num_nodes; i++)
00900     {
00901         Node<SPACE_DIM>* node = pElement->GetNode(i);
00902         neighbouring_elements_indices = node->rGetContainingElementIndices();
00904         for (std::set<unsigned>::const_iterator it = neighbouring_elements_indices.begin();
00905                  it != neighbouring_elements_indices.end(); ++it)
00906             {
00907                 neighbouring_elements.insert(this->GetElement(*it));
00908             }
00909     }
00910     neighbouring_elements.erase(pElement);
00911 
00912     //For each neighbouring element find the supporting nodes
00913     typedef typename std::set<Element<ELEMENT_DIM,SPACE_DIM> *>::const_iterator ElementIterator;
00914 
00915     for (ElementIterator it = neighbouring_elements.begin();
00916          it != neighbouring_elements.end(); ++it)
00917     {
00918         for (unsigned i = 0; i < num_nodes; i++)
00919         {
00920             neighbouring_nodes_indices.insert((*it)->GetNodeGlobalIndex(i));
00921         }
00922     }
00923     //Remove the nodes that support this element
00924     for (unsigned i = 0; i < num_nodes; i++)
00925     {
00926         neighbouring_nodes_indices.erase(pElement->GetNodeGlobalIndex(i));
00927     }
00928 
00929     //Get the circumsphere information
00930     c_vector <double, ELEMENT_DIM+1> this_circum_centre;
00931     
00932     this_circum_centre = pElement->CalculateCircumsphere(this->mElementJacobians[pElement->GetIndex()], this->mElementInverseJacobians[pElement->GetIndex()]);
00933 
00934     //Copy the actualy circumcentre into a smaller vector
00935     c_vector <double, ELEMENT_DIM> circum_centre;
00936     for (unsigned i=0;i<ELEMENT_DIM;i++)
00937     {
00938         circum_centre[i]=this_circum_centre[i];
00939     }
00940 
00941     for (std::set<unsigned>::const_iterator it = neighbouring_nodes_indices.begin();
00942              it != neighbouring_nodes_indices.end(); ++it)
00943     {
00944         c_vector <double, ELEMENT_DIM> node_location = this->GetNode(*it)->rGetLocation();
00945 
00946         // Calculate vector from circumcenter to node
00947         node_location -= circum_centre;
00948         // This is to calculate the squared distance betweeen them
00949         double squared_distance = inner_prod(node_location, node_location);
00950 
00951         // If the squared idstance is less than the elements circum-radius(squared),
00952         // then the voronoi property is violated.
00953 
00954         if (squared_distance < this_circum_centre[ELEMENT_DIM])
00955         {
00956             // We know the node is inside the circumsphere, but we don't know how far
00957             double radius = sqrt(this_circum_centre[ELEMENT_DIM]);
00958             double distance = radius - sqrt(squared_distance);
00959 
00960             // If the node penetration is greater than supplied maximum penetration factor
00961             if (distance/radius > maxPenetration)
00962             {
00963                 return false;
00964             }
00965         }
00966     }
00967     return true;
00968 }
00969 
00970 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00971 bool MutableMesh<ELEMENT_DIM, SPACE_DIM>::CheckVoronoi(double maxPenetration)
00972 {
00973     // Looping through all the elements in the mesh
00974     for (unsigned i=0; i < this->mElements.size();i++)
00975     {
00976         // Check if the element is not deleted
00977         if (!this->mElements[i]->IsDeleted())
00978         {
00979             // Checking the Voronoi of the Element
00980             if (CheckVoronoi(this->mElements[i], maxPenetration) == false)
00981             {
00982                 return false;
00983             }
00984         }
00985     }
00986     return true;
00987 }
00988 
00989 
00991 // Explicit instantiation
00993 
00994 template class MutableMesh<1,1>;
00995 template class MutableMesh<1,2>;
00996 template class MutableMesh<2,2>;
00997 template class MutableMesh<2,3>;
00998 template class MutableMesh<3,3>;

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