NDDEM
Cells.h
Go to the documentation of this file.
1 #ifndef CELLCONTACTDETECTION
2 #define CELLCONTACTDETECTION
3 
6 #include <boost/random.hpp>
7 #include <cstdlib>
8 #include <cstdio>
9 #include <vector>
10 #include <chrono>
11 #include <algorithm>
12 #include <numeric>
13 
14 #include "Boundaries.h"
15 #include "ternary.h"
16 
19 class Cell {
20 public:
21  std::vector<int> incell ;
22  std::vector<int> neighbours ;
23  std::vector<int> neigh_ghosts ;
24  std::vector<bitdim> neigh_ghosts_dim ;
25  std::vector<bitdim> neigh_ghosts_dir ;
26 
27  std::vector<int> neighbours_full ;
28  std::vector<int> neigh_ghosts_full ;
29  std::vector<bitdim> neigh_ghosts_full_dim ;
30  std::vector<bitdim> neigh_ghosts_full_dir ;
31 
32  template <class Archive>
33  void serialize( Archive & ar )
34  {
36  }
37 
38 } ;
39 
43 template <int d>
44 class Cells {
45 public:
46  int init_cells (std::vector<Boundary<d>> &boundaries, double ds) ;
47  int init_cells (std::vector<Boundary<d>> &boundaries, std::vector<double> & r) {double ds = 2.1*(*std::max_element(r.begin(), r.end())) ; return (init_cells(boundaries, ds)) ; }
48  int init_subcells (std::vector<Boundary<d>> &bounds, double delta_super[], const std::vector<int> & n_cell_super) ;
49  int init_allocate() ;
50  int init_finalise(std::vector<Boundary<d>> &bounds) ;
51  std::vector<std::vector<double>> boundary_handler (std::vector<Boundary<d>> &boundaries) ;
52  int allocate_to_cells (std::vector<std::vector<double>> & X) ;
53  int allocate_single (std::vector<double> & X, int grainid) ;
54  int contacts (int ID, std::pair<int,int> bounds, CLp_it_t<d> & CLp_it,
55  ContactList<d> & CLnew, std::vector<std::vector<double>> const & X, std::vector<double> const &r, double LE_displacement) ;
56  int contacts_external (int ID, Cells<d> &ocell, int delta_lvl, std::pair<int,int> bounds, CLp_it_t<d> & CLp_it,
57  ContactList<d> & CLnew, std::vector<std::vector<double>> const & X, std::vector<double> const &r, double LE_displacement) ;
58  int contacts_cell_cell (int ID, Cell & c1, Cell & c2, CLp_it_t<d> & CLp_it,
59  ContactList<d> & CLnew,std::vector<std::vector<double>> const & X,
60  std::vector<double> const &r, cp<d> & tmpcp ) ;
61  int contacts_cell_ghostcell (int ID, Cell & c1, Cell & c2, bitdim ghost, bitdim ghostdir, CLp_it_t<d> & CLp_it,
62  ContactList<d> & CLnew, std::vector<std::vector<double>> const & X, std::vector<double> const &r, double LE_displacement, cp<d> & tmpcp ) ;
63  bool cell_contact_insert (int ID, CLp_it_t<d> & CLp_it, const cp<d>& a) ;
64  int clear_all () ;
65 
66  //-------------------------------------------
67  int x2id (const std::vector<int>&v)
68  {
69  int res=0 ;
70  for (int dd=0; dd<d ; dd++)
71  {
72  if (v[dd] < 0 || v[dd]>=n_cell[dd]) {/*printf("WARN: particle outside the cell volume\n") ;*/ fflush(stdout) ; return -1 ; }
73  res += cum_n_cell[dd] * v[dd] ;
74  }
75  return res ;
76  }
77  //-------------------------------------------
78  std::vector<int> id2x (int id)
79  {
80  std::vector<int> ids (d,0) ;
81  for (int dd=0 ; dd<d ; dd++)
82  {
83  ids[dd] = id % n_cell[dd] ;
84  id /= n_cell[dd] ;
85  }
86  return ids ;
87  }
88  //-------------------------------------------
90  {
91  for (int i=0 ; i<cum_n_cell[d] ; i++)
92  {
93  if (x2id(id2x(i))!=i)
94  {
95  printf("ERROR %d\n", i) ;
96  return false ;
97  }
98  }
99  return true ;
100  }
101  //---------------------------------------------
102  double dsqr (std::vector<double> &X1, std::vector<double> &X2)
103  {
104  double sum = 0 ;
105  for (int k=0 ; k<d ; k++)
106  sum += (X1[k]-X2[k])*(X1[k]-X2[k]) ;
107  return sum ;
108  }
109  //---------------------------------------------
110  int clip_LEmoved_cell(int original, int considered, bitdim &ghost, bitdim &ghostdir)
111  {
112  int offset = (original/planesize)*planesize ;
113 
114  if (considered < offset)
115  {
116  considered += planesize ;
117  if ((ghost>>1)&1 && (ghostdir&1))
118  ghost &= ~(1<<1) ;
119  else
120  {
121  ghost |= (1<<1) ;
122  ghostdir |= (1<<1) ;
123  }
124  }
125 
126  if (considered >= offset+planesize)
127  {
128  considered -= planesize ;
129  if ((ghost>>1)&1 && !(ghostdir&1))
130  ghost &= ~(1<<1) ;
131  else
132  ghost |= (1<<1) ;
133  }
134 
135  return considered;
136  }
137 
138  std::vector<int> n_cell , cum_n_cell ;
139  std::vector<double> origin ;
140  std::vector<double> Delta ;
141  std::vector<Cell> cells ;
142  double delta[d] ;
143  int planesize=0 ;
144 
145  template <class Archive>
146  void serialize( Archive & ar )
147  {
149  }
150 } ;
151 
154 /*****************************************************************************************************
155  * *
156  * *
157  * *
158  * IMPLEMENTATIONS *
159  * *
160  * *
161  * *
162  * ***************************************************************************************************/
163 
164 template <int d>
165 std::vector<std::vector<double>> Cells<d>::boundary_handler (std::vector<Boundary<d>> &boundaries)
166 {
167  std::vector<std::vector<double>> res (d, std::vector<double>(2,0)) ;
168 
169  for (size_t i=0 ; i<boundaries.size() ; i++)
170  {
171  switch (boundaries[i].Type)
172  {
173  case WallType::PBC:
174  case WallType::PBC_LE:
175  res[i][0] = boundaries[i].xmin ;
176  res[i][1] = boundaries[i].xmax ;
177  Delta.resize(d) ;
178  Delta[i] = boundaries[i].delta ;
179  break ;
181  case WallType::ELLIPSE:
182  printf("ERR: this type of boundary is incompatible with cell contacts\n") ;
183  break ;
184  case WallType::WALL:
185  res[i][0] = boundaries[i].xmin ;
186  res[i][1] = boundaries[i].xmax ;
187  break ;
188  case WallType::SPHERE:
190  for (int dd=0 ; dd<d ; dd++)
191  {
192  res[dd][0] = boundaries[i].center[dd]-boundaries[i].radius ;
193  res[dd][1] = boundaries[i].center[dd]+boundaries[i].radius ;
194  }
195  break ;
197  for (int dd=0 ; dd<d ; dd++)
198  {
199  res[dd][0] = boundaries[i].center[dd]-boundaries[i].radius ;
200  if (dd != boundaries[i].axis)
201  res[dd][1] = boundaries[i].center[dd]+boundaries[i].radius ;
202  }
203  break ;
205  for (int dd=0 ; dd<d ; dd++)
206  {
207  if (dd==boundaries[i].axis) continue ;
208  res[dd][0] = boundaries[i].radius ;
209  res[dd][1] = boundaries[i].radius ;
210  }
211  break ;
212  default:
213  printf("ERR: unknown boundary condition for cell building.\n") ;
214  break;
215  }
216  }
217  return res ;
218 }
219 
220 //------------------------------------------------------------------------------------
221 template <int d>
222 int Cells<d>::init_subcells (std::vector<Boundary<d>> &bounds, double delta_super[], const std::vector<int> & n_cell_super)
223 {
224  init_allocate() ;
225  for (int i=0 ; i<d ; i++)
226  {
227  n_cell[i] = n_cell_super[i]*2 ;
228  delta[i] = delta_super[i]/2. ;
229  }
230 
231  init_finalise(bounds) ;
232  return 0;
233 }
234 //-------------------------------------------
235 template <int d>
236 int Cells<d>::init_cells(std::vector<Boundary<d>> &bounds, double ds)
237 {
238  printf("CELL SIZE: %g\n", ds) ;
239 
240  init_allocate() ;
241 
242  auto boundaries = boundary_handler(bounds) ;
243  for (int i=0 ; i<d ; i++)
244  {
245  n_cell[i] = floor((boundaries[i][1]-boundaries[i][0])/ds) ;
246  delta[i] = (boundaries[i][1]-boundaries[i][0])/n_cell[i] ;
247  }
248 
249  init_finalise(bounds) ;
250  return 0 ;
251 }
252 //-------------------------------------------
253 template <int d>
255 {
256  n_cell.resize(d,0);
257  cum_n_cell.resize(d+1,0) ;
258  origin.resize(d,0) ;
259  return 0;
260 }
261 //-------------------------------------------
262 template <int d>
263 int Cells<d>::init_finalise(std::vector<Boundary<d>> &bounds)
264 {
265  auto boundaries = boundary_handler(bounds) ;
266  cum_n_cell[0] = 1 ;
267  for (int i=0 ; i<d ; i++)
268  {
269  if (i>0)
270  cum_n_cell[i] = cum_n_cell[i-1]*n_cell[i-1] ;
271  origin[i] = boundaries[i][0] ;
272  }
273  cum_n_cell[d] = cum_n_cell[d-1]*n_cell[d-1] ;
274  planesize = cum_n_cell[2] ;
275 
276  cells.resize(cum_n_cell[d]) ;
277  for (auto &v: n_cell) printf("%d ", v) ;
278  printf("\n") ;
279  for (auto &v: cum_n_cell) printf("%d ", v) ;
280  printf("\n") ;
281  for (int i=0 ; i<d ; i++)
282  printf("%g ", delta[i]) ;
283  printf("\n") ;
284 
285  for (size_t i=0 ; i<cells.size() ; i++)
286  {
287  auto x_base = id2x(i) ;
288  auto x = x_base ;
289  //for (int dd=0 ; dd<d ; dd++) tmp[dd] = x_base[dd] ;
290 
291  //auto res = hilbert::v2::PositionToIndex<uint8_t, d> (tmp) ;
292  //for (auto & v: res)
293  // printf("%d ", v) ;
294  //printf("\n") ;
295  //cells[i].hilbert_idx = hilbert::v2::PositionToIndex<int, d> (tmp) ;
296 
297  cells[i].neighbours.reserve(pow(3,d)) ;
298 
299  ternary t ;
300  if (bounds[0].Type==WallType::PBC_LE) t.set_quat_bit(1) ;
301  t++ ;
302 
303  for ( ; t<pow(3,d) ; t++)
304  {
305  bool noadd = false ;
306  int pbc_le_crossing = 0;
307  x = x_base ;
308 
309  bitdim ghost = 0, ghostdir = 0 ;
310  for (int dd=0 ; dd<d ; dd++)
311  {
312  if ( t[dd]==2 )
313  {
314  if (pbc_le_crossing != 0 )
315  x[dd] += t[dd] * pbc_le_crossing ;
316  else
317  noadd = true ;
318  }
319  else
320  x[dd] += t[dd] ;
321 
322  if (x[dd]<0 )
323  {
324  if (bounds[0].Type==WallType::PBC_LE && dd==0)
325  {
326  pbc_le_crossing = 1 ;
327  ghost |= 1<<dd ;
328  ghostdir |= 1<<dd ;
329  x[dd] += n_cell[dd] ;
330  }
331  else if (bounds[dd].Type==WallType::PBC) // Only using positive ghosts
332  {
333  ghost |= 1<<dd ;
334  ghostdir |= 1<<dd ;
335  x[dd] += n_cell[dd] ;
336  }
337  else
338  {
339  noadd=true ;
340  break ;
341  }
342  }
343  else if (x[dd]>=n_cell[dd])
344  {
345  if (bounds[0].Type==WallType::PBC_LE && dd==0)
346  {
347  pbc_le_crossing = -1 ;
348  ghost |= 1<<dd ;
349  x[dd] -= n_cell[dd] ;
350  }
351  else if (bounds[dd].Type==WallType::PBC) // Only using positive ghosts
352  {
353  ghost |= 1<<dd ;
354  x[dd] -= n_cell[dd] ;
355  }
356  else
357  {
358  noadd = true ;
359  break ;
360  }
361  }
362  }
363  if (!noadd)
364  {
365  if (ghost>0)
366  {
367  unsigned int id = x2id(x) ;
368  if (bounds[0].Type==WallType::PBC_LE && (ghost&1)) // Add all the ghosts crossing the LE pbc positively
369  {
370  if (!(ghostdir&1))
371  {
372  cells[i].neigh_ghosts.push_back(id) ;
373  cells[i].neigh_ghosts_dim.push_back(ghost) ;
374  cells[i].neigh_ghosts_dir.push_back(ghostdir) ;
375  }
376  }
377  else
378  {
379  if (id>i) // if not a ghost pbc, just add.
380  {
381  cells[i].neigh_ghosts.push_back(id) ;
382  cells[i].neigh_ghosts_dim.push_back(ghost) ;
383  cells[i].neigh_ghosts_dir.push_back(ghostdir) ;
384  }
385  else
386  {
387  cells[i].neigh_ghosts_full.push_back(id) ;
388  cells[i].neigh_ghosts_full_dim.push_back(ghost) ;
389  cells[i].neigh_ghosts_full_dir.push_back(ghostdir) ;
390  }
391  }
392  }
393  else
394  cells[i].neighbours.push_back(x2id(x)) ;
395  }
396  }
397 
398  sort( cells[i].neighbours.begin(), cells[i].neighbours.end() );
399  int bef = cells[i].neighbours.size() ;
400  cells[i].neighbours.erase( unique( cells[i].neighbours.begin(), cells[i].neighbours.end() ), cells[i].neighbours.end() );
401  int aft = cells[i].neighbours.size() ;
402  if (bef-aft != 0) printf("ERR: no duplication of cells should happen with the algorithm.\n") ;
403 
404  cells[i].neighbours_full = cells[i].neighbours ;
405  cells[i].neighbours.erase(std::remove_if(cells[i].neighbours.begin(), cells[i].neighbours.end(),
406  [=](size_t x) { return x<=i ; }), cells[i].neighbours.end());
407  cells[i].neighbours_full.erase(std::remove_if(cells[i].neighbours_full.begin(), cells[i].neighbours_full.end(),
408  [=](size_t x) { return x>=i ; }), cells[i].neighbours_full.end());
409  }
410 
411  /*for (int i=0 ; i<cum_n_cell[d] ; i++)
412  {
413  printf("%d %ld | ", i, cells[i].neighbours.size()) ;
414  for (size_t j=0 ; j< cells[i].neighbours.size() ; j++)
415  printf("%d ", cells[i].neighbours[j]) ;
416  printf("|") ;
417  for (size_t j=0 ; j< cells[i].neighbours_full.size() ; j++)
418  printf("%d ", cells[i].neighbours_full [j]) ;
419  printf("||") ;
420  for (size_t j=0 ; j< cells[i].neigh_ghosts.size() ; j++)
421  printf("%d ", cells[i].neigh_ghosts [j]) ;
422  printf("|") ;
423  for (size_t j=0 ; j< cells[i].neigh_ghosts_full.size() ; j++)
424  printf("%d ", cells[i].neigh_ghosts_full [j]) ;
425  printf("\n") ;
426  }*/
427 
428  return 0 ;
429 }
430 //=================================================================
431 template <int d>
432 int Cells<d>::allocate_to_cells (std::vector<std::vector<double>> & X)
433 {
434  std::vector<int> v (d,0) ;
435 
436  clear_all() ;
437 
438  for (size_t i=0 ; i<X.size() ; i++)
439  {
440  for (int dd=0 ; dd<d ; dd++)
441  v[dd] = floor((X[i][dd]-origin[dd])/delta[dd]) ;
442  int id = x2id(v) ;
443  if (id != -1)
444  cells[id].incell.push_back(i) ;
445  }
446 
447  /*int tot = 0 ;
448  for (size_t i=0 ; i<cells.size() ; i++)
449  tot += cells[i].incell.size() ;
450  printf("%d ", tot) ; fflush(stdout) ;*/
451  return 0 ;
452 }
453 //=================================================================
454 template <int d>
456 {
457  //printf("==> %ld ", cells.size()) ; fflush(stdout) ;
458  for (size_t i=0 ; i<cells.size() ; i++)
459  cells[i].incell.clear() ;
460  return 0 ;
461 }
462 //=================================================================
463 template <int d>
464 int Cells<d>::allocate_single (std::vector<double> & X, int grainid)
465 {
466  std::vector<int> v (d,0) ;
467 
468  for (int dd=0 ; dd<d ; dd++)
469  v[dd] = floor((X[dd]-origin[dd])/delta[dd]) ;
470  int id = x2id(v) ;
471  if (id != -1)
472  cells[id].incell.push_back(grainid) ;
473 
474  /*int tot = 0 ;
475  for (size_t i=0 ; i<cells.size() ; i++)
476  tot += cells[i].incell.size() ;
477  printf("%d ", tot) ; fflush(stdout) ;*/
478  return id ;
479 }
480 //=================================================================
481 template <int d>
482 int Cells<d>::contacts (int ID, std::pair<int,int> bounds, CLp_it_t<d> & CLp_it,
483  ContactList<d> & CLnew,
484  std::vector<std::vector<double>> const & X, std::vector<double> const &r, double LE_displacement)
485 {
486  auto [cell_first, cell_last] = bounds ;
487  cp<d> tmpcp(0,0,0,nullptr) ; tmpcp.persisting = true ;
488  double sum=0 ;
489  int ncontact=0 ;
490  //printf("B%d ", ID) ; fflush(stdout) ;
491  for (int c=cell_first ; c<cell_last ; c++)
492  {
493  if (cells[c].incell.size()==0) continue ;
494  // Inner cell contact
495  for (size_t ii=0 ; ii<cells[c].incell.size() ; ii++)
496  for (size_t jj=ii+1 ; jj<cells[c].incell.size() ; jj++)
497  {
498  sum = 0 ;
499  int i = cells[c].incell[ii] ;
500  int j = cells[c].incell[jj] ;
501  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
502  sum+= (X[i][k]-X[j][k])*(X[i][k]-X[j][k]) ;
503  if (sum<(r[i]+r[j])*(r[i]+r[j]))
504  {
505  ncontact++ ;
506  if (i<j) {tmpcp.i = i ; tmpcp.j=j ;}
507  else { tmpcp.i = j ; tmpcp.j=i ;}
508  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=0 ; tmpcp.ghostdir=0 ;
509  if (!cell_contact_insert(ID, CLp_it, tmpcp))
510  {
511  CLnew.v.push_back(tmpcp) ;
512  }
513  }
514  }
515 
516  //neighbours contacts
517  for (size_t cc=0 ; cc<cells[c].neighbours.size() ; cc++)
518  {
519  int c2 = cells[c].neighbours[cc] ;
520  for (size_t ii=0 ; ii<cells[c].incell.size() ; ii++)
521  for (size_t jj=0 ; jj<cells[c2].incell.size() ; jj++)
522  {
523  sum = 0 ;
524  int i = cells[c].incell[ii] ;
525  int j = cells[c2].incell[jj] ;
526  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
527  sum+= (X[i][k]-X[j][k])*(X[i][k]-X[j][k]) ;
528  if (sum<(r[i]+r[j])*(r[i]+r[j]))
529  {
530  ncontact++ ;
531  if (i<j) {tmpcp.i = i ; tmpcp.j=j ;}
532  else { tmpcp.i = j ; tmpcp.j=i ;}
533  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=0 ; tmpcp.ghostdir=0 ;
534  if (!cell_contact_insert(ID, CLp_it, tmpcp)) CLnew.v.push_back(tmpcp) ;
535  }
536  }
537  }
538 
539  //ghost contacts
540  //printf("[%d ", c) ;
541  for (size_t cc=0 ; cc<cells[c].neigh_ghosts.size() ; cc++)
542  {
543  int c2 = cells[c].neigh_ghosts[cc] ;
544  bitdim ghost=cells[c].neigh_ghosts_dim[cc], ghostdir=cells[c].neigh_ghosts_dir[cc] ;
545 
546  if (LE_displacement && cells[c].neigh_ghosts_dim[cc]&1) // This is a ghost cell through a lees-edward BC
547  {
548  int newc2 = c2-floor(LE_displacement*(cells[c].neigh_ghosts_dir[cc]&1?-1:1)/delta[1]) * cum_n_cell[1] ;
549  c2 = clip_LEmoved_cell(c2, newc2, ghost, ghostdir) ;
550  }
551 
552  //printf("%d ", c2) ;
553 
554 
555  for (size_t ii=0 ; ii<cells[c].incell.size() ; ii++)
556  for (size_t jj=0 ; jj<cells[c2].incell.size() ; jj++)
557  {
558  double sum = 0 ;
559  int i = cells[c].incell[ii] ;
560  int j = cells[c2].incell[jj] ;
561  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
562  {
563  double additionaldelta=0 ;
564  if (k==1 && ghost&1)
565  additionaldelta = LE_displacement * (ghostdir&1?-1:1) ;
566  sum+= pow(( X[i][k]-X[j][k] - Delta[k]*(ghost>>k & 1)*((ghostdir>>k & 1)?-1:1) - additionaldelta),2) ;
567 
568  /*if ((i==1 && j==6) || (i==6 && j==1))
569  {
570  printf("! %d %g %g %g %g %g %X %X %d %d\n", k, X[i][k], X[j][k], Delta[k], X[j][k] + Delta[k]*(ghost>>k & 1)*((ghostdir>>k & 1)?-1:1) + additionaldelta, additionaldelta, ghost, ghostdir, c, c2) ;
571  }*/
572  }
573 
574  if (sum<(r[i]+r[j])*(r[i]+r[j]))
575  {
576  //printf(".\n") ; fflush(stdout) ;
577  ncontact++ ;
578  if (i<j) {tmpcp.i = i ; tmpcp.j=j ; tmpcp.ghostdir = ghostdir ;}
579  else { tmpcp.i = j ; tmpcp.j=i ; tmpcp.ghostdir = (~ghostdir)&ghost ;}
580  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=ghost ;
581  if (!cell_contact_insert(ID, CLp_it, tmpcp)) CLnew.v.push_back(tmpcp) ;
582  }
583  }
584  }
585 
586  //printf("]\n") ;
587  }
588  //printf("E%d ", ID) ; fflush(stdout) ;
589 
590  //printf("{%d %ld}", ncontact, CLnew.v.size()) ; fflush(stdout) ;
591  return 0 ;
592 }
593 //-----------------------------------------------------------------------------
594 template <int d>
595 bool Cells<d>::cell_contact_insert (int ID, CLp_it_t<d> & CLp_it, const cp<d>& a)
596  {
597  if (CLp_it.it_array_beg[a.i] == CLp_it.null_list.v.begin()) return false ;
598  //for (auto it = CLp_it.it_array_beg[a.i] ; it != CLp_it.it_array_end[a.i] ; it++)
599  for (auto it = CLp_it.it_array_beg[a.i] ; it != CLp_it.it_ends[ID] && it->i == a.i ; it++)
600  {
601  if ((*it)==a)
602  {
603  it->contactlength=a.contactlength ;
604  it->ghost=a.ghost ;
605  it->ghostdir=a.ghostdir ;
606  it->persisting = true ;
607  return true ;
608  }
609  }
610  return false ;
611  }
612 
613 //========================================================================================
614 template <int d>
615 int Cells<d>::contacts_cell_cell (int ID, Cell & c1, Cell & c2, CLp_it_t<d> & CLp_it,
616  ContactList<d> & CLnew,
617  std::vector<std::vector<double>> const & X, std::vector<double> const &r, cp<d> & tmpcp)
618 {
619  double sum ;
620  for (size_t ii=0 ; ii<c1.incell.size() ; ii++)
621  for (size_t jj=0 ; jj<c2.incell.size() ; jj++)
622  {
623  sum = 0 ;
624  int i = c1.incell[ii] ;
625  int j = c2.incell[jj] ;
626  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
627  sum+= (X[i][k]-X[j][k])*(X[i][k]-X[j][k]) ;
628  if (sum<(r[i]+r[j])*(r[i]+r[j]))
629  {
630  if (i<j) {tmpcp.i = i ; tmpcp.j=j ;}
631  else { tmpcp.i = j ; tmpcp.j=i ;}
632  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=0 ; tmpcp.ghostdir=0 ;
633  if (!cell_contact_insert(ID, CLp_it, tmpcp)) CLnew.v.push_back(tmpcp) ;
634  }
635  }
636  return 0;
637 }
638 //-------------------------------------------------------------------
639 template <int d>
640 int Cells<d>::contacts_cell_ghostcell (int ID, Cell & c1, Cell & c2, bitdim ghost, bitdim ghostdir, CLp_it_t<d> & CLp_it,
641  ContactList<d> & CLnew, std::vector<std::vector<double>> const & X, std::vector<double> const &r, double LE_displacement, cp<d> & tmpcp)
642 {
643  double sum ;
644  for (size_t ii=0 ; ii<c1.incell.size() ; ii++)
645  for (size_t jj=0 ; jj<c2.incell.size() ; jj++)
646  {
647  sum = 0 ;
648  int i = c1.incell[ii] ;
649  int j = c2.incell[jj] ;
650  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
651  {
652  double additionaldelta=0 ;
653  if (k==1 && ghost&1) additionaldelta = LE_displacement * (ghostdir&1?-1:1) ;
654  sum+= pow(( X[i][k]-X[j][k] - Delta[k]*(ghost>>k & 1)*((ghostdir>>k & 1)?-1:1) - additionaldelta),2) ;
655  }
656 
657  if (sum<(r[i]+r[j])*(r[i]+r[j]))
658  {
659  if (i<j) {tmpcp.i = i ; tmpcp.j=j ; tmpcp.ghostdir = ghostdir ;}
660  else { tmpcp.i = j ; tmpcp.j=i ; tmpcp.ghostdir = (~ghostdir)&ghost ;}
661  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=ghost ;
662  if (!cell_contact_insert(ID, CLp_it, tmpcp)) CLnew.v.push_back(tmpcp) ;
663  }
664  }
665  return 0;
666 }
667 //=========================================================================================
668 template <int d>
669 int Cells<d>::contacts_external (int ID, Cells<d> &ocell, int delta_lvl, std::pair<int,int> bounds, CLp_it_t<d> & CLp_it,
670  ContactList<d> & CLnew, std::vector<std::vector<double>> const & X, std::vector<double> const &r, double LE_displacement)
671 {
672  auto [cell_first, cell_last] = bounds ;
673  cp<d> tmpcp(0,0,0,nullptr) ; tmpcp.persisting = true ;
674 
675  for (int c=cell_first ; c<cell_last ; c++)
676  {
677  if (cells[c].incell.size()==0) continue ;
678 
679  auto xloc = id2x(c) ;
680  for (auto &v:xloc) v /= pow(2, delta_lvl) ;
681  int oid = ocell.x2id(xloc) ;
682 
683  // Outer cell contact
684  contacts_cell_cell(ID, cells[c], ocell.cells[oid], CLp_it, CLnew, X, r, tmpcp) ;
685 
686  for (size_t cc=0 ; cc<ocell.cells[oid].neighbours.size() ; cc++)
687  contacts_cell_cell(ID, cells[c], ocell.cells[ocell.cells[oid].neighbours[cc]], CLp_it, CLnew, X, r, tmpcp) ;
688  for (size_t cc=0 ; cc<ocell.cells[oid].neighbours_full.size() ; cc++)
689  contacts_cell_cell(ID, cells[c], ocell.cells[ocell.cells[oid].neighbours_full[cc]], CLp_it, CLnew, X, r, tmpcp) ;
690 
691  //outer cell ghost contacts
692  for (size_t cc=0 ; cc<ocell.cells[oid].neigh_ghosts.size() ; cc++)
693  {
694  int c2 = ocell.cells[oid].neigh_ghosts[cc] ;
695  bitdim ghost=ocell.cells[oid].neigh_ghosts_dim[cc], ghostdir=ocell.cells[oid].neigh_ghosts_dir[cc] ;
696 
697  /*if (LE_displacement && ocell.cells[oid].neigh_ghosts_dim[cc]&1) // This is a ghost cell through a lees-edward => UNTESTED FOR OCTREE TODO
698  {
699  int newc2 = c2-floor(LE_displacement*(ocell.cells[oid].neigh_ghosts_dir[cc]&1?-1:1)/ocell.delta[1]) * ocell.cum_n_cell[1] ;
700  c2 = clip_LEmoved_cell(c2, newc2, ghost, ghostdir) ;
701  }*/
702 
703  contacts_cell_ghostcell(ID, cells[c], ocell.cells[c2], ghost, ghostdir, CLp_it, CLnew, X, r, LE_displacement, tmpcp) ;
704  }
705 
706  for (size_t cc=0 ; cc<ocell.cells[oid].neigh_ghosts_full.size() ; cc++)
707  {
708  int c2 = ocell.cells[oid].neigh_ghosts_full[cc] ;
709  bitdim ghost=ocell.cells[oid].neigh_ghosts_full_dim[cc], ghostdir=ocell.cells[oid].neigh_ghosts_full_dir[cc] ;
710 
711  /*if (LE_displacement && ocell.cells[oid].neigh_ghosts_dim[cc]&1) // This is a ghost cell through a lees-edward => UNTESTED FOR OCTREE TODO
712  {
713  int newc2 = c2-floor(LE_displacement*(ocell.cells[oid].neigh_ghosts_dir[cc]&1?-1:1)/ocell.delta[1]) * ocell.cum_n_cell[1] ;
714  c2 = clip_LEmoved_cell(c2, newc2, ghost, ghostdir) ;
715  }*/
716 
717  contacts_cell_ghostcell(ID, cells[c], ocell.cells[c2], ghost, ghostdir, CLp_it, CLnew, X, r, LE_displacement, tmpcp) ;
718  }
719  }
720  return 0 ;
721 }
722 
723 //====================================================
724 /*template <int d>
725 int Cells<d>::contacts_hierarchy_below (Cells<d> &ocell, int delta_lvl, std::pair<int,int> bounds, ContactList<d> & CLall, ContactList<d> & CLnew, std::vector<std::vector<double>> const & X, std::vector<double> const &r, double LE_displacement)
726 {
727  auto [cell_first, cell_last] = bounds ;
728  cp<d> tmpcp(0,0,0,nullptr) ; tmpcp.persisting = true ;
729  double sum=0 ;
730  int ncontact=0 ;
731  for (int c=cell_first ; c<cell_last ; c++)
732  {
733  if (cells[c].incell.size()==0) continue ;
734 
735  auto xloc = id2x(c) ;
736  for (auto &v:xloc) v /= pow(2, delta_lvl) ;
737  int oid = ocell.x2id(xloc) ;
738 
739  // Outer cell contact
740  if (c==170 && oid==1) printf("Checking L1-170 against L0-1") ;
741  for (size_t ii=0 ; ii<cells[c].incell.size() ; ii++)
742  for (size_t jj=0 ; jj<ocell.cells[oid].incell.size() ; jj++)
743  {
744  sum = 0 ;
745  int i = cells[c].incell[ii] ;
746  int j = ocell.cells[oid].incell[jj] ;
747  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
748  sum+= (X[i][k]-X[j][k])*(X[i][k]-X[j][k]) ;
749  if (sum<(r[i]+r[j])*(r[i]+r[j]))
750  {
751  ncontact++ ;
752  if (i<j) {tmpcp.i = i ; tmpcp.j=j ;}
753  else { tmpcp.i = j ; tmpcp.j=i ;}
754  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=0 ; tmpcp.ghostdir=0 ;
755  if (!CLall.insert_cell(tmpcp)) CLnew.v.push_back(tmpcp) ;
756  }
757  }
758 
759  //Outer cell neighbours contacts
760  for (size_t cc=0 ; cc<ocell.cells[oid].neighbours.size() ; cc++)
761  {
762  int c2 = ocell.cells[oid].neighbours[cc] ;
763  if (c==194 && c2==1) printf("Checking L1-194 against L0-1") ;
764  for (size_t ii=0 ; ii<cells[c].incell.size() ; ii++)
765  for (size_t jj=0 ; jj<ocell.cells[c2].incell.size() ; jj++)
766  {
767  sum = 0 ;
768  int i = cells[c].incell[ii] ;
769  int j = ocell.cells[c2].incell[jj] ;
770  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
771  sum+= (X[i][k]-X[j][k])*(X[i][k]-X[j][k]) ;
772  if (sum<(r[i]+r[j])*(r[i]+r[j]))
773  {
774  ncontact++ ;
775  if (i<j) {tmpcp.i = i ; tmpcp.j=j ;}
776  else { tmpcp.i = j ; tmpcp.j=i ;}
777  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=0 ; tmpcp.ghostdir=0 ;
778  if (!CLall.insert_cell(tmpcp)) CLnew.v.push_back(tmpcp) ;
779  }
780  }
781  }
782 
783  //outer cell ghost contacts
784  for (size_t cc=0 ; cc<ocell.cells[oid].neigh_ghosts.size() ; cc++)
785  {
786  int c2 = ocell.cells[oid].neigh_ghosts[cc] ;
787  bitdim ghost=ocell.cells[oid].neigh_ghosts_dim[cc], ghostdir=ocell.cells[oid].neigh_ghosts_dir[cc] ;
788 
789  if (LE_displacement && ocell.cells[oid].neigh_ghosts_dim[cc]&1) // This is a ghost cell through a lees-edward => UNTESTED FOR OCTREE
790  {
791  int newc2 = c2-floor(LE_displacement*(ocell.cells[oid].neigh_ghosts_dir[cc]&1?-1:1)/ocell.delta[1]) * ocell.cum_n_cell[1] ;
792  c2 = clip_LEmoved_cell(c2, newc2, ghost, ghostdir) ;
793  }
794 
795  for (size_t ii=0 ; ii<cells[c].incell.size() ; ii++)
796  for (size_t jj=0 ; jj<ocell.cells[c2].incell.size() ; jj++)
797  {
798  double sum = 0 ;
799  int i = cells[c].incell[ii] ;
800  int j = ocell.cells[c2].incell[jj] ;
801  for (int k=0 ; sum<(r[i]+r[j])*(r[i]+r[j]) && k<d ; k++)
802  {
803  double additionaldelta=0 ;
804  if (k==1 && ghost&1)
805  additionaldelta = LE_displacement * (ghostdir&1?-1:1) ;
806  sum+= pow(( X[i][k]-X[j][k] - Delta[k]*(ghost>>k & 1)*((ghostdir>>k & 1)?-1:1) - additionaldelta),2) ;
807  }
808 
809  if (sum<(r[i]+r[j])*(r[i]+r[j]))
810  {
811  //printf(".\n") ; fflush(stdout) ;
812  ncontact++ ;
813  if (i<j) {tmpcp.i = i ; tmpcp.j=j ; tmpcp.ghostdir = ghostdir ;}
814  else { tmpcp.i = j ; tmpcp.j=i ; tmpcp.ghostdir = (~ghostdir)&ghost ;}
815  tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=ghost ;
816  if (!CLall.insert_cell(tmpcp)) CLnew.v.push_back(tmpcp) ;
817  }
818  }
819  }
820  }
821  return 0 ;
822 }*/
823 
824 #endif
825 //===========================================================
826 /*int main(int argc, char * argv[])
827 {
828  for (int i=0 ; i<4 ; i++)
829  for (int j=0 ; j<4 ; j++)
830  for (int k=0 ; k<4 ; k++)
831  {
832  long long id = hilbertDistance({i,j,k}, 4) ;
833  printf("%d %d %d | %lld \n", i,j,k, id) ;
834  }
835 
836 
837 
838  std::vector<std::vector<double>> bounds ;
839  for (int dd=0 ; dd<D ; dd++)
840  bounds.push_back({0,1}) ;
841  double ds = 1/8. ;
842 
843  boost::random::mt19937 rng(865);
844  boost::random::uniform_01<boost::mt19937> rand(rng) ;
845  auto start = std::chrono::high_resolution_clock::now();
846  auto elapsed = std::chrono::high_resolution_clock::now()-start;
847  auto duration= std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() ;
848 
849  std::vector<std::vector<double>> X (N, std::vector<double>(D,0)) ;
850  for (auto & v : X)
851  for (auto & w: v)
852  w = rand() ;
853 
854  double Dbase = 0.05 ; double Dsqr=Dbase*Dbase;
855  int count=0 ;
856 
857  //-----------------------------------------------------------
858  Cells<D> allcells;
859  start = std::chrono::high_resolution_clock::now();
860  allcells.init_cells(bounds, ds) ;
861  elapsed = std::chrono::high_resolution_clock::now()-start;
862  duration= std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() ;
863  printf("INIT duration: %g\n", duration/1000000.) ;
864  allcells.test_idempotent() ;
865  printf("INITIALISATION FINISHED\n") ; fflush(stdout) ;
866 
867 
868  //------------------------------------------------------------
869  start = std::chrono::high_resolution_clock::now();
870  count = 0;
871  allcells.allocate_to_cells(X) ;
872  count = allcells.check_contact(X, Dsqr) ;
873  elapsed = std::chrono::high_resolution_clock::now()-start;
874  duration= std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() ;
875  printf("CNT cells: %g %d\n", duration/1000000., count) ;
876 
877 
878  //------------------------------------------------------------
879  start = std::chrono::high_resolution_clock::now();
880  count =0 ;
881  for (int i=0 ; i<N ; i++)
882  for (int j=i+1 ; j<N ; j++)
883  {
884  double dst = allcells.dsqr(X[i], X[j]) ;
885  if (dst < Dsqr)
886  count ++ ;
887  }
888  elapsed = std::chrono::high_resolution_clock::now()-start;
889  duration= std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() ;
890  printf("CNT normal: %g %d\n", duration/1000000., count) ;
891 
892 
893 }*/
894 
895 
896 
897 
898 
899 
900 
901 
902 
903 
904 
905 
906 
907 
#define CEREAL_NVP(T)
Creates a name value pair for the variable T with the same name as the variable.
Definition: cereal.hpp:72
Definition: Boundaries.h:8
Individual cell for contact detection.
Definition: Cells.h:19
std::vector< int > neigh_ghosts
list of the ghost cells through the PBC
Definition: Cells.h:23
void serialize(Archive &ar)
Definition: Cells.h:33
std::vector< bitdim > neigh_ghosts_dir
Ghost cell directions going through PBC (1 is negative delta)
Definition: Cells.h:25
std::vector< int > incell
list of particles in the cell
Definition: Cells.h:21
std::vector< int > neighbours
list of cell neighbours to the current cell
Definition: Cells.h:22
std::vector< int > neighbours_full
list of cell neighbours to the current cell
Definition: Cells.h:27
std::vector< int > neigh_ghosts_full
list of the ghost cells through the PBC
Definition: Cells.h:28
std::vector< bitdim > neigh_ghosts_full_dim
Ghost cell dimensions going through PBC.
Definition: Cells.h:29
std::vector< bitdim > neigh_ghosts_full_dir
Ghost cell directions going through PBC (1 is negative delta)
Definition: Cells.h:30
std::vector< bitdim > neigh_ghosts_dim
Ghost cell dimensions going through PBC.
Definition: Cells.h:24
All the cells making the space, with related function for creating the cell array,...
Definition: Cells.h:44
std::vector< double > origin
Definition: Cells.h:139
int contacts_external(int ID, Cells< d > &ocell, int delta_lvl, std::pair< int, int > bounds, CLp_it_t< d > &CLp_it, ContactList< d > &CLnew, std::vector< std::vector< double >> const &X, std::vector< double > const &r, double LE_displacement)
Definition: Cells.h:669
int init_allocate()
Definition: Cells.h:254
int clear_all()
Definition: Cells.h:455
int init_finalise(std::vector< Boundary< d >> &bounds)
Definition: Cells.h:263
int contacts(int ID, std::pair< int, int > bounds, CLp_it_t< d > &CLp_it, ContactList< d > &CLnew, std::vector< std::vector< double >> const &X, std::vector< double > const &r, double LE_displacement)
Definition: Cells.h:482
int contacts_cell_ghostcell(int ID, Cell &c1, Cell &c2, bitdim ghost, bitdim ghostdir, CLp_it_t< d > &CLp_it, ContactList< d > &CLnew, std::vector< std::vector< double >> const &X, std::vector< double > const &r, double LE_displacement, cp< d > &tmpcp)
Definition: Cells.h:640
int allocate_single(std::vector< double > &X, int grainid)
Definition: Cells.h:464
int init_subcells(std::vector< Boundary< d >> &bounds, double delta_super[], const std::vector< int > &n_cell_super)
Definition: Cells.h:222
int allocate_to_cells(std::vector< std::vector< double >> &X)
Definition: Cells.h:432
int planesize
Definition: Cells.h:143
int init_cells(std::vector< Boundary< d >> &boundaries, std::vector< double > &r)
Definition: Cells.h:47
double delta[d]
Definition: Cells.h:142
int contacts_cell_cell(int ID, Cell &c1, Cell &c2, CLp_it_t< d > &CLp_it, ContactList< d > &CLnew, std::vector< std::vector< double >> const &X, std::vector< double > const &r, cp< d > &tmpcp)
Definition: Cells.h:615
int clip_LEmoved_cell(int original, int considered, bitdim &ghost, bitdim &ghostdir)
Definition: Cells.h:110
std::vector< int > id2x(int id)
Definition: Cells.h:78
void serialize(Archive &ar)
Definition: Cells.h:146
double dsqr(std::vector< double > &X1, std::vector< double > &X2)
Definition: Cells.h:102
std::vector< Cell > cells
Definition: Cells.h:141
std::vector< int > n_cell
Definition: Cells.h:138
std::vector< double > Delta
Definition: Cells.h:140
int x2id(const std::vector< int > &v)
Definition: Cells.h:67
std::vector< int > cum_n_cell
Definition: Cells.h:138
std::vector< std::vector< double > > boundary_handler(std::vector< Boundary< d >> &boundaries)
Definition: Cells.h:165
int init_cells(std::vector< Boundary< d >> &boundaries, double ds)
Definition: Cells.h:236
bool cell_contact_insert(int ID, CLp_it_t< d > &CLp_it, const cp< d > &a)
Definition: Cells.h:595
bool test_idempotent()
Definition: Cells.h:89
Handles lists of contacts.
Definition: ContactList.h:208
list< cp< d > > v
Contains the list of contact.
Definition: ContactList.h:277
Contact properties class.
Definition: ContactList.h:69
double contactlength
Length of the contact.
Definition: ContactList.h:115
int j
Index of second contacting particle or wall. If this is a wall contact, j=2*walldimension + (0 or 1 i...
Definition: ContactList.h:114
bool persisting
True if the contact is still maintained for the current ts.
Definition: ContactList.h:121
int i
Index of contacting particle.
Definition: ContactList.h:113
uint32_t ghost
Contain ghost information about ghost contact, cf detailed description.
Definition: ContactList.h:116
uint32_t ghostdir
Contain ghost information about ghost direction, cf detailed description.
Definition: ContactList.h:117
Definition: ternary.h:5
void set_quat_bit(int n)
Definition: ternary.h:91
unsigned int bitdim
Definition: Typedefs.h:17
@ ROTATINGSPHERE
uint d
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1181
PUGI_IMPL_FN void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7707
PUGI_IMPL_FN I unique(I begin, I end)
Definition: pugixml.cpp:7621
Type
Type of JSON value.
Definition: rapidjson.h:644
Simple packing structure for the iterators to the contact list regions per particle.
Definition: Multiproc.h:23
std::vector< typename list< cp< d > >::iterator > it_array_beg
Contains iterator related to each particle contacts.
Definition: Multiproc.h:49
ContactList< d > null_list
Empty list, effectively providing a null iterator.
Definition: Multiproc.h:51
std::vector< typename list< cp< d > >::iterator > it_ends
Definition: Multiproc.h:50