Chaste  Release::2024.1
PeriodicNodesOnlyMesh.cpp
1 /*
2 
3 Copyright (c) 2005-2021, 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 <map>
37 #include "PeriodicNodesOnlyMesh.hpp"
38 
39 template<unsigned SPACE_DIM>
41  : NodesOnlyMesh<SPACE_DIM>(),
42  mWidth(width)
43 {
44  // Convert periodic widths into a boolean vector
45  mIsDimPeriodic = zero_vector<bool>(SPACE_DIM);
46 
47  for (unsigned i = 0; i < SPACE_DIM; i++)
48  {
49  if (width[i]>0.0)
50  {
51  mIsDimPeriodic[i] = true;
52  }
53  }
54 }
55 
56 template<unsigned SPACE_DIM>
57 void PeriodicNodesOnlyMesh<SPACE_DIM>::SetUpBoxCollection(double cutOffLength, c_vector<double, 2*SPACE_DIM> domainSize, int numLocalRows, c_vector<bool,SPACE_DIM> isDimPeriodic)
58 {
59 
60  // Check that we haven't got too many processors; the maximum number of processors is width/cutOffLength in the y (2D)/z (3D) direction
61  if ( mIsDimPeriodic[SPACE_DIM-1] && ((mWidth[SPACE_DIM-1]+1e-14)/cutOffLength) < PetscTools::GetNumProcs() )
62  {
63  EXCEPTION("Too many processors for the periodic domain width and cut off length. NumProcs should be less than or equal to Y (in 2D) or Z (in 3D) width / Cut off length.\n");
64  }
65  // Container for converting the periodic dims vector to a true/false input into box collection setup
66  // For each periodic dimension:
67 
68  for (unsigned i=0; i < SPACE_DIM; i++)
69  {
70  if (mIsDimPeriodic[i])
71  {
72  // Ensure that the width is a multiple of cut-off length
73  if ( fmod(mWidth[i]+1e-14,cutOffLength ) > 2e-14 )
74  {
75  EXCEPTION("The periodic width must be a multiple of cut off length.");
76  }
77  // A width of two boxes gives different simulation results as some connections are considered twice.
78  else if ( mWidth[i]/cutOffLength <= (2.0+1e-14) )
79  {
80  EXCEPTION( "The periodic domain width cannot be less than 2*CutOffLength." );
81  }
82 
83  // We force the domain to the periodic widths
84  domainSize[ i*2 ] = 0;
85  domainSize[ i*2+1 ] = mWidth[i];
86  }
87  }
88  NodesOnlyMesh<SPACE_DIM>::SetUpBoxCollection(cutOffLength, domainSize, PETSC_DECIDE, mIsDimPeriodic);
89 
90  this->AddNodesToBoxes();
91 }
92 
93 template<unsigned SPACE_DIM>
94 c_vector<double, SPACE_DIM> PeriodicNodesOnlyMesh<SPACE_DIM>::GetPeriodicWidths() const
95 {
96  return mWidth;
97 }
98 
99 template<unsigned SPACE_DIM>
100 double PeriodicNodesOnlyMesh<SPACE_DIM>::GetWidth(const unsigned& rDimension) const
101 {
102  double width = 0.0;
103  assert(rDimension < SPACE_DIM);
104 
105  if ( !mIsDimPeriodic[rDimension] )
106  {
107  // If we are not a periodic dimension, we just return the width
108  width = MutableMesh<SPACE_DIM,SPACE_DIM>::GetWidth(rDimension);
109  }
110  else
111  {
112  width = mWidth[rDimension];
113  }
114  return width;
115 }
116 
117 template<unsigned SPACE_DIM>
118 void PeriodicNodesOnlyMesh<SPACE_DIM>::SetNode(unsigned nodeIndex, ChastePoint<SPACE_DIM> point, bool concreteMove)
119 {
120  // concreteMove should always be false for NodesOnlyMesh as no elements to check
121  assert(!concreteMove);
122 
123  c_vector<double, SPACE_DIM>& point_coord = point.rGetLocation();
124 
125  // Loop over the periodic dimensions and perform a periodic movement if necessary
126  for ( unsigned i = 0; i < SPACE_DIM; i++ )
127  {
128  if ( mIsDimPeriodic[i] )
129  {
130  double local_point_coord = point_coord(i);
131  double local_width = mWidth[i];
132  // We need to make sure that the fudge factor is greater than the one used to calculate the containing
133  // box in distributed box collection. Otherwise the forced domain width causes issues at the right domain edge.
134  double fudge_factor = 1.0e-13;
135  if ( local_point_coord >= local_width )
136  {
137  double new_coord = local_point_coord - local_width;
138 
139  point.SetCoordinate(i,new_coord);
140  }
141  else if ( local_point_coord > (local_width-fudge_factor))
142  {
143  // This is to ensure that the position is never equal to mWidth, which would be outside the box domain.
144  // This is due to the fact that mWidth-1e-16=mWidth
145  point.SetCoordinate(i,local_width-fudge_factor);
146  }
147  else if ( local_point_coord < 0.0 )
148  {
149  double new_coord = local_point_coord + local_width;
150 
151  // This is to ensure that the position is never equal to mWidth, which would be outside the box domain.
152  // This is due to the fact that mWidth-1e-16=mWidth
153  if ( new_coord > local_width-fudge_factor )
154  {
155  new_coord = local_width-fudge_factor;
156  }
157  point.SetCoordinate(i, new_coord);
158  }
159  }
160  }
161 
162  // Update the node's location
163  this->GetNode(nodeIndex)->SetPoint(point);
164 }
165 
166 template<unsigned SPACE_DIM>
168 {
169  // Call method on parent class
170  unsigned node_index = NodesOnlyMesh<SPACE_DIM>::AddNode(pNewNode);
171 
172  // If necessary move it to be back on the cylinder
173  ChastePoint<SPACE_DIM> new_node_point = pNewNode->GetPoint();
174  SetNode(node_index, new_node_point);
175 
176  return node_index;
177 
178 }
179 
180 template<unsigned SPACE_DIM>
181 c_vector<double, SPACE_DIM> PeriodicNodesOnlyMesh<SPACE_DIM>::GetVectorFromAtoB(const c_vector<double, SPACE_DIM>& rLocation1, const c_vector<double, SPACE_DIM>& rLocation2)
182 {
183  c_vector<double, SPACE_DIM> vector = rLocation2 - rLocation1;
184 
185  // Loop over the periodic dimensions and measure across boundaries
186  // if points are more than halfway across the width apart
187  for ( unsigned i = 0; i < SPACE_DIM; i++ )
188  {
189  if ( mIsDimPeriodic[i] )
190  {
191  vector(i) = fmod(vector(i),mWidth[i]);
192  if ( vector(i) > 0.5*mWidth[i] )
193  {
194  vector(i) -= mWidth[i];
195  }
196  else if (vector(i) < -0.5*mWidth[i] )
197  {
198  vector(i) += mWidth[i];
199  }
200  }
201  }
202 
203  return vector;
204 }
205 
206 // Refresh mesh -> Check and then move if outside box
207 template<unsigned SPACE_DIM>
209 {
210  // Loop over the periodic dimensions and if they are
211  // outside the domain, get the fmod and relocate
212  for ( typename std::vector<Node<SPACE_DIM> *>::iterator it_node = this->mNodes.begin();
213  it_node != this->mNodes.end(); ++it_node )
214  {
215  c_vector<double,SPACE_DIM> & location = (*it_node)->rGetModifiableLocation();
216 
217  for ( unsigned i = 0; i < SPACE_DIM; i++ )
218  {
219  if ( mIsDimPeriodic[i] )
220  {
221  if ( location(i) < 0.0 )
222  {
223  location(i) = fmod( location(i), mWidth[i] ) + mWidth[i];
224  }
225  else if ( location(i) >= mWidth[i] )
226  {
227  location(i) = fmod( location(i), mWidth[i] );
228  }
229  }
230  }
231  }
232 
233  // Now run the base class method
235 }
236 
238 // Explicit instantiation
240 
241 template class PeriodicNodesOnlyMesh<1>;
242 template class PeriodicNodesOnlyMesh<2>;
243 template class PeriodicNodesOnlyMesh<3>;
244 
245 // Serialization for Boost >= 1.36
ChastePoint< SPACE_DIM > GetPoint() const
Definition: Node.cpp:133
Definition: Node.hpp:58
c_vector< double, DIM > & rGetLocation()
Definition: ChastePoint.cpp:76
#define EXCEPTION(message)
Definition: Exception.hpp:143
void SetUpBoxCollection(const std::vector< Node< SPACE_DIM > * > &rNodes)
Node< SPACE_DIM > * GetNode(unsigned index) const
virtual void SetUpBoxCollection(double cutOffLength, c_vector< double, 2 *SPACE_DIM > domainSize, int numLocalRows=PETSC_DECIDE, c_vector< bool, SPACE_DIM > isDimPeriodic=zero_vector< bool >(SPACE_DIM))
c_vector< double, SPACE_DIM > mWidth
virtual double GetWidth(const unsigned &rDimension) const
std::vector< Node< SPACE_DIM > * > mNodes
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
void SetCoordinate(unsigned i, double value)
void SetNode(unsigned nodeIndex, ChastePoint< SPACE_DIM > point, bool concreteMove=false)
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
PeriodicNodesOnlyMesh(c_vector< double, SPACE_DIM > width)
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
void AddNodesToBoxes()
static unsigned GetNumProcs()
Definition: PetscTools.cpp:108
double GetWidth(const unsigned &rDimension) const
c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocation1, const c_vector< double, SPACE_DIM > &rLocation2)