From db9b5ba4ac75b3d4a2151e1b577928cfbb212bc1 Mon Sep 17 00:00:00 2001 From: Jaron Kent-Dobias Date: Thu, 16 Sep 2021 18:17:38 +0200 Subject: Implemented basic cluster flips. --- hard_spheres.cpp | 19 +++++++++++++--- soft_spheres.cpp | 26 +++++++++++++++------ spheres.hpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 101 insertions(+), 13 deletions(-) diff --git a/hard_spheres.cpp b/hard_spheres.cpp index b53f7cf..6a14953 100644 --- a/hard_spheres.cpp +++ b/hard_spheres.cpp @@ -29,10 +29,23 @@ int main(int argc, char* argv[]) { HardSphere<2>& s1 = r.pick(m.particles); HardSphere<2>& s2 = r.pick(m.particles); - - m.swap(1, s1, s2, r); - if (i % (N * 3) == 0) { + Vector<2> t1 = s1.x; + Vector<2> t2 = s2.x; + Vector<2> t = (t1 + t2) / 2; + + Matrix<2> mat; + + mat(0, 0) = -1; + mat(1, 1) = -1; + mat(0, 1) = 0; + mat(1, 0) = 0; + + Euclidean<2> g(t - mat * t, mat); + + std::cout << m.clusterFlip(1, g, s1, r) << std::endl; + + if (i % (N) == 0) { draw(m); } } diff --git a/soft_spheres.cpp b/soft_spheres.cpp index a71a472..cdd6f31 100644 --- a/soft_spheres.cpp +++ b/soft_spheres.cpp @@ -4,7 +4,7 @@ int main(int argc, char* argv[]) { const unsigned n = 12; unsigned N = 1200; - double R = 0.024; + double R = 0.023; double ε = 0.01; unsigned steps = 1e6; double β = 1; @@ -28,16 +28,28 @@ int main(int argc, char* argv[]) { Δxi = r.variate(0, ε); } - m.metropolis(β, s, Δx, r); + for (unsigned j = 0; j < N; j++) + m.metropolis(β, s, Δx, r); SoftSphere<2, n>& s1 = r.pick(m.particles); SoftSphere<2, n>& s2 = r.pick(m.particles); - - m.swap(β, s1, s2, r); - if (i % (N * 3) == 0) { - draw(m); - } + Vector<2> t1 = s1.x; + Vector<2> t2 = s2.x; + Vector<2> t = (t1 + t2) / 2; + + Matrix<2> mat; + + mat(0, 0) = -1; + mat(1, 1) = -1; + mat(0, 1) = 0; + mat(1, 0) = 0; + + Euclidean<2> g(t - mat * t, mat); + + std::cout << m.clusterFlip(1, g, s1, r) << std::endl; + + draw(m); } return 0; diff --git a/spheres.hpp b/spheres.hpp index 5ecad39..ef6b665 100644 --- a/spheres.hpp +++ b/spheres.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #include @@ -11,6 +13,7 @@ using Rng = randutils::random_generator; template using Vector = Eigen::Matrix; +template using Matrix = Eigen::Matrix; template class Position : public Vector { private: @@ -58,6 +61,7 @@ public: template concept Particle = requires(T v, const T& w) { { v.x } -> std::same_as>; + { v.m } -> std::same_as; { v.U(w) } -> std::same_as; }; @@ -93,6 +97,7 @@ private: for (unsigned i = 0; i < D; i++) { ind += pow(n, i) * std::floor(n * x(i)); } + assert(ind < lists.size()); return ind; } @@ -155,9 +160,10 @@ public: template class Sphere { public: Position x; + bool m; double r; - Sphere(const Position& x, double r) : x(x), r(r) {}; + Sphere(const Position& x, double r) : x(x), m(false), r(r) {}; double regularizedDistanceSquared(const Sphere& s) const { return (x - s.x).squaredNorm() / pow(r + s.r, 2); @@ -204,6 +210,24 @@ public: } }; +template class Euclidean { +public: + Vector t; + Matrix r; + + Euclidean() { + t.setZero(); + r.setIdentity(); + } + + Euclidean(const Vector& t0, const Matrix& r0) : t(t0), r(r0) {} + + Euclidean inverse() const { return Euclidean(-r.transpose() * t, r.transpose()); } + + Vector act(const Vector& x) const { return r * x; } + Position act(const Position& x) const { return (Position)(r * x) + t; } +}; + template T> class Model { private: NeighborLists nl; @@ -247,16 +271,20 @@ public: double energyChangeSwap(const T& p1, const T& p2) const { double ΔE = 0; + T p1New = p1; + T p2New = p2; + p1New.r = p2.r; + p2New.r = p1.r; for (const T* neighbor : neighborsOf(p1.x)) { if (neighbor != &p1 && neighbor != &p2) { ΔE -= neighbor->U(p1); - ΔE += neighbor->U({p1.x, p2.r}); + ΔE += neighbor->U(p1New); } } for (const T* neighbor : neighborsOf(p2.x)) { if (neighbor != &p1 && neighbor != &p2) { ΔE -= neighbor->U(p2); - ΔE += neighbor->U({p2.x, p1.r}); + ΔE += neighbor->U(p2New); } } @@ -286,4 +314,39 @@ public: return false; } } + + unsigned clusterFlip(double β, const Euclidean& R, T& p0, Rng& r) { + unsigned n = 0; + std::queue q; + q.push(&p0); + + while (!q.empty()) { + T* p = q.front(); + q.pop(); + + if (!p->m) { + p->m = true; + T pNew = *p; + pNew.x = R.act(p->x); + + for (T* neighbor : neighborsOf(pNew.x)) { + if (!neighbor->m) { + double ΔE = neighbor->U(pNew) - neighbor->U(*p); + if (1 - exp(-β * ΔE) > r.uniform(0.0, 1.0)) { + q.push(neighbor); + } + } + } + + move(*p, pNew.x); + n++; + } + } + + for (T& p : particles) { + p.m = false; + } + + return n; + } }; -- cgit v1.2.3-54-g00ecf