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