Chaste  Release::2018.1
Toroidal2dVertexMesh.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 "Toroidal2dVertexMesh.hpp"
37 
39  double height,
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  mHeight(height),
47  mpMeshForVtk(nullptr)
48 {
49  // Call ReMesh() to remove any deleted nodes and relabel
50  ReMesh();
51 }
52 
54 {
55 }
56 
58 {
59  if (mpMeshForVtk != NULL)
60  {
61  delete mpMeshForVtk;
62  }
63 }
64 
65 c_vector<double, 2> Toroidal2dVertexMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2)
66 {
67  assert(mWidth > 0.0);
68  assert(mHeight > 0.0);
69 
70  c_vector<double, 2> vector = rLocation2 - rLocation1;
71  vector[0] = fmod(vector[0], mWidth);
72  vector[1] = fmod(vector[1], mHeight);
73 
74  // If the points are more than halfway across the domain, measure the other way
75  if (vector[0] > 0.5*mWidth)
76  {
77  vector[0] -= mWidth;
78  }
79  else if (vector[0] < -0.5*mWidth)
80  {
81  vector[0] += mWidth;
82  }
83 
84  // If the points are more than halfway up the domain, measure the other way
85  if (vector[1] > 0.5*mHeight)
86  {
87  vector[1] -= mHeight;
88  }
89  else if (vector[1] < -0.5*mHeight)
90  {
91  vector[1] += mHeight;
92  }
93  return vector;
94 }
95 
96 void Toroidal2dVertexMesh::SetNode(unsigned nodeIndex, ChastePoint<2> point)
97 {
98  double x_coord = point.rGetLocation()[0];
99  double y_coord = point.rGetLocation()[1];
100 
101  // Perform a periodic movement if necessary
102  if (x_coord >= mWidth)
103  {
104  // Move point left
105  point.SetCoordinate(0, x_coord - mWidth);
106  }
107  else if (x_coord < 0.0)
108  {
109  // Move point right
110  point.SetCoordinate(0, x_coord + mWidth);
111  }
112  if (y_coord >= mHeight)
113  {
114  // Move point down
115  point.SetCoordinate(1, y_coord - mHeight);
116  }
117  else if (y_coord < 0.0)
118  {
119  // Move point up
120  point.SetCoordinate(1, y_coord + mHeight);
121  }
122 
123  // Update the node's location
124  MutableVertexMesh<2,2>::SetNode(nodeIndex, point);
125 }
126 
127 double Toroidal2dVertexMesh::GetWidth(const unsigned& rDimension) const
128 {
129  assert(rDimension==0 || rDimension==1);
130 
131  double width = mWidth;
132  if (rDimension == 1)
133  {
134  width = mHeight;
135  }
136 
137  return width;
138 }
139 
141 {
142  assert(height > 0);
143  mHeight = height;
144 }
145 
147 {
148  assert(width > 0);
149  mWidth = width;
150 }
151 
153 {
154  unsigned node_index = MutableVertexMesh<2,2>::AddNode(pNewNode);
155 
156  // If necessary move it to be back onto the torus
157  ChastePoint<2> new_node_point = pNewNode->GetPoint();
158  SetNode(node_index, new_node_point);
159 
160  return node_index;
161 }
162 
164 {
165  unsigned num_nodes = GetNumNodes();
166 
167  std::vector<Node<2>*> temp_nodes(4*num_nodes);
168  std::vector<VertexElement<2, 2>*> elements;
169 
170  // Create four copies of each node
171  for (unsigned index=0; index<num_nodes; index++)
172  {
173  c_vector<double, 2> location;
174  location = GetNode(index)->rGetLocation();
175 
176  // Node copy at original location
177  Node<2>* p_node = new Node<2>(index, false, location[0], location[1]);
178  temp_nodes[index] = p_node;
179 
180  // Node copy shifted right
181  p_node = new Node<2>(num_nodes + index, false, location[0] + mWidth, location[1]);
182  temp_nodes[num_nodes + index] = p_node;
183 
184  // Node copy shifted up
185  p_node = new Node<2>(2*num_nodes + index, false, location[0], location[1] + mHeight);
186  temp_nodes[2*num_nodes + index] = p_node;
187 
188  // Node copy shifted right and up
189  p_node = new Node<2>(3*num_nodes + index, false, location[0] + mWidth, location[1] + mHeight);
190  temp_nodes[3*num_nodes + index] = p_node;
191  }
192 
193  // Iterate over elements
195  elem_iter != GetElementIteratorEnd();
196  ++elem_iter)
197  {
198  unsigned elem_index = elem_iter->GetIndex();
199  unsigned num_nodes_in_elem = elem_iter->GetNumNodes();
200 
201  std::vector<Node<2>*> elem_nodes;
202 
203  // Compute whether the element straddles either periodic boundary
204  bool element_straddles_left_right_boundary = false;
205  bool element_straddles_top_bottom_boundary = false;
206 
207  const c_vector<double, 2>& r_this_node_location = elem_iter->GetNode(0)->rGetLocation();
208  for (unsigned local_index=0; local_index<num_nodes_in_elem; local_index++)
209  {
210  const c_vector<double, 2>& r_next_node_location = elem_iter->GetNode((local_index+1)%num_nodes_in_elem)->rGetLocation();
211  c_vector<double, 2> vector;
212  vector = r_next_node_location - r_this_node_location;
213 
214  if (fabs(vector[0]) > 0.5*mWidth)
215  {
216  element_straddles_left_right_boundary = true;
217  }
218  if (fabs(vector[1]) > 0.5*mHeight)
219  {
220  element_straddles_top_bottom_boundary = true;
221  }
222  }
223 
224  // Use the above information when duplicating the element
225  for (unsigned local_index=0; local_index<num_nodes_in_elem; local_index++)
226  {
227  unsigned this_node_index = elem_iter->GetNodeGlobalIndex(local_index);
228 
229  // If the element straddles the left/right periodic boundary...
230  if (element_straddles_left_right_boundary)
231  {
232  // ...and this node is located to the left of the centre of the mesh...
233  bool node_is_right_of_centre = (elem_iter->GetNode(local_index)->rGetLocation()[0] - 0.5*mWidth > 0);
234  if (!node_is_right_of_centre)
235  {
236  // ...then choose the equivalent node to the right
237  this_node_index += num_nodes;
238  }
239  }
240 
241  // If the element straddles the top/bottom periodic boundary...
242  if (element_straddles_top_bottom_boundary)
243  {
244  // ...and this node is located below the centre of the mesh...
245  bool node_is_above_centre = (elem_iter->GetNode(local_index)->rGetLocation()[1] - 0.5*mHeight > 0);
246  if (!node_is_above_centre)
247  {
248  // ...then choose the equivalent node above
249  this_node_index += 2*num_nodes;
250  }
251  }
252 
253  elem_nodes.push_back(temp_nodes[this_node_index]);
254  }
255 
256  VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_index, elem_nodes);
257  elements.push_back(p_element);
258  }
259 
260  // Now delete any nodes from the mesh for VTK that are not contained in any elements
261  std::vector<Node<2>*> nodes;
262  unsigned count = 0;
263  for (unsigned index=0; index<temp_nodes.size(); index++)
264  {
265  unsigned num_elems_containing_this_node = temp_nodes[index]->rGetContainingElementIndices().size();
266 
267  if (num_elems_containing_this_node == 0)
268  {
269  // Avoid memory leak
270  delete temp_nodes[index];
271  }
272  else
273  {
274  temp_nodes[index]->SetIndex(count);
275  nodes.push_back(temp_nodes[index]);
276  count++;
277  }
278  }
279 
280  if (mpMeshForVtk != nullptr)
281  {
282  delete mpMeshForVtk;
283  }
284 
285  mpMeshForVtk = new VertexMesh<2,2>(nodes, elements);
286  return mpMeshForVtk;
287 }
288 
289 void Toroidal2dVertexMesh::ConstructFromMeshReader(AbstractMeshReader<2,2>& rMeshReader, double width, double height)
290 {
291  assert(rMeshReader.HasNodePermutation() == false);
292 
293  // Store numbers of nodes and elements
294  unsigned num_nodes = rMeshReader.GetNumNodes();
295  unsigned num_elements = rMeshReader.GetNumElements();
296 
297  // Reserve memory for nodes
298  this->mNodes.reserve(num_nodes);
299 
300  rMeshReader.Reset();
301 
302  // Add nodes
303  std::vector<double> node_data;
304  for (unsigned node_idx = 0 ; node_idx < num_nodes ; node_idx++)
305  {
306  node_data = rMeshReader.GetNextNode();
307  node_data.pop_back();
308  this->mNodes.push_back(new Node<2>(node_idx, node_data, false));
309  }
310 
311  rMeshReader.Reset();
312 
313  // Reserve memory for elements
314  mElements.reserve(rMeshReader.GetNumElements());
315 
316  // Add elements
317  for (unsigned elem_idx = 0 ; elem_idx < num_elements ; elem_idx++)
318  {
319  // Get the data for this element
320  ElementData element_data = rMeshReader.GetNextElementData();
321 
322  // Get the nodes owned by this element
323  std::vector<Node<2>*> nodes;
324  unsigned num_nodes_in_element = element_data.NodeIndices.size();
325  for (unsigned j=0; j<num_nodes_in_element; j++)
326  {
327  assert(element_data.NodeIndices[j] < this->mNodes.size());
328  nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
329  }
330 
331  // Use nodes and index to construct this element
332  VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_idx, nodes);
333  mElements.push_back(p_element);
334 
335  if (rMeshReader.GetNumElementAttributes() > 0)
336  {
337  assert(rMeshReader.GetNumElementAttributes() == 1);
338  unsigned attribute_value = (unsigned) element_data.AttributeValue;
339  p_element->SetAttribute(attribute_value);
340  }
341  }
342 
343  /*
344  * Set width and height from function arguments, and validate by checking area is correct
345  */
346  this->mWidth = width;
347  this->mHeight = height;
348 
349  double total_surface_area = 0.0;
350  for (unsigned elem_idx = 0 ; elem_idx < num_elements ; elem_idx++)
351  {
352  total_surface_area += this->GetVolumeOfElement(elem_idx);
353  }
354 
355  if (fabs(mWidth * mHeight - total_surface_area) > 1e-6)
356  {
357  EXCEPTION("Mesh width and height do not match sheet surface area.");
358  }
359 
360  // Set default parameter values
361  this->mCellRearrangementRatio = 1.5;
362  this->mCellRearrangementThreshold = 0.01;
363  this->mT2Threshold = 0.001;
364  this->mMeshChangesDuringSimulation = true;
365  this->mpMeshForVtk = nullptr;
366 }
367 
368 // Serialization for Boost >= 1.36
void SetAttribute(double attribute)
unsigned AddNode(Node< 2 > *pNewNode)
double GetWidth(const unsigned &rDimension) const
virtual ElementData GetNextElementData()=0
Definition: Node.hpp:58
c_vector< double, DIM > & rGetLocation()
Definition: ChastePoint.cpp:76
void SetIndex(unsigned index)
Node< SPACE_DIM > * GetNode(unsigned index) const
#define EXCEPTION(message)
Definition: Exception.hpp:143
c_vector< double, 2 > GetVectorFromAtoB(const c_vector< double, 2 > &rLocation1, const c_vector< double, 2 > &rLocation2)
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
void ConstructFromMeshReader(AbstractMeshReader< 2, 2 > &rMeshReader, double width, double height)
std::vector< unsigned > NodeIndices
virtual bool HasNodePermutation()
VertexMesh< 2, 2 > * mpMeshForVtk
bool mMeshChangesDuringSimulation
std::vector< Node< SPACE_DIM > * > mNodes
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Definition: VertexMesh.hpp:679
virtual unsigned GetNumElements() const =0
void SetCoordinate(unsigned i, double value)
virtual void SetNode(unsigned nodeIndex, ChastePoint< SPACE_DIM > point)
void SetHeight(double height)
unsigned GetNumNodes() const
virtual void Reset()=0
virtual double GetVolumeOfElement(unsigned index)
virtual unsigned GetNumElementAttributes() const
std::vector< VertexElement< ELEMENT_DIM, SPACE_DIM > * > mElements
Definition: VertexMesh.hpp:80
void SetNode(unsigned nodeIndex, ChastePoint< 2 > point)
void SetWidth(double width)
ChastePoint< SPACE_DIM > GetPoint() const
Definition: Node.cpp:133
#define CHASTE_CLASS_EXPORT(T)
VertexMesh< 2, 2 > * GetMeshForVtk()
virtual std::vector< double > GetNextNode()=0
unsigned GetIndex() const
Definition: Node.cpp:158
VertexElementIterator GetElementIteratorEnd()
Definition: VertexMesh.hpp:686
virtual unsigned GetNumNodes() const =0