MercuryDPM  Beta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Mercury2D.cc
Go to the documentation of this file.
1 //Copyright (c) 2013-2014, The MercuryDPM Developers Team. All rights reserved.
2 //For the list of developers, see <http://www.MercuryDPM.org/Team>.
3 //
4 //Redistribution and use in source and binary forms, with or without
5 //modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name MercuryDPM nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 //DISCLAIMED. IN NO EVENT SHALL THE MERCURYDPM DEVELOPERS TEAM BE LIABLE FOR ANY
19 //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include "Mercury2D.h"
27 #include "Particles/BaseParticle.h"
28 
30 {
31  constructor();
32  logger(DEBUG, "Mercury2D::Mercury2D() constructor finished");
33 }
34 
41  : DPMBase(other), MercuryBase(other)
42 {
43  logger(DEBUG, "Mercury2D::Mercury2D(Mercury2D& other) copy constructor finished");
44 }
45 
53  : DPMBase(other), MercuryBase()
54 {
55  constructor();
56  logger(DEBUG, "Mercury2D::Mercury2D(DPMBase& other) finished");
57 }
58 
60 {
63 }
64 
72 void Mercury2D::hGridFindContactsWithinTargetCell(int x, int y, unsigned int l)
73 {
74  HGrid* hgrid=getHGrid();
75  unsigned int bucket = hgrid->computeHashBucketIndex(x, y, l);
76 
77  //Check if this function is already applied to this bucket
78  if (hgrid->getBucketIsChecked(bucket))
79  {
80  return;
81  }
82 
83  BaseParticle* p1 = hgrid->getFirstBaseParticleInBucket(bucket);
84  while (p1 != nullptr)
85  {
86  BaseParticle* p2 = p1->getHGridNextObject();
87  while (p2 != nullptr)
88  {
91  //Check if the BaseParticle* p1 and BaseParticle* p2 are really in the same cell (i.e. no hashing error has occurred)
92  if ((p1->getHGridX() == p2->getHGridX()) && (p1->getHGridY() == p2->getHGridY()) && (p1->getHGridLevel() == p2->getHGridLevel()))
93  {
94  computeInternalForces(p1, p2);
95  }
96  p2 = p2->getHGridNextObject();
97  }
98  p1 = p1->getHGridNextObject();
99  }
100  hgrid->setBucketIsChecked(bucket);
101 }
102 
114 void Mercury2D::hGridFindContactsWithTargetCell(int x, int y, unsigned int l, BaseParticle* obj)
115 {
116  //Check if the object is not in the same cell as being checked, CheckCell_current should handle these cases.
117  if ((obj->getHGridX() == x) && (obj->getHGridY() == y) && (obj->getHGridLevel() == l))
118  {
119  return;
120  }
121 
122  HGrid* hgrid = getHGrid();
123 
124  // Calculate the bucket
125  unsigned int bucket = hgrid->computeHashBucketIndex(x, y, l);
126 
127  // Loop through all objects in the bucket to find nearby objects
128  BaseParticle *p = hgrid->getFirstBaseParticleInBucket(bucket);
129  while (p != nullptr)
130  {
131 // \bug{TW: This check is not necessary, I believe. This is the most-expensive function in most codes (the two checks in this function slows down granular jet by 15%) and the selftests are not affected. DK: I do think this is neccesary, for example: If two cells hash to the same bucket and a particle in one of these cells check for collisions with the other cell. Then due to the hashingcollision it also gets all particles in it's own cell and thus generating false collisions. TW: ok, so let's leave it in, issue closed.}
132  //Check if the BaseParticle *p really is in the target cell (i.e. no hashing error has occurred)
133  if ((p->getHGridX() == x) && (p->getHGridY() == y) && (p->getHGridLevel() == l))
134  {
135  computeInternalForces(obj, p);
136  }
137  p = p->getHGridNextObject();
138  }
139 }
140 
147 {
148  HGrid* hgrid=getHGrid();
149  unsigned int startLevel = obj->getHGridLevel();
150 
151  switch (getHGridMethod())
152  {
153  case BOTTOMUP:
154  {
155  int occupiedLevelsMask = hgrid->getOccupiedLevelsMask() >> obj->getHGridLevel();
156  for (unsigned int level = startLevel; level < hgrid->getNumberOfLevels(); occupiedLevelsMask >>= 1, level++)
157  {
158  // If no objects in rest of grid, stop now
159  if (occupiedLevelsMask == 0)
160  {
161  break;
162  }
163 
164  // If no objects at this level, go on to the next level
165  if ((occupiedLevelsMask & 1) == 0)
166  {
167  continue;
168  }
169 
170  if (level == startLevel)
171  {
172  int x = obj->getHGridX();
173  int y = obj->getHGridY();
174 
176  hGridFindContactsWithTargetCell(x, y + 1, level, obj);
177  hGridFindContactsWithTargetCell(x + 1, y - 1, level, obj);
178  hGridFindContactsWithTargetCell(x + 1, y, level, obj);
179  hGridFindContactsWithTargetCell(x + 1, y + 1, level, obj);
180  }
181  else
182  {
183  int xs, ys, xe, ye;
184  Mdouble inv_size = hgrid->getInvCellSize(level);
185  xs = static_cast<int>(std::floor((obj->getPosition().X - obj->getInteractionRadius()) * inv_size - 0.5));
186  xe = static_cast<int>(std::floor((obj->getPosition().X + obj->getInteractionRadius()) * inv_size + 0.5));
187  ys = static_cast<int>(std::floor((obj->getPosition().Y - obj->getInteractionRadius()) * inv_size - 0.5));
188  ye = static_cast<int>(std::floor((obj->getPosition().Y + obj->getInteractionRadius()) * inv_size + 0.5));
189  for (int x = xs; x <= xe; ++x)
190  {
191  for (int y = ys; y <= ye; ++y)
192  {
193  hGridFindContactsWithTargetCell(x, y, level, obj);
194  }
195  }
196  }
197  }
198  break;
199  }
200  case TOPDOWN:
201  {
202  int occupiedLevelsMask = hgrid->getOccupiedLevelsMask();
203  for (unsigned int level = 0; level <= startLevel; occupiedLevelsMask >>= 1, level++)
204  {
205  // If no objects in rest of grid, stop now
206  if (occupiedLevelsMask == 0)
207  {
208  break;
209  }
210 
211  // If no objects at this level, go on to the next level
212  if ((occupiedLevelsMask & 1) == 0)
213  {
214  continue;
215  }
216 
217  if (level == startLevel)
218  {
219  int x = obj->getHGridX();
220  int y = obj->getHGridY();
221 
223  hGridFindContactsWithTargetCell(x, y + 1, level, obj);
224  hGridFindContactsWithTargetCell(x + 1, y - 1, level, obj);
225  hGridFindContactsWithTargetCell(x + 1, y, level, obj);
226  hGridFindContactsWithTargetCell(x + 1, y + 1, level, obj);
227  }
228  else
229  {
230  int xs, ys, xe, ye;
231  Mdouble inv_size = hgrid->getInvCellSize(level);
232  xs = static_cast<int>(std::floor((obj->getPosition().X - obj->getInteractionRadius()) * inv_size - 0.5));
233  xe = static_cast<int>(std::floor((obj->getPosition().X + obj->getInteractionRadius()) * inv_size + 0.5));
234  ys = static_cast<int>(std::floor((obj->getPosition().Y - obj->getInteractionRadius()) * inv_size - 0.5));
235  ye = static_cast<int>(std::floor((obj->getPosition().Y + obj->getInteractionRadius()) * inv_size + 0.5));
236  for (int x = xs; x <= xe; ++x)
237  {
238  for (int y = ys; y <= ye; ++y)
239  {
240  hGridFindContactsWithTargetCell(x, y, level, obj);
241  }
242  }
243  }
244  }
245  break;
246  }
247  }
248 }
249 
255 {
256  HGrid* hGrid=getHGrid();
257  if (hGrid)
258  {
259  unsigned int l = obj->getHGridLevel();
260  Mdouble inv_size = hGrid->getInvCellSize(l);
261 
262  int x = static_cast<int>(std::floor(obj->getPosition().X * inv_size));
263  int y = static_cast<int>(std::floor(obj->getPosition().Y * inv_size));
264 
265 #ifdef CONTACT_LIST_HGRID
266  if(obj->getHGridX() != x || obj->getHGridY() != y)
267  {
268  int bucket = hGrid->computeHashBucketIndex(x, y, l);
269 
270  //First the object has to be removed
271  hGridRemoveParticle(obj);
272 
273  //Also remove all contact associated with it
274  getPossibleContactList().remove_ParticlePosibleContacts(obj);
275 
276  //And now reinserted
278  obj->setHGridPrevObject(nullptr);
279  if(hGrid->getFirstBaseParticleInBucket(bucket))
280  {
282  }
283  hGrid->setFirstBaseParticleInBucket(bucket,obj);
284 
285  obj->setHGridX(x);
286  obj->setHGridY(y);
287  InsertObjAgainstGrid(obj);
288  }
289 #else
290  unsigned int bucket = hGrid->computeHashBucketIndex(x, y, l);
291 
293  obj->setHGridPrevObject(nullptr);
294  if (hGrid->getFirstBaseParticleInBucket(bucket))
295  {
297  }
298 
299  hGrid->setFirstBaseParticleInBucket(bucket, obj);
300 
301  obj->setHGridX(x);
302  obj->setHGridY(y);
303 #endif
304  }
305 }
306 
313 {
314  HGrid* hGrid = getHGrid();
315  if (hGrid != nullptr)
316  {
317  unsigned int bucket = getHGrid()->computeHashBucketIndex(obj->getHGridX(), obj->getHGridY(), obj->getHGridLevel());
318  if (obj->getHGridPrevObject())
319  {
321  }
322  else
323  {
324  if (getHGrid()->getFirstBaseParticleInBucket(bucket) == obj)
325  {
327  }
328  }
329 
330  if (obj->getHGridNextObject())
331  {
333  }
334  }
335 }
336 
352 bool Mercury2D::hGridHasContactsInTargetCell(int x, int y, unsigned int l, const BaseParticle *obj) const
354 {
355  // Loop through all objects in the bucket to find nearby objects
356  unsigned int bucket = getHGrid()->computeHashBucketIndex(x, y, l);
357 
358  const BaseParticle* p = getHGrid()->getFirstBaseParticleInBucket(bucket);
359  while (p != nullptr)
360  {
361  if ((p->getHGridX() == x) && (p->getHGridY() == y) && (p->getHGridLevel() == l))
362  {
363  if (areInContact(obj, p))
364  {
365  return true;
366  }
367  }
368  p = p->getHGridNextObject();
369  }
370  return false;
371 }
372 
382 {
383  if (getHGrid() == nullptr || getHGrid()->getNeedsRebuilding())
384  {
385  logger(INFO, "HGrid needs rebuilding for \"bool Mercury2D::hGridHasParticleContacts(BaseParticle *obj)\"");
386  hGridRebuild();
387  }
388 
389  Mdouble inv_size;
390  int occupiedLevelsMask = getHGrid()->getOccupiedLevelsMask();
391 
392  for (unsigned int level = 0; level < getHGrid()->getNumberOfLevels(); occupiedLevelsMask >>= 1, level++)
393  {
394  // If no objects in rest of grid, stop now
395  if (occupiedLevelsMask == 0)
396  {
397  logger(VERBOSE, "Level % and higher levels are empty.", level);
398  break;
399  }
400 
401  // If no objects at this level, go on to the next level
402  if ((occupiedLevelsMask & 1) == 0)
403  {
404  logger(VERBOSE, "Level % is empty", level);
405  continue;
406  }
407 
408  int xs, ys, xe, ye;
409  inv_size = getHGrid()->getInvCellSize(level);
410  xs = static_cast<int>(std::floor((obj->getPosition().X - obj->getInteractionRadius()) * inv_size - 0.5));
411  xe = static_cast<int>(std::floor((obj->getPosition().X + obj->getInteractionRadius()) * inv_size + 0.5));
412  ys = static_cast<int>(std::floor((obj->getPosition().Y - obj->getInteractionRadius()) * inv_size - 0.5));
413  ye = static_cast<int>(std::floor((obj->getPosition().Y + obj->getInteractionRadius()) * inv_size + 0.5));
414 
415  logger(VERBOSE, "Level % grid cells [%,%] x [%,%]", level, xs, xe, ys, ye);
416  for (int x = xs; x <= xe; ++x)
417  {
418  for (int y = ys; y <= ye; ++y)
419  {
420  if (hGridHasContactsInTargetCell(x, y, level, obj))
421  {
422  return true;
423  }
424  }
425  }
426  } //end for level
427 
428  return false;
429 }
430 
431 #ifdef CONTACT_LIST_HGRID
432 
438 void Mercury2D::InsertCell(int x, int y, unsigned int l, BaseParticle* obj)
439 {
440  // Loop through all objects in the bucket to find nearby objects
441  unsigned int bucket = getHGrid()->computeHashBucketIndex(x,y,l);
443 
444  while (p!=nullptr)
445  {
446  if ((p->getHGridX() == x) && (p->getHGridY() == y) && (p->getHGridLevel() == l) && (obj != p))
447  {
448  getPossibleContactList().add_PossibleContact(obj, p);
449  }
450  p = p->getHGridNextObject();
451  }
452 }
453 
460 void Mercury2D::InsertObjAgainstGrid(BaseParticle* obj)
461 {
462  Mdouble inv_size;
463  int occupiedLevelsMask_ = getHGrid()->getOccupiedLevelsMask();
464 
465  inv_size=getHGrid()->getInvCellSize(obj->getHGridLevel());
466 
467  double ownXMin = (obj->getHGridX()-0.5) * getHGrid()->getCellSize(obj->getHGridLevel());
468  double ownXMax = (obj->getHGridX() + 1.5) * getHGrid()->getCellSize(obj->getHGridLevel());
469  double ownYMin = (obj->getHGridY() - 0.5) * getHGrid()->getCellSize(obj->getHGridLevel());
470  double ownYMax = (obj->getHGridY() + 1.5) * getHGrid()->getCellSize(obj->getHGridLevel());
471 
472  for (int level = 0; level < getHGrid()->getNumberOfLevels(); occupiedLevelsMask_ >>= 1, level++)
473  {
474  // If no objects in rest of grid, stop now
475  if (occupiedLevelsMask_ == 0)
476  {
477  break;
478  }
479 
480  // If no objects at this level, go on to the next level
481  if ((occupiedLevelsMask_ & 1) == 0)
482  {
483  continue;
484  }
485 
486  // Treat level as a third dimension coordinate
487  inv_size = getHGrid()->getInvCellSize(level);
488 
489  //Insert this particle in the list of possible interactions for this level
490  //in the appropriate cells.
491  int xs, xe, ys, ye;
492  xs = static_cast<int>(std::floor(ownXMin * inv_size - 0.5));
493  xe = static_cast<int>(std::floor(ownXMax * inv_size + 0.5));
494  ys = static_cast<int>(std::floor(ownYMin * inv_size - 0.5));
495  ye = static_cast<int>(std::floor(ownYMax * inv_size + 0.5));
496 
497  for(int x = xs; x <= xe; ++x)
498  {
499  for(int y = ys; y <= ye; ++y)
500  {
501  InsertCell(x, y, level, obj);
502  }
503  }
504  } //end for level
505 }
506 #endif
The DPMBase header includes quite a few header files, defining all the handlers, which are essential...
Definition: DPMBase.h:61
Mdouble X
the vector components
Definition: Vector.h:52
bool hGridHasParticleContacts(const BaseParticle *obj) override
Test if a BaseParticle has any contacts in the HGrid.
Definition: Mercury2D.cc:381
bool areInContact(const BaseParticle *pI, const BaseParticle *pJ) const
Checks if two particle are in contact or is there any positive overlap.
Definition: DPMBase.cc:590
virtual void hGridFindContactsWithTargetCell(int x, int y, unsigned int l, BaseParticle *obj)
Finds contacts between given BaseParticle and the BaseParticle in the target cell.
Definition: Mercury2D.cc:114
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
void hGridUpdateParticle(BaseParticle *obj) override
Updates the cell (not the level) of a BaseParticle.
Definition: Mercury2D.cc:254
virtual void computeInternalForces(BaseParticle *i)
Computes the forces between particles (internal in the sense that the sum over all these forces is ze...
Definition: DPMBase.cc:1633
virtual void hGridFindContactsWithinTargetCell(int x, int y, unsigned int l)
Finds contacts between particles the in the target cell.
Definition: Mercury2D.cc:72
double Mdouble
void setHGridY(const int y)
Sets the particle's HGrid cell Y-coordinate.
void setHGridNextObject(BaseParticle *p)
Sets the pointer to the next object in the particle's HGrid cell & level.
void setParticleDimensions(unsigned int particleDimensions)
Allows the dimension of the particle (f.e. for mass) to be changed. e.g. discs or spheres...
Definition: DPMBase.cc:474
HGridMethod getHGridMethod() const
Gets whether the HGrid in this MercuryBase is BOTTOMUP or TOPDOWN.
Definition: MercuryBase.cc:439
void hGridRemoveParticle(BaseParticle *obj)
Removes a BaseParticle to the HGrid.
Definition: Mercury2D.cc:312
int getHGridY() const
Returns particle's HGrid cell Y-coordinate.
void constructor()
Function that sets the ParticleDimensions and SystemDimensions to 2.
Definition: Mercury2D.cc:59
void setSystemDimensions(unsigned int newDim)
Allows for the dimension of the simulation to be changed.
Definition: DPMBase.cc:453
void setHGridX(const int x)
Sets the particle's HGrid cell X-coordinate.
const Vec3D & getPosition() const
Returns the position of this BaseInteractable.
int getOccupiedLevelsMask() const
Gets the integer that represents which levels are occupied.
Definition: HGrid.cc:285
unsigned int getNumberOfLevels() const
Gets the number of levels of this HGrid.
Definition: HGrid.cc:234
This is the base class for both Mercury2D and Mercury3D. Note the actually abstract grid is defined i...
Definition: MercuryBase.h:74
In the HGrid class, here all information about the HGrid is stored.
Definition: HGrid.h:41
bool hGridHasContactsInTargetCell(int x, int y, unsigned int l, const BaseParticle *obj) const
Tests if the BaseParticle has contacts with other Particles in the target cell.
Definition: Mercury2D.cc:353
void setFirstBaseParticleInBucket(unsigned int i, BaseParticle *p)
Sets the first particle in bucket i to be the given BaseParticle.
Definition: HGrid.cc:243
void setBucketIsChecked(unsigned int i)
Sets that the bucket with the given index is checked to true.
Definition: HGrid.cc:226
const BaseParticle * getFirstBaseParticleInBucket(unsigned int i) const
Gets the first BaseParticle in the given bucket, const version.
Definition: HGrid.cc:209
Mdouble Y
Definition: Vector.h:52
void hGridRebuild()
This sets up the parameters required for the contact model.
Definition: MercuryBase.cc:201
double getCellSize(unsigned int i) const
Gets the size of the cells at the given level.
Definition: HGrid.cc:252
Mercury2D()
This is the default constructor. All it does is set sensible defaults.
Definition: Mercury2D.cc:29
void hGridFindOneSidedContacts(BaseParticle *obj) override
Finds contacts with the BaseParticle; avoids multiple checks.
Definition: Mercury2D.cc:146
void setHGridPrevObject(BaseParticle *p)
Sets the pointer to the previous object in the particle's HGrid cell & level.
BaseParticle * getHGridPrevObject() const
Returns pointer to previous object in particle's HGrid level & cell.
unsigned int computeHashBucketIndex(int x, int y, int z, unsigned int l) const
Computes hash bucket index in range [0, NUM_BUCKETS-1] for a 3D domain.
Definition: HGrid.cc:124
BaseParticle * getHGridNextObject() const
Returns pointer to next object in particle's HGrid level & cell.
unsigned int getHGridLevel() const
Returns particle's HGrid level.
Mdouble getInteractionRadius() const
Returns the particle's interaction radius, which might be different from radius_ (e.g., when dealing with wet particles)
HGrid * getHGrid()
Gets the HGrid used by this problem.
Definition: MercuryBase.cc:389
bool getBucketIsChecked(unsigned int i) const
Gets whether or not the bucket with index i is checked.
Definition: HGrid.cc:200
double getInvCellSize(unsigned int i) const
Gets 1/cellSize for the cells on level i.
Definition: HGrid.cc:261
This adds on the hierarchical grid code for 2D problems.
Definition: Mercury2D.h:35
int getHGridX() const
Returns particle's HGrid cell X-coordinate.