16 #if !__EMSCRIPTEN__ && __GNUC__ < 8
17 #include <experimental/filesystem>
18 namespace fs = std::experimental::filesystem ;
21 namespace fs = std::filesystem ;
34 #include <boost/random.hpp>
37 #define STR_PROTECT(s) static_cast<const char*>(s "\0")
39 #define STR_PROTECT(s) s
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} ;
66 auto res = s.find(
':') ;
double val ;
67 if (res==std::string::npos)
69 val=stod(s) ; first=
static_cast<T
>(val) ;
70 isconst=true ; delta=0 ;
71 last = std::numeric_limits<T>::max() ;
76 val=stod(s) ; first=
static_cast<T
>(val) ;
77 s=s.substr(res+1) ; res = s.find(
':') ;
78 if (res==std::string::npos)
80 val=stod(s) ; last=
static_cast<T
>(val) ;
85 val=stod(s) ; delta=
static_cast<T
>(val) ;
87 val=stod(s) ; last=
static_cast<T
>(val) ;
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)
100 if (iter>0 && !allow)
return {} ;
109 T res = first+delta*iter ;
110 if (res>last && !allow)
118 bool isconst = true ;
119 T first, last, delta=1 ;
121 template <
typename T>
145 forceinsphere(false),
150 Directory (
"Output"),
151 orientationtracking(true),
152 wallforcecompute(false),
153 wallforcerequested(false),
154 wallforcecomputed(false),
163 N=NN ; r.resize(
N,0.5) ;
167 Frozen.resize(
N,
false) ;
189 vector <std::pair<ExportType,ExportData>>
dumps ;
206 unsigned long int seed = 5489UL ;
207 double gravityrotateangle = 0.0;
211 std::string restart_filename=
"" ;
216 template <
class Archive>
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
226 int set_boundaries() ;
229 void perform_PBCLE_move() ;
235 { printf(
"ERR: forceinsphere expect the sphere to be the first wall.") ;
return false ; }
238 for (
int dd=0 ; dd<
d ; dd++) dst += (X[dd]-
Boundaries[0].center[dd])*(X[dd]-
Boundaries[0].center[dd]) ;
241 printf(
"%g ", dst) ; fflush(stdout) ;
242 boost::random::mt19937
rng(++seed);
243 boost::random::uniform_01<boost::mt19937> rand(
rng) ;
246 for(
int dd=0 ; dd <
d ; dd++)
253 printf(
"[INFO] Bringing back in sphere forcibly. \n"); fflush(stdout) ;
258 void perform_MOVINGWALL() ;
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;}
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) ;
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 () ;
274 void init_locations (
char *line,
v2d & X,
char *extras) ;
275 void init_radii (
char line[],
v1d & r) ;
277 void display_info(
int tint,
v2d& V,
v2d& Omega,
v2d& F,
v2d& Torque,
int,
int) ;
278 void quit_cleanly() ;
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) ;
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) ;
293 for (
int dd = 0 ; dd<
d ; dd++)
294 fprintf(out,
"Fn%d_i, ", dd) ;
296 for (
int dd = 0 ; dd<
d ; dd++)
297 fprintf(out,
"Ft%d_i, ", dd) ;
300 for (
int dd = 0 ; dd<
d*(
d-1)/2 ; dd++)
303 fprintf(out,
"Torque%d:%d_i, ", val.first, val.second) ;
305 for (
int dd = 0 ; dd<
d*(
d-1)/2 ; dd++)
308 fprintf(out,
"Torque%d:%d_j, ", val.first, val.second) ;
312 fprintf(out,
"GhostMask, ") ;
314 fprintf(out,
"GhostDir, ") ;
317 for (
int dd = 0 ; dd<
d ; dd++)
318 fprintf(out,
"lij%d, ", dd) ;
324 for (
auto & CLp : MP.
CLp)
326 for (
auto & contact: CLp.v)
329 fprintf(out,
"%d %d ", contact.i, contact.j) ;
332 for (
auto dd : X[contact.i])
333 fprintf(out,
"%g ", dd) ;
334 for (
auto dd : X[contact.j])
335 fprintf(out,
"%g ", dd) ;
338 for (
auto dd : contact.infos->Fn)
339 fprintf(out,
"%g ", dd) ;
341 for (
auto dd : contact.infos->Ft)
342 fprintf(out,
"%g ", dd) ;
346 for (
auto dd : contact.infos->Torquei)
347 fprintf(out,
"%g ", dd) ;
348 for (
auto dd : contact.infos->Torquej)
349 fprintf(out,
"%g ", dd) ;
353 fprintf(out,
"%d ", contact.ghost) ;
355 fprintf(out,
"%d ", contact.ghostdir) ;
359 auto [loc,branch] = contact.compute_branchvector(X, *
this) ;
361 for (
int dd = 0 ; dd<
d ; dd++) fprintf(out,
"%g ", branch[dd]) ;
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(); }
400 for (
int i=0 ; i<
d ; i++)
491 for (
int i=0 ; i<
N ; i++)
499 for (
int i=0; i<
N ; i++)
512 if (!in.is_open()) { printf(
"[Input] file cannot be open\n"); return ;}
516 interpret_command(in, X, V, Omega) ;
526 fs::path pcp (Directory+
"/in") ;
527 copy_file(p,pcp, fs::copy_options::overwrite_existing);
533 while (events.size()>0 && events.begin()->first < time)
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()) ;
543 std::istream&
operator>>(std::istream& in, std::variant<int*,double*,bool*> v)
545 printf(
"SETTING variable %ld\n", v.index());
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 ;
558 return (interpret_command(B, X, V, Omega)) ;
563 map <string, std::variant<int*,double*,bool*>> SetValueMap = {
570 {
"Mu_wall",&Mu_wall},
571 {
"damping",&damping},
574 {
"orientationtracking",&orientationtracking},
578 {
"gradientdescent_gamma", &graddesc_gamma},
579 {
"gradientdescent_tol", &graddesc_tol},
580 {
"cell_size", &cellsize},
581 {
"forceinsphere", &forceinsphere}
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"))
592 printf(
"[INFO] Using first particle mass to set rho: %g [M].[L]^-%d\n", rho,
d) ;
594 else if (!strcmp(line,
"inertia")) init_inertia() ;
595 else if (!strcmp(line,
"location"))
598 char extras[5000]; in.getline(extras, 5000) ;
599 init_locations(line, X, extras) ;
600 printf(
"[INFO] Set all particle locations\n") ;
602 else if (!strcmp(line,
"radius"))
604 in.getline(line, 5000) ;
605 init_radii(line, r) ;
606 printf(
"[INFO] Set all particle radii\n") ;
608 else printf(
"[WARN] Unknown auto command in input script\n") ;
609 printf(
"[INFO] Doing an auto \n") ;
611 auto setvalue = [&]() {
char line[5000] ; in >> line ;
613 in >> SetValueMap.at(line) ;
615 catch (
const std::out_of_range & e) {
616 if (!strcmp(line,
"dumps"))
628 else if (word==
"WALLFORCE") {wallforcecompute = true ;
goto LABEL_leave ;}
629 else {printf(
"Unknown dump type\n") ; }
633 if (word !=
"with") printf(
"ERR: expecting keyword 'with'\n") ;
637 for (
int i=0 ; i<nbparam ; i++)
644 else if (word ==
"Orientation")
646 orientationtracking=true ;
667 else printf(
"Unknown asked data %s\n", word.c_str()) ;
680 dumps.push_back(make_pair(dumpkind,dumplist)) ;
685 printf(
"[ERROR] Unknown parameter to set\n") ;
690 map<string,
function<void()>> Lvl0 ;
691 Lvl0[
"event"] = read_event ;
692 Lvl0[
"CG"] = discard_line ;
693 Lvl0[
"set"] = setvalue ;
694 Lvl0[
"auto"] = doauto ;
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"] = [&]()
701 in >> ids ;
for (
int i=0 ; i<d ; i++) in >> locs[i] ;
704 while (
id.has_value())
706 for (
int i=0 ;
id.has_value() && i<
d ; i++)
713 printf(
"[INFO] Changing particle location.\n") ;
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") ; } ;
723 Lvl0[
"ContactStrategy"] = [&](){ std::string s ; in >> s ;
if (s==
"naive") {contact_strategy =
ContactStrategies::NAIVE ; }
726 else {printf(
"[WARN] Unknown contact strategy\n") ; }} ;
727 Lvl0[
"gravityangle"] = [&](){
double intensity, angle ; in >> intensity >> angle ;
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") ;
733 Lvl0[
"gravityrotate"] = [&] () {
736 in >> grav_intensity >> grav_omega >> grav_rotdim[0] >> grav_rotdim[1] ;
737 printf(
"[INFO] Setting up a rotating gravity\n") ;
739 Lvl0[
"boundary"] = [&](){
size_t id ; in>>id ;
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"))
761 else if (!strcmp(line,
"ELLIPSE"))
763 else if (!strcmp(line,
"REMOVE"))
765 else printf(
"[WARN] Unknown boundary condition, unchanged.\n") ;
769 printf(
"[INFO] Changing BC.\n") ;
771 Lvl0[
"rigid"] = [&] ()
773 size_t id, npart ; in >> id ;
774 if (RigidBodies.
RB.size()<
id+1) RigidBodies.
RB.resize(
id+1) ;
780 std::vector<int> ids ;
int tmp ;
781 for (
size_t i=0 ; i<npart ; i++)
786 RigidBodies.
RB[id].setparticles(ids, X, m) ;
788 else if (s==
"gravity")
791 if (s==
"on") RigidBodies.
RB[id].cancelgravity = false ;
792 else if (s==
"off") RigidBodies.
RB[id].cancelgravity = true ;
794 else if (s==
"addforce")
796 for (
int dd=0 ; dd<
d ; dd++)
797 in >> RigidBodies.
RB[
id].addforce[dd] ;
799 else if (s==
"velocity")
801 for (
int dd=0 ; dd<
d ; dd++)
803 printf(
"%g %g\n", RigidBodies.
RB[0].setvel[0], RigidBodies.
RB[0].setvel[1]) ;
806 printf(
"[INFO] Defining a rigid body.\n") ;
808 Lvl0[
"mesh"] = [&] ()
812 if (s==
"file" || s==
"string")
817 std::ifstream i(s.c_str());
818 if (i.is_open()==
false) {printf(
"Cannot find the json file provided as argument\n") ; return ; }
823 std::getline(in, s) ;
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"])
831 Meshes.push_back({v[
STR_PROTECT(
"dimensionality")].get<
int>(), v[
"vertices"].
get<std::vector<std::vector<double>>>()}) ;
833 printf(
"[INFO] Mesh object added.\n") ;
837 else if (s==
"translate")
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) ;
843 else if (s==
"rotate")
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) ;
849 else if (s==
"remove")
853 Meshes.erase(Meshes.begin()+
id) ;
855 else if (s==
"export")
858 FILE * out = fopen(s.c_str(),
"w") ;
859 if (out==NULL) printf(
"[WARN] Cannot open file to export mesh") ;
862 fprintf(out,
"{\n \"dimension\": %d, \n \"objects\":[\n",
d) ;
863 for (
size_t i=0 ; i<Meshes.size() ; i++)
865 auto res = Meshes[i].export_json() ;
866 fprintf(out,
"%s", res.c_str()) ;
867 if (i<Meshes.size()-1) fprintf(out,
",\n") ;
869 fprintf(out,
"\n]}") ;
875 printf(
"[WARN] Unknown mesh subcommand\n") ;
878 Lvl0[
"restart"] = [&] () {
880 std::string s ; in >> s ;
882 restart_flag |= (1<<1) ;
884 restart_flag |= (2<<1) ;
891 in >> restart_filename ;
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() ; }
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) ;
922 printf(
"add_particle NOT IMPLEMENTED YET\n") ;
928 boost::random::mt19937
rng(seed);
929 boost::random::uniform_01<boost::mt19937> rand(
rng) ;
930 if (!strcmp(line,
"square"))
932 auto m = *(std::max_element(r.begin(), r.end())) ;
935 for (dd=0 ; dd<
d ; dd++) X[0][dd]=
Boundaries[dd].xmin+m ;
936 for (
int i=1 ; i<
N ; i++)
939 for (dd=0 ; dd<
d ; dd++)
947 if (dd==
d) {printf(
"WARN: cannot affect all particles on the square lattice, not enough space in the simulation box\n") ; break ; }
950 else if (!strcmp(line,
"randomsquare"))
952 auto m = *(std::max_element(r.begin(), r.end())) ;
955 for (dd=0 ; dd<
d ; dd++) X[0][dd]=
Boundaries[dd].xmin+m ;
956 for (
int i=1 ; i<
N ; i++)
959 for (dd=0 ; dd<
d ; dd++)
963 X[i][dd] =
Boundaries[dd].xmin+m + 0.1*m*(rand()-0.5) ;
967 if (dd==
d) {printf(
"WARN: cannot affect all particles on the square lattice, not enough space in the simulation box\n") ; break ; }
970 else if (!strcmp(line,
"randomdrop"))
973 for (
int i=0 ; i<
N ; i++)
975 for(
int dd=0 ; dd <
d ; dd++)
984 else if (!strcmp(line,
"insphere"))
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) ; }
991 for (
int i=0 ; i<
N ; i++)
994 printf(
".") ; fflush(stdout);
997 for(
int dd=0 ; dd <
d ; dd++)
1002 }
while ( sqrt(dst) > (
Boundaries[id].radius-2*r[i])) ;
1005 else if (!strcmp(line,
"incylinder"))
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) ; }
1012 for (
int i=0 ; i<
N ; i++)
1015 printf(
".") ; fflush(stdout);
1018 for(
int dd=0 ; dd <
d ; dd++)
1027 dst += X[i][dd]*X[i][dd] ;
1030 }
while ( sqrt(dst) > (
Boundaries[id].radius-2*r[i])) ;
1033 else if (!strcmp(line,
"roughinclineplane"))
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())) ;
1037 double delta=0.1*m ;
1038 for (
int dd=0 ; dd<
d ; dd++) X[0][dd]=
Boundaries[dd].xmin+m+delta ;
1040 for (
int i=1 ; i<
N ; i++)
1043 for (
int dd=
d-1 ; dd>=0 ; dd--)
1045 X[i][dd] += 2*m+2*delta ;
1051 if (X[i][0]==
Boundaries[0].xmin+m+delta) Frozen[i]=true ;
1053 for (
int dd=0 ; dd<
d ; dd++)
1054 X[i-1][dd] += (rand()-0.5)*2*delta ;
1057 else if (!strcmp(line,
"smallroughinclineplane"))
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())) ;
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);
1071 for (
int i=1 ; i<
N ; i++)
1074 if (i < i_bottom_layer ) {
1083 for (
int dd=
d-1 ; dd>=0 ; dd--)
1085 X[i][dd] += 2*m+2*delta ;
1087 if (i < i_bottom_layer ) {
1096 for (
int dd=0 ; dd<
d ; dd++) {
1097 if (i >= i_bottom_layer) {
1098 X[i][dd] += (rand()-0.5)*2*delta ;
1103 for (
int i=1 ; i<i_bottom_layer ; i++)
1105 X[i][0] += rand()*2*delta;
1108 else if (!strcmp(line,
"roughinclineplane2"))
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())) ;
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++)
1118 for (ddd=
d-1 ; ddd>=0 ; ddd--)
1130 X[i][ddd] += 2*m+2*delta ;
1137 if (ddd==0) bottomlayer=false ;
1141 X[i-1][0] += rand()*delta ;
1145 for (
int dd=0 ; dd<
d ; dd++)
1146 X[i-1][dd] += (rand()-0.5)*2*delta ;
1150 else if (!strcmp(line,
"quasicrystal"))
1152 auto m = *(std::max_element(r.begin(), r.end())) ;
1156 for (dd=0 ; dd<
d ; dd++) { X[0][dd]=
Boundaries[dd].xmin+m ; }
1157 for (
int i=1 ; i<
N ; i++)
1160 for (dd=0 ; dd<
d ; dd++)
1168 if (dd==
d) {printf(
"WARN: cannot affect all particles on the square lattice, not enough space in the simulation box\n") ; break ; }
1171 else if (!strcmp(line,
"fromfile"))
1173 while (*extras ==
' ') extras++ ;
1174 std::ifstream in(extras);
1176 if (!in) { std::cerr <<
"Failed to open the file." << std::endl;
return;}
1181 for (
int dd=0 ; dd<
d ; dd++)
1187 printf(
"ERR: undefined initial location function.\n") ;
1193 std::istringstream s(line) ;
1195 double minr, maxr, fraction, fuzz ;
1196 boost::random::mt19937
rng(seed);
1197 boost::random::uniform_01<boost::mt19937> rand(
rng) ;
1200 printf(
"[%s]\n", word.c_str()) ;
1201 if (word ==
"uniform")
1203 s >> minr ; s >> maxr ;
1204 for (
auto & v : r) v = rand()*(maxr-minr)+minr ;
1206 else if (word ==
"bidisperse")
1208 s >> minr ; s >> maxr ;
1213 double f = fraction*Vs/((1-fraction)*Vl+fraction*Vs) ;
1215 for (
auto & v : r) v = (rand()<f?maxr:minr) ;
1218 else if (word ==
"bidisperse_fuzzy")
1220 s >> minr ; s >> maxr ;
1226 double f = fraction*Vs/((1-fraction)*Vl+fraction*Vs) ;
1230 v = (rand()<f?maxr:minr) ;
1231 v = v + (rand()*2-1)*(fuzz*v) ;
1235 printf(
"WARN: unknown radius distribution automatic creation. Nothing done ...\n") ;
1243 static bool first=true ;
1244 static double Rmax, mmax ;
1247 Rmax=*max_element(r.begin(), r.end()) ;
1248 mmax=*max_element(m.begin(), m.end()) ;
1258 if (!first) printf(
"\e[8A") ;
1260 printf(
"\n\e[80G NContacts: %d | Nghosts: %d \n", nct, ngst) ;
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)) ;})) ;
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) ;
1279 if (first) first=false ;
1293 for (
auto v: r)
xmlout->
fic << v <<
" " ;
1301 for (
auto v : dumps)
1308 for (
auto v : dumps)
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)
1318 static bool xmlstarted=false ;
1320 for (
auto v : dumps)
1324 char path[500] ; sprintf(path,
"%s/dump-%05d.csv", Directory.c_str(), ti) ;
1336 char path[500] ; sprintf(path,
"%s/dumpA-%05d.csv", Directory.c_str(), ti) ;
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) ;
1354 char path[500] ; sprintf(path,
"%s/dump-%05d.vtk", Directory.c_str(), ti) ;
1359 vector<std::pair<ExportData, int>> mapping ;
1360 vector<vector<double>> contactdata ;
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)) ;
1371 vector <TensorInfos> val;
1380 vector<double> tmpid (
N, 0) ;
1381 for (
int i=0 ; i<
N ; i++)
1386 if (mapping.size()>1)
1390 for (
auto & v:mapping)
1415 printf(
"WARN: netcdf writing hasn't been tested and therefore is not plugged in\n") ;
1419 if (xmlstarted==
false)
1421 char path[500] ; sprintf(path,
"%s/dump.xml", Directory.c_str()) ;
1431 printf(
"Omega Mag not implemented yet\n");
1438 for (
auto & v:mapping)
1470 if (xmlstarted==
false)
1472 char path[500] ; sprintf(path,
"%s/dump.xml", Directory.c_str()) ;
1482 printf(
"Omega Mag not implemented yet\n");
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
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
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