NDDEM
Parameters.h
Go to the documentation of this file.
1 #ifndef PARAMETERS
2 #define PARAMETERS
3 
7 #include <cstdlib>
8 #include <cmath>
9 #include <cstdio>
10 #include <vector>
11 #include <iostream>
12 #include <fstream>
13 #include <map>
14 //#include <boost/variant.hpp>
15 #include <variant>
16 #if !__EMSCRIPTEN__ && __GNUC__ < 8
17  #include <experimental/filesystem>
18  namespace fs = std::experimental::filesystem ;
19 #else
20  #include <filesystem>
21  namespace fs = std::filesystem ;
22 #endif
23 
24 #include "Typedefs.h"
25 #include "Tools.h"
26 #include "Xml.h"
27 #include "Vtk.h"
28 #include "RigidBody.h"
29 #include "Mesh.h"
30 #include "Boundaries.h"
31 #include "json_parser.h"
32 //#include "json.hpp"
33 //
34 #include <boost/random.hpp>
35 
36 #ifdef EMSCRIPTEN
37  #define STR_PROTECT(s) static_cast<const char*>(s "\0")
38 #else
39  #define STR_PROTECT(s) s
40 #endif
41 
42 //using json = nlohmann::json;
43 using json = nddem::json ;
44 using namespace std ;
45 enum class ExportType {NONE=0, CSV=1, VTK=2, NETCDFF=4, XML=8, XMLbase64=16, CSVA=32, CSVCONTACT=64} ;
46 enum class ExportData {NONE=0, POSITION=0x1, VELOCITY=0x2, OMEGA=0x4, OMEGAMAG=0x8, ORIENTATION=0x10, COORDINATION=0x20, RADIUS=0x40, IDS=0x80, FN=0x100, FT=0x200, TORQUE=0x400, GHOSTMASK=0x800, GHOSTDIR=0x1000, BRANCHVECTOR=0x2000, FN_EL=0x4000, FN_VISC=0x8000, FT_EL=0x10000, FT_VISC=0x20000, FT_FRIC=0x40000, FT_FRICTYPE=0x80000, CONTACTPOSITION=0x100000, MASS=0x200000} ;
47 inline ExportType & operator|=(ExportType & a, const ExportType b) {a= static_cast<ExportType>(static_cast<int>(a) | static_cast<int>(b)); return a ; }
48 inline ExportData & operator|=(ExportData & a, const ExportData b) {a= static_cast<ExportData>(static_cast<int>(a) | static_cast<int>(b)); return a ; }
49 inline ExportData operator| (ExportData a, ExportData b) {auto c= static_cast<ExportData>(static_cast<int>(a) | static_cast<int>(b)); return c ; }
50 inline ExportData operator~ (ExportData a) {auto c= static_cast<ExportData>(~static_cast<int>(a)); return c ; }
51 inline ExportData & operator&=(ExportData & a, const ExportData b) {a= static_cast<ExportData>(static_cast<int>(a) & static_cast<int>(b)); return a ; }
52 inline ExportData & operator>>= (ExportData& w, int u) {w=static_cast<ExportData>(static_cast<int>(w)>>u) ; return w ; }
53 inline ExportData & operator<<= (ExportData& w, int u) {w=static_cast<ExportData>(static_cast<int>(w)<<u) ; return w ; }
54 inline bool operator& (ExportType & a, ExportType b) {return (static_cast<int>(a) & static_cast<int>(b)) ; }
55 inline bool operator& (ExportData & a, ExportData b) {return (static_cast<int>(a) & static_cast<int>(b)) ; }
56 
57 template <int d>
58 class Multiproc ;
59 
61 template <typename T>
62 class number_gen {
63 public:
64  void parse (std::string s)
65  {
66  auto res = s.find(':') ; double val ;
67  if (res==std::string::npos)
68  {
69  val=stod(s) ; first=static_cast<T>(val) ;
70  isconst=true ; delta=0 ;
71  last = std::numeric_limits<T>::max() ;
72  }
73  else
74  {
75  isconst=false ;
76  val=stod(s) ; first=static_cast<T>(val) ;
77  s=s.substr(res+1) ; res = s.find(':') ;
78  if (res==std::string::npos)
79  {
80  val=stod(s) ; last=static_cast<T>(val) ;
81  delta=1 ;
82  }
83  else
84  {
85  val=stod(s) ; delta=static_cast<T>(val) ;
86  s=s.substr(res+1) ;
87  val=stod(s) ; last=static_cast<T>(val) ;
88  }
89  }
90  iter=0 ;
91  }
92 
93  void reset () {iter = 0 ; }
94  int niter() { return isconst?1:(floor((last-first)/delta)+1) ; }
95  T cur() {return first+delta*iter ; }
96  std::optional<T> operator() (bool allow=false)
97  {
98  if (isconst)
99  {
100  if (iter>0 && !allow) return {} ;
101  else
102  {
103  iter ++ ;
104  return first ;
105  }
106  }
107  else
108  {
109  T res = first+delta*iter ;
110  if (res>last && !allow)
111  return {} ;
112  iter++ ;
113  return res ;
114  }
115  }
116 private:
117  int iter=0 ;
118  bool isconst = true ;
119  T first, last, delta=1 ;
120 };
121 template <typename T>
122 std::istream & operator>> (std::istream & in, number_gen<T> & n) {std::string s; in >>s ; n.parse(s) ; return in ; }
123 
127 template <int d>
128 class Parameters {
129 public :
131  Parameters (int NN):
132  N(5), //number of particles
133  tdump(100000000), //dump data every these timesteps
134  tinfo(100),
135  T(5000), //number of timesteps
136  dt(0.0001), //timestep
137  rho(1), //density (unit [M.L^(-d)]) WARNING UNUSED
138  Kn(0.0001) , //Hooke stiffness
139  Kt(0.00001) , //Tangential stiffness
140  Gamman(0.0001), //Normal damping
141  Gammat(0), //Tangential damping
142  Mu(0.5), // Friction coefficient
143  Mu_wall(0.5), // Wall friction coefficient
144  damping(0.0),
145  forceinsphere(false),
146  cellsize(-1),
147  contact_strategy(ContactStrategies::NAIVE),
148  //dumpkind(ExportType::NONE), //How to dump: 0=nothing, 1=csv, 2=vtk
149  //dumplist(ExportData::POSITION),
150  Directory ("Output"),
151  orientationtracking(true),
152  wallforcecompute(false),
153  wallforcerequested(false),
154  wallforcecomputed(false),
155  graddesc_gamma(0.1),
156  graddesc_tol(1e-5)
157  {
158  reset_ND(NN) ;
159  }
160 
161  void reset_ND (int NN)
162  {
163  N=NN ; r.resize(N,0.5) ; //particle size
164  m.resize(N, 1e-2); // Set the masses directly
165  I.resize(N,1) ; //Momentum of inertia (particles are sphere)
166  g.resize(d,0) ; // Initialise gravity
167  Frozen.resize(N,false) ;
168 
169  Boundaries.resize(d) ; // Boundary type in [:,3]: 0=regular pbc, 1=wall}
170  }
171 
172  int N;
173  int tdump ;
174  int tinfo ;
175  double T ;
176  double dt ;
177  double rho;
178  double Kn ;
179  double Kt ;
180  double Gamman;
181  double Gammat ;
182  double Mu ;
183  double Mu_wall; //< Wall friction
184  double damping; //< Artificial rolling damping
185  bool forceinsphere; //< Artificial rolling damping
186  double cellsize ;
187  ContactModels ContactModel=HOOKE ;
188  ContactStrategies contact_strategy = NAIVE ;
189  vector <std::pair<ExportType,ExportData>> dumps ;
190  //ExportType dumpkind ;
191  //ExportData dumplist ;
192  vector <double> r ;
193  vector <double> m ;
194  vector <double> I ;
195  vector <double> g ;
196  vector <bool> Frozen ;
197  vector < Boundary<d> > Boundaries ;
198  string Directory ;
203  double graddesc_gamma ;
204  double graddesc_tol ;
206  unsigned long int seed = 5489UL ;
207  double gravityrotateangle = 0.0;
209  vector <Mesh<d>> Meshes ;
210  int n_restart=-1 ;
211  std::string restart_filename="" ;
212  unsigned char restart_flag ;
213 
214  multimap<float, string> events ;
215 
216  template <class Archive>
217  void serialize(Archive &ar) {
218  ar(N, tdump, tinfo, T, dt, rho, Kn, Kt, Gamman, Gammat, Mu, Mu_wall, damping, forceinsphere, cellsize, ContactModel, contact_strategy,
219  dumps, r, m, I, g, Frozen, Boundaries, Directory, orientationtracking, wallforcecompute, wallforcerequested, wallforcecomputed,
220  graddesc_gamma, graddesc_tol, contactforcedump, seed, gravityrotateangle, RigidBodies, Meshes, events,
221  n_restart, restart_filename, restart_flag
222  ) ;
223  }
224 
225 // Useful functions
226  int set_boundaries() ;
227  //int init_particles(v2d & X, v2d & A) ;
228  void perform_PBC(v1d & X, uint32_t & PBCFlags) ;
229  void perform_PBCLE_move() ;
230  void perform_PBCLE (v1d & X, v1d & V, uint32_t & PBCFlag) ;
232  {
233  bool res = false ;
234  if (! Boundaries[0].is_sphere())
235  { printf("ERR: forceinsphere expect the sphere to be the first wall.") ; return false ; }
236 
237  double dst = 0 ;
238  for (int dd=0 ; dd<d ; dd++) dst += (X[dd]-Boundaries[0].center[dd])*(X[dd]-Boundaries[0].center[dd]) ;
239  if (dst > Boundaries[0].radius*Boundaries[0].radius || std::isnan(dst))
240  {
241  printf("%g ", dst) ; fflush(stdout) ;
242  boost::random::mt19937 rng(++seed);
243  boost::random::uniform_01<boost::mt19937> rand(rng) ;
244  do {
245  dst=0 ;
246  for(int dd=0 ; dd < d ; dd++)
247  {
248  X[dd] = (rand()*Boundaries[0].radius*2-Boundaries[0].radius) + Boundaries[0].center[dd] ;
249  dst += (Boundaries[0].center[dd]-X[dd])*(Boundaries[0].center[dd]-X[dd]) ;
250  }
251  } while ( dst > Boundaries[0].radius * Boundaries[0].radius) ;
252  res = true ;
253  printf("[INFO] Bringing back in sphere forcibly. \n"); fflush(stdout) ;
254  }
255  return res ;
256  }
257 
258  void perform_MOVINGWALL() ;
259  int init_mass() ;
260  int init_inertia() ;
261 
262  void do_nothing (double time __attribute__((unused))) {return;}
263  double grav_intensity = 10, grav_omega=1 ; int grav_rotdim[2]={0,1} ;
264  void do_gravityrotate (double deltatime) {gravityrotateangle += deltatime*grav_omega; g[grav_rotdim[0]]=grav_intensity*cos(gravityrotateangle); g[grav_rotdim[1]]=grav_intensity*sin(gravityrotateangle); return;}
265  void (Parameters::*update_gravity) (double time) = &Parameters::do_nothing ;
266 
267  void load_datafile (char path[], v2d & X, v2d & V, v2d & Omega) ;
268  void check_events(float time, v2d & X, v2d & V, v2d & Omega) ;
269  void interpret_command (istream & in, v2d & X, v2d & V, v2d & Omega) ;
270  void interpret_command (string & in, v2d & X, v2d & V, v2d & Omega) ;
271 
272  void remove_particle (int idx, v2d & X, v2d & V, v2d & A, v2d & Omega, v2d & F, v2d & FOld, v2d & Torque, v2d & TorqueOld) ;
273  void add_particle (/*v2d & X, v2d & V, v2d & A, v2d & Omega, v2d & F, v2d & FOld, v2d & Torque, v2d & TorqueOld*/) ;
274  void init_locations (char *line, v2d & X, char *extras) ;
275  void init_radii (char line[], v1d & r) ;
276 
277  void display_info(int tint, v2d& V, v2d& Omega, v2d& F, v2d& Torque, int, int) ;
278  void quit_cleanly() ;
279  void finalise();
280  void xml_header () ;
281  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) ;
282  int savecsvcontact (FILE * out, ExportData outflags, Multiproc<d> & MP, cv2d & X)
283  {
284  if (outflags & ExportData::IDS) fprintf(out, "id_i, id_j, ") ;
285  if (outflags & ExportData::CONTACTPOSITION || outflags & ExportData::POSITION)
286  {
287  for (int dd = 0 ; dd<d ; dd++)
288  fprintf(out, "x%d_i, ", dd) ;
289  for (int dd = 0 ; dd<d ; dd++)
290  fprintf(out, "x%d_j, ", dd) ;
291  }
292  if (outflags & ExportData::FN)
293  for (int dd = 0 ; dd<d ; dd++)
294  fprintf(out, "Fn%d_i, ", dd) ;
295  if (outflags & ExportData::FT)
296  for (int dd = 0 ; dd<d ; dd++)
297  fprintf(out, "Ft%d_i, ", dd) ;
298  if (outflags & ExportData::TORQUE)
299  {
300  for (int dd = 0 ; dd<d*(d-1)/2 ; dd++)
301  {
302  auto val = Tools<d>::MASIndex[dd] ;
303  fprintf(out, "Torque%d:%d_i, ", val.first, val.second) ;
304  }
305  for (int dd = 0 ; dd<d*(d-1)/2 ; dd++)
306  {
307  auto val = Tools<d>::MASIndex[dd] ;
308  fprintf(out, "Torque%d:%d_j, ", val.first, val.second) ;
309  }
310  }
311  if (outflags & ExportData::GHOSTMASK)
312  fprintf(out, "GhostMask, ") ;
313  if (outflags & ExportData::GHOSTDIR)
314  fprintf(out, "GhostDir, ") ;
315  if (outflags & ExportData::BRANCHVECTOR)
316  {
317  for (int dd = 0 ; dd<d ; dd++)
318  fprintf(out, "lij%d, ", dd) ;
319  }
320 
321  fseek (out, -2, SEEK_CUR) ;
322  fprintf(out, "\n") ;
323 
324  for (auto & CLp : MP.CLp)
325  {
326  for (auto & contact: CLp.v)
327  {
328  if (outflags & ExportData::IDS)
329  fprintf(out, "%d %d ", contact.i, contact.j) ;
330  if (outflags & ExportData::CONTACTPOSITION || outflags & ExportData::POSITION)
331  {
332  for (auto dd : X[contact.i])
333  fprintf(out, "%g ", dd) ;
334  for (auto dd : X[contact.j])
335  fprintf(out, "%g ", dd) ;
336  }
337  if (outflags & ExportData::FN)
338  for (auto dd : contact.infos->Fn)
339  fprintf(out, "%g ", dd) ;
340  if (outflags & ExportData::FT)
341  for (auto dd : contact.infos->Ft)
342  fprintf(out, "%g ", dd) ;
343 
344  if (outflags & ExportData::TORQUE)
345  {
346  for (auto dd : contact.infos->Torquei)
347  fprintf(out, "%g ", dd) ;
348  for (auto dd : contact.infos->Torquej)
349  fprintf(out, "%g ", dd) ;
350  }
351 
352  if (outflags & ExportData::GHOSTMASK)
353  fprintf(out, "%d ", contact.ghost) ;
354  if (outflags & ExportData::GHOSTDIR)
355  fprintf(out, "%d ", contact.ghostdir) ;
356 
357  if (outflags & ExportData::BRANCHVECTOR)
358  {
359  auto [loc,branch] = contact.compute_branchvector(X, *this) ;
360 
361  for (int dd = 0 ; dd<d ; dd++) fprintf(out, "%g ", branch[dd]) ;
362  }
363  fprintf(out, "\n") ;
364  }
365  }
366  return 0 ;
367  }
368 
369 
370 // For Xml Writing
372 } ;
375 /*****************************************************************************************************
376  * *
377  * *
378  * *
379  * IMPLEMENTATIONS *
380  * *
381  * *
382  * *
383  * ***************************************************************************************************/
384 double nan_or_double (istream & in)
385 {
386  char c; std::string word ;
387  if (!in.good()) return std::numeric_limits<double>::quiet_NaN();
388  while (isspace(c = in.peek())) in.get();
389  if ( !isdigit(c) && c!='-' && c!='.') { in >> word ; return std::numeric_limits<double>::quiet_NaN(); }
390  double x ;
391  in >> x;
392  return x ;
393 }
394 
395 
397 template <int d>
399 {
400  for (int i=0 ; i<d ; i++)
401  {
402  Boundaries[i].xmin= 0 ;
403  Boundaries[i].xmax= 1 ;
404  Boundaries[i].delta=1 ; //Precomputed to increase speed
405  Boundaries[i].Type = WallType::PBC ; // PBC by default
406  }
407  //np.savetxt('Boundaries.csv', Boundaries , delimiter=',', fmt='%.6g', header='Low,High,Size,Type', comments='')
408  return 0 ;
409 }
410 //----------------------------------------------------
411 template <int d>
413 {
414  for (size_t j=0 ; j<Boundaries.size() ; j++)
415  {
416  if (Boundaries[j].Type== WallType::PBC) //PBC
417  {
418  if (X[j]<Boundaries[j].xmin) {X[j] += Boundaries[j].delta ; PBCFlag |= (1<<j) ;}
419  else if (X[j]>Boundaries[j].xmax) {X[j] -= Boundaries[j].delta ; PBCFlag |= (1<<j) ;}
420  }
421  }
422 }
423 //----------------------------------------------------
424 template <int d>
425 void Parameters<d>::perform_PBCLE (v1d & X, v1d & V, uint32_t & PBCFlag)
426 {
427  if (Boundaries[0].Type == WallType::PBC_LE)
428  {
429  if (X[0]<Boundaries[0].xmin)
430  {
431  X[0] += Boundaries[0].delta ; PBCFlag |= 1 ;
432  X[1] += Boundaries[0].displacement ;
433  V[1] += Boundaries[0].delta*Boundaries[0].vel ; ;
434  }
435  else if (X[0]>Boundaries[0].xmax)
436  {
437  X[0] -= Boundaries[0].delta ; PBCFlag |= 1 ;
438  X[1] -= Boundaries[0].displacement ;
439  V[1] -= Boundaries[0].delta*Boundaries[0].vel ; ;
440  }
441 
442  if ( X[1]<Boundaries[1].xmin) {X[1]+=Boundaries[1].delta ; PBCFlag |= 2 ; }
443  if ( X[1]>Boundaries[1].xmax) {X[1]-=Boundaries[1].delta ; PBCFlag |= 2 ; }
444  }
445 }
446 //----------------------------------------------------
447 template <int d>
449 {
451  {
452  Boundaries[0].displacement += dt*Boundaries[0].vel*Boundaries[0].delta ;
453  if (Boundaries[0].displacement>Boundaries[1].xmax)
454  Boundaries[0].displacement -= Boundaries[1].delta ;
455  }
456 }
457 //----------------------------------------------------
458 template <int d>
460 {
461  for (size_t j=0 ; j<Boundaries.size() ; j++)
462  {
464  {
465  Boundaries[j].xmin += Boundaries[j].velmin * dt ;
466  Boundaries[j].xmax += Boundaries[j].velmax * dt ;
467  }
468  }
469 }
470 //-----------------------------------------------------
471 /*int Parameters::init_particles(v2d & X, v2d & A)
472 {
473  boost::random::mt19937 rng;
474  boost::random::uniform_01<boost::mt19937> rand(rng) ;
475  for (int i=0 ; i<N ; i++)
476  for (int dd=0 ; dd<d ; dd++)
477  {
478  X[i][dd]=rand()*(Boundaries[dd][2]-Boundaries[dd][3]*2*r[i])+(Boundaries[dd][0]+Boundaries[dd][3]*r[i]);//avoid too much overlap with walls
479  //m[i]=volume(r[i])*rho ;
480 
481  }
482  //X[0][5]=0.14 ;
483  //V[0][:]=np.zeros((1,d))+0.0001*unitvec(0) ;
484  //X[1][:]=np.ones((1,d))*0.7 ; X[1,5]=0.2 ; X[1,4]=0.71 ;
485  //X[1][:]=np.array([0.21,0.21,0.9,0.2]) ;
486  return 0 ;
487 }*/
488 template <int d>
490 {
491  for (int i=0 ; i<N ; i++)
492  m[i]=rho*Tools<d>::Volume(r[i]) ;
493 return 0 ;
494 }
495 
496 template <int d>
498 {
499  for (int i=0; i<N ; i++)
500  {
501  I[i]=Tools<d>::InertiaMomentum (r[i], rho) ;
502  }
503  return 0 ;
504 }
505 //---------------------------------------------------
506 template <int d>
507 void Parameters<d>::load_datafile (char path[], v2d & X, v2d & V, v2d & Omega)
508 {
509  ifstream in ;
510 
511  in.open(path) ;
512  if (!in.is_open()) { printf("[Input] file cannot be open\n"); return ;}
513 
514  while (! in.eof())
515  {
516  interpret_command(in, X, V, Omega) ;
517  }
518 
519  for (auto v : dumps)
520  if (v.first==ExportType::XML || v.first==ExportType::XMLbase64)
521  xmlout= new XMLWriter(Directory+"/dump.xml") ;
522 
523  in.close() ;
524  // Self copy :)
525  fs::path p (path) ;
526  fs::path pcp (Directory+"/in") ;// pcp/= p.filename() ;
527  copy_file(p,pcp, fs::copy_options::overwrite_existing);
528 }
529 //-------------------------------------------------
530 template <int d>
531 void Parameters<d>::check_events(float time, v2d & X, v2d & V, v2d & Omega)
532 {
533  while (events.size()>0 && events.begin()->first < time)
534  {
535  stringstream command ; command.str(events.begin()->second) ;
536  printf("\nThe following event is implemented now: %s\n", events.begin()->second.c_str()) ;
537  interpret_command(command, X,V,Omega) ;
538  events.erase(events.begin()) ;
539  }
540 
541 }
542 //------------------------------------------------------
543 std::istream& operator>>(std::istream& in, std::variant<int*,double*,bool*> v)
544 {
545  printf("SETTING variable %ld\n", v.index());
546  switch(v.index())
547  {
548  case 0: in >> *(std::get<int*>(v)) ; break ;
549  case 1: in >> *(std::get<double*>(v)); break ;
550  case 2: in >> *(std::get<bool*>(v)); break ;
551  }
552  return(in) ;}
553 //------------------------------------------------------
554 template <int d>
555 void Parameters<d>::interpret_command (string &in, v2d & X, v2d & V, v2d & Omega)
556 {
557  stringstream B(in) ;
558  return (interpret_command(B, X, V, Omega)) ;
559 }
560 template <int d>
561 void Parameters<d>::interpret_command (istream & in, v2d & X, v2d & V, v2d & Omega)
562 {
563  map <string, std::variant<int*,double*,bool*>> SetValueMap = {
564  {"Kn",&Kn},
565  {"Kt",&Kt},
566  {"GammaN",&Gamman},
567  {"GammaT",&Gammat},
568  {"rho",&rho},
569  {"Mu",&Mu},
570  {"Mu_wall",&Mu_wall},
571  {"damping",&damping},
572  {"T",&T},
573  {"tdump",&tdump},
574  {"orientationtracking",&orientationtracking},
575  {"tinfo",&tinfo},
576  {"dt",&dt},
577  //{"skin", &skin},
578  {"gradientdescent_gamma", &graddesc_gamma},
579  {"gradientdescent_tol", &graddesc_tol},
580  {"cell_size", &cellsize},
581  {"forceinsphere", &forceinsphere}
582  } ;
583 
584 // Lambda definitions
585  auto discard_line = [&](){char line [5000] ; in.getline(line, 5000) ; } ;
586  auto read_event = [&](){float time ; char line [5000] ; in >> time ; in.getline (line, 5000) ; events.insert(make_pair(time,line)) ; printf("[INFO] Registering an event: %g -> %s\n", time, line) ;} ;
587  auto doauto = [&]() { char line [5000] ; in>>line ;
588  if (!strcmp(line, "mass")) init_mass() ;
589  else if (!strcmp(line, "rho"))
590  {
591  rho= m[0]/Tools<d>::Volume(r[0]) ;
592  printf("[INFO] Using first particle mass to set rho: %g [M].[L]^-%d\n", rho, d) ;
593  }
594  else if (!strcmp(line, "inertia")) init_inertia() ;
595  else if (!strcmp(line, "location"))
596  {
597  in >> line ;
598  char extras[5000]; in.getline(extras, 5000) ;
599  init_locations(line, X, extras) ;
600  printf("[INFO] Set all particle locations\n") ;
601  }
602  else if (!strcmp(line, "radius"))
603  {
604  in.getline(line, 5000) ;
605  init_radii(line, r) ;
606  printf("[INFO] Set all particle radii\n") ;
607  }
608  else printf("[WARN] Unknown auto command in input script\n") ;
609  printf("[INFO] Doing an auto \n") ;
610  } ;
611  auto setvalue = [&]() { char line[5000] ; in >> line ;
612  try {
613  in >> SetValueMap.at(line) ;
614  }
615  catch (const std::out_of_range & e) {
616  if (!strcmp(line, "dumps"))
617  {
618  string word ;
619  in>>word ;
620  ExportType dumpkind=ExportType::NONE ;
621  if (word=="CSV") dumpkind = ExportType::CSV ;
622  else if (word=="VTK") dumpkind = ExportType::VTK ;
623  else if (word=="NETCDFF") dumpkind = ExportType::NETCDFF ;
624  else if (word=="XML") dumpkind = ExportType::XML ;
625  else if (word=="XMLbase64") dumpkind = ExportType::XMLbase64 ;
626  else if (word=="CSVA") dumpkind = ExportType::CSVA ;
627  else if (word=="CONTACTFORCES") {dumpkind = ExportType::CSVCONTACT ; contactforcedump = true ; }
628  else if (word=="WALLFORCE") {wallforcecompute = true ; goto LABEL_leave ;} //Jumps at the end of the section
629  else {printf("Unknown dump type\n") ; }
630 
631  { // New section so g++ doesn't complains about the goto ...
632  in>>word ;
633  if (word != "with") printf("ERR: expecting keyword 'with'\n") ;
634  int nbparam ;
635  ExportData dumplist = ExportData::NONE ;
636  in>>nbparam ;
637  for (int i=0 ; i<nbparam ; i++)
638  {
639  in>>word ;
640  if (word=="Position") dumplist |= ExportData::POSITION ;
641  else if (word =="Velocity") dumplist |= ExportData::VELOCITY ;
642  else if (word =="Omega") dumplist |= ExportData::OMEGA ;
643  else if (word =="OmegaMag") dumplist |= ExportData::OMEGAMAG ;
644  else if (word =="Orientation")
645  {
646  orientationtracking=true ;
647  dumplist |= ExportData::ORIENTATION ;
648  }
649  else if (word =="Coordination") dumplist |= ExportData::COORDINATION ;
650  else if (word =="Radius") dumplist |= ExportData::RADIUS ;
651  else if (word =="Mass") dumplist |= ExportData::MASS ;
652 
653  else if (word =="Ids") dumplist |= ExportData::IDS ; // Contact properties
654  else if (word =="Fn") dumplist |= ExportData::FN ;
655  else if (word =="Ft") dumplist |= ExportData::FT ;
656  else if (word =="Torque") dumplist |= ExportData::TORQUE ;
657  else if (word =="Branch") dumplist |= ExportData::BRANCHVECTOR ;
658  else if (word =="Fn_el") dumplist |= ExportData::FN_EL ;
659  else if (word =="Fn_visc") dumplist |= ExportData::FN_VISC ;
660  else if (word =="Ft_el") dumplist |= ExportData::FT_EL ;
661  else if (word =="Ft_visc") dumplist |= ExportData::FT_VISC ;
662  else if (word =="Ft_fric") dumplist |= ExportData::FT_FRIC ;
663  else if (word =="Ft_frictype") dumplist |= ExportData::FT_FRICTYPE ;
664  else if (word =="Ghost_mask") dumplist |= ExportData::GHOSTMASK ;
665  else if (word =="Ghost_direction") dumplist |= ExportData::GHOSTDIR;
666 
667  else printf("Unknown asked data %s\n", word.c_str()) ;
668  }
669 
671  /*if constexpr (!SAVE_FORCE_COMPONENTS)
672  {
673  if (dumplist & (ExportData::FN_EL | ExportData::FN_VISC | ExportData::FT_EL | ExportData::FT_VISC | ExportData::FT_FRIC | ExportData::FT_FRICTYPE))
674  {
675  printf("WARN: NDDEM was compiled without support for force subcomponents exporting. Removing from the dump output.") ;
676  dumplist &= ~(ExportData::FN_EL | ExportData::FN_VISC | ExportData::FT_EL | ExportData::FT_VISC | ExportData::FT_FRIC | ExportData::FT_FRICTYPE) ;
677  }
678  }*/
679 
680  dumps.push_back(make_pair(dumpkind,dumplist)) ;
681  }
682  LABEL_leave: ; // Goto label (I know, not beautiful, but makes sense here really)
683  }
684  else
685  printf("[ERROR] Unknown parameter to set\n") ;
686  }
687  } ; // END of the setvalue lambda
688 
689 // Function mapping
690  map<string, function<void()>> Lvl0 ;
691  Lvl0["event"] = read_event ;
692  Lvl0["CG"] = discard_line ; // Discard CoarseGraining functions in DEM
693  Lvl0["set"] = setvalue ;
694  Lvl0["auto"] = doauto ;
695 
696  Lvl0["directory"] = [&](){in>>Directory ; if (! fs::exists(Directory)) fs::create_directory(Directory); };
697  Lvl0["dimensions"] = [&](){int nn; int dd ; in>>dd>>nn ; if (N!=nn || d!=dd) {printf("[ERROR] Dimension of number of particles not matching the input file requirements d=%d N=%d\n", d, N) ; std::exit(2) ; }} ;
698  Lvl0["location"] = [&]()
699  {
700  number_gen<int> ids ; number_gen<double> locs[d] ;
701  in >> ids ; for (int i=0 ; i<d ; i++) in >> locs[i] ;
702 
703  auto id=ids() ;
704  while (id.has_value())
705  {
706  for (int i=0 ; id.has_value() && i<d ; i++)
707  X[id.value()][i]= locs[i](true).value() ;
708  id = ids() ;
709  }
710  //try { while (1) for (int i=0, id=ids() ; i<d; i++) X[id][i]= locs[i](true) ; } catch(...) {}
711  //int id ; in>>id ; for (int i=0 ; i<d ; i++) {in >> X[id][i] ;}
712  //for (int i=0, id=ids(); i<d ; i++) { X[id][i]= locs[i]() ;}
713  printf("[INFO] Changing particle location.\n") ;
714 
715  } ;
716  Lvl0["velocity"] = [&](){int id ; in>>id ; for (int i=0 ; i<d ; i++) {in >> V[id][i] ;} printf("[INFO] Changing particle velocity.\n") ; } ;
717  Lvl0["omega"] = [&](){int id ; in>>id ; for (int i=0 ; i<d*(d-1)/2 ; i++) {in >> Omega[id][i] ;} printf("[INFO] Changing particle angular velocity.\n") ; } ;
718  Lvl0["freeze"] = [&](){int id ; in>>id ; Frozen[id]=true ; printf("[INFO] Freezing particle.\n") ;} ;
719  Lvl0["radius"] = [&](){int id ; double radius ; in>>id>>radius ; if(id==-1) r = v1d(N,radius) ; else r[id]=radius ; printf("[INFO] Set radius of particle.\n") ;} ;
720  Lvl0["mass"] = [&](){int id ; double mass ; in>>id>>mass ; if(id==-1) m = v1d(N,mass ) ; else r[id]=mass ; printf("[INFO] Set mass of particle.\n") ;} ;
721  Lvl0["gravity"] = [&](){for (int i=0 ; i<d ; i++) {in >> g[i] ;} printf("[INFO] Changing gravity.\n") ; } ;
722  Lvl0["ContactModel"] = [&](){ std::string s ; in >> s ; if (s=="Hertz") {ContactModel=ContactModels::HERTZ ;printf("[INFO] Using Hertz model\n") ;} else ContactModel=ContactModels::HOOKE ; } ;
723  Lvl0["ContactStrategy"] = [&](){ std::string s ; in >> s ; if (s=="naive") {contact_strategy = ContactStrategies::NAIVE ; }
724  else if (s=="cells") {contact_strategy = ContactStrategies::CELLS ; }
725  else if (s=="octree") {contact_strategy = ContactStrategies::OCTREE ; }
726  else {printf("[WARN] Unknown contact strategy\n") ; }} ;
727  Lvl0["gravityangle"] = [&](){ double intensity, angle ; in >> intensity >> angle ;
728  Tools<d>::setzero(g) ;
729  g[0] = -intensity * cos(angle / 180. * M_PI) ;
730  g[1] = intensity * sin(angle / 180. * M_PI) ;
731  printf("[INFO] Changing gravity angle in degree between x0 and x1.\n") ;
732  } ;
733  Lvl0["gravityrotate"] = [&] () {
734  update_gravity =&Parameters::do_gravityrotate;
735  Tools<d>::setzero(g) ;
736  in >> grav_intensity >> grav_omega >> grav_rotdim[0] >> grav_rotdim[1] ;
737  printf("[INFO] Setting up a rotating gravity\n") ;
738  } ;
739  Lvl0["boundary"] = [&](){size_t id ; in>>id ;
740  if (id>=Boundaries.size()) {Boundaries.resize(id+1) ;}
741  char line [5000] ; in>>line ;
742  if (!strcmp(line, "PBC"))
744  else if (!strcmp(line, "WALL"))
746  else if (!strcmp(line, "MOVINGWALL"))
748  else if (!strcmp(line, "SPHERE"))
750  else if (!strcmp(line, "HEMISPHERE"))
752  else if (!strcmp(line, "AXIALCYLINDER"))
754  else if (!strcmp(line, "ROTATINGSPHERE"))
756  else if (!strcmp(line, "PBCLE"))
757  {
758  assert((id==0)) ;
759  Boundaries[id].Type=WallType::PBC_LE ;
760  }
761  else if (!strcmp(line, "ELLIPSE"))
762  Boundaries[id].Type=WallType::ELLIPSE ;
763  else if (!strcmp(line, "REMOVE"))
764  { Boundaries.erase(Boundaries.begin() + id); return ; }
765  else printf("[WARN] Unknown boundary condition, unchanged.\n") ;
766 
767  Boundaries[id].read_line(in) ;
768 
769  printf("[INFO] Changing BC.\n") ;
770  };
771  Lvl0["rigid"] = [&] ()
772  {
773  size_t id, npart ; in >> id ;
774  if (RigidBodies.RB.size()<id+1) RigidBodies.RB.resize(id+1) ;
775  string s ; in>>s ;
776 
777  if (s=="set")
778  {
779  in >> npart ;
780  std::vector<int> ids ; int tmp ;
781  for (size_t i=0 ; i<npart ; i++)
782  {
783  in >> tmp ;
784  ids.push_back(tmp) ;
785  }
786  RigidBodies.RB[id].setparticles(ids, X, m) ;
787  }
788  else if (s=="gravity")
789  {
790  in >> s ;
791  if (s=="on") RigidBodies.RB[id].cancelgravity = false ;
792  else if (s=="off") RigidBodies.RB[id].cancelgravity = true ;
793  }
794  else if (s=="addforce")
795  {
796  for (int dd=0 ; dd<d ; dd++)
797  in >> RigidBodies.RB[id].addforce[dd] ; //= nan_or_double(in) ;
798  }
799  else if (s=="velocity")
800  {
801  for (int dd=0 ; dd<d ; dd++)
802  RigidBodies.RB[id].setvel[dd] = nan_or_double(in) ;
803  printf("%g %g\n", RigidBodies.RB[0].setvel[0], RigidBodies.RB[0].setvel[1]) ;
804  }
805 
806  printf("[INFO] Defining a rigid body.\n") ;
807  };
808  Lvl0["mesh"] = [&] ()
809  {
810  string s ; in>>s ;
811  json j;
812  if (s=="file" || s=="string")
813  {
814  if (s=="file")
815  {
816  in >> s ;
817  std::ifstream i(s.c_str());
818  if (i.is_open()==false) {printf("Cannot find the json file provided as argument\n") ; return ; }
819  i >> j;
820  }
821  else
822  {
823  std::getline(in, s) ;
824  j=json::parse(s) ;
825  }
826  //try
827  {
828  if (j["dimension"].get<int>()!=d) {printf("Incorrect dimension in the json Mesh file: %d, expecting %d.\n", j["dimension"].get<int>(),d) ; return ;}
829  for (auto & v: j["objects"])
830  {
831  Meshes.push_back({v[STR_PROTECT("dimensionality")].get<int>(), v["vertices"].get<std::vector<std::vector<double>>>()}) ;
832 
833  printf("[INFO] Mesh object added.\n") ;
834  }
835  }
836  }
837  else if (s=="translate")
838  {
839  std::vector<double> t(d,0) ;
840  for (int i=0 ; i<d ; i++) in>>t[i] ;
841  for (auto &v: Meshes) v.translate(t) ;
842  }
843  else if (s=="rotate")
844  {
845  std::vector<double> r(d*d, 0) ;
846  for (int i=0 ; i<d*d ; i++) in >> r[i] ;
847  for (auto &v: Meshes) v.rotate(r) ;
848  }
849  else if (s=="remove")
850  {
851  int id ;
852  in >> id ;
853  Meshes.erase(Meshes.begin()+id) ;
854  }
855  else if (s=="export")
856  {
857  in >> s ;
858  FILE * out = fopen(s.c_str(), "w") ;
859  if (out==NULL) printf("[WARN] Cannot open file to export mesh") ;
860  else
861  {
862  fprintf(out, "{\n \"dimension\": %d, \n \"objects\":[\n", d) ;
863  for (size_t i=0 ; i<Meshes.size() ; i++)
864  {
865  auto res = Meshes[i].export_json() ;
866  fprintf(out, "%s", res.c_str()) ;
867  if (i<Meshes.size()-1) fprintf(out, ",\n") ;
868  }
869  fprintf(out, "\n]}") ;
870  fclose(out) ;
871  }
872  //for (auto & v: Meshes) v.disp() ;
873  }
874  else
875  printf("[WARN] Unknown mesh subcommand\n") ;
876 
877  };
878  Lvl0["restart"] = [&] () {
879  restart_flag=0 ;
880  std::string s ; in >> s ;
881  if (s=="ignore")
882  restart_flag |= (1<<1) ;
883  else if (s=="force")
884  restart_flag |= (2<<1) ;
885 
886  in >> s ;
887  if (s=="keepall")
888  restart_flag |= 1 ;
889 
890  in >> n_restart ;
891  in >> restart_filename ;
892  } ;
893 
894 
895 // Processing
896  string line ;
897  in>>line;
898  if (line[0]=='#') {discard_line() ; return ;}
899  try {Lvl0.at(line)() ; }
900  catch (const std::out_of_range & e) { printf("LVL0 command unknown: %s\n", line.c_str()) ; discard_line() ; }
901 
902 }
903 //================================================================================================================================================
904 
905 //=====================================
906 template <int d>
907 void Parameters<d>::remove_particle (int idx, v2d & X, v2d & V, v2d & A, v2d & Omega, v2d & F, v2d & FOld, v2d & Torque, v2d & TorqueOld)
908 {
909  printf("WARN: it is probably a bad idea to use remove particle which hasn't been tested ... \n") ;
910  X.erase (X.begin()+idx) ; V.erase (V.begin()+idx) ;
911  A.erase (A.begin()+idx) ; Omega.erase (Omega.begin()+idx) ;
912  F.erase (F.begin()+idx) ; FOld.erase (FOld.begin()+idx) ;
913  Torque.erase (Torque.begin()+idx) ; TorqueOld.erase (TorqueOld.begin()+idx) ;
914  I.erase(I.begin()+idx) ; m.erase(m.begin()+idx) ; r.erase(r.begin()+idx) ;
915  Frozen.erase(Frozen.begin()+idx) ;
916  N-- ;
917 }
918 //--------------------
919 template <int d>
920 void Parameters<d>::add_particle (/*v2d & X, v2d & V, v2d & A, v2d & Omega, v2d & F, v2d & FOld, v2d & Torque, v2d & TorqueOld*/)
921 {
922  printf("add_particle NOT IMPLEMENTED YET\n") ;
923 }
924 //----------------
925 template <int d>
926 void Parameters<d>::init_locations (char *line, v2d & X, char *extras)
927 {
928  boost::random::mt19937 rng(seed);
929  boost::random::uniform_01<boost::mt19937> rand(rng) ;
930  if (!strcmp(line, "square"))
931  {
932  auto m = *(std::max_element(r.begin(), r.end())) ;
933  printf("%g\n", m) ;
934  int dd ;
935  for (dd=0 ; dd<d ; dd++) X[0][dd]=Boundaries[dd].xmin+m ;
936  for (int i=1 ; i<N ; i++)
937  {
938  X[i]=X[i-1] ;
939  for (dd=0 ; dd<d ; dd++)
940  {
941  X[i][dd] += 2*m ;
942  if (X[i][dd] > Boundaries[dd].xmax-m)
943  X[i][dd] = Boundaries[dd].xmin+m ;
944  else
945  break ;
946  }
947  if (dd==d) {printf("WARN: cannot affect all particles on the square lattice, not enough space in the simulation box\n") ; break ; }
948  }
949  }
950  else if (!strcmp(line, "randomsquare"))
951  {
952  auto m = *(std::max_element(r.begin(), r.end())) ;
953  printf("%g\n", m) ;
954  int dd ;
955  for (dd=0 ; dd<d ; dd++) X[0][dd]=Boundaries[dd].xmin+m ;
956  for (int i=1 ; i<N ; i++)
957  {
958  X[i]=X[i-1] ;
959  for (dd=0 ; dd<d ; dd++)
960  {
961  X[i][dd] += 2*m ;
962  if (X[i][dd] > Boundaries[dd].xmax-m)
963  X[i][dd] = Boundaries[dd].xmin+m + 0.1*m*(rand()-0.5) ;
964  else
965  break ;
966  }
967  if (dd==d) {printf("WARN: cannot affect all particles on the square lattice, not enough space in the simulation box\n") ; break ; }
968  }
969  }
970  else if (!strcmp(line, "randomdrop"))
971  {
972 
973  for (int i=0 ; i<N ; i++)
974  {
975  for(int dd=0 ; dd < d ; dd++)
976  {
977  if (Boundaries[dd].Type==WallType::PBC)
978  X[i][dd] = rand()*Boundaries[dd].delta + Boundaries[dd].xmin ;
979  else
980  X[i][dd] = rand()*(Boundaries[dd].delta-2*r[i]) + Boundaries[dd].xmin + r[i] ;
981  }
982  }
983  }
984  else if (!strcmp(line, "insphere"))
985  {
986  //printf("Location::insphere assumes that wall #d is a sphere") ; fflush(stdout) ;
987  auto w = std::find_if(Boundaries.begin(), Boundaries.end(), [](auto u){return (u.Type==WallType::SPHERE || u.Type==WallType::ROTATINGSPHERE) ; }) ;
988  if ( w == Boundaries.end()) {printf("ERR: the spherical wall cannot be found\n") ; fflush(stdout) ; }
989  int id = w-Boundaries.begin() ;
990 
991  for (int i=0 ; i<N ; i++)
992  {
993  double dst=0 ;
994  printf(".") ; fflush(stdout);
995  do {
996  dst=0 ;
997  for(int dd=0 ; dd < d ; dd++)
998  {
999  X[i][dd] = (rand()*Boundaries[id].radius*2-Boundaries[id].radius) + Boundaries[id].center[dd] ;
1000  dst += (Boundaries[id].center[dd]-X[i][dd])*(Boundaries[id].center[dd]-X[i][dd]) ;
1001  }
1002  } while ( sqrt(dst) > (Boundaries[id].radius-2*r[i])) ;
1003  }
1004  }
1005  else if (!strcmp(line, "incylinder"))
1006  {
1007  //printf("Location::insphere assumes that wall #d is a sphere") ; fflush(stdout) ;
1008  auto w = std::find_if(Boundaries.begin(), Boundaries.end(), [](auto u){return (u.Type==WallType::AXIALCYLINDER) ; }) ;
1009  if ( w== Boundaries.end()) {printf("ERR: the cylinder wall cannot be found\n") ; fflush(stdout) ; }
1010  int id = w-Boundaries.begin() ;
1011 
1012  for (int i=0 ; i<N ; i++)
1013  {
1014  double dst=0 ;
1015  printf(".") ; fflush(stdout);
1016  do {
1017  dst=0 ;
1018  for(int dd=0 ; dd < d ; dd++)
1019  {
1020  if (dd == Boundaries[id].axis)
1021  {
1022  X[i][dd] = rand() * (Boundaries[Boundaries[id].axis].delta-2*r[i]) + Boundaries[Boundaries[id].axis].xmin + r[i] ;
1023  }
1024  else
1025  {
1026  X[i][dd] = (rand()*Boundaries[id].radius*2-Boundaries[id].radius) ;
1027  dst += X[i][dd]*X[i][dd] ;
1028  }
1029  }
1030  } while ( sqrt(dst) > (Boundaries[id].radius-2*r[i])) ;
1031  }
1032  }
1033  else if (!strcmp(line, "roughinclineplane"))
1034  {
1035  printf("Location::roughinclineplane assumes a plane of normal [1,0,0...] at location 0 along the 1st dimension.") ; fflush(stdout) ;
1036  auto m = *(std::max_element(r.begin(), r.end())) ; // Max radius
1037  double delta=0.1*m ;
1038  for (int dd=0 ; dd<d ; dd++) X[0][dd]=Boundaries[dd].xmin+m+delta ;
1039  Frozen[0]=true ;
1040  for (int i=1 ; i<N ; i++)
1041  {
1042  X[i]=X[i-1] ;
1043  for (int dd=d-1 ; dd>=0 ; dd--)
1044  {
1045  X[i][dd] += 2*m+2*delta ;
1046  if (X[i][dd]>Boundaries[dd].xmax-m-delta)
1047  X[i][dd] = Boundaries[dd].xmin+m+delta ;
1048  else
1049  break ;
1050  }
1051  if (X[i][0]==Boundaries[0].xmin+m+delta) Frozen[i]=true ;
1052  // randomize the previous grain
1053  for (int dd=0 ; dd<d ; dd++)
1054  X[i-1][dd] += (rand()-0.5)*2*delta ;
1055  }
1056  }
1057  else if (!strcmp(line, "smallroughinclineplane"))
1058  {
1059  printf("Location::smallroughinclineplane assumes a plane of normal [1,0,0...] at location 0 along the 1st dimension. The frozen particles are forced to be the smallest particle radius\n") ; fflush(stdout) ;
1060  auto r_max = *(std::max_element(r.begin(), r.end())) ; // Max radius
1061  auto r_min = *(std::min_element(r.begin(), r.end())) ; // Max radius
1062  double m = r_max;
1063  double delta=0.1*r_max ;
1064  int i_bottom_layer = 1;
1065  for (int dd=1 ; dd<d ; dd++)
1066  i_bottom_layer *= floor(Boundaries[dd].delta/(2*r_min+0.2*r_min)) ;
1067  printf("BOTTOM LAYER NUMBER: %d\n", i_bottom_layer);
1068  // for (int dd=1 ; dd<d ; dd++) X[0][dd]=Boundaries[dd].xmin+r_max+delta ; // skip first dimension
1069  Frozen[0]=true ;
1070  r[0] = r_min;
1071  for (int i=1 ; i<N ; i++)
1072  {
1073  X[i]=X[i-1] ;
1074  if (i < i_bottom_layer ) {
1075  Frozen[i]=true ;
1076  r[i] = r_min;
1077  m = r_min;
1078  delta = 0.1*r_min;
1079  } else {
1080  m = r_max;
1081  delta = 0.1*r_max;
1082  }
1083  for (int dd=d-1 ; dd>=0 ; dd--)
1084  {
1085  X[i][dd] += 2*m+2*delta ;
1086  if (X[i][dd]>Boundaries[dd].xmax-m-delta)
1087  if (i < i_bottom_layer ) {
1088  X[i][dd] = 0 ;
1089  } else {
1090  X[i][dd] = Boundaries[dd].xmin+m+delta ;
1091  }
1092  else
1093  break ;
1094  }
1095  // randomize this grain EXCEPT if it is a boundary particle
1096  for (int dd=0 ; dd<d ; dd++) {
1097  if (i >= i_bottom_layer) {
1098  X[i][dd] += (rand()-0.5)*2*delta ;
1099  }
1100  }
1101  }
1102  // add some randomness to boundary particles in first dimension only
1103  for (int i=1 ; i<i_bottom_layer ; i++)
1104  {
1105  X[i][0] += rand()*2*delta;
1106  }
1107  }
1108  else if (!strcmp(line, "roughinclineplane2"))
1109  {
1110  printf("Location::roughinclineplane assumes a plane of normal [1,0,0...] at location 0 along the 1st dimension.") ; fflush(stdout) ;
1111  auto m = *(std::max_element(r.begin(), r.end())) ; // Max radius
1112  double delta=0.1*m ; int ddd ;
1113  for (int dd=0 ; dd<d ; dd++) X[0][dd]=Boundaries[dd].xmin+m ;
1114  Frozen[0]=true ; bool bottomlayer=true ;
1115  for (int i=1 ; i<N ; i++)
1116  {
1117  X[i]=X[i-1] ;
1118  for (ddd=d-1 ; ddd>=0 ; ddd--)
1119  {
1120  if (bottomlayer)
1121  {
1122  X[i][ddd]+= 2*m ;
1123  if (X[i][ddd]>Boundaries[ddd].xmax-m)
1124  X[i][ddd] = Boundaries[ddd].xmin+m ;
1125  else
1126  break ;
1127  }
1128  else
1129  {
1130  X[i][ddd] += 2*m+2*delta ;
1131  if (X[i][ddd]>Boundaries[ddd].xmax-m-delta)
1132  X[i][ddd] = Boundaries[ddd].xmin+m+delta ;
1133  else
1134  break ;
1135  }
1136  }
1137  if (ddd==0) bottomlayer=false ;
1138  if (bottomlayer)
1139  {
1140  Frozen[i-1]=true ;
1141  X[i-1][0] += rand()*delta ; // Randomness only on x0, and only >r (above the bottom wall)
1142  }
1143  else
1144  {
1145  for (int dd=0 ; dd<d ; dd++)
1146  X[i-1][dd] += (rand()-0.5)*2*delta ;
1147  }
1148  }
1149  }
1150  else if (!strcmp(line, "quasicrystal"))
1151  {
1152  auto m = *(std::max_element(r.begin(), r.end())) ; // largest radius
1153  printf("%g\n", m) ;
1154  int dd ;
1155  // X is an array of particle locations
1156  for (dd=0 ; dd<d ; dd++) { X[0][dd]=Boundaries[dd].xmin+m ; } // d is number of dimensions, dd is its index
1157  for (int i=1 ; i<N ; i++) // number of particles
1158  {
1159  X[i]=X[i-1] ; // get previous particle location
1160  for (dd=0 ; dd<d ; dd++) // iterate over dimensions
1161  {
1162  X[i][dd] += 2*m ; // add a diameter
1163  if (X[i][dd]>Boundaries[dd].xmax-m) // if too close to 'right'
1164  X[i][dd] = Boundaries[dd].xmin+m ; // bring back to 'left'
1165  else
1166  break ;
1167  }
1168  if (dd==d) {printf("WARN: cannot affect all particles on the square lattice, not enough space in the simulation box\n") ; break ; }
1169  }
1170  }
1171  else if (!strcmp(line, "fromfile"))
1172  {
1173  while (*extras == ' ') extras++ ;
1174  std::ifstream in(extras); // Open the file
1175 
1176  if (!in) { std::cerr << "Failed to open the file." << std::endl; return;}
1177  while (!in.eof())
1178  {
1179  int idx ;
1180  in >> idx ;
1181  for (int dd=0 ; dd<d ; dd++)
1182  in >> X[idx][dd] ;
1183  in >> r[idx] ;
1184  }
1185  }
1186  else
1187  printf("ERR: undefined initial location function.\n") ;
1188 }
1189 //-----------------------------
1190 template <int d>
1191 void Parameters<d>::init_radii (char line[], v1d & r)
1192 {
1193  std::istringstream s(line) ;
1194  std::string word ;
1195  double minr, maxr, fraction, fuzz ;
1196  boost::random::mt19937 rng(seed);
1197  boost::random::uniform_01<boost::mt19937> rand(rng) ;
1198 
1199  s >> word ;
1200  printf("[%s]\n", word.c_str()) ;
1201  if (word == "uniform")
1202  {
1203  s >> minr ; s >> maxr ;
1204  for (auto & v : r) v = rand()*(maxr-minr)+minr ;
1205  }
1206  else if (word == "bidisperse")
1207  {
1208  s >> minr ; s >> maxr ;
1209  s >> fraction ;
1210 
1211  double Vs=Tools<d>::Volume(minr) ;
1212  double Vl=Tools<d>::Volume(maxr) ;
1213  double f = fraction*Vs/((1-fraction)*Vl+fraction*Vs) ;
1214 
1215  for (auto & v : r) v = (rand()<f?maxr:minr) ;
1216 
1217  }
1218  else if (word == "bidisperse_fuzzy")
1219  {
1220  s >> minr ; s >> maxr ;
1221  s >> fraction ;
1222  s >> fuzz ;
1223 
1224  double Vs=Tools<d>::Volume(minr) ;
1225  double Vl=Tools<d>::Volume(maxr) ;
1226  double f = fraction*Vs/((1-fraction)*Vl+fraction*Vs) ;
1227 
1228  for (auto & v : r)
1229  {
1230  v = (rand()<f?maxr:minr) ;
1231  v = v + (rand()*2-1)*(fuzz*v) ;
1232  }
1233  }
1234  else
1235  printf("WARN: unknown radius distribution automatic creation. Nothing done ...\n") ;
1236 }
1237 
1238 
1239 //======================================
1240 template <int d>
1241 void Parameters<d>::display_info(int tint, v2d& V, v2d& Omega, v2d& F, v2d& Torque, int nct, int ngst)
1242 {
1243 static bool first=true ;
1244 static double Rmax, mmax ;
1245 if (first)
1246 {
1247  Rmax=*max_element(r.begin(), r.end()) ;
1248  mmax=*max_element(m.begin(), m.end()) ;
1249  //printf("\e[10S\e[9A") ;
1250 }
1251 
1252 //printf("\e[s%c\n", letters[tint%4]) ;
1253 //printf("\033%c %c\n", 0x37, letters[tint%4]) ;
1254 if (tint%tinfo==0)
1255 {
1256  //for (int i=0 ; i<(tint*100)/int(T/dt) ; i++) printf("#") ;
1257  //printf("%d %d %d ",tint, T, (tint*100)/T) ;
1258  if (!first) printf("\e[8A") ;
1259  printf("\e[80G") ;
1260  printf("\n\e[80G NContacts: %d | Nghosts: %d \n", nct, ngst) ;
1261 
1262  double Vmax=Tools<d>::norm(*max_element(V.begin(), V.end(), [](cv1d &a, cv1d &b) {return (Tools<d>::normsq(a)<Tools<d>::normsq(b)) ;})) ;
1263  double Omegamax=Tools<d>::skewnorm(*max_element(Omega.begin(), Omega.end(), [](cv1d &a, cv1d &b) {return (Tools<d>::skewnormsq(a)<Tools<d>::skewnormsq(b)) ;})) ;
1264  double Torquemax=Tools<d>::skewnorm(*max_element(Torque.begin(), Torque.end(), [](cv1d &a, cv1d &b) {return (Tools<d>::skewnormsq(a)<Tools<d>::skewnormsq(b)) ;})) ;
1265  double Fmax=Tools<d>::norm(*max_element(F.begin(), F.end(), [](cv1d &a, cv1d &b) {return (Tools<d>::normsq(a)<Tools<d>::normsq(b)) ;})) ;
1266 
1267  printf("\n") ;
1268  printf("\e[80G Max V: %15g | V dt / R = %15g \n", Vmax, Vmax*dt/Rmax) ;
1269  printf("\e[80G Max O: %15g | Omega dt = %15g \n", Omegamax, Omegamax*dt) ;
1270  printf("\e[80G Max F: %15g | F dt dt / m r = %15g \n", Fmax, Fmax*dt*dt/(mmax*Rmax)) ;
1271  printf("\e[80G Max M: %15g | M dt / m R R = %15g \n", Torquemax, Torquemax*dt/(mmax*Rmax*Rmax)) ;
1272  printf("\e[80G | g dt dt / R = %15g \n", Tools<d>::norm(g)*dt*dt/Rmax) ;
1273 
1274 //printf("\e[u") ;
1275 //printf("\\033%c", 0x38) ;
1276 printf("\e[0G") ;
1277 fflush(stdout) ;
1278 }
1279 if (first) first=false ;
1280 }
1281 //------------------------------------------
1282 template <int d>
1284 {
1285  xmlout->openbranch("boundaries", {make_pair("length", to_string(d*2))}) ;
1287  for (int i=0 ; i<d ; i++) xmlout->fic << Boundaries[0].center[d]-Boundaries[0].radius << " " << Boundaries[0].center[d]+Boundaries[0].radius << " " ;
1288  else
1289  for (int i=0 ; i<d ; i++) xmlout->fic << Boundaries[i].xmin << " " << Boundaries[i].xmax << " " ;
1290  xmlout->closebranch() ;
1291 
1292  xmlout->openbranch("radius", {make_pair("length", to_string(N))}) ;
1293  for (auto v: r) xmlout->fic << v << " " ;
1294  xmlout->closebranch() ;
1295 }
1296 
1297 //-----------------------------------------
1298 template <int d>
1300 {
1301  for (auto v : dumps)
1302  if ((v.first == ExportType::XML) || (v.first == ExportType::XMLbase64))
1303  xmlout->emergencyclose() ;
1304 }
1305 template <int d>
1307 {
1308  for (auto v : dumps)
1309  if ((v.first == ExportType::XML) || (v.first == ExportType::XMLbase64))
1310  xmlout->close() ;
1311 }
1312 
1313 
1314 //========================================
1315 template <int d>
1316 int Parameters<d>::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)
1317 {
1318  static bool xmlstarted=false ;
1319 
1320  for (auto v : dumps)
1321  {
1322  if (v.first==ExportType::CSV)
1323  {
1324  char path[500] ; sprintf(path, "%s/dump-%05d.csv", Directory.c_str(), ti) ;
1325  Tools<d>::norm(Vmag, V) ; Tools<d>::norm(OmegaMag, Omega) ;
1326  if ( v.second & ExportData::VELOCITY)
1327  {
1328  Tools<d>::savecsv(path, X, V, r, PBCFlags, Vmag, OmegaMag, Z) ; //These are always written for CSV, independent of the dumplist
1329  }
1330  else
1331  {
1332  Tools<d>::savecsv(path, X, r, PBCFlags, Vmag, OmegaMag, Z) ; //These are always written for CSV, independent of the dumplist
1333  }
1334  if (v.second & ExportData::ORIENTATION)
1335  {
1336  char path[500] ; sprintf(path, "%s/dumpA-%05d.csv", Directory.c_str(), ti) ;
1337  Tools<d>::savecsv(path, A) ;
1338  }
1339  }
1340 
1341 
1342  if (v.first == ExportType::CSVCONTACT)
1343  {
1344  char path[500] ; sprintf(path, "%s/dumpcontactforce-%05d.csv", Directory.c_str(), ti) ;
1345  FILE * out = fopen(path, "w") ;
1346  if (out == NULL) {printf("[ERR] Cannot open file for contact force writing.\n") ; fflush(stdout) ; return 1 ; }
1347  savecsvcontact(out, v.second, MP, X) ;
1348  fclose(out) ;
1349  }
1350 
1351  if (v.first == ExportType::VTK)
1352  {
1353  v2d tmp ;
1354  char path[500] ; sprintf(path, "%s/dump-%05d.vtk", Directory.c_str(), ti) ;
1355 
1356  FILE * out = vtkwriter::open (path, d) ;
1357  vtkwriter::write_points(out, X, d) ;
1358 
1359  vector<std::pair<ExportData, int>> mapping ;
1360  vector<vector<double>> contactdata ;
1362  {
1363  std::tie(mapping, contactdata) = MP.contacts2array(v.second, X, *this) ;
1364  if (mapping[0].first != ExportData::IDS) printf("ERR: something went wrong in writing contact data in the vtk file %X\n", static_cast<unsigned int>(mapping[0].first)) ;
1365  vtkwriter::write_contactlines (out, contactdata) ;
1366  }
1367 
1368  vtkwriter::start_pointdata(out, X) ;
1370 
1371  vector <TensorInfos> val;
1372  if (v.second & ExportData::VELOCITY) vtkwriter::write_data(out, {"Velocity", TensorType::VECTOR, &V}, d) ;
1373  if (v.second & ExportData::OMEGA) vtkwriter::write_data(out, {"Omega", TensorType::SKEWTENSOR, &Omega}, d) ;
1374  if (v.second & ExportData::OMEGAMAG) {tmp.push_back(OmegaMag) ; vtkwriter::write_data(out, {"OmegaMag", TensorType::SCALAR, &tmp}, d) ;}
1375  if (v.second & ExportData::ORIENTATION) vtkwriter::write_data(out, {"ORIENTATION", TensorType::TENSOR, &A}, d) ;
1376  if (v.second & ExportData::RADIUS) {tmp.push_back(r) ; vtkwriter::write_data(out, {"RADIUS", TensorType::SCALAR, &tmp}, d) ;}
1377  if (v.second & ExportData::MASS) {tmp.push_back(m) ; vtkwriter::write_data(out, {"MASS", TensorType::SCALAR, &tmp}, d) ;}
1378  if (v.second & ExportData::COORDINATION) {tmp.push_back(Z) ; vtkwriter::write_data(out, {"Coordination", TensorType::SCALAR, &tmp}, d) ; }
1379  if (v.second & ExportData::IDS) {
1380  vector<double> tmpid (N, 0) ;
1381  for (int i=0 ; i<N ; i++)
1382  tmpid[i]=i ;
1383  tmp.push_back(tmpid) ; vtkwriter::write_data(out, {"Id", TensorType::SCALAR, &tmp}, d) ;
1384  }
1385 
1386  if (mapping.size()>1)
1387  {
1388  vtkwriter::start_celldata(out, X.size(), contactdata.size());
1389 
1390  for (auto & v:mapping)
1391  {
1392  switch(v.first){
1393  case ExportData::CONTACTPOSITION : vtkwriter::write_celldata (out, "Locations", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1394  case ExportData::FN : vtkwriter::write_celldata (out, "NormalForce", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1395  case ExportData::FT : vtkwriter::write_celldata (out, "TangentialForce", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1396  case ExportData::BRANCHVECTOR : vtkwriter::write_celldata (out, "BranchVector", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1397  case ExportData::FN_EL : vtkwriter::write_celldata (out, "ElasticNormalForce", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1398  case ExportData::FN_VISC : vtkwriter::write_celldata (out, "ViscousNormalForce", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1399  case ExportData::FT_EL : vtkwriter::write_celldata (out, "ElasticTangentialForce", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1400  case ExportData::FT_VISC : vtkwriter::write_celldata (out, "VisousTangentialForce", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1401  case ExportData::FT_FRIC : vtkwriter::write_celldata (out, "FrictionForce", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1402  case ExportData::FT_FRICTYPE : vtkwriter::write_celldata (out, "FrictionActivated", contactdata, TensorType::VECTOR, v.second, N, d) ; break ;
1403  case ExportData::GHOSTMASK : vtkwriter::write_celldata (out, "GhostMask", contactdata, TensorType::SCALARMASK, v.second, N, d) ; break ;
1404  case ExportData::GHOSTDIR : vtkwriter::write_celldata (out, "GhostDirection", contactdata, TensorType::SCALARMASK, v.second, N, d) ; break ;
1405  default: break ;
1406  }
1407  }
1408  }
1409 
1410  vtkwriter::close(out) ;
1411  //Tools<d>::savevtk(path, N, Boundaries, X, r, {}) ;
1412  }
1413 
1414  if (v.first == ExportType::NETCDFF)
1415  printf("WARN: netcdf writing hasn't been tested and therefore is not plugged in\n") ;
1416 
1417  if (v.first == ExportType::XML)
1418  {
1419  if (xmlstarted==false)
1420  {
1421  char path[500] ; sprintf(path, "%s/dump.xml", Directory.c_str()) ;
1422  xmlout->header(d, path) ;
1423  xml_header() ;
1424  xmlstarted=true ;
1425  }
1426  xmlout->startTS(t);
1429  if (v.second & ExportData::OMEGA) xmlout->writeArray("Omega", &Omega, ArrayType::particles, EncodingType::ascii);
1430  if (v.second & ExportData::OMEGAMAG)
1431  printf("Omega Mag not implemented yet\n");
1434 
1436  {
1437  auto [mapping, tmp] = MP.contacts2array(v.second, X, *this) ;
1438  for (auto & v:mapping)
1439  {
1440  switch(v.first){
1441  case ExportData::IDS: xmlout->writeArray("Ids", &tmp, v.second, 2, ArrayType::contacts, EncodingType::ascii) ; break ;
1442  case ExportData::CONTACTPOSITION : xmlout->writeArray("Locations", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1443  case ExportData::FN : xmlout->writeArray("Normal force", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1444  case ExportData::FT : xmlout->writeArray("Tangential force", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1445  case ExportData::BRANCHVECTOR : xmlout->writeArray("Branch vector", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1446  case ExportData::FN_EL : xmlout->writeArray("Elastic normal force", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1447  case ExportData::FN_VISC : xmlout->writeArray("Viscous normal force", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1448  case ExportData::FT_EL : xmlout->writeArray("Elastic tangential force", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1449  case ExportData::FT_VISC : xmlout->writeArray("Visous tangential force", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1450  case ExportData::FT_FRIC : xmlout->writeArray("Friction force", &tmp, v.second, d, ArrayType::contacts, EncodingType::ascii) ; break ;
1451  case ExportData::FT_FRICTYPE : xmlout->writeArray("Friction activated", &tmp, v.second, 1, ArrayType::contacts, EncodingType::ascii) ; break ;
1452  case ExportData::GHOSTMASK : xmlout->writeArray("Ghost mask", &tmp, v.second, 1, ArrayType::contacts, EncodingType::ascii) ; break ;
1453  case ExportData::GHOSTDIR : xmlout->writeArray("Ghost direction", &tmp, v.second, 1, ArrayType::contacts, EncodingType::ascii) ; break ;
1454  default: break ;
1455  }
1456  }
1457  }
1458 
1459 // case ExportData::POSITION: res.push_back(loc) ; break ;
1460 // case ExportData::FN: res.push_back(contact.infos->Fn) ; break ;
1461 // case ExportData::FT: res.push_back(contact.infos->Ft) ; break ;
1462 // case ExportData::GHOSTMASK: res.push_back(contact.infos->ghost) ; break ;
1463 // case ExportData::GHOSTDIR : res.push_back(contact.infos->ghostdir) ; break ;
1464 // case ExportData::BRANCHVECTOR: res.push_back(branch) ; break ;
1465  xmlout->stopTS();
1466  }
1467 
1468  if (v.first == ExportType::XMLbase64)
1469  {
1470  if (xmlstarted==false)
1471  {
1472  char path[500] ; sprintf(path, "%s/dump.xml", Directory.c_str()) ;
1473  xmlout->header(d, path) ;
1474  xml_header() ;
1475  xmlstarted=true ;
1476  }
1477  xmlout->startTS(t);
1480  if (v.second & ExportData::OMEGA) xmlout->writeArray("Omega", &Omega, ArrayType::particles, EncodingType::base64);
1481  if (v.second & ExportData::OMEGAMAG)
1482  printf("Omega Mag not implemented yet\n");
1485  xmlout->stopTS();
1486  }
1487 
1488  }
1489 return 0 ;
1490 }
1491 
1492 #endif
double nan_or_double(istream &in)
Definition: Parameters.h:384
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)))
Manual multiprocessor handling for OpenMP, for max efficiency & avoiding bugs & race conditions,...
Definition: Multiproc.h:60
vector< ContactList< d > > CLp
ContactList particle-particle for each processor.
Definition: Multiproc.h:271
Generic class to handle the simulation set up.
Definition: Parameters.h:128
vector< double > g
Gravity vector.
Definition: Parameters.h:195
void do_nothing(double time __attribute__((unused)))
Definition: Parameters.h:262
bool contactforcedump
Extract the forces between grains as well?
Definition: Parameters.h:205
bool orientationtracking
Track orientation?
Definition: Parameters.h:199
void load_datafile(char path[], v2d &X, v2d &V, v2d &Omega)
Load and parse input script.
Definition: Parameters.h:507
void remove_particle(int idx, v2d &X, v2d &V, v2d &A, v2d &Omega, v2d &F, v2d &FOld, v2d &Torque, v2d &TorqueOld)
Not tested.
Definition: Parameters.h:907
XMLWriter * xmlout
Definition: Parameters.h:371
bool perform_forceinsphere(v1d &X)
Definition: Parameters.h:231
void perform_PBCLE_move()
Definition: Parameters.h:448
void do_gravityrotate(double deltatime)
Definition: Parameters.h:264
double T
Run until this time (note it is a floating point).
Definition: Parameters.h:175
void quit_cleanly()
Close opened dump files in the event of an emergency quit (usually a SIGINT signal to the process)
Definition: Parameters.h:1299
void init_radii(char line[], v1d &r)
Set particle radii.
Definition: Parameters.h:1191
bool forceinsphere
Definition: Parameters.h:185
void serialize(Archive &ar)
Definition: Parameters.h:217
void xml_header()
Write the Xml header (should go into a file dedicated to the writing though ...)
Definition: Parameters.h:1283
bool wallforcecompute
Compute for on the wall?
Definition: Parameters.h:200
vector< double > r
Particle radii.
Definition: Parameters.h:192
int N
Number of particles.
Definition: Parameters.h:172
void display_info(int tint, v2d &V, v2d &Omega, v2d &F, v2d &Torque, int, int)
On screen information display.
Definition: Parameters.h:1241
RigidBodies_< d > RigidBodies
Handle all the rigid bodies.
Definition: Parameters.h:208
void perform_PBCLE(v1d &X, v1d &V, uint32_t &PBCFlag)
Definition: Parameters.h:425
int tinfo
Show detail information on scren every this many timesteps.
Definition: Parameters.h:174
double Kt
Tangential spring constant.
Definition: Parameters.h:179
double Gamman
Normal dissipation.
Definition: Parameters.h:180
bool wallforcerequested
Compute for on the wall?
Definition: Parameters.h:201
double graddesc_gamma
Decay rate parameters for the gradient descent algorithm.
Definition: Parameters.h:203
void finalise()
Close opened dump files.
Definition: Parameters.h:1306
Parameters()
Definition: Parameters.h:130
string Directory
Saving directory.
Definition: Parameters.h:198
int savecsvcontact(FILE *out, ExportData outflags, Multiproc< d > &MP, cv2d &X)
Definition: Parameters.h:282
double Kn
Normal spring constant.
Definition: Parameters.h:178
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:1316
int set_boundaries()
Set default boundaries.
Definition: Parameters.h:398
double damping
Definition: Parameters.h:184
vector< bool > Frozen
Frozen atom if true.
Definition: Parameters.h:196
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:412
vector< Mesh< d > > Meshes
Handle all meshes.
Definition: Parameters.h:209
multimap< float, string > events
For storing events. first is the time at which the event triggers, second is the event command string...
Definition: Parameters.h:214
Parameters(int NN)
Set the default values for all parameters. Calls to setup parameter function should be provided after...
Definition: Parameters.h:131
vector< double > m
Particle mass.
Definition: Parameters.h:193
double cellsize
Size of cells for contact detection.
Definition: Parameters.h:186
void reset_ND(int NN)
reset the full simulation.
Definition: Parameters.h:161
vector< Boundary< d > > Boundaries
List of boundaries. Second dimension is {min, max, length, type}.
Definition: Parameters.h:197
double Mu
Fricton.
Definition: Parameters.h:182
int init_inertia()
Initialise particle moment of inertia.
Definition: Parameters.h:497
void check_events(float time, v2d &X, v2d &V, v2d &Omega)
Verify if an event triggers at the current time time.
Definition: Parameters.h:531
double rho
density
Definition: Parameters.h:177
void add_particle()
Not implemented.
Definition: Parameters.h:920
bool wallforcecomputed
Compute for on the wall?
Definition: Parameters.h:202
void interpret_command(istream &in, v2d &X, v2d &V, v2d &Omega)
Parse input script commands.
Definition: Parameters.h:561
double graddesc_tol
Tolerance for the gradient descent algorithm.
Definition: Parameters.h:204
int init_mass()
Initialise particle mass.
Definition: Parameters.h:489
vector< double > I
Particule moment of inertia.
Definition: Parameters.h:194
vector< std::pair< ExportType, ExportData > > dumps
Vector linking dump file and data dumped.
Definition: Parameters.h:189
void init_locations(char *line, v2d &X, char *extras)
Set particle locations.
Definition: Parameters.h:926
void perform_MOVINGWALL()
Move the boundary wall if moving.
Definition: Parameters.h:459
int tdump
Write dump file every this many timesteps.
Definition: Parameters.h:173
double Gammat
Tangential dissipation.
Definition: Parameters.h:181
double Mu_wall
Definition: Parameters.h:183
unsigned char restart_flag
Definition: Parameters.h:212
Definition: RigidBody.h:48
std::vector< RigidBody< d > > RB
Definition: RigidBody.h:51
Static class to handle multi-dimensional mathematics, and more. It gets specialised for speed with te...
Definition: Tools.h:101
Definition: Xml.h:28
void emergencyclose()
Definition: Xml.cpp:179
void header(int dimension, string input)
Definition: Xml.cpp:38
void startTS(double ts)
Definition: Xml.cpp:54
void writeArray(string name, vector< vector< double >> *x, int beg, int length, ArrayType t, EncodingType te=EncodingType::ascii)
Definition: Xml.cpp:64
void stopTS()
Definition: Xml.cpp:59
bool closebranch()
Definition: Xml.cpp:15
void openbranch(string name, vector< pair< string, string >> attributes)
Definition: Xml.cpp:4
void close()
Definition: Xml.cpp:161
ofstream fic
Definition: Xml.h:47
namespace for Niels Lohmann
Definition: json.hpp:20203
Small class to handle number generator (ie. first:step:last syntax)
Definition: Parameters.h:62
int niter()
Definition: Parameters.h:94
void reset()
Definition: Parameters.h:93
void parse(std::string s)
Definition: Parameters.h:64
T cur()
Definition: Parameters.h:95
@ NONE
Definition: Coarsing.h:58
vector< vector< double > > v2d
Definition: Typedefs.h:10
static void savecsv(char path[], cv2d &X, cv1d &r, const vector< uint32_t > &PBCFlags, cv1d &Vmag, cv1d &OmegaMag, [[maybe_unused]] cv1d &Z)
Save the location and a few more informations in a CSV file.
Definition: Tools.h:380
ExportData & operator>>=(ExportData &w, int u)
Definition: Parameters.h:52
ExportData operator|(ExportData a, ExportData b)
Definition: Parameters.h:49
static void setzero(v2d &a)
Set a matrix to zero in-place.
Definition: Tools.h:117
ExportType & operator|=(ExportType &a, const ExportType b)
Definition: Parameters.h:47
ContactStrategies
Definition: Typedefs.h:22
ExportData operator~(ExportData a)
Definition: Parameters.h:50
static double skewnorm(cv1d &a)
Norm of a skew-symetric matrix.
Definition: Tools.h:125
ExportData
Definition: Parameters.h:46
static double InertiaMomentum(double R, double rho)
Compute the hypersphere moment of inertia.
Definition: Tools.h:865
@ radius
Definition: Typedefs.h:19
@ mass
Definition: Typedefs.h:19
ExportType
Definition: Parameters.h:45
#define STR_PROTECT(s)
Definition: Parameters.h:39
ContactModels
Definition: Typedefs.h:21
bool operator&(ExportType &a, ExportType b)
Definition: Parameters.h:54
auto contacts2array(ExportData exp, cv2d &X, Parameters< d > &P)
pack the contact data in a 2d array
Definition: Multiproc.h:568
const vector< double > cv1d
Definition: Typedefs.h:13
const vector< vector< double > > cv2d
Definition: Typedefs.h:14
ExportData & operator<<=(ExportData &w, int u)
Definition: Parameters.h:53
XMLWriter * xmlout
Definition: DEMND.cpp:22
ExportData & operator&=(ExportData &a, const ExportData b)
Definition: Parameters.h:51
vector< double > v1d
Definition: Typedefs.h:9
static double norm(const vector< double > &a)
Norm of a vector.
Definition: Tools.h:119
static double Volume(double R)
Compute the hypersphere volume.
Definition: Tools.h:853
std::istream & operator>>(std::istream &in, number_gen< T > &n)
Definition: Parameters.h:122
@ CELLS
Definition: Typedefs.h:22
@ OCTREE
Definition: Typedefs.h:22
@ NAIVE
Definition: Typedefs.h:22
@ HERTZ
Definition: Typedefs.h:21
@ HOOKE
Definition: Typedefs.h:21
@ ROTATINGSPHERE
uint d
int N
v2d Boundaries
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.hpp:5657
struct JsonValue json
Definition: json_parser.h:15
Definition: json.hpp:5678
int write_data(FILE *out, TensorInfos v, int d)
Definition: Vtk.h:73
FILE * open(char path[], int d)
Definition: Vtk.h:4
int write_points(FILE *out, cv2d &X, int d)
Definition: Vtk.h:16
int write_contactlines(FILE *out, cv2d &ids)
Definition: Vtk.h:25
int write_celldata(FILE *out, std::string name, cv2d &v, TensorType order, int idx, int N, int d)
Definition: Vtk.h:103
int write_dimension_data(FILE *out, cv2d &X, cv1d &r, int d, vector< Boundary< dd > > boundaries)
Definition: Vtk.h:47
void close(FILE *out)
Definition: Vtk.h:123
int start_celldata(FILE *out, int N, int Ncf)
Definition: Vtk.h:40
int start_pointdata(FILE *out, cv2d &X)
Definition: Vtk.h:34
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1282
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1181
PUGI_IMPL_FN I min_element(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7604
Type
Type of JSON value.
Definition: rapidjson.h:644
unsigned int uint32_t
Definition: stdint.h:126
#define SEEK_CUR
Definition: zconf.h:512