Chaste  Release::3.4
Toroidal2dVertexMesh.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 "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 = GetNode(index)->rGetLocation();
157 
158  // Node copy at original location
159  Node<2>* p_node = new Node<2>(index, false, location[0], location[1]);
160  temp_nodes[index] = p_node;
161 
162  // Node copy shifted right
163  p_node = new Node<2>(num_nodes + index, false, location[0] + mWidth, location[1]);
164  temp_nodes[num_nodes + index] = p_node;
165 
166  // Node copy shifted up
167  p_node = new Node<2>(2*num_nodes + index, false, location[0], location[1] + mHeight);
168  temp_nodes[2*num_nodes + index] = p_node;
169 
170  // Node copy shifted right and up
171  p_node = new Node<2>(3*num_nodes + index, false, location[0] + mWidth, location[1] + mHeight);
172  temp_nodes[3*num_nodes + index] = p_node;
173  }
174 
175  // Iterate over elements
177  elem_iter != GetElementIteratorEnd();
178  ++elem_iter)
179  {
180  unsigned elem_index = elem_iter->GetIndex();
181  unsigned num_nodes_in_elem = elem_iter->GetNumNodes();
182 
183  std::vector<Node<2>*> elem_nodes;
184 
185  // Compute whether the element straddles either periodic boundary
186  bool element_straddles_left_right_boundary = false;
187  bool element_straddles_top_bottom_boundary = false;
188 
189  c_vector<double, 2> this_node_location = elem_iter->GetNode(0)->rGetLocation();
190  for (unsigned local_index=0; local_index<num_nodes_in_elem; local_index++)
191  {
192  c_vector<double, 2> next_node_location = elem_iter->GetNode((local_index+1)%num_nodes_in_elem)->rGetLocation();
193  c_vector<double, 2> vector = next_node_location - this_node_location;
194 
195  if (fabs(vector[0]) > 0.5*mWidth)
196  {
197  element_straddles_left_right_boundary = true;
198  }
199  if (fabs(vector[1]) > 0.5*mHeight)
200  {
201  element_straddles_top_bottom_boundary = true;
202  }
203  }
204 
205  // Use the above information when duplicating the element
206  for (unsigned local_index=0; local_index<num_nodes_in_elem; local_index++)
207  {
208  unsigned this_node_index = elem_iter->GetNodeGlobalIndex(local_index);
209 
210  // If the element straddles the left/right periodic boundary...
211  if (element_straddles_left_right_boundary)
212  {
213  // ...and this node is located to the left of the centre of the mesh...
214  bool node_is_right_of_centre = (elem_iter->GetNode(local_index)->rGetLocation()[0] - 0.5*mWidth > 0);
215  if (!node_is_right_of_centre)
216  {
217  // ...then choose the equivalent node to the right
218  this_node_index += num_nodes;
219  }
220  }
221 
222  // If the element straddles the top/bottom periodic boundary...
223  if (element_straddles_top_bottom_boundary)
224  {
225  // ...and this node is located below the centre of the mesh...
226  bool node_is_above_centre = (elem_iter->GetNode(local_index)->rGetLocation()[1] - 0.5*mHeight > 0);
227  if (!node_is_above_centre)
228  {
229  // ...then choose the equivalent node above
230  this_node_index += 2*num_nodes;
231  }
232  }
233 
234  elem_nodes.push_back(temp_nodes[this_node_index]);
235  }
236 
237  VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_index, elem_nodes);
238  elements.push_back(p_element);
239  }
240 
241  // Now delete any nodes from the mesh for VTK that are not contained in any elements
242  std::vector<Node<2>*> nodes;
243  unsigned count = 0;
244  for (unsigned index=0; index<temp_nodes.size(); index++)
245  {
246  unsigned num_elems_containing_this_node = temp_nodes[index]->rGetContainingElementIndices().size();
247 
248  if (num_elems_containing_this_node == 0)
249  {
250  // Avoid memory leak
251  delete temp_nodes[index];
252  }
253  else
254  {
255  temp_nodes[index]->SetIndex(count);
256  nodes.push_back(temp_nodes[index]);
257  count++;
258  }
259  }
260 
262  return p_mesh;
263 }
264 
265 void Toroidal2dVertexMesh::ConstructFromMeshReader(AbstractMeshReader<2,2>& rMeshReader, double width, double height)
266 {
267  assert(rMeshReader.HasNodePermutation() == false);
268 
269  // Store numbers of nodes and elements
270  unsigned num_nodes = rMeshReader.GetNumNodes();
271  unsigned num_elements = rMeshReader.GetNumElements();
272 
273  // Reserve memory for nodes
274  this->mNodes.reserve(num_nodes);
275 
276  rMeshReader.Reset();
277 
278  // Add nodes
279  std::vector<double> node_data;
280  for (unsigned node_idx = 0 ; node_idx < num_nodes ; node_idx++)
281  {
282  node_data = rMeshReader.GetNextNode();
283  node_data.pop_back();
284  this->mNodes.push_back(new Node<2>(node_idx, node_data, false));
285  }
286 
287  rMeshReader.Reset();
288 
289  // Reserve memory for elements
290  mElements.reserve(rMeshReader.GetNumElements());
291 
292  // Add elements
293  for (unsigned elem_idx = 0 ; elem_idx < num_elements ; elem_idx++)
294  {
295  // Get the data for this element
296  ElementData element_data = rMeshReader.GetNextElementData();
297 
298  // Get the nodes owned by this element
299  std::vector<Node<2>*> nodes;
300  unsigned num_nodes_in_element = element_data.NodeIndices.size();
301  for (unsigned j=0; j<num_nodes_in_element; j++)
302  {
303  assert(element_data.NodeIndices[j] < this->mNodes.size());
304  nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
305  }
306 
307  // Use nodes and index to construct this element
308  VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_idx, nodes);
309  mElements.push_back(p_element);
310 
311  if (rMeshReader.GetNumElementAttributes() > 0)
312  {
313  assert(rMeshReader.GetNumElementAttributes() == 1);
314  unsigned attribute_value = (unsigned) element_data.AttributeValue;
315  p_element->SetAttribute(attribute_value);
316  }
317  }
318 
319  /*
320  * Set width and height from function arguments, and validate by checking area is correct
321  */
322  this->mWidth = width;
323  this->mHeight = height;
324 
325  double total_surface_area = 0.0;
326  for (unsigned elem_idx = 0 ; elem_idx < num_elements ; elem_idx++)
327  {
328  total_surface_area += this->GetVolumeOfElement(elem_idx);
329  }
330 
331  if (fabs(mWidth * mHeight - total_surface_area) > 1e-6)
332  {
333  EXCEPTION("Mesh width and height do not match sheet surface area.");
334  }
335 
336  // Set default parameter values
337  this->mCellRearrangementRatio = 1.5;
338  this->mCellRearrangementThreshold = 0.01;
339  this->mT2Threshold = 0.001;
340  this->mMeshChangesDuringSimulation = true;
341 }
342 
343 // 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:134
#define CHASTE_CLASS_EXPORT(T)
virtual std::vector< double > GetNextNode()=0
unsigned GetIndex() const
Definition: Node.cpp:159
VertexElementIterator GetElementIteratorEnd()
Definition: VertexMesh.hpp:675
virtual unsigned GetNumNodes() const =0