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