NDDEM
DEMND.h
Go to the documentation of this file.
1 #include <cstdlib>
2 #include <cmath>
3 #include <cstdio>
4 #include <vector>
5 #include <ctime>
6 #include <cstring>
7 
8 #include <random>
9 #ifndef NO_OPENMP
10  #include <omp.h>
11 #endif
12 
13 #include "cereal/types/vector.hpp"
14 #include "cereal/types/chrono.hpp"
16 #include "cereal/types/utility.hpp"
17 #include "cereal/types/string.hpp"
18 #include "cereal/types/map.hpp"
19 #include "cereal/types/list.hpp"
21 #include "cereal/archives/xml.hpp"
22 
23 //#include "callgrind.h"
24 //#include <ittnotify.h>
25 
26 #include "Typedefs.h"
27 #include "Parameters.h"
28 #include "Contacts.h"
29 #include "ContactList.h"
30 #include "Multiproc.h"
31 #include "Cells.h"
32 #include "Octree.h"
33 #include "Boundaries.h"
34 #ifdef EMSCRIPTEN
35  #include <emscripten.h>
36  #include <emscripten/bind.h>
37 
38  #ifndef JS_CONVERT_ARRAYS
39  #define JS_CONVERT_ARRAYS
40  using namespace emscripten;
41  using Vector2Djs = emscripten::val ;
42  using Vector1Djs = emscripten::val ;
43 
44  template <typename T>
45  emscripten::val to_js_array(const std::vector<std::vector<T>>& data) {
46  using namespace emscripten;
47  val outer = val::array();
48  for (size_t i = 0; i < data.size(); ++i) {
49  val inner = val::array();
50  for (size_t j = 0; j < data[i].size(); ++j) {
51  inner.set(j, data[i][j]);
52  }
53  outer.set(i, inner);
54  }
55  return outer;
56  }
57  template <typename T>
58  emscripten::val to_js_array(const std::vector<T>& data) {
59  using namespace emscripten;
60  val outer = val::array();
61  for (size_t i = 0; i < data.size(); ++i) {
62  outer.set(i, data[i]);
63  }
64  return outer;
65  }
66 
67  std::vector<double> from_js_array(emscripten::val jsArray) {
68  std::vector<double> vec;
69  size_t length = jsArray["length"].as<unsigned>();
70  vec.reserve(length);
71  for (unsigned i = 0; i < length; ++i) {
72  vec.push_back(jsArray[i].as<double>());
73  }
74  return vec;
75 }
76  #endif
77 #else
78  using Vector2Djs = std::vector<std::vector<double>> ;
79  using Vector1Djs = std::vector<double> ;
80  template <typename T> std::vector<std::vector<T>> to_js_array(std::vector<std::vector<T>>& data) {return data ; }
81  template <typename T> std::vector<T> to_js_array(std::vector<T>& data) {return data ; }
82  template <typename T> std::vector<T> from_js_array(std::vector<T>& data) {return data ; }
83 #endif
84 
111 extern vector <std::pair<ExportType,ExportData>> * toclean ;
112 extern XMLWriter * xmlout ;
113 
114 
115 template <int d>
116 class Simulation {
117 public:
119  int N ;
120  std::vector < std::vector <double> > X ;
121  std::vector < std::vector <double> > V ;
122  std::vector < std::vector <double> > A ;
123  std::vector < std::vector <double> > Omega ;
124  std::vector < std::vector <double> > F ;
125  std::vector < std::vector <double> > FOld ;
126  std::vector < std::vector <double> > Torque ;
127  std::vector < std::vector <double> > TorqueOld ;
128  std::vector < double > Vmag ;
129  std::vector < double > OmegaMag ;
130  std::vector < double > Z ;
131  std::vector < std::vector <double> > Fcorr ;
132  std::vector < std::vector <double> > TorqueCorr ;
133 
134  std::vector < std::optional<int> > RigidBodyId ;
135 
136  std::vector <SpecificAction<d>> ExternalAction ;
137 
138  std::vector <uint32_t> PBCFlags ;
139  std::vector < std::vector <double> > WallForce ;
140  std::vector<std::vector<double>> empty_array ;
141  std::vector < std::vector <double> > ParticleForce ;
142 
143  vector <uint32_t> Ghost ;
144  vector <uint32_t> Ghost_dir ;
146 
147  int numthread=1 ;
151 
152  double t ; int ti ;
153  double dt ;
154  clock_t tnow, tprevious ;
155 
156  //-----------------------------------------
157  void save_restart(const std::string &filename) {
158  std::ofstream os(filename, std::ios::binary);
159  cereal::BinaryOutputArchive archive(os);
160  //std::ofstream os(filename);
161  //cereal::XMLOutputArchive archive(os);
162  archive(*this);
163  }
164  void load_restart(const std::string &filename) {
165  std::ifstream os(filename, std::ios::binary);
166  std::cout << "FILEOPEN:" << filename << " " << os.is_open() << "\n" ; fflush(stdout) ;
167  cereal::BinaryInputArchive archive(os);
168  //std::ifstream os(filename);
169  //cereal::XMLInputArchive archive(os);
170  archive(*this);
171 
172  #ifndef NO_OPENMP
173  const char* env_p = std::getenv("OMP_NUM_THREADS") ;
174  if (env_p!=nullptr) numthread = atoi (env_p) ;
175  omp_set_num_threads(numthread) ;
176  #endif
177 
178  MP.C.resize(MP.P, Contacts<d>(P)) ; // Empty default contacts are not saved. Need to rebuild them.
179 
180  // Iterators are invalidated when saving, need to rebuild them
182  {
183  MP.CLp_it.init(P.N, MP.P) ;
184  MP.CLp_it.rebuild(MP.CLp) ;
185  }
186 
187  toclean = &(P.dumps) ;
188  xmlout = P.xmlout ;
189  }
190 
191  template <class Archive>
192  void serialize( Archive & ar )
193  {
194  ar(N,
195  CEREAL_NVP(X), V, A, Omega, F, FOld, Torque, TorqueOld, Vmag, OmegaMag, Z, Fcorr, TorqueCorr, RigidBodyId,
196  PBCFlags, WallForce, empty_array, ParticleForce, Ghost, Ghost_dir, Atmp,
197  numthread, t, ti, dt, tnow, tprevious,
198  P, MP, cells, ExternalAction, octree
199  );
200  }
201  //-----------------------------------------
202 
203  //==========================================================
204  Simulation(int NN) {
205  P = Parameters<d>(NN) ;
207  if (!Tools<d>::check_initialised(d)) printf("ERR: Something terribly wrong happened\n") ;
208  assert(d<(static_cast<int>(sizeof(int))*8-1)) ; //TODO
209  // Array initialisations
210  N=P.N ;
211  X.resize(N, std::vector <double> (d, 0)) ;
212  // X[0][0] = 123;
213  V.resize(N, std::vector <double> (d, 0)) ;
214  A.resize(N, std::vector <double> (d*d, 0)) ; for (int i=0 ; i<N ; i++) A[i]=Tools<d>::Eye ;
215  Omega.resize(N, std::vector <double> (d*(d-1)/2, 0)) ; //Rotational velocity matrix (antisymetrical)
216  F.resize(N, std::vector <double> (d, 0)) ;
217  FOld.resize(N, std::vector <double> (d, 0)) ;
218  Torque.resize(N, std::vector <double> (d*(d-1)/2, 0)) ;
219  TorqueOld.resize(N, std::vector <double> (d*(d-1)/2, 0)) ;
220 
221  Vmag.resize (N,0) ;
222  OmegaMag.resize (N,0) ;
223  Z.resize (N,0) ;
224  Fcorr.resize (N, std::vector <double> (d, 0)) ;
225  TorqueCorr.resize (N, std::vector <double> (d*(d-1)/2, 0)) ;
226  RigidBodyId.resize(N,{}) ;
227 
228  PBCFlags.resize (N, 0) ;
229  WallForce.resize (2*d, std::vector <double> (d,0)) ;
230  empty_array.resize(1, std::vector <double> (1, 0)) ;
231 
232  Ghost.resize (N, 0) ;
233  Ghost_dir.resize (N, 0) ;
234 
235  Atmp.resize (d*d, 0) ;
236 
237  // Initial state setup
238  P.set_boundaries() ;
239  }
240  //-------------------------------------------------------------------------
243  void init_from_file (char filename[])
244  {
245  P.load_datafile (filename, X, V, Omega) ;
246  }
247  //-------------------------------------------------------------------------
252  void finalise_init () {
253  //if (strcmp(argv[3], "default"))
254  // P.load_datafile (argv[3], X, V, Omega) ;
255 
256  for (auto v : P.dumps)
257  if (v.first==ExportType::XML || v.first==ExportType::XMLbase64)
258  P.xmlout= new XMLWriter(P.Directory+"/dump.xml") ;
259  toclean = &(P.dumps) ;
260  xmlout = P.xmlout ;
261 
262  P.RigidBodies.allocate (RigidBodyId) ;
263 
264  #ifndef NO_OPENMP
265  const char* env_p = std::getenv("OMP_NUM_THREADS") ;
266  if (env_p!=nullptr) numthread = atoi (env_p) ;
267  omp_set_num_threads(numthread) ;
268  #endif
269 
270  MP.initialise(N, numthread, P) ;
271 
273  {
274  printf("INITIALISE CELLS\n") ; fflush(stdout) ;
275  auto rmax = std::max_element(P.r.begin(), P.r.end()) ;
276  printf("%g ", *rmax) ;
277  cells.init_cells(P.Boundaries, P.cellsize==-1?(*rmax*2.1):P.cellsize) ;
278  MP.splitcells(cells.cells.size()) ;
279  MP.CLp_it.init(N, numthread) ;
280  }
282  {
283  printf("INITIALISE OCTREE\n") ; fflush(stdout) ;
284  octree.init_cells(P.Boundaries, P.r) ;
285  MP.splitcells(octree.cells_to_split()) ;
286  MP.CLp_it.init(N, numthread) ;
287  }
288 
289  dt=P.dt ;
290  t=0 ; ti=0 ;
291  tprevious=clock() ;
292  printf("[INFO] Orientation tracking is %s\n", P.orientationtracking?"True":"False") ;
293  }
294  //-------------------------------------------------------------------
299  void interpret_command (string in)
300  {
301  P.interpret_command(in, X,V,Omega) ;
302  }
303  //--------------------------------------------------------------------
308  {
309  int nsteps = P.T/dt ;
310  step_forward(nsteps) ;
311  }
312  //----
317  void step_forward (int nt)
318  {
319  for (int ntt=0 ; ntt<nt ; ntt++, t+=dt, ti++)
320  {
321  //if (ntt==990) {CALLGRIND_START_INSTRUMENTATION ;}
322 
323  // printf("UP TO TIME: %g with timestep: %g\n", t, dt);
324  // printf("%g %g %g\n", X[0][0],X[0][1],X[0][2]);
325  bool isdumptime = (ntt==nt-1) || (ti % P.tdump==0) ;
326  //P.display_info(ti, V, Omega, F, Torque, 0, 0) ;
327  if (ti%P.tinfo==0)
328  {
329  tnow = clock();
330  printf("\r%10g | %5.2g%% | %d iterations in %10gs | %5d | finish in %10gs",t, t/P.T*100, P.tinfo,
331  double(tnow - tprevious) / CLOCKS_PER_SEC, ti, ((P.T-t)/(P.tinfo*dt))*(double(tnow - tprevious) / CLOCKS_PER_SEC)) ;
332  //fprintf(logfile, "%d %10g %lu %lu\n", ti, double(tnow - tprevious) / CLOCKS_PER_SEC, MP.CLp[0].v.size(), MP.CLw[0].v.size()) ;
333  fflush(stdout) ;
334  tprevious=tnow ;
335  }
336 
337  //----- Velocity Verlet step 1 : compute the new positions
338  #pragma omp parallel for default(none) shared (N) shared(X) shared(P) shared(V) shared(FOld) shared(Omega) shared(PBCFlags) shared(dt) shared(Ghost) shared(Ghost_dir) shared(A)
339  for (int i=0 ; i<N ; i++)
340  {
341  double disp, totdisp=0 ;
342  for (int dd=0 ; dd<d ; dd++)
343  {
344  disp = V[i][dd]*dt + FOld[i][dd] * (dt * dt / P.m[i] /2.) ;
345  X[i][dd] += disp ;
346  totdisp += disp*disp ;
347  }
348  //displacement[i] += sqrt(totdisp) ;
349  //if (displacement[i] > maxdisp[0]) {maxdisp[1]=maxdisp[0] ; maxdisp[0]=displacement[i] ; } // ERROR RACE CONDITION ON MAXDISP
350 
351  // Simpler version to make A evolve (Euler, doesn't need to be accurate actually, A is never used for the dynamics), and Gram-Shmidt orthonormalising after ...
352  if (P.orientationtracking)
353  {
354  v1d tmpO (d*d,0), tmpterm1 (d*d,0) ;
355  Tools<d>::skewexpand(tmpO, Omega[i]) ;
356  Tools<d>::matmult(tmpterm1, tmpO, A[i]) ;
357  for (int dd=0 ; dd<d*d ; dd++)
358  A[i][dd] -= tmpterm1[dd] * dt ;
360  }
361 
362  // Boundary conditions ...
363  P.perform_PBC(X[i], PBCFlags[i]) ;
364  P.perform_PBCLE(X[i], V[i], PBCFlags[i]) ;
365 
366  // Find ghosts
367  Ghost[i]=0 ; Ghost_dir[i]=0 ;
368  uint32_t mask=1 ;
369 
370  for (size_t j=0 ; j<P.Boundaries.size() ; j++, mask<<=1)
371  {
372  if (!P.Boundaries[j].is_periodic()) continue ;
373  if (X[i][j] <= P.Boundaries[j].xmin + P.r[i]) {Ghost[i] |= mask ; }
374  else if (X[i][j] >= P.Boundaries[j].xmax - P.r[i]) {Ghost[i] |= mask ; Ghost_dir[i] |= mask ;}
375  }
376 
377  if (P.Boundaries[0].Type == WallType::PBC_LE && (Ghost[i]&1)) // We need to consider the case where we have a ghost through the LE_PBC
378  {
379  mask = (1<<30) ; // WARNING dim 30 will be used for LEPBC!!
380  double tmpyloc = X[i][1] + (Ghost_dir[i]&1?-1:1)*P.Boundaries[0].displacement ;
381  if (tmpyloc > P.Boundaries[1].xmax) tmpyloc -= P.Boundaries[1].delta ;
382  if (tmpyloc < P.Boundaries[1].xmin) tmpyloc += P.Boundaries[1].delta ;
383  if (tmpyloc <= P.Boundaries[1].xmin + P.r[i]) {Ghost[i] |= mask ; }
384  else if (tmpyloc >= P.Boundaries[1].xmax - P.r[i]) {Ghost[i] |= mask ; Ghost_dir[i] |= mask ;}
385 
386  }
387 
388  if (P.forceinsphere)
389  P.perform_forceinsphere(X[i]) ;
390 
391  //Nghosts=Ghosts.size() ;
392  } // END PARALLEL SECTION
393 
394  P.perform_MOVINGWALL() ;
395  P.perform_PBCLE_move() ;
396  std::invoke (P.update_gravity, &P, dt) ;
399 
400  // ----- Contact detection ------
401  double LE_displacement ;
402  if (P.Boundaries[0].Type == WallType::PBC_LE)
403  LE_displacement = P.Boundaries[0].displacement ;
404  else
405  LE_displacement = 0 ;
406 
407  for (int i=0 ; i<MP.P ; i++)
408  MP.CLp_it.it_ends[i] = MP.CLp[i].v.end() ;
409 
410  #pragma omp parallel default(none) shared(MP) shared(P) shared(N) shared(X) shared(Ghost) shared(Ghost_dir) shared(RigidBodyId) shared (stdout) shared(cells) shared(LE_displacement)
411  {
412  #ifdef NO_OPENMP
413  int ID = 0 ;
414  #else
415  int ID = omp_get_thread_num();
416  double timebeg = omp_get_wtime();
417  #endif
418  cpm<d> tmpcpm(0,0,0,0,nullptr) ;
419  cp<d> tmpcp(0,0,0,nullptr) ; double sum=0 ;
420 
421  ContactList<d> & CLw = MP.CLw[ID] ; ContactListMesh<d> & CLm = MP.CLm[ID] ;
422  CLw.reset(); CLm.reset() ;
423 
425  {
426  cells.contacts(ID, {MP.sharecell[ID], MP.sharecell[ID+1]}, MP.CLp_it, MP.CLp_new[ID], X, P.r, LE_displacement) ;
427  }
429  {
430  octree.contacts(ID, {MP.sharecell[ID], MP.sharecell[ID+1]}, MP.CLp_it, MP.CLp_new[ID], X, P.r, LE_displacement) ;
431  }
432  else
433  {
434  ContactList<d> & CLp = MP.CLp[ID] ;
435  CLp.reset() ;
436 
437  for (int i=MP.share[ID] ; i<MP.share[ID+1] ; i++)
438  {
439  // Contact detection between particles
440  tmpcp.setinfo(CLp.default_action());
441  tmpcp.i=i ;
442  for (int j=i+1 ; j<N ; j++) // Regular particles
443  {
444 
445  if (RigidBodyId[i].has_value() && RigidBodyId[j].has_value() && RigidBodyId[i]==RigidBodyId[j]) continue ;
446  if (Ghost[j] | Ghost[i])
447  {
448  tmpcp.j=j ; tmpcp.ghostdir=Ghost_dir[j] | (Ghost[i]&(~Ghost_dir[i])) ;
449  bitdim tmpghost = Ghost[j] | Ghost[i] ;
450  if (P.Boundaries[0].Type == WallType::PBC_LE && (Ghost[i]&1))
451  {
452  double tmpyloc = X[j][1] + (tmpcp.ghostdir&1?-1:1)*P.Boundaries[0].displacement ;
453  if (tmpyloc > P.Boundaries[1].xmax) tmpyloc -= P.Boundaries[1].delta ;
454  if (tmpyloc < P.Boundaries[1].xmin) tmpyloc += P.Boundaries[1].delta ;
455  if (tmpyloc <= P.Boundaries[1].xmin + P.r[i]) {tmpghost |= (1<<30) ; }
456  else if (tmpyloc >= P.Boundaries[1].xmax - P.r[i]) {tmpghost |= (1<<30) ; tmpcp.ghostdir |= (1<<30) ;}
457  }
458 
459  //CLp.check_ghost (Ghost[j], P, X[i], X[j], tmpcp) ;
460  (CLp.*CLp.check_ghost) (tmpghost, P, X[i], X[j], P.r[i], P.r[j], tmpcp, 0,0,0) ;
461  }
462  else
463  {
464  sum=0 ;
465  for (int k=0 ; sum<(P.r[i]+P.r[j])*(P.r[i]+P.r[j]) && k<d ; k++) sum+= (X[i][k]-X[j][k])*(X[i][k]-X[j][k]) ;
466  if (sum<(P.r[i]+P.r[j])*(P.r[i]+P.r[j]))
467  {
468  tmpcp.j=j ; tmpcp.contactlength=sqrt(sum) ; tmpcp.ghost=0 ; tmpcp.ghostdir=0 ;
469  CLp.insert(tmpcp) ;
470  }
471  }
472  }
473  }
474  CLp.finalise() ;
475  }
476 
477  for (int i=MP.share[ID] ; i<MP.share[ID+1] ; i++)
478  {
479  // Contact detection between particles and walls
480  tmpcp.setinfo(CLw.default_action());
481  tmpcp.i=i ; tmpcp.ghost=0 ;
482  for (size_t j=0 ; j<P.Boundaries.size() ; j++) // Wall contacts
483  {
484  if (P.Boundaries[j].Type==WallType::PBC) continue ;
485 
486  if (P.Boundaries[j].Type==WallType::WALL || P.Boundaries[j].Type==WallType::MOVINGWALL)
487  {
488  tmpcp.contactlength=fabs(X[i][j]-P.Boundaries[j].xmin) ;
489  if (tmpcp.contactlength<P.r[i])
490  {
491  tmpcp.j=(2*j+0);
492  CLw.insert(tmpcp) ;
493  }
494 
495  tmpcp.contactlength=fabs(X[i][j]-P.Boundaries[j].xmax) ;
496  if (tmpcp.contactlength<P.r[i])
497  {
498  tmpcp.j=(2*j+1);
499  CLw.insert(tmpcp) ;
500  }
501  }
502  else if (P.Boundaries[j].Type==WallType::SPHERE ||
503  P.Boundaries[j].Type==WallType::HEMISPHERE ||
505  {
506  tmpcp.contactlength=0 ;
507  for (int dd=0 ; dd<d ; dd++)
508  tmpcp.contactlength += (P.Boundaries[j].center[dd] - X[i][dd])*(P.Boundaries[j].center[dd] - X[i][dd]) ;
509 
510  if (tmpcp.contactlength < (P.Boundaries[j].radius + P.r[i])*(P.Boundaries[j].radius + P.r[i]) &&
511  tmpcp.contactlength > (P.Boundaries[j].radius - P.r[i])*(P.Boundaries[j].radius - P.r[i]))
512  {
513  tmpcp.contactlength = sqrt(tmpcp.contactlength) - P.Boundaries[j].radius ;
514  if (tmpcp.contactlength < 0) tmpcp.j=2*j;
515  else tmpcp.j=2*j+1 ;
516  tmpcp.contactlength = fabs(tmpcp.contactlength) ;
517  CLw.insert(tmpcp) ;
518  }
519  }
520  else if (P.Boundaries[j].Type==WallType::AXIALCYLINDER)
521  {
522  tmpcp.contactlength=0 ;
523 
524  for (int dd=0 ; dd<d ; dd++)
525  {
526  if (dd == P.Boundaries[j].axis) continue ;
527  tmpcp.contactlength += (P.Boundaries[j].center[dd] - X[i][dd])*(P.Boundaries[j].center[dd] - X[i][dd]) ;
528  }
529  if (tmpcp.contactlength < (P.Boundaries[j].radius + P.r[i])*(P.Boundaries[j].radius + P.r[i]) &&
530  tmpcp.contactlength > (P.Boundaries[j].radius - P.r[i])*(P.Boundaries[j].radius - P.r[i]))
531  {
532  tmpcp.contactlength = sqrt(tmpcp.contactlength) - P.Boundaries[j].radius ;
533  if (tmpcp.contactlength < 0) tmpcp.j=2*j;
534  else tmpcp.j=2*j+1 ;
535  tmpcp.contactlength = fabs(tmpcp.contactlength) ;
536  CLw.insert(tmpcp) ;
537  }
538  }
539  else if (P.Boundaries[j].Type==WallType::ELLIPSE)
540  {
541  static_assert((sizeof(double)==8)) ;
542 
543  double tparam ;
544  std::tie(tparam, tmpcp.contactlength) = Tools_2D::contact_ellipse_disk (X[i], P.Boundaries[j].semiaxisx, P.Boundaries[j].semiaxisy, P.Boundaries[j].centerx, P.Boundaries[j].centery, P.graddesc_gamma, P.graddesc_tol) ;
545  if (tmpcp.contactlength<P.r[i])
546  {
547  tmpcp.j=2*j ;
548  #pragma GCC diagnostic push
549  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
550  tmpcp.ghost = *(reinterpret_cast<uint32_t*>(&tparam)) ;
551  tmpcp.ghostdir=*(reinterpret_cast<uint64_t*>(&tparam))>>32 ; //ugly bit punning, I'm so sorry...
552  #pragma GCC diagnostic pop
553  CLw.insert(tmpcp) ;
554  }
555  }
556  }
557 
558  // Contact detection between particles and meshes
559  tmpcpm.setinfo(CLm.default_action()) ;
560  tmpcpm.i=i ;
561  for (size_t j=0 ; j<P.Meshes.size() ; j++) //TODO Meshes incompatible with PBC
562  {
563  bool a= CLm.check_mesh_dst_contact(P.Meshes[j], X[i], P.r[i], tmpcpm) ;
564  //printf("%d %g %g |", a, tmpcpm.contactlength, P.skin) ;
565  if (a && tmpcpm.contactlength < P.r[i])
566  {
567  CLm.insert(tmpcpm) ;
568  }
569  }
570  }
571  CLw.finalise() ;
572  CLm.finalise() ;
573  #ifndef NO_OPENMP
574  MP.timing_contacts[ID] += omp_get_wtime()-timebeg;
575  #endif
576  } //END PARALLEL SECTION
577 
579  {
580  MP.merge_newcontacts() ;
581  for (int i=0 ; i<N ; i++)
582  MP.CLp_it.it_array_beg[i] = MP.CLp_it.null_list.v.begin() ;
583  }
584 
585  //-------------------------------------------------------------------------------
586  // Force and torque computation
587  Tools<d>::setzero(F) ; Tools<d>::setzero(Fcorr) ; Tools<d>::setzero(TorqueCorr) ;
588  Tools<d>::setgravity(F, P.g, P.m); // Actually set gravity is effectively also doing the setzero
589  Tools<d>::setzero(Torque);
590 
591  for (auto it = ExternalAction.begin() ; it<ExternalAction.end() ; /*KEEP EMPTY*/ )
592  {
593  Tools<d>::vAddFew(F[it->id], it->Fn, it->Ft, Fcorr[it->id]) ;
594  Tools<d>::vAddOne(Torque[it->id], it->Torquei, TorqueCorr[it->id]) ;
595 
596  it->duration -- ;
597  if (it->duration<=0)
598  ExternalAction.erase(it) ;
599  else
600  it++ ;
601  }
602 
603  //Particle - particle contacts
604  #pragma omp parallel default(none) shared(MP) shared(P) shared(X) shared(V) shared(Omega) shared(F) shared(Fcorr) shared(TorqueCorr) shared(Torque) shared(stdout) shared(isdumptime)
605  {
606  #ifdef NO_OPENMP
607  int ID = 0 ;
608  #else
609  int ID = omp_get_thread_num();
610  double timebeg = omp_get_wtime();
611  #endif
612  ContactList<d> & CLp = MP.CLp[ID] ; ContactList<d> & CLw = MP.CLw[ID] ; ContactListMesh<d> & CLm = MP.CLm[ID] ;
613  Contacts<d> & C =MP.C[ID] ;
614  v1d tmpcn (d,0) ; v1d tmpvel (d,0) ;
615 
616  // Particle-particle contacts
617  //printf("====%d %g=====\n", ti, P.Boundaries[0].displacement) ;
618  int curi = -1 ;
619  for (auto it = CLp.v.begin() ; it!=CLp.v.end() ; it++)
620  {
621  // We need to do some contact handling first. This should technically only be done for non-NAIVE contact detection, but it shouldn't hurt the NAIVE, and is a very mild slow down.
622  while (it != CLp.v.end() && !it->persisting)
623  it = CLp.v.erase(it) ;
624  if (it == CLp.v.end())
625  break ;
626 
627  if ( it->i != curi )
628  {
629  MP.CLp_it.it_array_beg[it->i] = it ;
630  curi = it->i ;
631  }
632 
633  // Proceed if the contact needs to be considered
634  if (it->ghost==0)
635  {
636  C.particle_particle(X[it->i], V[it->i], Omega[it->i], P.r[it->i], P.m[it->i],
637  X[it->j], V[it->j], Omega[it->j], P.r[it->j], P.m[it->j], *it, isdumptime) ;
638  }
639  else
640  {
641  // printf("%d\n", it->ghost) ; fflush(stdout) ;
642  (C.*C.particle_ghost) (X[it->i], V[it->i], Omega[it->i], P.r[it->i], P.m[it->i],
643  X[it->j], V[it->j], Omega[it->j], P.r[it->j], P.m[it->j], *it, isdumptime);//, logghosts) ;
644  }
645  if (isdumptime) it->saveinfo(C.Act) ;
646 
647  Tools<d>::vAddFew(F[it->i], C.Act.Fn, C.Act.Ft, Fcorr[it->i]) ;
648  Tools<d>::vAddOne(Torque[it->i], C.Act.Torquei, TorqueCorr[it->i]) ;
649 
650  if (MP.ismine(ID,it->j))
651  {
652  Tools<d>::vSubFew(F[it->j], C.Act.Fn, C.Act.Ft, Fcorr[it->j]) ;
653  Tools<d>::vAddOne(Torque[it->j], C.Act.Torquej, TorqueCorr[it->j]) ;
654  }
655  else
656  MP.delaying(ID, it->j, C.Act) ;
657 
658  it->persisting = false ;
659 
660  //Tools<d>::vAdd(F[it->i], Act.Fn, Act.Ft) ; Tools<d>::vSub(F[it->j], Act.Fn, Act.Ft) ; //F[it->i] += (Act.Fn + Act.Ft) ; F[it->j] -= (Act.Fn + Act.Ft) ;
661  //Torque[it->i] += Act.Torquei ; Torque[it->j] += Act.Torquej ;
662  }
663  //if (curi!= -1)
664  // MP.CLp_it.it_array_end[curi] = CLp.v.end() ;
665 
666  // Particle wall contacts
667  for (auto it = CLw.v.begin() ; it!=CLw.v.end() ; it++)
668  {
669  if (P.Boundaries[it->j/2].Type == WallType::SPHERE ||
670  P.Boundaries[it->j/2].Type == WallType::HEMISPHERE)
671  {
672  if ( P.Boundaries[it->j/2].Type == WallType::HEMISPHERE &&
673  X[it->i][P.Boundaries[it->j/2].axis]>P.Boundaries[it->j/2].center[P.Boundaries[it->j/2].axis]+P.r[it->i]) continue ;
674  for (int dd = 0 ; dd<d ; dd++)
675  tmpcn[dd] = (X[it->i][dd]-P.Boundaries[it->j/2].center[dd])*((it->j%2==0)?-1:1) ;
676  tmpcn/=Tools<d>::norm(tmpcn) ;
677  C.particle_wall( V[it->i],Omega[it->i],P.r[it->i], P.m[it->i], tmpcn, *it) ;
678  }
679  else if (P.Boundaries[it->j/2].Type == WallType::AXIALCYLINDER)
680  {
681  tmpcn[P.Boundaries[it->j/2].axis]= 0 ;
682  for (int dd = 0 ; dd<d ; dd++)
683  {
684  if (dd == P.Boundaries[it->j/2].axis) continue ;
685  tmpcn[dd] = (X[it->i][dd]-P.Boundaries[it->j/2].center[dd])*((it->j%2==0)?-1:1) ;
686  }
687  tmpcn/=Tools<d>::norm(tmpcn) ;
688  C.particle_wall( V[it->i],Omega[it->i],P.r[it->i], P.m[it->i], tmpcn, *it) ;
689  }
690  else if (P.Boundaries[it->j/2].Type == WallType::ROTATINGSPHERE)
691  {
692  for (int dd = 0 ; dd<d ; dd++)
693  tmpcn[dd] = (X[it->i][dd]-P.Boundaries[it->j/2].center[dd])*((it->j%2==0)?-1:1) ;
694  tmpcn/=Tools<d>::norm(tmpcn) ;
695  Tools<d>::surfacevelocity(tmpvel, X[it->i]+tmpcn*(-P.r[it->i]), &(P.Boundaries[it->j/2].center[0]) , nullptr, &(P.Boundaries[it->j/2].omega[0])) ;
696  //printf("%g | %g %g | %g %g | %g %g\n", P.Boundaries[it->j/2][4+2], (X[it->i]+tmpcn*(-P.r[it->i]))[0], (X[it->i]+tmpcn*(-P.r[it->i]))[1], P.Boundaries[it->j/2][4], P.Boundaries[it->j/2][5], tmpvel[0], tmpvel[1]) ; fflush(stdout) ;
697  C.particle_movingwall(V[it->i],Omega[it->i],P.r[it->i], P.m[it->i], tmpcn, tmpvel, *it) ;
698  }
699  else if (P.Boundaries[it->j/2].Type == WallType::ELLIPSE)
700  {
701  assert((d==2)) ;
702  std::vector<double> tmpcn(2) ;
703  #pragma GCC diagnostic push
704  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
705  uint64_t c=((uint64_t)(it->ghostdir) <<32 | (uint64_t)(it->ghost)) ;
706  double tparam = *reinterpret_cast<double*>(&c) ;
707  #pragma GCC diagnostic pop
708  tmpcn[0]=X[it->i][0]-(P.Boundaries[it->j/2].centerx+P.Boundaries[it->j/2].semiaxisx*cos(tparam)) ;
709  tmpcn[1]=X[it->i][1]-(P.Boundaries[it->j/2].centery+P.Boundaries[it->j/2].semiaxisy*sin(tparam)) ;
710  tmpcn/=sqrt(tmpcn[0]*tmpcn[0]+tmpcn[1]*tmpcn[1]);
711  C.particle_wall( V[it->i],Omega[it->i],P.r[it->i], P.m[it->i], tmpcn, *it) ;
712  }
713  else
714  {
715 
716  Tools<d>::unitvec(tmpcn, it->j/2) ;
717  tmpcn=tmpcn*(-((it->j%2==0)?-1:1)) ; // l give the orientation (+1 or -1)
718  C.particle_wall( V[it->i],Omega[it->i],P.r[it->i], P.m[it->i], tmpcn, *it) ;
719  }
720 
721  //Tools<d>::vAdd(F[it->i], Act.Fn, Act.Ft) ; // F[it->i] += (Act.Fn+Act.Ft) ;
722  //Torque[it->i] += Act.Torquei ;
723 
724  Tools<d>::vAddFew(F[it->i], C.Act.Fn, C.Act.Ft, Fcorr[it->i]) ;
725  Tools<d>::vAddOne(Torque[it->i], C.Act.Torquei, TorqueCorr[it->i]) ;
726 
727  if ( P.wallforcecompute || ( P.wallforcerequested && !P.wallforcecomputed ) ) MP.delayingwall(ID, it->j, C.Act) ;
728  }
729 
730  // Particle mesh contacts
731  for (auto it = CLm.v.begin() ; it != CLm.v.end() ; it++)
732  {
733  //printf("@ %g | %g %g %g | %d \n", it->contactlength, it->contactpoint[0], it->contactpoint[1], it->contactpoint[2], it->submeshid) ; fflush(stdout) ;
734  C.particle_mesh ( X[it->i], V[it->i], Omega[it->i], P.r[it->i], P.m[it->i], *it) ;
735 
736  Tools<d>::vAddFew(F[it->i], C.Act.Fn, C.Act.Ft, Fcorr[it->i]) ;
737  Tools<d>::vAddOne(Torque[it->i], C.Act.Torquei, TorqueCorr[it->i]) ;
738  }
739 
740  #ifndef NO_OPENMP
741  MP.timing_forces[ID] += omp_get_wtime()-timebeg;
742  #endif
743  } //END PARALLEL PART
744  //ParticleForce = calculateParticleForce() ;
745 
746  // Finish by sequencially adding the grains that were not owned by the parallel proc when computed
747  for (int i=0 ; i<MP.P ; i++)
748  {
749  for (uint j=0 ; j<MP.delayed_size[i] ; j++)
750  {
751  Tools<d>::vSubFew(F[MP.delayedj[i][j]], MP.delayed[i][j].Fn, MP.delayed[i][j].Ft, Fcorr[MP.delayedj[i][j]]) ;
752  Tools<d>::vAddOne(Torque[MP.delayedj[i][j]], MP.delayed[i][j].Torquej, TorqueCorr[MP.delayedj[i][j]]) ;
753  }
754  }
755 
756  MP.delayed_clean() ;
757 
758  // Benchmark::stop_clock("Forces");
759  //---------- Velocity Verlet step 3 : compute the new velocities
760  // Benchmark::start_clock("Verlet last");
761 
762  P.RigidBodies.process_forces(V, F, Torque, P.m, P.g) ;
763 
764 
765  #pragma omp parallel for default(none) shared(N) shared(P) shared(V) shared(Omega) shared(F) shared(FOld) shared(Torque) shared(TorqueOld) shared(dt)
766  for (int i=0 ; i<N ; i++)
767  {
768  //printf("%10g %10g %10g\n%10g %10g %10g\n%10g %10g %10g\n\n", A[0][0], A[0][1], A[0][2], A[0][3], A[0][4], A[0][5], A[0][6], A[0][7], A[0][8]) ;
769  if (P.Frozen[i]) {Tools<d>::setzero(TorqueOld[i]) ; Tools<d>::setzero(F[i]) ; Tools<d>::setzero(FOld[i]) ; /*Tools<d>::setzero(V[i]) ; */ Tools<d>::setzero(Omega[i]) ; }
770 
771  Tools<d>::vAddScaled(V[i], dt/2./P.m[i], F[i], FOld[i]) ; //V[i] += (F[i] + FOld[i])*(dt/2./P.m[i]) ;
772  Tools<d>::vAddScaled(Omega[i], dt/2./P.I[i], Torque[i], TorqueOld[i]) ; // Omega[i] += (Torque[i]+TorqueOld[i])*(dt/2./P.I[i]) ;
773  if ( !P.Frozen[i] && P.damping > 0.0 ) {
774  Tools<d>::vSubScaled(Omega[i], P.damping, Omega[i]) ; // BENJY - add damping to Omega
775  Tools<d>::vSubScaled(V[i], P.damping, V[i]) ; // BENJY - add damping to velocity
776  }
777 
778  FOld[i]=F[i] ;
779  TorqueOld[i]=Torque[i] ;
780  } // END OF PARALLEL SECTION
781 
782  // Benchmark::stop_clock("Verlet last");
783 
784 
785  // Check events
786  P.check_events(t, X,V,Omega) ;
787 
789  {
790  P.wallforcecomputed = true;
791  Tools<d>::setzero(WallForce) ;
792  for (int i=0 ; i<MP.P ; i++)
793  for (uint j=0 ; j<MP.delayedwall_size[i] ; j++)
794  Tools<d>::vSubFew(WallForce[MP.delayedwallj[i][j]], MP.delayedwall[i][j].Fn, MP.delayedwall[i][j].Ft) ;
795  }
796 
797  // Output something at some point I guess
798  if (ti % P.tdump==0)
799  {
800  Tools<d>::setzero(Z) ; for (auto &v: MP.CLp) v.coordinance(Z) ;
801  P.dumphandling (ti, t, X, V, Vmag, A, Omega, OmegaMag, PBCFlags, Z, MP) ;
802  std::fill(PBCFlags.begin(), PBCFlags.end(), 0);
803 
804  if (P.wallforcecompute)
805  {
806  char path[5000] ; sprintf(path, "%s/LogWallForce-%05d.txt", P.Directory.c_str(), ti) ;
807  Tools<d>::setzero(WallForce) ;
808 
809  for (int i=0 ; i<MP.P ; i++)
810  for (uint j=0 ; j<MP.delayedwall_size[i] ; j++)
811  Tools<d>::vSubFew(WallForce[MP.delayedwallj[i][j]], MP.delayedwall[i][j].Fn, MP.delayedwall[i][j].Ft) ;
812 
813  Tools<d>::savetxt(path, WallForce, ( char const *)("Force on the various walls")) ;
814  }
815 
816  //fprintf(stderr, "%g %g\n", X[0][0], X[0][1]) ;
817  }
818  if (P.n_restart >= 0 && ti % P.n_restart == 0 && ti != 0)
819  {
820  if (P.restart_flag & 1)
821  save_restart(P.Directory + "/" + P.restart_filename+"-"+std::to_string(ti)) ;
822  else
823  save_restart(P.Directory + "/" + P.restart_filename+"-"+((ti/P.n_restart)%2==0?"even":"odd")) ;
824  }
825 
827 
828 
829  // Load balancing on the procs as needed
830  #ifndef NO_OPENMP
831  MP.num_time++ ;
832  if (MP.num_time>50)
833  {
835  // Cleaning the load balancing
836  MP.num_time = 0 ;
837  MP.timing_contacts = vector<double>(MP.P,0) ;
838  MP.timing_forces = vector<double>(MP.P,0) ;
839  }
840  #endif
841 
842  //save_restart(*this, "restart_archive.bin") ;
843  }
844  }
845 
846  //-------------------------
850  void finalise ()
851  {
852  P.finalise() ;
853  printf("This is the end ...\n") ;
854  //fclose(logfile) ;
855  }
856 
857  //-------------------------------------------------------------------
859  Vector2Djs getX() { return to_js_array(X); }
860 
862  Vector1Djs getRadii() { return to_js_array(P.r); }
863 
865  void setRadius(int id, double radius) { P.r[id] = radius; } // NOTE: NOT UPDATING THE MASS!!! THIS IS SUCH A BAD IDEA
866 
868  void setMass(int id, double mass) { P.m[id] = mass; }
869 
872 
874  Vector1Djs getRotationRate() { Tools<d>::norm(OmegaMag, Omega) ; return to_js_array(OmegaMag); }
875 
878  {
879  auto [_, res] = MP.contacts2array (ExportData::IDS | ExportData::FN, X, P) ;
880  return to_js_array(res);
881  }
882 
885  {
886  auto [_, res] = MP.contacts2array (static_cast<ExportData>(flags), X, P) ;
887  return to_js_array(res);
888  }
889 
890 
891 
892  // /** \brief DEPRECATED Expose the array of contact forces and velocities. \ingroup API */
893  /*std::vector<std::vector<double>> calculateParticleForce()
894  {
895  std::vector<std::vector<double>> res ;
896  std::vector<double> tmpfrc ;
897  tmpfrc.resize(2+4*d) ;
898  for (size_t i=0 ; i<MP.CLp.size() ; i++)
899  {
900  for (auto it = MP.CLp[i].v.begin() ; it!=MP.CLp[i].v.end() ; it++)
901  {
902  if (it->infos == nullptr) continue ;
903  tmpfrc[0]=it->i ;
904  tmpfrc[1]=it->j ;
905  for (int j=0 ; j<d ; j++) tmpfrc[2+j]=it->infos->Fn[j] ;
906  for (int j=0 ; j<d ; j++) tmpfrc[2+d+j]=it->infos->Ft[j] ;
907  for (int j=0 ; j<d ; j++) tmpfrc[2+2*d+j]=it->infos->vn[j] ;
908  for (int j=0 ; j<d ; j++) tmpfrc[2+3*d+j]=it->infos->vt[j] ;
909  res.push_back(tmpfrc) ;
910  }
911  }
912 
913  return res;
914  }*/
915 
917  //void setX(std::vector < std::vector <double> > X_) { X = X_; }
918 
920  void setVelocity(int id, Vector1Djs vel) {
921  auto vel2 = from_js_array(vel) ;
922  for (int i=0 ; i<d ; i++) {
923  V[id][i] = vel2[i];
924  }
925  }
926 
929  auto omega2 = from_js_array(omega) ;
930  for (int i=0; i<(d*(d-1)/2); i++) {
931  Omega[id][i] = omega2[i];
932  }
933  }
934 
935 
937  void fixParticle(int a, Vector1Djs loc) {
938  auto loc2 = from_js_array (loc) ;
939  for (int i=0 ; i<d ; i++) {
940  X[a][i] = loc2[i];
941  V[a][i] = 0;
942  }
943  for (int i=0; i<(d*(d-1)/2); i++) {
944  Omega[a][i] = 0;
945  }
946  }
947 
949  void setFrozen(int a) {
950  P.Frozen[a] = true;
951  }
952 
954  double getTime() { return t; }
955 
957  double getGravityAngle() { return P.gravityrotateangle; }
958 
959 
962 
964  Vector1Djs getBoundary(int a) { return to_js_array(P.Boundaries[a].as_vector()); }
965  void setBoundary(int a, Vector1Djs loc) {
966  auto loc2 = from_js_array(loc) ;
967  P.Boundaries[a].xmin = loc2[0]; // low value
968  P.Boundaries[a].xmax = loc2[1]; // high value
969  P.Boundaries[a].delta = loc2[1] - loc2[0]; // length
970  if ( P.Boundaries[a].Type == WallType::PBC_LE ) {
971  P.Boundaries[a].vel = loc2[2];
972  }
973  }
974 
977  // std::cout<<P.wallforcerequested<<" "<<P.wallforcecomputed<<std::endl;
978  P.wallforcerequested = true;
979  if ( P.wallforcecomputed ) {
980  P.wallforcerequested = false;
981  P.wallforcecomputed = false;
982  return to_js_array(WallForce);
983  }
984  else {
985  return to_js_array(empty_array) ;
986  }
987  }
988 
990  void setExternalForce (int id, int duration, Vector1Djs force)
991  {
992  auto force2 = from_js_array(force) ;
993 
994  printf("\nSetting the force: %g %g %g %g\n", force2[0],force2[1],force2[2],force2[3]);
995  ExternalAction.resize(ExternalAction.size()+1) ;
996  ExternalAction[ExternalAction.size()-1].id = id ;
997  ExternalAction[ExternalAction.size()-1].duration = duration ;
998  ExternalAction[ExternalAction.size()-1].set(force2, v1d(d,0), v1d(d*(d-1)/2,0), v1d(d*(d-1)/2,0)) ;
999  }
1000 
1001  void randomDrop()
1002  {
1003  unsigned long int seed = 5489UL ;
1004  boost::random::mt19937 rng(seed);
1005  boost::random::uniform_01<boost::mt19937> rand(rng) ;
1006  for (int i=0 ; i<N ; i++)
1007  {
1008  for(int dd=0 ; dd < d ; dd++)
1009  {
1010  if (P.Boundaries[dd].Type==WallType::PBC)
1011  X[i][dd] = rand()*P.Boundaries[dd].delta + P.Boundaries[dd].xmin ;
1012  else
1013  X[i][dd] = rand()*(P.Boundaries[dd].delta-2*P.r[i]) + P.Boundaries[dd].xmin + P.r[i] ;
1014  }
1015  }
1016  }
1017 
1018 } ;
1019 
1020 #ifdef EMSCRIPTEN
1021 #ifdef USEBINDINGS
1022 #include "emscripten_specific.h"
1023 #endif
1024 #endif
1025 
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
Definition: ArrayCwiseUnaryOps.h:187
EIGEN_DEVICE_FUNC const CosReturnType cos() const
Definition: ArrayCwiseUnaryOps.h:237
EIGEN_DEVICE_FUNC const SinReturnType sin() const
Definition: ArrayCwiseUnaryOps.h:255
std::vector< T > from_js_array(std::vector< T > &data)
Definition: DEMND.h:82
std::vector< std::vector< double > > Vector2Djs
Definition: DEMND.h:78
std::vector< double > Vector1Djs
Definition: DEMND.h:79
std::vector< std::vector< T > > to_js_array(std::vector< std::vector< T >> &data)
Definition: DEMND.h:80
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.hpp:25318
boost::random::mt19937 rng(static_cast< unsigned int >(std::time(nullptr)))
Binary input and output archives.
#define CEREAL_NVP(T)
Creates a name value pair for the variable T with the same name as the variable.
Definition: cereal.hpp:72
Support for types found in <chrono>
All the cells making the space, with related function for creating the cell array,...
Definition: Cells.h:44
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 allocate_to_cells(std::vector< std::vector< double >> &X)
Definition: Cells.h:432
std::vector< Cell > cells
Definition: Cells.h:141
int init_cells(std::vector< Boundary< d >> &boundaries, double ds)
Definition: Cells.h:236
Handles lists of contacts with meshes.
Definition: ContactList.h:298
bool check_mesh_dst_contact(Mesh< d > &mesh, cv1d &Xo, double r, cpm< d > &c)
Definition: ContactList.h:310
Action< d > * default_action()
Easy allocation of a default contact to initialise new contacts.
Definition: ContactList.h:301
list< cpm< d > > v
Definition: ContactList.h:300
void reset()
Go to the contact list beginning.
Definition: ContactList.h:302
void finalise()
Definition: ContactList.h:303
Handles lists of contacts.
Definition: ContactList.h:208
bool(ContactList::* check_ghost)(bitdim, const Parameters< d > &, cv1d &, cv1d &, double, double, cp< d > &, int startd, double partialsum, bitdim mask)
Definition: ContactList.h:270
list< cp< d > > v
Contains the list of contact.
Definition: ContactList.h:277
void finalise()
Go to the end of the contact list, erasing any remaining contact which opened.
Definition: ContactList.h:213
Action< d > * default_action()
Easy allocation of a default contact to initialise new contacts.
Definition: ContactList.h:272
void reset()
Go to the contact list beginning.
Definition: ContactList.h:211
Calculate contact forces.
Definition: Contacts.h:23
void(Contacts::* particle_ghost)(cv1d &Xi, cv1d &Vi, cv1d &Omegai, double ri, double mi, cv1d &Xj, cv1d &Vj, cv1d &Omegaj, double rj, double mj, cp< d > &Contact, bool isdumptime)
Function pointer to the function to calculate the ghost-to-particle contact forces.
Definition: Contacts.h:40
Action< d > Act
Resulting Action.
Definition: Contacts.h:129
Manual multiprocessor handling for OpenMP, for max efficiency & avoiding bugs & race conditions,...
Definition: Multiproc.h:60
vector< uint > delayed_size
Max length of the delayed vector for each thread. Can grow as needed on call to delaying()
Definition: Multiproc.h:285
vector< double > timing_contacts
Definition: Multiproc.h:278
int P
Number of threads.
Definition: Multiproc.h:291
vector< Contacts< d > > C
Dummy Contacts for independent calculation per processor.
Definition: Multiproc.h:275
vector< uint > delayedwall_size
Max length of the delayed wall vector for each thread. Can grow as needed on call to delaying()
Definition: Multiproc.h:289
vector< vector< Action< d > > > delayedwall
Records the delayed Action.
Definition: Multiproc.h:287
vector< ContactListMesh< d > > CLm
ContactList particle-mesh for each processor.
Definition: Multiproc.h:274
vector< vector< Action< d > > > delayed
Records the delayed Action.
Definition: Multiproc.h:283
vector< ContactList< d > > CLp
ContactList particle-particle for each processor.
Definition: Multiproc.h:271
void merge_newcontacts()
Definition: Multiproc.h:94
vector< int > share
Particle share between threads. A thread ID own particles with index between share[ID] and share[ID+1...
Definition: Multiproc.h:276
vector< ContactList< d > > CLw
ContactList particle-wall for each processor.
Definition: Multiproc.h:273
CLp_it_t< d > CLp_it
Iterator list for fast access to particle contacts.
Definition: Multiproc.h:280
bool ismine(int ID, int j)
Check if a particle j belongs to the thread ID.
Definition: Multiproc.h:87
int num_time
Number of sample of time spent. Resets when load_balance() is called.
Definition: Multiproc.h:279
vector< int > sharecell
Cell share between threads (for contact detection based on cells). A thread ID own cells with index b...
Definition: Multiproc.h:277
vector< double > timing_forces
Used to record the time spent by each thread.
Definition: Multiproc.h:278
vector< vector< int > > delayedj
Records the j id of the particle in the associated delayed action.
Definition: Multiproc.h:284
vector< ContactList< d > > CLp_new
New particle-particle contacts for each processor.
Definition: Multiproc.h:272
vector< vector< int > > delayedwallj
Records the j id of the wall in the associated delayed action.
Definition: Multiproc.h:288
void initialise(int NN, int PP, Parameters< d > &Param)
Definition: Multiproc.h:63
Definition: Octree.h:11
int init_cells(std::vector< Boundary< d >> &boundaries, std::vector< double > &r)
Definition: Octree.h:13
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: Octree.h:78
int cells_to_split()
Definition: Octree.h:42
int allocate_to_cells(std::vector< std::vector< double >> &X)
Definition: Octree.h:58
Generic class to handle the simulation set up.
Definition: Parameters.h:128
ContactStrategies contact_strategy
Strategy for the contact detection.
Definition: Parameters.h:188
vector< double > g
Gravity vector.
Definition: Parameters.h:197
int n_restart
Restart writing frequency.
Definition: Parameters.h:212
bool orientationtracking
Track orientation?
Definition: Parameters.h:201
void load_datafile(char path[], v2d &X, v2d &V, v2d &Omega)
Load and parse input script.
Definition: Parameters.h:446
XMLWriter * xmlout
Pointer to the (optional) xml dump object.
Definition: Parameters.h:190
void(Parameters::* update_gravity)(double time)
Definition: Parameters.h:264
bool perform_forceinsphere(v1d &X)
Definition: Parameters.h:382
void perform_PBCLE_move()
Definition: Parameters.h:358
double T
Run until this time (note it is a floating point).
Definition: Parameters.h:175
bool forceinsphere
Definition: Parameters.h:185
bool wallforcecompute
Compute for on the wall?
Definition: Parameters.h:202
vector< double > r
Particle radii.
Definition: Parameters.h:194
int N
Number of particles.
Definition: Parameters.h:172
RigidBodies_< d > RigidBodies
Handle all the rigid bodies.
Definition: Parameters.h:210
void perform_PBCLE(v1d &X, v1d &V, uint32_t &PBCFlag)
Definition: Parameters.h:335
int tinfo
Show detail information on scren every this many timesteps.
Definition: Parameters.h:174
bool wallforcerequested
Compute for on the wall?
Definition: Parameters.h:203
double graddesc_gamma
Decay rate parameters for the gradient descent algorithm.
Definition: Parameters.h:205
void finalise()
Close opened dump files.
Definition: Parameters.h:1241
string Directory
Saving directory.
Definition: Parameters.h:200
int dumphandling(int ti, double t, v2d &X, v2d &V, v1d &Vmag, v2d &A, v2d &Omega, v1d &OmegaMag, vector< uint32_t > &PBCFlags, v1d &Z, Multiproc< d > &MP)
Dump writing functions.
Definition: Parameters.h:1251
int set_boundaries()
Set default boundaries.
Definition: Parameters.h:308
double damping
Definition: Parameters.h:184
vector< bool > Frozen
Frozen atom if true.
Definition: Parameters.h:198
double dt
timestep
Definition: Parameters.h:176
void perform_PBC(v1d &X, uint32_t &PBCFlags)
Bring particle back in the simulation box if the grains cross the boundaries.
Definition: Parameters.h:322
vector< Mesh< d > > Meshes
Handle all meshes.
Definition: Parameters.h:211
std::string restart_filename
Restart filename.
Definition: Parameters.h:213
vector< double > m
Particle mass.
Definition: Parameters.h:195
double cellsize
Size of cells for contact detection.
Definition: Parameters.h:186
vector< Boundary< d > > Boundaries
List of boundaries. Second dimension is {min, max, length, type}.
Definition: Parameters.h:199
void check_events(float time, v2d &X, v2d &V, v2d &Omega)
Verify if an event triggers at the current time time.
Definition: Parameters.h:466
bool wallforcecomputed
Compute for on the wall?
Definition: Parameters.h:204
void interpret_command(istream &in, v2d &X, v2d &V, v2d &Omega)
Parse input script commands.
Definition: Parameters.h:496
double graddesc_tol
Tolerance for the gradient descent algorithm.
Definition: Parameters.h:206
vector< double > I
Particule moment of inertia.
Definition: Parameters.h:196
vector< std::pair< ExportType, ExportData > > dumps
Vector linking dump file and data dumped.
Definition: Parameters.h:189
void perform_MOVINGWALL()
Move the boundary wall if moving.
Definition: Parameters.h:369
double gravityrotateangle
Definition: Parameters.h:209
int tdump
Write dump file every this many timesteps.
Definition: Parameters.h:173
unsigned char restart_flag
Definition: Parameters.h:214
Definition: DEMND.h:116
vector< uint32_t > Ghost_dir
Definition: DEMND.h:144
std::vector< std::vector< double > > FOld
Definition: DEMND.h:125
int N
Definition: DEMND.h:119
std::vector< double > Vmag
Definition: DEMND.h:128
v1d Atmp
Definition: DEMND.h:145
std::vector< std::vector< double > > Fcorr
Definition: DEMND.h:131
Cells< d > cells
Definition: DEMND.h:149
std::vector< std::vector< double > > V
Definition: DEMND.h:121
std::vector< std::vector< double > > A
Definition: DEMND.h:122
void serialize(Archive &ar)
Definition: DEMND.h:192
double dt
Definition: DEMND.h:153
Multiproc< d > MP
Definition: DEMND.h:148
std::vector< std::vector< double > > Torque
Definition: DEMND.h:126
std::vector< std::vector< double > > ParticleForce
Definition: DEMND.h:141
std::vector< uint32_t > PBCFlags
Definition: DEMND.h:138
void randomDrop()
Definition: DEMND.h:1001
void init_from_file(char filename[])
Initialise the simulation from a file.
Definition: DEMND.h:243
std::vector< double > Z
Definition: DEMND.h:130
std::vector< SpecificAction< d > > ExternalAction
Definition: DEMND.h:136
std::vector< std::optional< int > > RigidBodyId
Definition: DEMND.h:134
Octree< d > octree
Definition: DEMND.h:150
Simulation(int NN)
Definition: DEMND.h:204
double t
Definition: DEMND.h:152
vector< uint32_t > Ghost
Definition: DEMND.h:143
void save_restart(const std::string &filename)
Definition: DEMND.h:157
std::vector< std::vector< double > > empty_array
Definition: DEMND.h:140
std::vector< std::vector< double > > TorqueOld
Definition: DEMND.h:127
clock_t tnow
Definition: DEMND.h:154
std::vector< std::vector< double > > TorqueCorr
Definition: DEMND.h:132
std::vector< std::vector< double > > X
Definition: DEMND.h:120
Parameters< d > P
Definition: DEMND.h:118
std::vector< std::vector< double > > Omega
Definition: DEMND.h:123
void setBoundary(int a, Vector1Djs loc)
Definition: DEMND.h:965
std::vector< std::vector< double > > WallForce
Definition: DEMND.h:139
std::vector< double > OmegaMag
Definition: DEMND.h:129
void step_forward_all()
Run the whole simulation as defined in the input script.
Definition: DEMND.h:307
std::vector< std::vector< double > > F
Definition: DEMND.h:124
void load_restart(const std::string &filename)
Definition: DEMND.h:164
static std::tuple< double, double > contact_ellipse_disk(std::vector< double > &X, double a, double b, double cx, double cy, double gamma=0.1, double tol=1e-5)
Definition: Tools.h:62
Static class to handle multi-dimensional mathematics, and more. It gets specialised for speed with te...
Definition: Tools.h:101
static void vAddScaled(v1d &res, double v, cv1d &a, cv1d &b)
Addition of 3 vectors in-place.
Definition: Tools.h:183
static void vAddFew(v1d &res, cv1d &a, cv1d &b)
Definition: Tools.h:182
static void vAddOne(v1d &res, cv1d &a, v1d &Corr)
Addition of 2 vectors in-place with error correction (Kahan summation algorithm)
Definition: Tools.h:217
static void vSubFew(v1d &res, cv1d &a, cv1d &b)
Subtraction of 2 vectors .
Definition: Tools.h:185
static void vSubScaled(v1d &res, double v, cv1d &a)
Subtraction of a scaled vector .
Definition: Tools.h:186
Definition: Xml.h:29
An input archive designed to load data saved using BinaryOutputArchive.
Definition: binary.hpp:89
An output archive designed to save data in a compact binary representation.
Definition: binary.hpp:52
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
int i
Index of contacting particle.
Definition: ContactList.h:113
void setinfo(Action< d > *a)
Set information for contact force.
Definition: ContactList.h:92
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
Contact properties for mesh contacts (mainly), including contact point location, specialising cp.
Definition: ContactList.h:177
void setRadius(int id, double radius)
Set the radius of a specific particle.
Definition: DEMND.h:865
void setFrozen(int a)
Freeze a single particle.
Definition: DEMND.h:949
Vector1Djs getBoundary(int a)
Expose the array of boundaries.
Definition: DEMND.h:964
Vector2Djs getWallForce()
Expose the array of wall forces.
Definition: DEMND.h:976
Vector1Djs getRadii()
Expose the array of radii.
Definition: DEMND.h:862
void interpret_command(string in)
Interpret individual script command from string.
Definition: DEMND.h:299
void step_forward(int nt)
Advance the simulation for nt steps (actual duration nt*dt).
Definition: DEMND.h:317
Vector2Djs getContactForce()
DEPRECATED: Use getContactInfo with the appropriate flags instead. Expose the array of particle id an...
Definition: DEMND.h:877
void setMass(int id, double mass)
Set the mass of a specific particle.
Definition: DEMND.h:868
Vector1Djs getRotationRate()
Expose the array of orientation rate.
Definition: DEMND.h:874
void setExternalForce(int id, int duration, Vector1Djs force)
Set an additional external force on a particle for a certain duration.
Definition: DEMND.h:990
Vector2Djs getOrientation()
Expose the array of orientation.
Definition: DEMND.h:961
void finalise()
Settles the simulation, closing open files etc.
Definition: DEMND.h:850
Vector2Djs getX()
Expose the array of locations.
Definition: DEMND.h:859
Vector2Djs getVelocity()
Expose the array of velocities.
Definition: DEMND.h:871
void setAngularVelocity(int id, Vector1Djs omega)
Set the angular velocity of a single particle.
Definition: DEMND.h:928
void setVelocity(int id, Vector1Djs vel)
Set the array of locations.
Definition: DEMND.h:920
double getGravityAngle()
Expose the current gravity angle.
Definition: DEMND.h:957
Vector2Djs getContactInfos(int flags)
Expose the array of contact information.
Definition: DEMND.h:884
void finalise_init()
Tell NDDEM that the simulations are now initialised and we can start running.
Definition: DEMND.h:252
double getTime()
Expose the current time.
Definition: DEMND.h:954
void fixParticle(int a, Vector1Djs loc)
Set a single particle location, velocity, and angular velocity.
Definition: DEMND.h:937
void delaying(int ID, int j, Action< d > &act)
Record the action to be added later to the relevent atom in sequencial settings, avoid potential race...
Definition: Multiproc.h:385
static void orthonormalise(v1d &A)
Orthonormalise A using the Gram-Shmidt process, in place.
Definition: Tools.h:741
static void setzero(v2d &a)
Set a matrix to zero in-place.
Definition: Tools.h:117
static void unitvec(vector< double > &v, int n)
Construct a unit vector in place.
Definition: Tools.h:735
void particle_particle(cv1d &Xi, cv1d &Vi, cv1d &Omegai, double ri, double mi, cv1d &Xj, cv1d &Vj, cv1d &Omegaj, double rj, double mj, cp< d > &Contact, bool isdumptime)
Force & torque between 2 particles.
Definition: Contacts.h:171
ExportData
Definition: Parameters.h:46
@ vel
Definition: Typedefs.h:19
@ omega
Definition: Typedefs.h:19
@ radius
Definition: Typedefs.h:19
@ mass
Definition: Typedefs.h:19
void particle_mesh(cv1d &Xi, cv1d &Vi, cv1d &Omegai, double ri, double mi, cpm< d > &Contact)
Force & torque between particle and mesh.
Definition: Contacts.h:401
void particle_movingwall(cv1d &Vi, cv1d &Omegai, double ri, double mi, cv1d &cn, cv1d &Vj, cp< d > &Contact)
Force & torque between a particle and a moving wall. Vj is the velocity of the wall at the contact po...
Definition: Contacts.h:331
static int savetxt(char path[], const v2d &table, char const header[])
Definition: Tools.h:349
void load_balance(ContactStrategies contactstrategy)
Modify the atom share between threads to achieve better load balance between the threads based on the...
Definition: Multiproc.h:437
unsigned int uint
Definition: Typedefs.h:8
void delayedwall_clean()
Clean the record of the force on the wal.
Definition: Multiproc.h:428
auto contacts2array(ExportData exp, cv2d &X, Parameters< d > &P)
pack the contact data in a 2d array
Definition: Multiproc.h:568
int insert(const cpm< d > &a)
Insert a contact, maintaining sorting with increasing i, and removing missing contacts on traversal.
Definition: ContactList.h:451
void delayed_clean()
Clean the record list.
Definition: Multiproc.h:420
int insert(const cp< d > &a)
Insert a contact, maintaining sorting with increasing i, and removing missing contacts on traversal.
Definition: ContactList.h:430
static v1d matmult(cv1d &A, cv1d &B)
Multiply 2 matrix together.
Definition: Tools.h:680
unsigned int bitdim
Definition: Typedefs.h:17
static v1d skewexpand(cv1d &A)
Return the skew symetrix matrix M stored on d(d-1)/2 component as a full flattened matrix with d^2 co...
Definition: Tools.h:660
vector< std::pair< ExportType, ExportData > > * toclean
Definition: DEMND.cpp:21
void particle_wall(cv1d &Vi, cv1d &Omegai, double ri, double mi, cv1d &cn, cp< d > &Contact)
Force & torque between a particle and a wall.
Definition: Contacts.h:261
void delayingwall(int ID, int j, Action< d > &act)
Record the action on the wall. Only usefull if the force on the wall needs to be calculated.
Definition: Multiproc.h:402
XMLWriter * xmlout
Definition: DEMND.cpp:22
static void setgravity(v2d &a, v1d &g, v1d &m)
Set the gravity. .
Definition: Tools.h:154
void splitcells(int C)
Definition: Multiproc.h:376
vector< double > v1d
Definition: Typedefs.h:9
static void surfacevelocity(v1d &res, cv1d &p, double *com, double *vel_com, double *omega_com)
Definition: Tools.h:131
static void initialise()
Initialise the member variables, in particular the variables to handle skew-symmetric flattened matri...
Definition: Tools.h:318
static double norm(const vector< double > &a)
Norm of a vector.
Definition: Tools.h:119
@ CELLS
Definition: Typedefs.h:22
@ OCTREE
Definition: Typedefs.h:22
@ ROTATINGSPHERE
uint d
int N
Support for types found in <list>
Support for types found in <map>
Support for std::optional.
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1181
unsigned int uint32_t
Definition: stdint.h:126
unsigned __int64 uint64_t
Definition: stdint.h:136
Support for types found in <string>
Support for types found in <utility>
Support for types found in <vector>
XML input and output archives.