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