-
Notifications
You must be signed in to change notification settings - Fork 4
/
constraints.hpp
751 lines (658 loc) · 25.7 KB
/
constraints.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
#include "interaction.hpp"
#ifndef CONSTRAINTS_H
#define CONSTRAINTS_H
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <complex>
using namespace std;
typedef std::complex<flt> cmplx; // need the std:: for SWIG complex.i, not sure why
class constraint {
public:
virtual void apply(Box &box) = 0;
virtual int ndof() = 0;
virtual ~constraint(){};
};
class coordConstraint : public constraint {
private:
atom* a;
bool fixed[3];
Vec loc;
public:
coordConstraint(atom* atm, bool fixx, bool fixy, bool fixz, Vec loc) :
a(atm), loc(loc) {fixed[0] = fixx; fixed[1] = fixy; fixed[2] = fixz;};
coordConstraint(atom* atm, bool fixx, bool fixy, bool fixz) :
a(atm), loc(a->x) {fixed[0] = fixx; fixed[1] = fixy; fixed[2] = fixz;};
coordConstraint(atom* atm) :
a(atm), loc(a->x) {fixed[0] = fixed[1] = fixed[2] = true;};
int ndof(){return (int)fixed[0] + (int)fixed[1] + (int)fixed[2];};
void apply(Box &box){
for(uint i=0; i<3; i++){
if(not fixed[i]) continue;
a->f[i] = 0;
a->v[i] = 0;
a->x[i] = loc[i];
}
}
};
class coordCOMConstraint : public constraint {
private:
sptr<atomgroup> a;
bool fixed[3];
Vec loc;
public:
coordCOMConstraint(sptr<atomgroup> atm, bool fixx, bool fixy, bool fixz, Vec loc) :
a(atm), loc(loc) {fixed[0] = fixx; fixed[1] = fixy; fixed[2] = fixz;};
coordCOMConstraint(sptr<atomgroup> atm, bool fixx, bool fixy, bool fixz) :
a(atm), loc(a->com()) {fixed[0] = fixx; fixed[1] = fixy; fixed[2] = fixz;};
coordCOMConstraint(sptr<atomgroup> atm) :
a(atm), loc(a->com()) {fixed[0] = fixed[1] = fixed[2] = true;};
int ndof(){return (int)fixed[0] + (int)fixed[1] + (int)fixed[2];};
void apply(Box &box){
Vec com = a->com() - loc;
Vec comv = a->comv();
Vec totf = Vec();
for(uint i=0; i< a->size(); i++){
totf += (*a)[i].f;
}
Vec tota = totf / a->mass();
for(uint i=0; i< a->size(); i++){
atom &atm = (*a)[i];
Vec df = (tota * (atm.m));
for(uint j=0; j<3; j++){
if(not fixed[j]) continue;
atm.f[j] -= df[j];
atm.v[j] -= comv[j];
atm.x[j] -= com[j];
}
}
}
};
class relativeConstraint : public constraint {
private:
atom *a1, *a2;
bool fixed[3];
Vec loc;
public:
relativeConstraint(atom* atm1, atom* atm2, bool fixx, bool fixy, bool fixz, Vec loc) :
a1(atm1), a2(atm2), loc(loc) {
fixed[0] = fixx; fixed[1] = fixy; fixed[2] = fixz;};
relativeConstraint(atom* atm1, atom* atm2, bool fixx, bool fixy, bool fixz) :
a1(atm1), a2(atm2), loc(a2->x - a1->x) {
fixed[0] = fixx; fixed[1] = fixy; fixed[2] = fixz;};
relativeConstraint(atom* atm1, atom* atm2) :
a1(atm1), a2(atm2), loc(a2->x - a1->x) {
fixed[0] = fixed[1] = fixed[2] = true;};
int ndof(){return (int)fixed[0] + (int)fixed[1] + (int)fixed[2];};
void apply(Box &box){
flt mratio1 = a1->m / (a1->m + a2->m);
flt mratio2 = a2->m / (a1->m + a2->m);
Vec totf = a2->f + a1->f;
Vec dv = a2->v - a1->v;
Vec dx = a2->x - a1->x;
for(uint i=0; i<NDIM; i++){
if(not fixed[i]) continue;
a1->f[i] = totf[i]*mratio1;
a2->f[i] = totf[i]*mratio2;
a1->v[i] += dv[i]/2;
a2->v[i] -= dv[i]/2;
a1->x[i] += dx[i]/2;
a2->x[i] -= dx[i]/2;
assert(abs(a2->v[i] - a1->v[i]) < 1e-5);
assert(abs(a2->x[i] - a1->x[i]) < 1e-5);
}
}
};
class distConstraint : public constraint {
private:
atomid a1, a2;
flt dist;
public:
distConstraint(atomid atm1, atomid atm2, flt dist) :
a1(atm1), a2(atm2), dist(dist) {};
distConstraint(atomid atm1, atomid atm2) :
a1(atm1), a2(atm2), dist((a1->x - a2->x).mag()){};
int ndof(){return 1;};
void apply(Box &box){
flt M = (a1->m + a2->m);
flt mratio1 = a1->m / M;
flt mratio2 = a2->m / M;
Vec dx = a2->x - a1->x;
flt dxmag = dx.mag();
Vec dxnorm = dx / dxmag;
a1->x += dx * ((1 - dist/dxmag)*mratio2);
a2->x -= dx * ((1 - dist/dxmag)*mratio1);
//~ dx = a2->x - a1->x;
//~ dxmag = dx.mag();
//~ dxnorm = dx / dxmag; dxnorm should still be the same
Vec baddv = dxnorm * ((a2->v - a1->v).dot(dxnorm)/2);
a1->v += baddv;
a2->v -= baddv;
// newv2 • u = v2 - |baddv|
// newv1 • u = v1 + |baddv|
// (newv2 - newv1) • u = (v2 - v1 - (2*baddv)) • u
// = ((v2 - v1)•u - (2*baddv)•u)
// = (|baddv|*2 - |baddv|*2) = 0
// assert((a2->v - a1->v).dot(dxnorm) < 1e-8);
if((a2->v - a1->v).dot(dxnorm) > 1e-8){
throw std::overflow_error("Velocities are not minimal.");
}
// TODO: Fix mass ratio stuff
Vec baddf = dxnorm * ((a2->f - a1->f).dot(dxnorm)/2);
a1->f += baddf;
a2->f -= baddf;
// assert((a2->f - a1->f).dot(dxnorm) < 1e-8);
if((a2->f - a1->f).dot(dxnorm) > 1e-8){
throw std::overflow_error("Forces are not minimal.");
}
}
};
class linearConstraint : public constraint {
private:
sptr<atomgroup> atms;
flt dist;
flt lincom, I, M;
public:
linearConstraint(sptr<atomgroup> atms, flt dist) :
atms(atms), dist(dist), lincom(0), I(0), M(0) {
for(uint i = 0; i < atms->size(); i++){
M += (*atms)[i].m;
lincom += (dist*i)*(*atms)[i].m;
}
lincom /= M;
for(uint i = 0; i < atms->size(); i++){
flt dx = (dist*i - lincom);
I += (*atms)[i].m * dx * dx;
}
};
int ndof(){return atms->size()-1;};
void apply(Box &box){
Vec com = atms->com();
Vec comv = atms->comv();
Vec comf = Vec();
uint sz = atms->size();
Vec lvec = Vec();
#ifdef VEC3D
Vec L = Vec();
Vec omega = Vec();
Vec tau = Vec();
Vec alpha = Vec();
#else
flt L = 0;
flt omega = 0;
flt tau = 0;
flt alpha = 0;
#endif
for(uint i = 0; i < sz; i++){
flt chaindist = i * dist - lincom;
atom& ai = (*atms)[i];
Vec dx = ai.x - com;
comf += ai.f;
lvec += dx.norm() * chaindist;
L += dx.cross(ai.v) * ai.m;
tau += dx.cross(ai.f);
}
lvec.normalize();
omega = L / I;
alpha = tau / I;
for(uint i = 0; i < sz; i++){
flt chaindist = i * dist - lincom;
Vec dx = lvec*chaindist;
atom& ai = (*atms)[i];
ai.x = com + dx;
ai.v = comv + dx.cross(omega);
ai.f = comf + (dx.cross(alpha)*ai.m);
}
}
};
class NPHGaussianConstraint : public constraint {
private:
sptr<OriginBox> box;
flt ddV, dV; // that's dV²/dt², dV/dt
vector<sptr<atomgroup> > groups;
public:
NPHGaussianConstraint(sptr<OriginBox> box, vector<sptr<atomgroup> > groups) :
box(box), ddV(0), dV(0), groups(groups){};
int ndof(){return 0;};
void apply(Box &box2){
//~ flt V = box->V();
assert(boost::static_pointer_cast<Box>(box).get() == &box2);
//~ vector<atomgroup*>::iterator git;
//~ for(git = groups.begin(); git<groups.end(); git++){
//~ atomgroup &m = **git;
//~ for(uint i=0; i<m.size(); i++){
//~ m[i].v +=
//~ }
//~ }
};
};
class ContactTracker : public statetracker{
protected:
sptr<atomgroup> atoms;
vector<flt> dists;
vector<vector<bool> > contacts;
unsigned long long breaks;
unsigned long long formations;
unsigned long long incontact;
public:
ContactTracker(sptr<Box> box, sptr<atomgroup> atoms, vector<flt> dists);
void update(Box &box);
unsigned long long broken(){return breaks;};
unsigned long long formed(){return formations;};
unsigned long long number(){return incontact;};
};
inline ContactTracker* ContactTrackerD(sptr<Box> box, sptr<atomgroup> atoms, vector<double> dists){
vector<flt> newdists = vector<flt>();
for(uint i=0; i<dists.size(); i++){
newdists.push_back(dists[i]);
}
return new ContactTracker(box, atoms, newdists);
}
class EnergyTracker : public statetracker{
protected:
sptr<atomgroup> atoms;
vector<sptr<interaction> > interactions;
uint N;
uint nskip, nskipped;
flt U0;
flt Es, Us, Ks;
flt Esq, Usq, Ksq;
public:
EnergyTracker(sptr<atomgroup> atoms,
vector<sptr<interaction> > interactions, uint nskip=1)
: atoms(atoms),
interactions(interactions), N(0), nskip(max(nskip,1u)), nskipped(0),
U0(0),Es(0),Us(0),Ks(0), Esq(0), Usq(0), Ksq(0){};
void update(Box &box);
void reset(){
nskipped=0;
N=0; Es=0; Us=0; Ks=0;
Esq=0; Usq=0; Ksq=0;
};
void setU0(flt newU0){
U0 = newU0;
reset();
};
void setU0(Box &box);
flt getU0(){return U0;};
flt E(){return Es/((flt) N);};
flt U(){return Us/((flt) N);};
flt K(){return Ks/((flt) N);};
flt Estd(){return sqrt(Esq/N -Es*Es/N/N);};
flt Kstd(){return sqrt(Ksq/N -Ks*Ks/N/N);};
flt Ustd(){return sqrt(Usq/N -Us*Us/N/N);};
flt Esqmean(){return Esq/N;};
flt Ksqmean(){return Ksq/N;};
flt Usqmean(){return Usq/N;};
//~ flt Ustd(){return sqrt((Usq -(U*U)) / ((flt) N));};
//~ flt Kstd(){return sqrt((Ksq -(K*K)) / ((flt) N));};
uint n(){return N;};
};
class RsqTracker1 {
// Tracks only a single dt (skip)
public:
vector<Vec> pastlocs;
vector<Vec> xyz2sums;
vector<Vec> xyz4sums;
vector<flt> r4sums;
unsigned long skip, count;
public:
RsqTracker1(atomgroup& atoms, unsigned long skip, Vec com);
void reset(atomgroup& atoms, Vec com);
bool update(Box& box, atomgroup& atoms, unsigned long t, Vec com); // updates if necessary.
vector<Vec> xyz2();
vector<Vec> xyz4();
vector<flt> r4();
unsigned long get_skip(){return skip;};
unsigned long get_count(){return count;};
};
class RsqTracker : public statetracker {
public:
sptr<atomgroup> atoms;
vector<RsqTracker1> singles;
unsigned long curt;
bool usecom;
public:
RsqTracker(sptr<atomgroup> atoms, vector<unsigned long> ns, bool usecom=true);
void reset();
void update(Box &box);
vector<vector<Vec> > xyz2();
vector<vector<flt> > r2();
vector<vector<Vec> > xyz4();
vector<vector<flt> > r4();
vector<flt> counts();
};
////////////////////////////////////////////////////////////////////////
// ISF tracking
// code is similar to Rsqtracker.
// It tracks ISF(k, Δt) with one ISFTracker1 per Δt.
// k is of type 'flt', representing a length; it will average over
// k(x hat), k(y hat), k(z hat).
class ISFTracker1 {
// Tracks only a single dt (skip)
public:
vector<Vec> pastlocs;
vector<vector<Array<cmplx, NDIM> > > ISFsums; // (number of ks x number of particles x number of dimensions)
vector<flt> ks;
unsigned long skip, count;
public:
ISFTracker1(atomgroup& atoms, unsigned long skip, vector<flt> ks, Vec com);
void reset(atomgroup& atoms, Vec com);
bool update(Box& box, atomgroup& atoms, unsigned long t, Vec com); // updates if necessary.
vector<vector<cmplx> > ISFs();
vector<vector<Array<cmplx, NDIM> > > ISFxyz();
unsigned long get_skip(){return skip;};
unsigned long get_count(){return count;};
};
class ISFTracker : public statetracker {
public:
sptr<atomgroup> atoms;
vector<ISFTracker1> singles;
unsigned long curt;
bool usecom;
public:
ISFTracker(sptr<atomgroup> atoms, vector<flt> ks,
vector<unsigned long> ns, bool usecom=false);
void reset();
void update(Box &box);
vector<vector<vector<Array<cmplx, NDIM> > > > ISFxyz();
vector<vector<vector<cmplx> > > ISFs();
vector<flt> counts();
};
////////////////////////////////////////////////////////////////////////
// For comparing two jammed structures
/* We have two packings, A and B, and want to know the sequence {A1, A2, A3...}
* such that particle A1 of packing 1 matches particle 1 of packing B.
* A jamminglist is a partial list; it has a list {A1 .. An}, with n / N
* particles assigned, with a total distance² of distsq.
*/
class jamminglist {
public:
vector<uint> assigned;
flt distsq;
jamminglist() : assigned(), distsq(0){};
jamminglist(const jamminglist& other)
: assigned(other.assigned), distsq(other.distsq){};
jamminglist(const jamminglist& other, uint expand, flt addeddist)
: assigned(other.size() + 1, 0), distsq(other.distsq + addeddist){
for(uint i=0; i < other.size(); i++){
assigned[i] = other.assigned[i];
}
assigned[assigned.size()-1] = expand;
}
inline uint size() const {return (uint) assigned.size();};
bool operator<(const jamminglist& other);
};
class jammingtree {
private:
sptr<Box> box;
list<jamminglist> jlists;
vector<Vec> A;
vector<Vec> B;
public:
jammingtree(sptr<Box> box, vector<Vec>& A, vector<Vec>& B)
: box(box), jlists(), A(A), B(B) {
jlists.push_back(jamminglist());
assert(A.size() <= B.size());
};
bool expand(){
jamminglist curjlist = jlists.front();
vector<uint>& curlist = curjlist.assigned;
if(curlist.size() >= A.size()){
//~ cout << "List already too big\n";
return false;
}
list<jamminglist> newlists = list<jamminglist>();
for(uint i=0; i < B.size(); i++){
vector<uint>::iterator found = find(curlist.begin(), curlist.end(), i);
//if (find(curlist.begin(), curlist.end(), i) != curlist.end()){
if (found != curlist.end()){
//~ cout << "Found " << i << "\n";
//cout << found << '\n';
continue;
}
flt newdist = box->diff(A[curlist.size()], B[i]).sq();
jamminglist newjlist = jamminglist(curjlist, i, newdist);
newlists.push_back(newjlist);
//~ cout << "Made " << i << "\n";
}
if(newlists.empty()){
//~ cout << "No lists made\n";
return false;
}
//~ cout << "Have " << newlists.size() << "\n";
newlists.sort();
//~ cout << "Sorted.\n";
jlists.pop_front();
//~ cout << "Popped.\n";
jlists.merge(newlists);
//~ cout << "Merged to size " << jlists.size() << "best dist now " << jlists.front().distsq << "\n";
return true;
}
bool expand(uint n){
bool retval=false;
for(uint i=0; i<n; i++){
retval = expand();
}
return retval;
}
list<jamminglist> &mylist(){return jlists;};
list<jamminglist> copylist(){return jlists;};
jamminglist curbest(){
jamminglist j = jamminglist(jlists.front());
//~ cout << "Best size: " << j.size() << " dist: " << j.distsq;
//~ if(j.size() > 0) cout << " Elements: [" << j.assigned[0] << ", " << j.assigned[j.size()-1] << "]";
//~ cout << '\n';
return j;
//return jamminglist(jlists.front());
};
uint size(){return (uint) jlists.size();};
};
#ifdef VEC2D
class jamminglistrot : public jamminglist {
public:
uint rotation;
jamminglistrot() : jamminglist(), rotation(0){};
jamminglistrot(uint rot) : jamminglist(), rotation(rot){};
jamminglistrot(const jamminglistrot& other)
: jamminglist(other), rotation(other.rotation){};
jamminglistrot(const jamminglistrot& other, uint expand, flt addeddist)
: jamminglist(other, expand, addeddist), rotation(other.rotation){};
bool operator<(const jamminglistrot& other);
};
// Includes rotations, flips, and translations.
class jammingtree2 {
protected:
sptr<Box> box;
list<jamminglistrot> jlists;
vector<Vec> A;
vector<vector<Vec> > Bs;
public:
// make all 8 possible rotations / flips
// then subtract off all possible COMVs
jammingtree2(sptr<Box>box, vector<Vec>& A, vector<Vec>& B);
flt distance(jamminglistrot& jlist);
list<jamminglistrot> expand(jamminglistrot curjlist);
virtual bool expand();
bool expand(uint n){
bool retval=false;
for(uint i=0; i<n; i++){
retval = expand();
if(!retval) break;
}
return retval;
}
bool expandto(flt maxdistsq){
bool retval = true;
while((maxdistsq <= 0 or jlists.front().distsq < maxdistsq) and retval){
retval = expand();
};
return retval;
}
static Vec straight_diff(Box &bx, vector<Vec>& A, vector<Vec>& B);
static flt straight_distsq(Box &bx, vector<Vec>& A, vector<Vec>& B);
list<jamminglistrot> &mylist(){return jlists;};
list<jamminglistrot> copylist(){return jlists;};
list<jamminglistrot> copylist(uint n){
list<jamminglistrot>::iterator last = jlists.begin();
advance(last, n);
return list<jamminglistrot>(jlists.begin(), last);
};
jamminglistrot curbest(){
if(jlists.empty()){
jamminglistrot bad_list = jamminglistrot();
bad_list.distsq = -1;
return bad_list;
}
jamminglistrot j = jamminglistrot(jlists.front());
//~ cout << "Best size: " << j.size() << " dist: " << j.distsq;
//~ if(j.size() > 0) cout << " Elements: [" << j.assigned[0] << ", " << j.assigned[j.size()-1] << "]";
//~ cout << '\n';
return j;
//return jamminglist(jlists.front());
};
//jamminglistrot operator[](uint i){
// assert(i < jlists.size());
// return jamminglistrot(jlists[i]);
//};
uint size(){return (uint) jlists.size();};
vector<Vec> locationsB(jamminglistrot jlist);
vector<Vec> locationsB(){return locationsB(curbest());};
vector<Vec> locationsA(jamminglistrot jlist);
vector<Vec> locationsA(){return locationsA(curbest());};
virtual ~jammingtree2(){};
};
class jammingtreeBD : public jammingtree2 {
/* For a bi-disperse packing.
* 'cutoff' is the number of particles of the first kind; i.e., the
* A vector should have A[0]..A[cutoff-1] be of particle type 1,
* and A[cutoff]..A[N-1] of particle type 2.
* This does much the same as jammingtree2, but doesn't check any
* reordering in which particles of one type are relabeled as another.
* For exampe, with 2+2 particles (cutoff 2), we check
* [0123],[1023],[0132],[1032]
* But not
* [0213],[0231],[0312],[0321],[1203],[1230],[1302],[1320],...
* This means at most (cutoff! (N-cutoff)!) combinations are checked,
* and not all N!, which can save a lot of time (as well as
* rejecting false combinations).
*/
protected:
uint cutoff1,cutoff2;
public:
jammingtreeBD(sptr<Box>box, vector<Vec>& A, vector<Vec>& B, uint cutoff) :
jammingtree2(box, A, B), cutoff1(cutoff), cutoff2(cutoff){};
jammingtreeBD(sptr<Box>box, vector<Vec>& A, vector<Vec>& B,
uint cutoffA, uint cutoffB);// :
//jammingtree2(box, A, B), cutoff1(cutoffA), cutoff2(cutoffB){};
list<jamminglistrot> expand(jamminglistrot curjlist);
bool expand();
bool expand(uint n){return jammingtree2::expand(n);};
};
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Finding Percolation
*
* Plan:
* struct Node {
* uint n;
* Vec x;
* }
*
* struct Connectivity {
* sptr<OriginBox>;
* vector<Node> nodes;
* set<Node, vector<Node> > neighbors; # with both directions in
* }
*
* make_connectivity(sptr<OriginBox>, NListed<A,P>) {
* # for each pair, if energy != 0, add it to the Connectivity
* }
*
* or
*
* make_connectivity(sptr<OriginBox>, neighborlist, ... sigmas) {
* # for each pair, if box.diff(a1.x, a2.x) < (sigma1 < sigma2)/2, add it to the list
* }
*
* struct path {
* Vec<uint> distance # Euclidean distance from first node to last. Note this is not
* # the same as box.diff(last - first), because it might go
* # a longer way around the box
* vector<uint> nodes # nodes visited
* }
*
* Maybe implement <, ==, > by using length of nodes first and what the nodes are second
*
* Implement ... circular_from(uint n, check_all=true):
* - Do a breadth-first search starting from n, including only nodes > n.
* - While searching, build map<node, path>, which is the Euclidean distance from the start node
* to the current node via the path traveled
* - If you get to an already visited node, compare the current Vec path to the previous one. If
* the same:
* - either replace the old path (if new_path < old_path) or don't
* - Do not follow connections
* If different, we've found a percolation:
* - Mark percolations with "map<uint, path> cycles"; the key is the dimension, and
* the value (vector<uint>) is the path.
* - If(check_all && cycles.size() >= 1) return cycles
* - else if cycles.size() >= NDIM return cycles
* - If you finish without finding any (or enough), return cycles
*
* Implement ... find_percolation(...):
* - for each n, run circular_from(uint n, false)
* - if any have a cycle, return it!
*
* Implement ... find_percolations(...):
* - for each n, run circular_from(uint n, true)
* - keep merging results
* - if cycles.size() >= NDIM return cycles
* - if you get to the end, return cycles
*/
class CNode {
public:
int n;
Vec x;
CNode() : n(-1){};
CNode(int n, Vec x) : n(n), x(x){};
bool operator!=(const CNode& other) const { return n != other.n;};
bool operator==(const CNode& other) const { return n == other.n;};
bool operator<(const CNode& other) const { return n < other.n;};
bool operator>(const CNode& other) const { return n > other.n;};
};
class CNodePath {
public:
Vec distance;
vector<CNode> nodes;
public:
CNodePath(){};
CNodePath(CNode node){nodes.push_back(node);};
CNodePath(CNodePath other, CNode node, OriginBox& box) :
distance(other.distance), nodes(other.nodes){add(node, box);};
void add(CNode node, OriginBox& box);
uint size(){return (uint) nodes.size();};
};
// The class that actually finds percolation.
// TODO:
/*
* add a way to work with a neighborlist for initial construction
*/
class Connectivity {
public:
sptr<OriginBox> box;
set<CNode> nodes;
map<int, vector<CNode> > neighbors;
array<bool, NDIM> nonzero(Vec diff_vec); // is it nonzero. Specifically, is any dimension > L/2?
CNodePath make_cycle(CNodePath forward, CNodePath backward);
map<uint, CNodePath> circular_from(CNode node, set<uint>& visited, bool check_all);
public:
Connectivity(sptr<OriginBox> box) : box(box){};
void add_edge(CNode node1, CNode node2);
// assumes diameters are additive
// Note that "diameter" should generally be the attractive diameter
void add(vector<Vec> locs, vector<flt> diameters);
map<uint, CNodePath> find_percolation(bool check_all_dims=true);
};
#endif