Chaste  Release::3.4
AbstractMesh.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 "AbstractMesh.hpp"
37 #include "Exception.hpp"
38 
40 // Implementation
42 
43 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
45  : mpDistributedVectorFactory(NULL),
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  }
59  if (mpDistributedVectorFactory)
60  {
61  delete mpDistributedVectorFactory;
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 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
119 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::ReadNodesPerProcessorFile(const std::string& rNodesPerProcessorFile)
120 {
122 }
123 
124 
125 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
127 {
128  //Does nothing, since an AbstractMesh has no elements
129 }
130 
131 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
133 {
134  if (mpDistributedVectorFactory == NULL)
135  {
136  mpDistributedVectorFactory = new DistributedVectorFactory(GetNumNodes());
138  {
139  SetElementOwnerships(); // So any parallel implementation with shared mesh has owners set
140  }
141  }
142  return mpDistributedVectorFactory;
143 }
144 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
146 {
147  if (mpDistributedVectorFactory)
148  {
149  EXCEPTION("Cannot change the mesh's distributed vector factory once it has been set.");
150  }
151  if (pFactory->GetNumProcs() != PetscTools::GetNumProcs())
152  {
153  EXCEPTION("The distributed vector factory provided to the mesh is for the wrong number of processes.");
154  }
155  mpDistributedVectorFactory = pFactory;
156 }
157 
158 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
160 {
162 }
163 
164 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
166 {
167  return mBoundaryNodes.begin();
168 }
169 
170 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
172 {
173  return mBoundaryNodes.end();
174 }
175 
176 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
178 {
179  if (!IsMeshOnDisk())
180  {
181  EXCEPTION("This mesh was not constructed from a file.");
182  }
183 
184  return mMeshFileBaseName;
185 }
186 
187 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
189 {
190  return (mMeshFileBaseName != "");
191 }
192 
193 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
195 {
196  return mNodePermutation;
197 }
198 
199 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
201  const c_vector<double, SPACE_DIM>& rLocationA, const c_vector<double, SPACE_DIM>& rLocationB)
202 {
203  c_vector<double, SPACE_DIM> vector = rLocationB - rLocationA;
204  return vector;
205 }
206 
207 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
209 {
210  c_vector<double, SPACE_DIM> vector = GetVectorFromAtoB(mNodes[indexA]->rGetLocation(),
211  mNodes[indexB]->rGetLocation());
212  return norm_2(vector);
213 }
214 
215 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
216 double AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetWidth(const unsigned& rDimension) const
217 {
218  assert(rDimension < SPACE_DIM);
219  return CalculateBoundingBox(mNodes).GetWidth(rDimension);
220 }
221 
222 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
224 {
225  // Work out the max and min location in each co-ordinate direction.
226  c_vector<double, SPACE_DIM> minimum_point;
227  c_vector<double, SPACE_DIM> maximum_point;
228 
229  // Deal with the special case of no nodes by returning a cuboid with zero volume.
230  if (rNodes.empty())
231  {
232  minimum_point = scalar_vector<double>(SPACE_DIM, 0.0);
233  maximum_point = scalar_vector<double>(SPACE_DIM, 0.0);
234  }
235  else
236  {
237  minimum_point = scalar_vector<double>(SPACE_DIM, DBL_MAX);
238  maximum_point = scalar_vector<double>(SPACE_DIM, -DBL_MAX);
239 
240  // Iterate through nodes
242  for (unsigned index=0; index<rNodes.size(); index++)
243  {
244  if (!rNodes[index]->IsDeleted())
245  {
246  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
247  c_vector<double, SPACE_DIM> position;
248  position = rNodes[index]->rGetLocation();
249 
250  // Update max/min
251  for (unsigned i=0; i<SPACE_DIM; i++)
252  {
253  if (position[i] < minimum_point[i])
254  {
255  minimum_point[i] = position[i];
256  }
257  if (position[i] > maximum_point[i])
258  {
259  maximum_point[i] = position[i];
260  }
261  }
262  }
263  }
264  }
265 
266  ChastePoint<SPACE_DIM> min(minimum_point);
267  ChastePoint<SPACE_DIM> max(maximum_point);
268 
269  return ChasteCuboid<SPACE_DIM>(min, max);
270 }
271 
272 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
274 {
275  ChasteCuboid<SPACE_DIM> bounding_cuboid = CalculateBoundingBox(mNodes);
276 
277  return bounding_cuboid;
278 }
279 
280 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
282 {
283  if (mNodes.empty())
284  {
285  // This happens in parallel if a process isn't assigned any nodes.
286  return UINT_MAX;
287  }
288  // Hold the best distance from node to point found so far
289  // and the (local) node at which this was recorded
290  unsigned best_node_index = 0u;
291  double best_node_point_distance = DBL_MAX;
292 
293  c_vector<double, SPACE_DIM> test_location = rTestPoint.rGetLocation();
294  // Now loop through the nodes, calculating the distance and updating best_node_point_distance
295  for (unsigned node_index = 0; node_index < mNodes.size(); node_index++)
296  {
297  // Calculate the distance from the chosen point to the current node
298  double node_point_distance = norm_2( GetVectorFromAtoB(mNodes[node_index]->rGetLocation(), test_location) );
299  // Update the "best" distance and node index if necessary
300  if (node_point_distance < best_node_point_distance)
301  {
302  best_node_index = node_index;
303  best_node_point_distance = node_point_distance;
304  }
305  }
306 
307  // Return the global index of the closest node to the point
308  // (which differs from the local index "best_node_index" in parallel)
309  // In the distributed case, we'll have to do an AllReduce next
310  return mNodes[best_node_index]->GetIndex();
311 }
312 
313 
314 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
315 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Scale(const double xScale, const double yScale, const double zScale)
316 {
317  unsigned num_nodes = mNodes.size();
318 
319  for (unsigned i=0; i<num_nodes; i++)
320  {
321  c_vector<double, SPACE_DIM>& r_location = mNodes[i]->rGetModifiableLocation();
322  if (SPACE_DIM>=3)
323  {
324  r_location[2] *= zScale;
325  }
326  if (SPACE_DIM>=2)
327  {
328  r_location[1] *= yScale;
329  }
330  r_location[0] *= xScale;
331  }
332 
333  RefreshMesh();
334 }
335 
336 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
338  const double xMovement,
339  const double yMovement,
340  const double zMovement)
341 {
342  c_vector<double, SPACE_DIM> displacement;
343 
344  switch (SPACE_DIM)
345  {
346  case 3:
347  displacement[2] = zMovement;
348  case 2:
349  displacement[1] = yMovement;
350  case 1:
351  displacement[0] = xMovement;
352  }
353 
354  Translate(displacement);
355 }
356 
357 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
358 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Translate(const c_vector<double, SPACE_DIM>& rDisplacement)
359 {
360  unsigned num_nodes = this->mNodes.size();
361 
362  for (unsigned i=0; i<num_nodes; i++)
363  {
364  c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
365  r_location += rDisplacement;
366  }
367 
368  RefreshMesh();
369 }
370 
371 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
372 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_matrix<double , SPACE_DIM, SPACE_DIM> rotationMatrix)
373 {
374  unsigned num_nodes = this->mNodes.size();
375 
376  for (unsigned i=0; i<num_nodes; i++)
377  {
378  c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
379  r_location = prod(rotationMatrix, r_location);
380  }
381 
382  RefreshMesh();
383 }
384 
385 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
386 void AbstractMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_vector<double,3> axis, double angle)
387 {
388  assert(SPACE_DIM == 3);
389  double norm = norm_2(axis);
390  c_vector<double,3> unit_axis=axis/norm;
391 
392  c_matrix<double, SPACE_DIM,SPACE_DIM> rotation_matrix;
393 
394  double c = cos(angle);
395  double s = sin(angle);
396 
397  rotation_matrix(0,0) = unit_axis(0)*unit_axis(0)+c*(1-unit_axis(0)*unit_axis(0));
398  rotation_matrix(0,1) = unit_axis(0)*unit_axis(1)*(1-c) - unit_axis(2)*s;
399  rotation_matrix(1,0) = unit_axis(0)*unit_axis(1)*(1-c) + unit_axis(2)*s;
400  rotation_matrix(1,1) = unit_axis(1)*unit_axis(1)+c*(1-unit_axis(1)*unit_axis(1));
401  rotation_matrix(0,2) = unit_axis(0)*unit_axis(2)*(1-c)+unit_axis(1)*s;
402  rotation_matrix(1,2) = unit_axis(1)*unit_axis(2)*(1-c)-unit_axis(0)*s;
403  rotation_matrix(2,0) = unit_axis(0)*unit_axis(2)*(1-c)-unit_axis(1)*s;
404  rotation_matrix(2,1) = unit_axis(1)*unit_axis(2)*(1-c)+unit_axis(0)*s;
405  rotation_matrix(2,2) = unit_axis(2)*unit_axis(2)+c*(1-unit_axis(2)*unit_axis(2));
406 
407  Rotate(rotation_matrix);
408 }
409 
410 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
412 {
413  if (SPACE_DIM != 3)
414  {
415  EXCEPTION("This rotation is only valid in 3D");
416  }
417  c_matrix<double , SPACE_DIM, SPACE_DIM> x_rotation_matrix=identity_matrix<double>(SPACE_DIM);
418 
419  x_rotation_matrix(1,1) = cos(theta);
420  x_rotation_matrix(1,2) = sin(theta);
421  x_rotation_matrix(2,1) = -sin(theta);
422  x_rotation_matrix(2,2) = cos(theta);
423  Rotate(x_rotation_matrix);
424 }
425 
426 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
428 {
429  if (SPACE_DIM != 3)
430  {
431  EXCEPTION("This rotation is only valid in 3D");
432  }
433  c_matrix<double , SPACE_DIM, SPACE_DIM> y_rotation_matrix=identity_matrix<double>(SPACE_DIM);
434 
435  y_rotation_matrix(0,0) = cos(theta);
436  y_rotation_matrix(0,2) = -sin(theta);
437  y_rotation_matrix(2,0) = sin(theta);
438  y_rotation_matrix(2,2) = cos(theta);
439 
440 
441  Rotate(y_rotation_matrix);
442 }
443 
444 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
446 {
447  if (SPACE_DIM < 2)
448  {
449  EXCEPTION("This rotation is not valid in less than 2D");
450  }
451  c_matrix<double , SPACE_DIM, SPACE_DIM> z_rotation_matrix=identity_matrix<double>(SPACE_DIM);
452 
453 
454  z_rotation_matrix(0,0) = cos(theta);
455  z_rotation_matrix(0,1) = sin(theta);
456  z_rotation_matrix(1,0) = -sin(theta);
457  z_rotation_matrix(1,1) = cos(theta);
458 
459  Rotate(z_rotation_matrix);
460 }
461 
462 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
464 {
465  RotateZ(theta);
466 }
467 
468 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
470 {
471 }
472 
473 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
475 {
476  return mMeshChangesDuringSimulation;
477 }
478 
479 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
481 {
482  unsigned max_num=0u;
483  for (unsigned local_node_index=0; local_node_index<mNodes.size(); local_node_index++)
484  {
485  unsigned num=mNodes[local_node_index]->GetNumContainingElements();
486  if (num>max_num)
487  {
488  max_num=num;
489  }
490  }
491  return max_num;
492 }
493 
494 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
496 {
497  // We just forget what the original file was, which has the desired effect
498  mMeshFileBaseName = "";
499 }
500 
502 // Explicit instantiation
504 
505 template class AbstractMesh<1,1>;
506 template class AbstractMesh<1,2>;
507 template class AbstractMesh<1,3>;
508 template class AbstractMesh<2,2>;
509 template class AbstractMesh<2,3>;
510 template class AbstractMesh<3,3>;
virtual DistributedVectorFactory * GetDistributedVectorFactory()
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
const std::vector< unsigned > & rGetNodePermutation() const
bool IsMeshChanging() const
virtual void Translate(const c_vector< double, SPACE_DIM > &rDisplacement)
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()
double GetDistanceBetweenNodes(unsigned indexA, unsigned indexB)
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)