Chaste  Release::2017.1
AbstractMesh.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 "AbstractMesh.hpp"
37 #include "Exception.hpp"
38 
40 // Implementation
42 
43 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
45  : mpDistributedVectorFactory(nullptr),
46  mMeshFileBaseName(""),
47  mMeshChangesDuringSimulation(false)
48 {
49 }
50 
51 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
53 {
54  // Iterate over nodes and free the memory
55  for (unsigned i=0; i<mNodes.size(); i++)
56  {
57  delete mNodes[i];
58  }
60  {
62  }
63 }
64 
65 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
67 {
68  return mNodes.size();
69 }
70 
71 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
73 {
74  return mBoundaryNodes.size();
75 }
76 
77 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
79 {
80  return mNodes.size();
81 }
82 
83 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
85 {
86  /* Note, this implementation assumes that all nodes have the same number of attributes
87  * so that the first node in the container is indicative of the others.*/
88  assert(mNodes.size() != 0u);
89  return mNodes[0]->GetNumNodeAttributes();
90 }
91 
92 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
94 {
95  unsigned local_index = SolveNodeMapping(index);
96  return mNodes[local_index];
97 }
98 
99 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
101 {
102  return GetNode(index);
103 }
104 
105 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
107 {
108  if (mNodePermutation.empty())
109  {
110  return GetNode(index);
111  }
112  else
113  {
114  return GetNode(mNodePermutation[index]);
115  }
116 }
117 
118 // LCOV_EXCL_START
119 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
120 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::ReadNodesPerProcessorFile(const std::string& rNodesPerProcessorFile)
121 {
123 }
124 // LCOV_EXCL_STOP
125 
126 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
128 {
129  // Does nothing, since an AbstractMesh has no elements
130 }
131 
132 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
134 {
135  if (mpDistributedVectorFactory == nullptr)
136  {
139  {
140  SetElementOwnerships(); // So any parallel implementation with shared mesh has owners set
141  }
142  }
144 }
145 
146 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
148 {
150  {
151  EXCEPTION("Cannot change the mesh's distributed vector factory once it has been set.");
152  }
153  if (pFactory->GetNumProcs() != PetscTools::GetNumProcs())
154  {
155  EXCEPTION("The distributed vector factory provided to the mesh is for the wrong number of processes.");
156  }
157  mpDistributedVectorFactory = pFactory;
158 }
159 
160 // LCOV_EXCL_START
161 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
163 {
165 }
166 // LCOV_EXCL_STOP
167 
168 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
170 {
171  return mBoundaryNodes.begin();
172 }
173 
174 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
176 {
177  return mBoundaryNodes.end();
178 }
179 
180 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
182 {
183  if (!IsMeshOnDisk())
184  {
185  EXCEPTION("This mesh was not constructed from a file.");
186  }
187 
188  return mMeshFileBaseName;
189 }
190 
191 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
193 {
194  return (mMeshFileBaseName != "");
195 }
196 
197 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
199 {
200  return mNodePermutation;
201 }
202 
203 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
205  const c_vector<double, SPACE_DIM>& rLocationA, const c_vector<double, SPACE_DIM>& rLocationB)
206 {
207  c_vector<double, SPACE_DIM> vector = rLocationB - rLocationA;
208  return vector;
209 }
210 
211 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
213 {
214  c_vector<double, SPACE_DIM> vector = GetVectorFromAtoB(mNodes[indexA]->rGetLocation(),
215  mNodes[indexB]->rGetLocation());
216  return norm_2(vector);
217 }
218 
219 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
220 double AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetWidth(const unsigned& rDimension) const
221 {
222  assert(rDimension < SPACE_DIM);
223  return CalculateBoundingBox(mNodes).GetWidth(rDimension);
224 }
225 
226 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
228 {
229  // Work out the max and min location in each co-ordinate direction.
230  c_vector<double, SPACE_DIM> minimum_point;
231  c_vector<double, SPACE_DIM> maximum_point;
232 
233  // Deal with the special case of no nodes by returning a cuboid with zero volume.
234  if (rNodes.empty())
235  {
236  minimum_point = scalar_vector<double>(SPACE_DIM, 0.0);
237  maximum_point = scalar_vector<double>(SPACE_DIM, 0.0);
238  }
239  else
240  {
241  minimum_point = scalar_vector<double>(SPACE_DIM, DBL_MAX);
242  maximum_point = scalar_vector<double>(SPACE_DIM, -DBL_MAX);
243 
244  // Iterate through nodes
246  for (unsigned index=0; index<rNodes.size(); index++)
247  {
248  if (!rNodes[index]->IsDeleted())
249  {
250  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
251  c_vector<double, SPACE_DIM> position;
252  position = rNodes[index]->rGetLocation();
253 
254  // Update max/min
255  for (unsigned i=0; i<SPACE_DIM; i++)
256  {
257  if (position[i] < minimum_point[i])
258  {
259  minimum_point[i] = position[i];
260  }
261  if (position[i] > maximum_point[i])
262  {
263  maximum_point[i] = position[i];
264  }
265  }
266  }
267  }
268  }
269 
270  ChastePoint<SPACE_DIM> min(minimum_point);
271  ChastePoint<SPACE_DIM> max(maximum_point);
272 
273  return ChasteCuboid<SPACE_DIM>(min, max);
274 }
275 
276 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
278 {
280 
281  return bounding_cuboid;
282 }
283 
284 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
286 {
287  if (mNodes.empty())
288  {
289  /*
290  * This happens in parallel if a process isn't assigned any nodes.
291  * This case is covered in TestDistributedTetrahedralMesh::TestConstructLinearMeshSmallest
292  * but only when there are 3 or more processes
293  */
294  return UINT_MAX; // LCOV_EXCL_LINE
295  }
296  // Hold the best distance from node to point found so far
297  // and the (local) node at which this was recorded
298  unsigned best_node_index = 0u;
299  double best_node_point_distance = DBL_MAX;
300 
301  const c_vector<double, SPACE_DIM>& test_location = rTestPoint.rGetLocation();
302  // Now loop through the nodes, calculating the distance and updating best_node_point_distance
303  for (unsigned node_index = 0; node_index < mNodes.size(); node_index++)
304  {
305  // Calculate the distance from the chosen point to the current node
306  double node_point_distance = norm_2( GetVectorFromAtoB(mNodes[node_index]->rGetLocation(), test_location) );
307  // Update the "best" distance and node index if necessary
308  if (node_point_distance < best_node_point_distance)
309  {
310  best_node_index = node_index;
311  best_node_point_distance = node_point_distance;
312  }
313  }
314 
315  // Return the global index of the closest node to the point
316  // (which differs from the local index "best_node_index" in parallel)
317  // In the distributed case, we'll have to do an AllReduce next
318  return mNodes[best_node_index]->GetIndex();
319 }
320 
321 
322 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
323 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Scale(const double xScale, const double yScale, const double zScale)
324 {
325  unsigned num_nodes = mNodes.size();
326 
327  for (unsigned i=0; i<num_nodes; i++)
328  {
329  c_vector<double, SPACE_DIM>& r_location = mNodes[i]->rGetModifiableLocation();
330  if (SPACE_DIM>=3)
331  {
332  r_location[2] *= zScale;
333  }
334  if (SPACE_DIM>=2)
335  {
336  r_location[1] *= yScale;
337  }
338  r_location[0] *= xScale;
339  }
340 
341  RefreshMesh();
342 }
343 
344 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
346  const double xMovement,
347  const double yMovement,
348  const double zMovement)
349 {
350  c_vector<double, SPACE_DIM> displacement;
351 
352  switch (SPACE_DIM)
353  {
354  case 3:
355  displacement[2] = zMovement;
356  case 2:
357  displacement[1] = yMovement;
358  case 1:
359  displacement[0] = xMovement;
360  }
361 
362  Translate(displacement);
363 }
364 
365 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
366 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Translate(const c_vector<double, SPACE_DIM>& rDisplacement)
367 {
368  unsigned num_nodes = this->mNodes.size();
369 
370  for (unsigned i=0; i<num_nodes; i++)
371  {
372  c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
373  r_location += rDisplacement;
374  }
375 
376  RefreshMesh();
377 }
378 
379 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
380 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_matrix<double , SPACE_DIM, SPACE_DIM> rotationMatrix)
381 {
382  unsigned num_nodes = this->mNodes.size();
383 
384  for (unsigned i=0; i<num_nodes; i++)
385  {
386  c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
387  r_location = prod(rotationMatrix, r_location);
388  }
389 
390  RefreshMesh();
391 }
392 
393 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
394 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_vector<double,3> axis, double angle)
395 {
396  assert(SPACE_DIM == 3); // LCOV_EXCL_LINE
397  double norm = norm_2(axis);
398  c_vector<double,3> unit_axis=axis/norm;
399 
400  c_matrix<double, SPACE_DIM,SPACE_DIM> rotation_matrix;
401 
402  double c = cos(angle);
403  double s = sin(angle);
404 
405  rotation_matrix(0,0) = unit_axis(0)*unit_axis(0)+c*(1-unit_axis(0)*unit_axis(0));
406  rotation_matrix(0,1) = unit_axis(0)*unit_axis(1)*(1-c) - unit_axis(2)*s;
407  rotation_matrix(1,0) = unit_axis(0)*unit_axis(1)*(1-c) + unit_axis(2)*s;
408  rotation_matrix(1,1) = unit_axis(1)*unit_axis(1)+c*(1-unit_axis(1)*unit_axis(1));
409  rotation_matrix(0,2) = unit_axis(0)*unit_axis(2)*(1-c)+unit_axis(1)*s;
410  rotation_matrix(1,2) = unit_axis(1)*unit_axis(2)*(1-c)-unit_axis(0)*s;
411  rotation_matrix(2,0) = unit_axis(0)*unit_axis(2)*(1-c)-unit_axis(1)*s;
412  rotation_matrix(2,1) = unit_axis(1)*unit_axis(2)*(1-c)+unit_axis(0)*s;
413  rotation_matrix(2,2) = unit_axis(2)*unit_axis(2)+c*(1-unit_axis(2)*unit_axis(2));
414 
415  Rotate(rotation_matrix);
416 }
417 
418 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
420 {
421  if (SPACE_DIM != 3)
422  {
423  EXCEPTION("This rotation is only valid in 3D");
424  }
425  c_matrix<double , SPACE_DIM, SPACE_DIM> x_rotation_matrix=identity_matrix<double>(SPACE_DIM);
426 
427  x_rotation_matrix(1,1) = cos(theta);
428  x_rotation_matrix(1,2) = sin(theta);
429  x_rotation_matrix(2,1) = -sin(theta);
430  x_rotation_matrix(2,2) = cos(theta);
431  Rotate(x_rotation_matrix);
432 }
433 
434 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
436 {
437  if (SPACE_DIM != 3)
438  {
439  EXCEPTION("This rotation is only valid in 3D");
440  }
441  c_matrix<double , SPACE_DIM, SPACE_DIM> y_rotation_matrix=identity_matrix<double>(SPACE_DIM);
442 
443  y_rotation_matrix(0,0) = cos(theta);
444  y_rotation_matrix(0,2) = -sin(theta);
445  y_rotation_matrix(2,0) = sin(theta);
446  y_rotation_matrix(2,2) = cos(theta);
447 
448 
449  Rotate(y_rotation_matrix);
450 }
451 
452 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
454 {
455  if (SPACE_DIM < 2)
456  {
457  EXCEPTION("This rotation is not valid in less than 2D");
458  }
459  c_matrix<double , SPACE_DIM, SPACE_DIM> z_rotation_matrix=identity_matrix<double>(SPACE_DIM);
460 
461 
462  z_rotation_matrix(0,0) = cos(theta);
463  z_rotation_matrix(0,1) = sin(theta);
464  z_rotation_matrix(1,0) = -sin(theta);
465  z_rotation_matrix(1,1) = cos(theta);
466 
467  Rotate(z_rotation_matrix);
468 }
469 
470 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
472 {
473  RotateZ(theta);
474 }
475 
476 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
478 {
479 }
480 
481 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
483 {
485 }
486 
487 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
489 {
490  unsigned max_num=0u;
491  for (unsigned local_node_index=0; local_node_index<mNodes.size(); local_node_index++)
492  {
493  unsigned num=mNodes[local_node_index]->GetNumContainingElements();
494  if (num>max_num)
495  {
496  max_num=num;
497  }
498  }
499  return max_num;
500 }
501 
502 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
504 {
505  // We just forget what the original file was, which has the desired effect
506  mMeshFileBaseName = "";
507 }
508 
509 // Explicit instantiation
510 template class AbstractMesh<1,1>;
511 template class AbstractMesh<1,2>;
512 template class AbstractMesh<1,3>;
513 template class AbstractMesh<2,2>;
514 template class AbstractMesh<2,3>;
515 template class AbstractMesh<3,3>;
virtual DistributedVectorFactory * GetDistributedVectorFactory()
std::vector< Node< SPACE_DIM > * > mBoundaryNodes
virtual void ReadNodesPerProcessorFile(const std::string &rNodesPerProcessorFile)
virtual unsigned GetNearestNodeIndex(const ChastePoint< SPACE_DIM > &rTestPoint)
Definition: Node.hpp:58
c_vector< double, DIM > & rGetLocation()
Definition: ChastePoint.cpp:76
virtual void RefreshMesh()
virtual Node< SPACE_DIM > * GetNodeOrHaloNode(unsigned index) const
virtual unsigned SolveNodeMapping(unsigned index) const =0
const std::vector< unsigned > & rGetNodePermutation() const
bool IsMeshChanging() const
virtual void Translate(const c_vector< double, SPACE_DIM > &rDisplacement)
std::vector< unsigned > mNodePermutation
Node< SPACE_DIM > * GetNode(unsigned index) const
#define EXCEPTION(message)
Definition: Exception.hpp:143
unsigned CalculateMaximumContainingElementsPerProcess() const
std::string GetMeshFileBaseName() const
virtual ChasteCuboid< SPACE_DIM > CalculateBoundingBox() const
virtual unsigned GetNumNodes() const
virtual void PermuteNodes()
BoundaryNodeIterator GetBoundaryNodeIteratorBegin() const
virtual unsigned GetNumAllNodes() const
#define NEVER_REACHED
Definition: Exception.hpp:206
virtual void SetElementOwnerships()
std::string mMeshFileBaseName
double GetDistanceBetweenNodes(unsigned indexA, unsigned indexB)
bool mMeshChangesDuringSimulation
std::vector< Node< SPACE_DIM > * > mNodes
DistributedVectorFactory * mpDistributedVectorFactory
unsigned GetNumBoundaryNodes() const
unsigned GetNumNodeAttributes() const
std::vector< Node< SPACE_DIM > * >::const_iterator BoundaryNodeIterator
bool IsMeshOnDisk() const
virtual ~AbstractMesh()
void SetMeshHasChangedSinceLoading()
static bool IsParallel()
Definition: PetscTools.cpp:97
virtual double GetWidth(const unsigned &rDimension) const
virtual void Rotate(c_matrix< double, SPACE_DIM, SPACE_DIM > rotationMatrix)
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
BoundaryNodeIterator GetBoundaryNodeIteratorEnd() const
virtual void Scale(const double xFactor=1.0, const double yFactor=1.0, const double zFactor=1.0)
virtual void SetDistributedVectorFactory(DistributedVectorFactory *pFactory)
static unsigned GetNumProcs()
Definition: PetscTools.cpp:108
void RotateY(const double theta)
void RotateZ(const double theta)
Node< SPACE_DIM > * GetNodeFromPrePermutationIndex(unsigned index) const
void RotateX(const double theta)