Chaste  Release::2018.1
Cylindrical2dVertexMesh.cpp
1 /*
2 
3 Copyright (c) 2005-2018, 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 "Cylindrical2dVertexMesh.hpp"
37 #include "Cylindrical2dMesh.hpp"
38 
40  std::vector<Node<2>*> nodes,
41  std::vector<VertexElement<2, 2>*> vertexElements,
42  double cellRearrangementThreshold,
43  double t2Threshold)
44  : MutableVertexMesh<2,2>(nodes, vertexElements, cellRearrangementThreshold, t2Threshold),
45  mWidth(width),
46  mpMeshForVtk(nullptr)
47 {
48  // Call ReMesh() to remove any deleted nodes and relabel
49  ReMesh();
50 }
51 
53  : mWidth(rMesh.GetWidth(0)),
54  mpMeshForVtk(nullptr)
55 {
56  mpDelaunayMesh = &rMesh;
57 
58  // Reset member variables and clear mNodes, mFaces and mElements
59  Clear();
60 
61  unsigned num_elements = mpDelaunayMesh->GetNumAllNodes();
62  unsigned num_nodes = mpDelaunayMesh->GetNumAllElements();
63 
64  // Allocate memory for mNodes and mElements
65  this->mNodes.reserve(num_nodes);
66 
67  // Create as many elements as there are nodes in the mesh
68  mElements.reserve(num_elements);
69 
70  for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
71  {
72  VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_index);
73  mElements.push_back(p_element);
74  }
75 
76  // Populate mNodes
78 
79  // Loop over all generated nodes and check they're not outside [0,mWidth]
80  for (unsigned i=0; i<num_nodes; i++)
81  {
82  double x_location = mNodes[i]->rGetLocation()[0];
83  if (x_location < 0)
84  {
85  mNodes[i]->rGetModifiableLocation()[0] = x_location + mWidth;
86  }
87  else if (x_location > mWidth)
88  {
89  mNodes[i]->rGetModifiableLocation()[0] = x_location - mWidth;
90  }
91  }
92 
93  // Loop over elements of the Delaunay mesh (which are nodes/vertices of this mesh)
94  for (unsigned i=0; i<num_nodes; i++)
95  {
96  // Loop over nodes owned by this triangular element in the Delaunay mesh
97  // Add this node/vertex to each of the 3 vertex elements
98  for (unsigned local_index=0; local_index<3; local_index++)
99  {
100  unsigned elem_index = mpDelaunayMesh->GetElement(i)->GetNodeGlobalIndex(local_index);
101  unsigned num_nodes_in_elem = mElements[elem_index]->GetNumNodes();
102  unsigned end_index = num_nodes_in_elem>0 ? num_nodes_in_elem-1 : 0;
103 
104  mElements[elem_index]->AddNode(this->mNodes[i], end_index);
105  }
106  }
107 
108  // Reorder mNodes anticlockwise
109  for (unsigned elem_index=0; elem_index<mElements.size(); elem_index++)
110  {
116  std::vector<std::pair<double, unsigned> > index_angle_list;
117  for (unsigned local_index=0; local_index<mElements[elem_index]->GetNumNodes(); local_index++)
118  {
119  c_vector<double, 2> vectorA = mpDelaunayMesh->GetNode(elem_index)->rGetLocation();
120  c_vector<double, 2> vectorB = mElements[elem_index]->GetNodeLocation(local_index);
121  c_vector<double, 2> centre_to_vertex = mpDelaunayMesh->GetVectorFromAtoB(vectorA, vectorB);
122 
123  double angle = atan2(centre_to_vertex(1), centre_to_vertex(0));
124  unsigned global_index = mElements[elem_index]->GetNodeGlobalIndex(local_index);
125 
126  std::pair<double, unsigned> pair(angle, global_index);
127  index_angle_list.push_back(pair);
128  }
129 
130  // Sort the list in order of increasing angle
131  sort(index_angle_list.begin(), index_angle_list.end());
132 
133  // Create a new Voronoi element and pass in the appropriate Nodes, ordered anticlockwise
134  VertexElement<2,2>* p_new_element = new VertexElement<2,2>(elem_index);
135  for (unsigned count = 0; count < index_angle_list.size(); count++)
136  {
137  unsigned local_index = count>1 ? count-1 : 0;
138  p_new_element->AddNode(mNodes[index_angle_list[count].second], local_index);
139  }
140 
141  // Replace the relevant member of mElements with this Voronoi element
142  delete mElements[elem_index];
143  mElements[elem_index] = p_new_element;
144  }
145 
146  this->mMeshChangesDuringSimulation = false;
147 }
148 
150  : mpMeshForVtk(nullptr)
151 {
152 }
153 
155 {
156  if (mpMeshForVtk != nullptr)
157  {
158  delete mpMeshForVtk;
159  }
160 }
161 
162 c_vector<double, 2> Cylindrical2dVertexMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
163 {
164  assert(mWidth > 0.0);
165 
166  c_vector<double, 2> vector = rLocation2 - rLocation1;
167  vector[0] = fmod(vector[0], mWidth);
168 
169  // If the points are more than halfway around the cylinder apart, measure the other way
170  if (vector[0] > 0.5*mWidth)
171  {
172  vector[0] -= mWidth;
173  }
174  else if (vector[0] < -0.5*mWidth)
175  {
176  vector[0] += mWidth;
177  }
178  return vector;
179 }
180 
181 void Cylindrical2dVertexMesh::SetNode(unsigned nodeIndex, ChastePoint<2> point)
182 {
183  double x_coord = point.rGetLocation()[0];
184 
185  // Perform a periodic movement if necessary
186  if (x_coord >= mWidth)
187  {
188  // Move point to the left
189  point.SetCoordinate(0, x_coord - mWidth);
190  }
191  else if (x_coord < 0.0)
192  {
193  // Move point to the right
194  point.SetCoordinate(0, x_coord + mWidth);
195  }
196 
197  // Update the node's location
198  MutableVertexMesh<2,2>::SetNode(nodeIndex, point);
199 }
200 
201 double Cylindrical2dVertexMesh::GetWidth(const unsigned& rDimension) const
202 {
203  double width = 0.0;
204  assert(rDimension==0 || rDimension==1);
205  if (rDimension==0)
206  {
207  width = mWidth;
208  }
209  else
210  {
211  width = VertexMesh<2,2>::GetWidth(rDimension);
212  }
213  return width;
214 }
215 
217 {
218  unsigned node_index = MutableVertexMesh<2,2>::AddNode(pNewNode);
219 
220  // If necessary move it to be back on the cylinder
221  ChastePoint<2> new_node_point = pNewNode->GetPoint();
222  SetNode(node_index, new_node_point);
223 
224  return node_index;
225 }
226 
227 void Cylindrical2dVertexMesh::Scale(const double xScale, const double yScale, const double zScale)
228 {
229  assert(zScale == 1.0);
230 
231  AbstractMesh<2, 2>::Scale(xScale, yScale);
232 
233  // Also rescale the width of the mesh (this effectively scales the domain)
234  mWidth *= xScale;
235 }
236 
238 {
239  unsigned num_nodes = GetNumNodes();
240 
241  std::vector<Node<2>*> temp_nodes(2*num_nodes);
242  std::vector<VertexElement<2, 2>*> elements;
243 
244  // Create four copies of each node
245  for (unsigned index=0; index<num_nodes; index++)
246  {
247  c_vector<double, 2> location;
248  location = GetNode(index)->rGetLocation();
249 
250  // Node copy at original location
251  Node<2>* p_node = new Node<2>(index, false, location[0], location[1]);
252  temp_nodes[index] = p_node;
253 
254  // Node copy shifted right
255  p_node = new Node<2>(num_nodes + index, false, location[0] + mWidth, location[1]);
256  temp_nodes[num_nodes + index] = p_node;
257  }
258 
259  // Iterate over elements
261  elem_iter != GetElementIteratorEnd();
262  ++elem_iter)
263  {
264  unsigned elem_index = elem_iter->GetIndex();
265  unsigned num_nodes_in_elem = elem_iter->GetNumNodes();
266 
267  std::vector<Node<2>*> elem_nodes;
268 
269  // Compute whether the element straddles either periodic boundary
270  bool element_straddles_left_right_boundary = false;
271 
272  const c_vector<double, 2>& r_this_node_location = elem_iter->GetNode(0)->rGetLocation();
273  for (unsigned local_index=0; local_index<num_nodes_in_elem; local_index++)
274  {
275  const c_vector<double, 2>& r_next_node_location = elem_iter->GetNode((local_index+1)%num_nodes_in_elem)->rGetLocation();
276  c_vector<double, 2> vector;
277  vector = r_next_node_location - r_this_node_location;
278 
279  if (fabs(vector[0]) > 0.5*mWidth)
280  {
281  element_straddles_left_right_boundary = true;
282  }
283  }
284 
285  // Use the above information when duplicating the element
286  for (unsigned local_index=0; local_index<num_nodes_in_elem; local_index++)
287  {
288  unsigned this_node_index = elem_iter->GetNodeGlobalIndex(local_index);
289 
290  // If the element straddles the left/right periodic boundary...
291  if (element_straddles_left_right_boundary)
292  {
293  // ...and this node is located to the left of the centre of the mesh...
294  bool node_is_right_of_centre = (elem_iter->GetNode(local_index)->rGetLocation()[0] - 0.5*mWidth > 0);
295  if (!node_is_right_of_centre)
296  {
297  // ...then choose the equivalent node to the right
298  this_node_index += num_nodes;
299  }
300  }
301 
302  elem_nodes.push_back(temp_nodes[this_node_index]);
303  }
304 
305  VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_index, elem_nodes);
306  elements.push_back(p_element);
307  }
308 
309  // Now delete any nodes from the mesh for VTK that are not contained in any elements
310  std::vector<Node<2>*> nodes;
311  unsigned count = 0;
312  for (unsigned index=0; index<temp_nodes.size(); index++)
313  {
314  unsigned num_elems_containing_this_node = temp_nodes[index]->rGetContainingElementIndices().size();
315 
316  if (num_elems_containing_this_node == 0)
317  {
318  // Avoid memory leak
319  delete temp_nodes[index];
320  }
321  else
322  {
323  temp_nodes[index]->SetIndex(count);
324  nodes.push_back(temp_nodes[index]);
325  count++;
326  }
327  }
328 
329  if (mpMeshForVtk != nullptr)
330  {
331  delete mpMeshForVtk;
332  }
333 
334  mpMeshForVtk = new VertexMesh<2,2>(nodes, elements);
335  return mpMeshForVtk;
336 }
337 
338 // Serialization for Boost >= 1.36
Definition: Node.hpp:58
c_vector< double, DIM > & rGetLocation()
Definition: ChastePoint.cpp:76
void SetIndex(unsigned index)
VertexMesh< 2, 2 > * mpMeshForVtk
unsigned AddNode(Node< 2 > *pNewNode)
Node< SPACE_DIM > * GetNode(unsigned index) const
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
double GetWidth(const unsigned &rDimension) const
void GenerateVerticesFromElementCircumcentres(TetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
Definition: VertexMesh.cpp:390
VertexMesh< 2, 2 > * GetMeshForVtk()
bool mMeshChangesDuringSimulation
void SetNode(unsigned nodeIndex, ChastePoint< 2 > point)
void AddNode(Node< SPACE_DIM > *pNode, const unsigned &rIndex)
std::vector< Node< SPACE_DIM > * > mNodes
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Definition: VertexMesh.hpp:679
void SetCoordinate(unsigned i, double value)
virtual void SetNode(unsigned nodeIndex, ChastePoint< SPACE_DIM > point)
c_vector< double, 2 > GetVectorFromAtoB(const c_vector< double, 2 > &rLocation1, const c_vector< double, 2 > &rLocation2)
unsigned GetNumNodes() const
std::vector< VertexElement< ELEMENT_DIM, SPACE_DIM > * > mElements
Definition: VertexMesh.hpp:80
ChastePoint< SPACE_DIM > GetPoint() const
Definition: Node.cpp:133
virtual double GetWidth(const unsigned &rDimension) const
#define CHASTE_CLASS_EXPORT(T)
virtual void Scale(const double xFactor=1.0, const double yFactor=1.0, const double zFactor=1.0)
unsigned GetIndex() const
Definition: Node.cpp:158
VertexElementIterator GetElementIteratorEnd()
Definition: VertexMesh.hpp:686
TetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpDelaunayMesh
Definition: VertexMesh.hpp:101
void Scale(const double xScale=1.0, const double yScale=1.0, const double zScale=1.0)