Chaste  Release::2017.1
MutableMesh.cpp
1 /*
2 
3 Copyright (c) 2005-2017, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include <map>
37 #include <cstring>
38 
39 #include "MutableMesh.hpp"
40 #include "OutputFileHandler.hpp"
41 
42 //Jonathan Shewchuk's triangle and Hang Si's tetgen
43 #define REAL double
44 #define VOID void
45 #include "triangle.h"
46 #include "tetgen.h"
47 #undef REAL
48 #undef VOID
49 
50 
51 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
53  : mAddedNodes(false)
54 {
55  this->mMeshChangesDuringSimulation = true;
56 }
57 
58 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
60 {
61  this->mMeshChangesDuringSimulation = true;
62  Clear();
63  for (unsigned index=0; index<nodes.size(); index++)
64  {
65  Node<SPACE_DIM>* p_temp_node = nodes[index];
66  this->mNodes.push_back(p_temp_node);
67  }
68  mAddedNodes = true;
69  NodeMap node_map(nodes.size());
70  ReMesh(node_map);
71 }
72 
73 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
75 {
76  Clear();
77 }
78 
79 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
81 {
82  if (mDeletedNodeIndices.empty())
83  {
84  pNewNode->SetIndex(this->mNodes.size());
85  this->mNodes.push_back(pNewNode);
86  }
87  else
88  {
89  unsigned index = mDeletedNodeIndices.back();
90  pNewNode->SetIndex(index);
91  mDeletedNodeIndices.pop_back();
92  delete this->mNodes[index];
93  this->mNodes[index] = pNewNode;
94  }
95  mAddedNodes = true;
96  return pNewNode->GetIndex();
97 }
98 
99 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
101 {
102  unsigned new_elt_index;
103 
104  if (mDeletedElementIndices.empty())
105  {
106  new_elt_index = this->mElements.size();
107  this->mElements.push_back(pNewElement);
108  pNewElement->ResetIndex(new_elt_index);
109  }
110  else
111  {
112  unsigned index = mDeletedElementIndices.back();
113  pNewElement->ResetIndex(index);
114  mDeletedElementIndices.pop_back();
115  delete this->mElements[index];
116  this->mElements[index] = pNewElement;
117  }
118 
119  return pNewElement->GetIndex();
120 }
121 
122 
123 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
125 {
126  mDeletedElementIndices.clear();
128  mDeletedNodeIndices.clear();
129  mAddedNodes = false;
130 
132 }
133 
134 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
136 {
137  return this->mBoundaryElements.size() - mDeletedBoundaryElementIndices.size();
138 }
139 
140 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
142 {
143  return this->mElements.size() - mDeletedElementIndices.size();
144 }
145 
146 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
148 {
149  return this->mNodes.size() - mDeletedNodeIndices.size();
150 }
151 
158 template<>
159 void MutableMesh<1, 1>::RescaleMeshFromBoundaryNode(ChastePoint<1> updatedPoint, unsigned boundaryNodeIndex)
160 {
161  assert(this->GetNode(boundaryNodeIndex)->IsBoundaryNode());
162  double scaleFactor = updatedPoint[0] / this->GetNode(boundaryNodeIndex)->GetPoint()[0];
163  double temp;
164  for (unsigned i=0; i < boundaryNodeIndex+1; i++)
165  {
166  temp = scaleFactor * this->mNodes[i]->GetPoint()[0];
167  ChastePoint<1> newPoint(temp);
168  this->mNodes[i]->SetPoint(newPoint);
169  }
170  this->RefreshMesh();
171 }
172 
173 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
176  bool concreteMove)
177 {
178  this->mNodes[index]->SetPoint(point);
179 
180  if (concreteMove)
181  {
182  for (typename Node<SPACE_DIM>::ContainingBoundaryElementIterator it = this->mNodes[index]->ContainingBoundaryElementsBegin();
183  it != this->mNodes[index]->ContainingBoundaryElementsEnd();
184  ++it)
185  {
186  try
187  {
188  this->GetBoundaryElement(*it)->CalculateWeightedDirection(this->mBoundaryElementWeightedDirections[ (*it) ],
189  this->mBoundaryElementJacobianDeterminants[ (*it) ]);
190  }
191  catch (Exception&)
192  {
193  EXCEPTION("Moving node caused a boundary element to have a non-positive Jacobian determinant");
194  }
195  }
196  for (typename Node<SPACE_DIM>::ContainingElementIterator it = this->mNodes[index]->ContainingElementsBegin();
197  it != this->mNodes[index]->ContainingElementsEnd();
198  ++it)
199  {
200  if (ELEMENT_DIM == SPACE_DIM)
201  {
202  try
203  {
204  this->GetElement(*it)->CalculateInverseJacobian(this->mElementJacobians[ (*it) ],
205  this->mElementJacobianDeterminants[ (*it) ],
206  this->mElementInverseJacobians[ (*it) ]);
207  }
208  catch (Exception&)
209  {
210  EXCEPTION("Moving node caused an element to have a non-positive Jacobian determinant");
211  }
212  }
213  else
214  {
215  c_vector<double,SPACE_DIM> previous_direction = this->mElementWeightedDirections[ (*it) ];
216 
217  this->GetElement(*it)->CalculateWeightedDirection(this->mElementWeightedDirections[ (*it) ],
218  this->mElementJacobianDeterminants[ (*it) ]);
219 
220  if (inner_prod(previous_direction, this->mElementWeightedDirections[ (*it) ]) < 0)
221  {
222  EXCEPTION("Moving node caused an subspace element to change direction");
223  }
224 
225  }
226  }
227  }
228 }
229 
230 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
232 {
233  if (this->mNodes[index]->IsDeleted())
234  {
235  EXCEPTION("Trying to delete a deleted node");
236  }
237  unsigned target_index = (unsigned)(-1);
238  bool found_target=false;
239  for (typename Node<SPACE_DIM>::ContainingElementIterator it = this->mNodes[index]->ContainingElementsBegin();
240  !found_target && it != this->mNodes[index]->ContainingElementsEnd();
241  ++it)
242  {
243  Element <ELEMENT_DIM,SPACE_DIM>* p_element = this->GetElement(*it);
244  for (unsigned i=0; i<=ELEMENT_DIM && !found_target; i++)
245  {
246  target_index = p_element->GetNodeGlobalIndex(i);
247  try
248  {
249  MoveMergeNode(index, target_index, false);
250  found_target = true;
251  }
252  catch (Exception&)
253  {
254  // Just try the next node
255  }
256  }
257  }
258  if (!found_target)
259  {
260  EXCEPTION("Failure to delete node");
261  }
262 
263  MoveMergeNode(index, target_index);
264 }
265 
266 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
268 {
269  assert(!this->mElements[index]->IsDeleted());
270  this->mElements[index]->MarkAsDeleted();
271  mDeletedElementIndices.push_back(index);
272 
273  // Delete any nodes that are no longer attached to mesh
274  for (unsigned node_index = 0; node_index < this->mElements[index]->GetNumNodes(); ++node_index)
275  {
276  if (this->mElements[index]->GetNode(node_index)->GetNumContainingElements() == 0u)
277  {
278  if (this->mElements[index]->GetNode(node_index)->GetNumBoundaryElements() == 0u)
279  {
280  this->mElements[index]->GetNode(node_index)->MarkAsDeleted();
281  mDeletedNodeIndices.push_back(this->mElements[index]->GetNode(node_index)->GetIndex());
282  }
283  else if (this->mElements[index]->GetNode(node_index)->GetNumBoundaryElements() == 1u && ELEMENT_DIM == 1)
284  {
285  std::set<unsigned> indices = this->mElements[index]->GetNode(node_index)->rGetContainingBoundaryElementIndices();
286  assert(indices.size() == 1u);
287  this->mBoundaryElements[*indices.begin()]->MarkAsDeleted();
288  mDeletedBoundaryElementIndices.push_back(*indices.begin());
289 
290  this->mElements[index]->GetNode(node_index)->MarkAsDeleted();
291  mDeletedNodeIndices.push_back(this->mElements[index]->GetNode(node_index)->GetIndex());
292  }
293  }
294  }
295 }
296 
297 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
299 {
300  this->mNodes[index]->MarkAsDeleted();
301  mDeletedNodeIndices.push_back(index);
302 }
303 
304 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
306  unsigned targetIndex,
307  bool concreteMove)
308 {
309  if (this->mNodes[index]->IsDeleted())
310  {
311  EXCEPTION("Trying to move a deleted node");
312  }
313 
314  if (index == targetIndex)
315  {
316  EXCEPTION("Trying to merge a node with itself");
317  }
318  if (this->mNodes[index]->IsBoundaryNode())
319  {
320  if (!this->mNodes[targetIndex]->IsBoundaryNode())
321  {
322  EXCEPTION("A boundary node can only be moved on to another boundary node");
323  }
324  }
325  std::set<unsigned> unshared_element_indices;
326  std::set_difference(this->mNodes[index]->rGetContainingElementIndices().begin(),
327  this->mNodes[index]->rGetContainingElementIndices().end(),
328  this->mNodes[targetIndex]->rGetContainingElementIndices().begin(),
329  this->mNodes[targetIndex]->rGetContainingElementIndices().end(),
330  std::inserter(unshared_element_indices, unshared_element_indices.begin()));
331 
332 
333  if (unshared_element_indices.size() == this->mNodes[index]->rGetContainingElementIndices().size())
334  {
335  EXCEPTION("These nodes cannot be merged since they are not neighbours");
336  }
337 
338  std::set<unsigned> unshared_boundary_element_indices;
339  std::set_difference(this->mNodes[index]->rGetContainingBoundaryElementIndices().begin(),
340  this->mNodes[index]->rGetContainingBoundaryElementIndices().end(),
341  this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().begin(),
342  this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().end(),
343  std::inserter(unshared_boundary_element_indices, unshared_boundary_element_indices.begin()));
344 
345 
346  if (this->mNodes[index]->IsBoundaryNode())
347  {
348  if (unshared_boundary_element_indices.size()
349  == this->mNodes[index]->rGetContainingBoundaryElementIndices().size())
350  {
351  //May be redundant (only thrown in 1D tests)
352  EXCEPTION("These nodes cannot be merged since they are not neighbours on the boundary");
353  }
354  }
355 
356  this->mNodes[index]->rGetModifiableLocation() = this->mNodes[targetIndex]->rGetLocation();
357 
358  for (std::set<unsigned>::const_iterator element_iter=unshared_element_indices.begin();
359  element_iter != unshared_element_indices.end();
360  element_iter++)
361  {
362  try
363  {
364  if (SPACE_DIM == ELEMENT_DIM)
365  {
366  this->GetElement(*element_iter)->CalculateInverseJacobian(this->mElementJacobians[(*element_iter)],
367  this->mElementJacobianDeterminants[(*element_iter)],
368  this->mElementInverseJacobians[ (*element_iter) ]);
369  }
370  else
371  {
372  this->GetElement(*element_iter)->CalculateWeightedDirection(this->mElementWeightedDirections[(*element_iter)],
373  this->mElementJacobianDeterminants[(*element_iter)]);
374  }
375 
376  if (concreteMove)
377  {
378  this->GetElement(*element_iter)->ReplaceNode(this->mNodes[index], this->mNodes[targetIndex]);
379  }
380 
381  }
382  catch (Exception&)
383  {
384  EXCEPTION("Moving node caused an element to have a non-positive Jacobian determinant");
385  }
386  }
387 
388  for (std::set<unsigned>::const_iterator boundary_element_iter=
389  unshared_boundary_element_indices.begin();
390  boundary_element_iter != unshared_boundary_element_indices.end();
391  boundary_element_iter++)
392  {
393 
394  this->GetBoundaryElement(*boundary_element_iter)->CalculateWeightedDirection(this->mBoundaryElementWeightedDirections[(*boundary_element_iter)],
395  this->mBoundaryElementJacobianDeterminants[(*boundary_element_iter)]);
396 
397  if (concreteMove)
398  {
399  this->GetBoundaryElement(*boundary_element_iter)->ReplaceNode(this->mNodes[index], this->mNodes[targetIndex]);
400  }
401  }
402 
403  std::set<unsigned> shared_element_indices;
404  std::set_intersection(this->mNodes[index]->rGetContainingElementIndices().begin(),
405  this->mNodes[index]->rGetContainingElementIndices().end(),
406  this->mNodes[targetIndex]->rGetContainingElementIndices().begin(),
407  this->mNodes[targetIndex]->rGetContainingElementIndices().end(),
408  std::inserter(shared_element_indices, shared_element_indices.begin()));
409 
410  for (std::set<unsigned>::const_iterator element_iter=shared_element_indices.begin();
411  element_iter != shared_element_indices.end();
412  element_iter++)
413  {
414  if (concreteMove)
415  {
416  this->GetElement(*element_iter)->MarkAsDeleted();
417  this->mElementJacobianDeterminants[ (*element_iter) ] = 0.0; //This used to be done in MarkAsDeleted
418  mDeletedElementIndices.push_back(*element_iter);
419  }
420  else
421  {
422  this->mElementJacobianDeterminants[ (*element_iter) ] = 0.0;
423  }
424  }
425 
426 
427  std::set<unsigned> shared_boundary_element_indices;
428  std::set_intersection(this->mNodes[index]->rGetContainingBoundaryElementIndices().begin(),
429  this->mNodes[index]->rGetContainingBoundaryElementIndices().end(),
430  this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().begin(),
431  this->mNodes[targetIndex]->rGetContainingBoundaryElementIndices().end(),
432  std::inserter(shared_boundary_element_indices, shared_boundary_element_indices.begin()));
433 
434  for (std::set<unsigned>::const_iterator boundary_element_iter=shared_boundary_element_indices.begin();
435  boundary_element_iter != shared_boundary_element_indices.end();
436  boundary_element_iter++)
437  {
438  if (concreteMove)
439  {
440  this->GetBoundaryElement(*boundary_element_iter)->MarkAsDeleted();
441  this->mBoundaryElementJacobianDeterminants[ (*boundary_element_iter) ] = 0.0; //This used to be done in MarkAsDeleted
442  mDeletedBoundaryElementIndices.push_back(*boundary_element_iter);
443  }
444  else
445  {
446  this->mBoundaryElementJacobianDeterminants[ (*boundary_element_iter) ] = 0.0;
447  this->mBoundaryElementWeightedDirections[ (*boundary_element_iter) ] = zero_vector<double>(SPACE_DIM);
448  }
449  }
450 
451  if (concreteMove)
452  {
453  this->mNodes[index]->MarkAsDeleted();
454  mDeletedNodeIndices.push_back(index);
455  }
456 }
457 
458 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
462 {
463  //Check that the point is in the element
464  if (pElement->IncludesPoint(point, true) == false)
465  {
466  EXCEPTION("RefineElement could not be started (point is not in element)");
467  }
468 
469  // Add a new node from the point that is passed to RefineElement
470  unsigned new_node_index = AddNode(new Node<SPACE_DIM>(0, point.rGetLocation()));
471  // Note: the first argument is the index of the node, which is going to be
472  // overridden by AddNode, so it can safely be ignored
473 
474  // This loop constructs the extra elements which are going to fill the space
475  for (unsigned i = 0; i < ELEMENT_DIM; i++)
476  {
477 
478  // First, make a copy of the current element making sure we update its index
479  unsigned new_elt_index;
480  if (mDeletedElementIndices.empty())
481  {
482  new_elt_index = this->mElements.size();
483  }
484  else
485  {
486  new_elt_index = mDeletedElementIndices.back();
487  mDeletedElementIndices.pop_back();
488  }
489 
490  Element<ELEMENT_DIM,SPACE_DIM>* p_new_element=
491  new Element<ELEMENT_DIM,SPACE_DIM>(*pElement, new_elt_index);
492 
493  // Second, update the node in the element with the new one
494  p_new_element->UpdateNode(ELEMENT_DIM-1-i, this->mNodes[new_node_index]);
495 
496  // Third, add the new element to the set
497  if ((unsigned) new_elt_index == this->mElements.size())
498  {
499  this->mElements.push_back(p_new_element);
500  }
501  else
502  {
503  delete this->mElements[new_elt_index];
504  this->mElements[new_elt_index] = p_new_element;
505  }
506  }
507 
508  // Lastly, update the last node in the element to be refined
509  pElement->UpdateNode(ELEMENT_DIM, this->mNodes[new_node_index]);
510 
511  return new_node_index;
512 }
513 
514 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
516 {
517  if (!this->mNodes[index]->IsBoundaryNode() )
518  {
519  EXCEPTION(" You may only delete a boundary node ");
520  }
521 
522  this->mNodes[index]->MarkAsDeleted();
523  mDeletedNodeIndices.push_back(index);
524 
525  // Update the boundary node vector
526  typename std::vector<Node<SPACE_DIM>*>::iterator b_node_iter
527  = std::find(this->mBoundaryNodes.begin(), this->mBoundaryNodes.end(), this->mNodes[index]);
528  this->mBoundaryNodes.erase(b_node_iter);
529 
530  // Remove boundary elements containing this node
531  std::set<unsigned> boundary_element_indices = this->mNodes[index]->rGetContainingBoundaryElementIndices();
532  std::set<unsigned>::const_iterator boundary_element_indices_iterator = boundary_element_indices.begin();
533  while (boundary_element_indices_iterator != boundary_element_indices.end())
534  {
535  BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* p_boundary_element = this->GetBoundaryElement(*boundary_element_indices_iterator);
536  p_boundary_element->MarkAsDeleted();
537  mDeletedBoundaryElementIndices.push_back(*boundary_element_indices_iterator);
538  boundary_element_indices_iterator++;
539  }
540 
541  // Remove elements containing this node
542  std::set<unsigned> element_indices = this->mNodes[index]->rGetContainingElementIndices();
543  std::set<unsigned>::const_iterator element_indices_iterator = element_indices.begin();
544  while (element_indices_iterator != element_indices.end())
545  {
546  Element<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(*element_indices_iterator);
547  for (unsigned i=0; i<p_element->GetNumNodes(); i++)
548  {
549  Node<SPACE_DIM>* p_node = p_element->GetNode(i);
550  if (!p_node->IsDeleted())
551  {
552  p_node->SetAsBoundaryNode();
553  // Update the boundary node vector
554  this->mBoundaryNodes.push_back(p_node);
555  }
556  }
557  p_element->MarkAsDeleted();
558  mDeletedElementIndices.push_back(p_element->GetIndex());
559  element_indices_iterator++;
560  }
561 }
562 
563 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
565 {
566  assert(!mAddedNodes);
567  map.Resize(this->GetNumAllNodes());
568 
569  std::vector<Element<ELEMENT_DIM, SPACE_DIM> *> live_elements;
570 
571  for (unsigned i=0; i<this->mElements.size(); i++)
572  {
573  assert(i==this->mElements[i]->GetIndex()); // We need this to be true to be able to reindex the Jacobian cache
574  if (this->mElements[i]->IsDeleted())
575  {
576  delete this->mElements[i];
577  }
578  else
579  {
580  live_elements.push_back(this->mElements[i]);
581 
582  unsigned this_element_index = this->mElements[i]->GetIndex();
583  if (SPACE_DIM == ELEMENT_DIM)
584  {
585  this->mElementJacobians[live_elements.size()-1] = this->mElementJacobians[this_element_index];
586  this->mElementInverseJacobians[live_elements.size()-1] = this->mElementInverseJacobians[this_element_index];
587  }
588  else
589  {
590  this->mElementWeightedDirections[live_elements.size()-1] = this->mElementWeightedDirections[this_element_index];
591  }
592  this->mElementJacobianDeterminants[live_elements.size()-1] = this->mElementJacobianDeterminants[this_element_index];
593  }
594  }
595 
596  assert(mDeletedElementIndices.size() == this->mElements.size()-live_elements.size());
597  mDeletedElementIndices.clear();
598  this->mElements = live_elements;
599  unsigned num_elements = this->mElements.size();
600 
601  if (SPACE_DIM == ELEMENT_DIM)
602  {
603  this->mElementJacobians.resize(num_elements);
604  this->mElementInverseJacobians.resize(num_elements);
605  }
606  else
607  {
608  this->mElementWeightedDirections.resize(num_elements);
609  }
610  this->mElementJacobianDeterminants.resize(num_elements);
611 
612  std::vector<Node<SPACE_DIM> *> live_nodes;
613  for (unsigned i=0; i<this->mNodes.size(); i++)
614  {
615  if (this->mNodes[i]->IsDeleted())
616  {
617  delete this->mNodes[i];
618  map.SetDeleted(i);
619  }
620  else
621  {
622  live_nodes.push_back(this->mNodes[i]);
623  // the nodes will have their index set to be the index into the live_nodes
624  // vector further down
625  map.SetNewIndex(i, (unsigned)(live_nodes.size()-1));
626  }
627  }
628 
629  assert(mDeletedNodeIndices.size() == this->mNodes.size()-live_nodes.size());
630  this->mNodes = live_nodes;
631  mDeletedNodeIndices.clear();
632 
633  std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *> live_boundary_elements;
634  for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
635  {
636  if (this->mBoundaryElements[i]->IsDeleted())
637  {
638  delete this->mBoundaryElements[i];
639  }
640  else
641  {
642  live_boundary_elements.push_back(this->mBoundaryElements[i]);
643 
644  this->mBoundaryElementWeightedDirections[live_boundary_elements.size()-1] = this->mBoundaryElementWeightedDirections[this->mBoundaryElements[i]->GetIndex()];
645  this->mBoundaryElementJacobianDeterminants[live_boundary_elements.size()-1] = this->mBoundaryElementJacobianDeterminants[this->mBoundaryElements[i]->GetIndex()];
646  }
647  }
648 
649  assert(mDeletedBoundaryElementIndices.size() == this->mBoundaryElements.size()-live_boundary_elements.size());
650  this->mBoundaryElements = live_boundary_elements;
652 
653  unsigned num_boundary_elements = this->mBoundaryElements.size();
654 
655  this->mBoundaryElementWeightedDirections.resize(num_boundary_elements);
656  this->mBoundaryElementJacobianDeterminants.resize(num_boundary_elements);
657 
658  for (unsigned i=0; i<this->mNodes.size(); i++)
659  {
660  this->mNodes[i]->SetIndex(i);
661  }
662 
663  for (unsigned i=0; i<this->mElements.size(); i++)
664  {
665 
666  this->mElements[i]->ResetIndex(i);
667  }
668 
669  for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
670  {
671  this->mBoundaryElements[i]->ResetIndex(i);
672  }
673 }
674 
675 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
677 {
678  // Make sure that we are in the correct dimension - this code will be eliminated at compile time
679  assert( ELEMENT_DIM == SPACE_DIM ); // LCOV_EXCL_LINE
680 
681  // Avoid some triangle/tetgen errors: need at least four
682  // nodes for tetgen, and at least three for triangle
683  if (GetNumNodes() <= SPACE_DIM)
684  {
685  EXCEPTION("The number of nodes must exceed the spatial dimension.");
686  }
687 
688  // Make sure the map is big enough
689  map.Resize(this->GetNumAllNodes());
690  if (mAddedNodes || !mDeletedNodeIndices.empty())
691  {
692  // Size of mesh is about to change
693  if (this->mpDistributedVectorFactory)
694  {
695  delete this->mpDistributedVectorFactory;
697  }
698  }
699  if (SPACE_DIM == 1)
700  {
701  // Store the node locations
702  std::vector<c_vector<double, SPACE_DIM> > old_node_locations;
703  unsigned new_index = 0;
704  for (unsigned i=0; i<this->GetNumAllNodes(); i++)
705  {
706  if (this->mNodes[i]->IsDeleted())
707  {
708  map.SetDeleted(i);
709  }
710  else
711  {
712  map.SetNewIndex(i, new_index);
713  old_node_locations.push_back(this->mNodes[i]->rGetLocation());
714  new_index++;
715  }
716  }
717 
718  // Remove current data
719  Clear();
720 
721  // Construct the nodes and boundary nodes
722  for (unsigned node_index=0; node_index<old_node_locations.size(); node_index++)
723  {
724  // As we're in 1D, the boundary nodes are simply at either end of the mesh
725  bool is_boundary_node = (node_index==0 || node_index==old_node_locations.size()-1);
726 
727  Node<SPACE_DIM>* p_node = new Node<SPACE_DIM>(node_index, old_node_locations[node_index], is_boundary_node);
728  this->mNodes.push_back(p_node);
729 
730  if (is_boundary_node)
731  {
732  this->mBoundaryNodes.push_back(p_node);
733  }
734  }
735 
736  // Create a map between node indices and node locations
737  std::map<double, unsigned> location_index_map;
738  for (unsigned i=0; i<this->mNodes.size(); i++)
739  {
740  location_index_map[this->mNodes[i]->rGetLocation()[0]] = this->mNodes[i]->GetIndex();
741  }
742 
743  // Use this map to generate a vector of node indices that are ordered spatially
744  std::vector<unsigned> node_indices_ordered_spatially;
745  for (std::map<double, unsigned>::iterator iter = location_index_map.begin();
746  iter != location_index_map.end();
747  ++iter)
748  {
749  node_indices_ordered_spatially.push_back(iter->second);
750  }
751 
752  // Construct the elements
753  this->mElements.reserve(old_node_locations.size()-1);
754  for (unsigned element_index=0; element_index<old_node_locations.size()-1; element_index++)
755  {
756  std::vector<Node<SPACE_DIM>*> nodes;
757  for (unsigned j=0; j<2; j++)
758  {
759  unsigned global_node_index = node_indices_ordered_spatially[element_index + j];
760  assert(global_node_index < this->mNodes.size());
761  nodes.push_back(this->mNodes[global_node_index]);
762  }
763  this->mElements.push_back(new Element<ELEMENT_DIM, SPACE_DIM>(element_index, nodes));
764  }
765 
766  // Construct the two boundary elements - as we're in 1D, these are simply at either end of the mesh
767  std::vector<Node<SPACE_DIM>*> nodes;
768  nodes.push_back(this->mNodes[0]);
769  this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>(0, nodes));
770 
771  nodes.clear();
772  nodes.push_back(this->mNodes[old_node_locations.size()-1]);
773  this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>(1, nodes));
774 
776  }
777  else if (SPACE_DIM==2) // In 2D, remesh using triangle via library calls
778  {
779  struct triangulateio mesher_input, mesher_output;
780  this->InitialiseTriangulateIo(mesher_input);
781  this->InitialiseTriangulateIo(mesher_output);
782 
783  this->ExportToMesher(map, mesher_input);
784 
785  // Library call
786  triangulate((char*)"Qze", &mesher_input, &mesher_output, nullptr);
787 
788  this->ImportFromMesher(mesher_output, mesher_output.numberoftriangles, mesher_output.trianglelist, mesher_output.numberofedges, mesher_output.edgelist, mesher_output.edgemarkerlist);
789 
790  //Tidy up triangle
791  this->FreeTriangulateIo(mesher_input);
792  this->FreeTriangulateIo(mesher_output);
793  }
794  else // in 3D, remesh using tetgen
795  {
796 
797  class tetgen::tetgenio mesher_input, mesher_output;
798 
799  this->ExportToMesher(map, mesher_input);
800 
801  // Library call
802  tetgen::tetrahedralize((char*)"Qz", &mesher_input, &mesher_output);
803 
804  this->ImportFromMesher(mesher_output, mesher_output.numberoftetrahedra, mesher_output.tetrahedronlist, mesher_output.numberoftrifaces, mesher_output.trifacelist, nullptr);
805  }
806 }
807 
808 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
810 {
811  NodeMap map(GetNumNodes());
812  ReMesh(map);
813 }
814 
815 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
816 std::vector<c_vector<unsigned, 5> > MutableMesh<ELEMENT_DIM, SPACE_DIM>::SplitLongEdges(double cutoffLength)
817 {
818  assert(ELEMENT_DIM == 2); // LCOV_EXCL_LINE
819  assert(SPACE_DIM == 3); // LCOV_EXCL_LINE
820 
821  std::vector<c_vector<unsigned, 5> > history;
822 
823  bool long_edge_exists = true;
824 
825  while (long_edge_exists)
826  {
827  std::set<std::pair<unsigned, unsigned> > long_edges;
828 
829  // Loop over elements to check for Long edges
831  elem_iter != this->GetElementIteratorEnd();
832  ++elem_iter)
833  {
834  unsigned num_nodes = ELEMENT_DIM+1;
835 
836  // Loop over element vertices
837  for (unsigned local_index=0; local_index<num_nodes; local_index++)
838  {
839  // Find locations of current node (node a) and anticlockwise node (node b)
840  Node<SPACE_DIM>* p_node_a = elem_iter->GetNode(local_index);
841  unsigned local_index_plus_one = (local_index+1)%num_nodes;
842  Node<SPACE_DIM>* p_node_b = elem_iter->GetNode(local_index_plus_one);
843 
844  // Find distance between nodes
845  double distance_between_nodes = this->GetDistanceBetweenNodes(p_node_a->GetIndex(), p_node_b->GetIndex());
846 
847  if (distance_between_nodes > cutoffLength)
848  {
849  if (p_node_a->GetIndex() < p_node_b->GetIndex())
850  {
851  std::pair<unsigned, unsigned> long_edge(p_node_a->GetIndex(),p_node_b->GetIndex());
852  long_edges.insert(long_edge);
853  }
854  else
855  {
856  std::pair<unsigned, unsigned> long_edge(p_node_b->GetIndex(),p_node_a->GetIndex());
857  long_edges.insert(long_edge);
858  }
859  }
860  }
861  }
862 
863  if (long_edges.size() > 0) //Split the edges in decreasing order.
864  {
865  while (long_edges.size() > 0)
866  {
867  double longest_edge = 0.0;
868  std::set<std::pair<unsigned, unsigned> >::iterator longest_edge_iter;
869 
870  //Find the longest edge in the set and split it
871  for (std::set<std::pair<unsigned, unsigned> >::iterator edge_iter = long_edges.begin();
872  edge_iter != long_edges.end();
873  ++edge_iter)
874  {
875  unsigned node_a_global_index = edge_iter->first;
876  unsigned node_b_global_index = edge_iter->second;
877 
878  double distance_between_nodes = this->GetDistanceBetweenNodes(node_a_global_index, node_b_global_index);
879 
880  if (distance_between_nodes > longest_edge)
881  {
882  longest_edge = distance_between_nodes;
883  longest_edge_iter = edge_iter;
884  }
885  }
886  assert(longest_edge >0);
887 
888  c_vector<unsigned, 3> new_node_index = SplitEdge(this->GetNode(longest_edge_iter->first), this->GetNode(longest_edge_iter->second));
889 
890  c_vector<unsigned, 5> node_set;
891  node_set(0) = new_node_index[0];
892  node_set(1) = longest_edge_iter->first;
893  node_set(2) = longest_edge_iter->second;
894  node_set(3) = new_node_index[1];
895  node_set(4) = new_node_index[2];
896  history.push_back(node_set);
897 
898  // Delete pair from set
899  long_edges.erase(*longest_edge_iter);
900  }
901  }
902  else
903  {
904  long_edge_exists = false;
905  }
906  }
907 
908  return history;
909 }
910 
911 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
913 {
914  c_vector<unsigned, 3> new_node_index_vector;
915 
916  std::set<unsigned> elements_of_node_a = pNodeA->rGetContainingElementIndices();
917  std::set<unsigned> elements_of_node_b = pNodeB->rGetContainingElementIndices();
918 
919  std::set<unsigned> intersection_elements;
920  std::set_intersection(elements_of_node_a.begin(), elements_of_node_a.end(),
921  elements_of_node_b.begin(), elements_of_node_b.end(),
922  std::inserter(intersection_elements, intersection_elements.begin()));
923 
924  // Create the new node
925  c_vector<double, SPACE_DIM> new_node_location = pNodeA->rGetLocation() + 0.5*this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeB->rGetLocation());
926 
927  bool is_boundary_node = intersection_elements.size() == 1; // If only in one element then its on the boundary
928 
929  Node<SPACE_DIM>* p_new_node = new Node<SPACE_DIM>(0u,new_node_location,is_boundary_node); // Index is rewritten once added to mesh
930 
931  unsigned new_node_index = this->AddNode(p_new_node);
932 
933  new_node_index_vector[0] = new_node_index;
934 
935  unsigned counter = 1;
936 
937  for (std::set<unsigned>::const_iterator it = intersection_elements.begin(); it != intersection_elements.end(); ++it)
938  {
939  unsigned elementIndex = *it;
940 
941  Element<ELEMENT_DIM,SPACE_DIM>* p_original_element = this->GetElement(elementIndex);
942 
943  // First, make a copy of the current element and assign an unused index
944  Element<ELEMENT_DIM,SPACE_DIM>* p_new_element = new Element<ELEMENT_DIM,SPACE_DIM>(*p_original_element, UINT_MAX);
945 
946  // Second, add the new element to the set of existing elements. This method will assign a proper index to the element.
947  AddElement(p_new_element);
948 
949  // Third, update node a in the element with the new one
950  p_new_element->ReplaceNode(pNodeA, this->mNodes[new_node_index]);
951 
952  // Last, update node b in the original element with the new one
953  p_original_element->ReplaceNode(pNodeB, this->mNodes[new_node_index]);
954 
955  //Add node in both of these elements to new_node_index_vector (this enables us to add a new spring in the MeshBasedCellPopulation
956  unsigned other_node_index = UNSIGNED_UNSET;
957 
958  if ((p_original_element->GetNodeGlobalIndex(0) != new_node_index) &&
959  (p_original_element->GetNodeGlobalIndex(0) != pNodeA->GetIndex()))
960  {
961  other_node_index = p_original_element->GetNodeGlobalIndex(0);
962  }
963  else if ((p_original_element->GetNodeGlobalIndex(1) != new_node_index) &&
964  (p_original_element->GetNodeGlobalIndex(1) != pNodeA->GetIndex()))
965  {
966  other_node_index = p_original_element->GetNodeGlobalIndex(1);
967  }
968  else if ((p_original_element->GetNodeGlobalIndex(2) != new_node_index) &&
969  (p_original_element->GetNodeGlobalIndex(2) != pNodeA->GetIndex()))
970  {
971  other_node_index = p_original_element->GetNodeGlobalIndex(2);
972  }
973  else
974  {
976  }
977  new_node_index_vector[counter] = other_node_index;
978  counter++;
979  }
980 
981  assert(counter < 4);
982  assert(counter > 1);// need to be in at least one element
983 
984  if (counter == 2) // only one new element
985  {
986  new_node_index_vector[2] = UNSIGNED_UNSET;
987  }
988 
989  return new_node_index_vector;
990 }
991 
992 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
994 {
995  assert(ELEMENT_DIM == SPACE_DIM); // LCOV_EXCL_LINE
996  unsigned num_nodes = pElement->GetNumNodes();
997  std::set<unsigned> neighbouring_elements_indices;
998  std::set< Element<ELEMENT_DIM,SPACE_DIM> *> neighbouring_elements;
999  std::set<unsigned> neighbouring_nodes_indices;
1000 
1001  // Form a set of neighbouring elements via the nodes
1002  for (unsigned i=0; i<num_nodes; i++)
1003  {
1004  Node<SPACE_DIM>* p_node = pElement->GetNode(i);
1005  neighbouring_elements_indices = p_node->rGetContainingElementIndices();
1006  for (std::set<unsigned>::const_iterator it = neighbouring_elements_indices.begin();
1007  it != neighbouring_elements_indices.end();
1008  ++it)
1009  {
1010  neighbouring_elements.insert(this->GetElement(*it));
1011  }
1012  }
1013  neighbouring_elements.erase(pElement);
1014 
1015  // For each neighbouring element find the supporting nodes
1016  typedef typename std::set<Element<ELEMENT_DIM,SPACE_DIM> *>::const_iterator ElementIterator;
1017 
1018  for (ElementIterator it = neighbouring_elements.begin();
1019  it != neighbouring_elements.end();
1020  ++it)
1021  {
1022  for (unsigned i=0; i<num_nodes; i++)
1023  {
1024  neighbouring_nodes_indices.insert((*it)->GetNodeGlobalIndex(i));
1025  }
1026  }
1027 
1028  // Remove the nodes that support this element
1029  for (unsigned i = 0; i < num_nodes; i++)
1030  {
1031  neighbouring_nodes_indices.erase(pElement->GetNodeGlobalIndex(i));
1032  }
1033 
1034  // Get the circumsphere information
1035  c_vector<double, SPACE_DIM+1> this_circum_centre;
1036 
1037  this_circum_centre = pElement->CalculateCircumsphere(this->mElementJacobians[pElement->GetIndex()], this->mElementInverseJacobians[pElement->GetIndex()]);
1038 
1039  // Copy the actualy circumcentre into a smaller vector
1040  c_vector<double, ELEMENT_DIM> circum_centre;
1041  for (unsigned i=0; i<ELEMENT_DIM; i++)
1042  {
1043  circum_centre[i] = this_circum_centre[i];
1044  }
1045 
1046  for (std::set<unsigned>::const_iterator it = neighbouring_nodes_indices.begin();
1047  it != neighbouring_nodes_indices.end();
1048  ++it)
1049  {
1050  c_vector<double, ELEMENT_DIM> node_location;
1051  node_location = this->GetNode(*it)->rGetLocation();
1052 
1053  // Calculate vector from circumcenter to node
1054  node_location -= circum_centre;
1055 
1056  // This is to calculate the squared distance betweeen them
1057  double squared_distance = inner_prod(node_location, node_location);
1058 
1059  // If the squared idstance is less than the elements circum-radius(squared),
1060  // then the Voronoi property is violated.
1061  if (squared_distance < this_circum_centre[ELEMENT_DIM])
1062  {
1063  // We know the node is inside the circumsphere, but we don't know how far
1064  double radius = sqrt(this_circum_centre[ELEMENT_DIM]);
1065  double distance = radius - sqrt(squared_distance);
1066 
1067  // If the node penetration is greater than supplied maximum penetration factor
1068  if (distance/radius > maxPenetration)
1069  {
1070  return false;
1071  }
1072  }
1073  }
1074  return true;
1075 }
1076 
1077 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1079 {
1080  // Looping through all the elements in the mesh
1082  for (unsigned i=0; i<this->mElements.size(); i++)
1083  {
1084  // Check if the element is not deleted
1085  if (!this->mElements[i]->IsDeleted())
1086  {
1087  // Checking the Voronoi of the Element
1088  if (CheckIsVoronoi(this->mElements[i], maxPenetration) == false)
1089  {
1090  return false;
1091  }
1092  }
1093  }
1094  return true;
1095 }
1096 
1097 // Explicit instantiation
1098 template class MutableMesh<1,1>;
1099 template class MutableMesh<1,2>;
1100 template class MutableMesh<1,3>;
1101 template class MutableMesh<2,2>;
1102 template class MutableMesh<2,3>;
1103 template class MutableMesh<3,3>;
1104 
1105 // Serialization for Boost >= 1.36
std::vector< c_vector< unsigned, 5 > > SplitLongEdges(double cutoffLength)
std::vector< c_matrix< double, SPACE_DIM, ELEMENT_DIM > > mElementJacobians
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
std::vector< Element< ELEMENT_DIM, SPACE_DIM > * > mElements
std::vector< Node< SPACE_DIM > * > mBoundaryNodes
c_vector< double, SPACE_DIM+1 > CalculateCircumsphere(c_matrix< double, SPACE_DIM, ELEMENT_DIM > &rJacobian, c_matrix< double, ELEMENT_DIM, SPACE_DIM > &rInverseJacobian)
Definition: Element.cpp:118
void ImportFromMesher(MESHER_IO &mesherOutput, unsigned numberOfElements, int *elementList, unsigned numberOfFaces, int *faceList, int *edgeMarkerList)
Definition: Node.hpp:58
c_vector< double, DIM > & rGetLocation()
Definition: ChastePoint.cpp:76
void SetAsBoundaryNode(bool value=true)
Definition: Node.cpp:127
std::vector< unsigned > mDeletedBoundaryElementIndices
unsigned GetNodeGlobalIndex(unsigned localIndex) const
void DeleteNodePriorToReMesh(unsigned index)
void UpdateNode(const unsigned &rIndex, Node< SPACE_DIM > *pNode)
Definition: Element.cpp:89
void ResetIndex(unsigned index)
Definition: Element.cpp:104
Node< SPACE_DIM > * GetNode(unsigned index) const
#define EXCEPTION(message)
Definition: Exception.hpp:143
virtual void RefreshJacobianCachedData()
std::vector< c_matrix< double, ELEMENT_DIM, SPACE_DIM > > mElementInverseJacobians
unsigned RefineElement(Element< ELEMENT_DIM, SPACE_DIM > *pElement, ChastePoint< SPACE_DIM > point)
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
void RescaleMeshFromBoundaryNode(ChastePoint< 1 > updatedPoint, unsigned boundaryNodeIndex)
void ReplaceNode(Node< SPACE_DIM > *pOldNode, Node< SPACE_DIM > *pNewNode)
void ReIndex(NodeMap &map)
bool CheckIsVoronoi(Element< ELEMENT_DIM, SPACE_DIM > *pElement, double maxPenetration)
std::set< unsigned > & rGetContainingElementIndices()
Definition: Node.cpp:300
void SetIndex(unsigned index)
Definition: Node.cpp:121
virtual unsigned GetNumAllNodes() const
#define NEVER_REACHED
Definition: Exception.hpp:206
virtual void SetNode(unsigned index, ChastePoint< SPACE_DIM > point, bool concreteMove=true)
unsigned GetNumElements() const
void ExportToMesher(NodeMap &map, MESHER_IO &mesherInput, int *elementList=nullptr)
virtual unsigned AddNode(Node< SPACE_DIM > *pNewNode)
Definition: MutableMesh.cpp:80
void SetNewIndex(unsigned oldIndex, unsigned newIndex)
Definition: NodeMap.cpp:66
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
void MarkAsDeleted()
Definition: Element.cpp:74
unsigned GetNumNodes() const
double GetDistanceBetweenNodes(unsigned indexA, unsigned indexB)
std::vector< unsigned > mDeletedNodeIndices
virtual void DeleteNode(unsigned index)
bool mMeshChangesDuringSimulation
std::vector< Node< SPACE_DIM > * > mNodes
DistributedVectorFactory * mpDistributedVectorFactory
void InitialiseTriangulateIo(triangulateio &mesherIo)
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * > mBoundaryElements
unsigned GetNumNodes() const
void SetDeleted(unsigned index)
Definition: NodeMap.cpp:76
std::vector< double > mElementJacobianDeterminants
const unsigned UNSIGNED_UNSET
Definition: Exception.hpp:52
std::vector< c_vector< double, SPACE_DIM > > mBoundaryElementWeightedDirections
virtual void DeleteElement(unsigned index)
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * GetBoundaryElement(unsigned index) const
unsigned AddElement(Element< ELEMENT_DIM, SPACE_DIM > *pNewElement)
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:139
void MoveMergeNode(unsigned index, unsigned targetIndex, bool concreteMove=true)
virtual void Clear()
unsigned GetIndex() const
std::vector< double > mBoundaryElementJacobianDeterminants
bool IncludesPoint(const ChastePoint< SPACE_DIM > &rTestPoint, bool strict=false)
Definition: Element.cpp:313
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
unsigned GetNumBoundaryElements() const
std::vector< c_vector< double, SPACE_DIM > > mElementWeightedDirections
unsigned GetIndex() const
Definition: Node.cpp:158
c_vector< unsigned, 3 > SplitEdge(Node< SPACE_DIM > *pNodeA, Node< SPACE_DIM > *pNodeB)
bool IsDeleted() const
Definition: Node.cpp:412
void DeleteBoundaryNodeAt(unsigned index)
virtual ~MutableMesh()
Definition: MutableMesh.cpp:74
std::vector< unsigned > mDeletedElementIndices
void FreeTriangulateIo(triangulateio &mesherIo)
void Resize(unsigned size)
Definition: NodeMap.cpp:52