montecarlo.h
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 #ifndef MONTECARLO_H_
15 #define MONTECARLO_H_
16 
17 #include "xthread.h"
18 
19 #include "support.h"
20 #include "atomic.h"
21 
22 #include <math.h>
23 #include <vector>
24 #include <deque>
25 
26 #include <gsl/gsl_sf_erf.h>
27 //! erfc(x)=1-erf(x)=(2/sqrt(PI))int_x^inf exp(-t^2)dt
28 #define erfc_(x) gsl_sf_erfc(x)
29 
30 #include <iostream>
31 #include <complex>
32 
33 //! Bohr magnetron [J/T]
34 #define MU_B 9.27410e-24
35 //! Boltzman const. [J/K]
36 #define K_B 1.38062e-23
37 //! Abogadro's number [1/mol]
38 #define N_A 6.02217e23
39 
40 //! Moment of A site. [mu_B]
41 #define A_MOMENT 10.0
42 //! lattice constant [m]
43 #define LATTICE_CONST 10.12e-10
44 #define LATTICE_VOLUME (LATTICE_CONST*LATTICE_CONST*LATTICE_CONST)
45 
46 #define SEC_CACHE_ON_FACTOR 0.02
47 #define SEC_CACHE_OFF_FACTOR 0.01
48 #define THIRD_CACHE_ON_FACTOR 0.05
49 #define THIRD_CACHE_OFF_FACTOR 0.02
50 
51 //! For SIMD vectorization.
52 //#define PACK_4FLOAT
53 
54 //! Nearest neighbor exchange interaction [K]
55 #define J_NN -1.24
56 
57 //! Hyperfine coupling constant between O(1) and the nearest Dy. [T/mu_B]
58 #define AHF_DY_O1_DIPOLE (MU_B*1e-7/pow(sqrt(3.0)/8.0*LATTICE_CONST, 3.0)*2.0)
59 //! w/ correction determined by 17O-NMR in the spin-ice state.
60 #define AHF_DY_O1 (AHF_DY_O1_DIPOLE + (-25.06e6+19.64e6)/5.7719e6/A_MOMENT/(4.0/sqrt(3.0)))
61 
63 {
64 public:
65  template <typename T>
66  struct Vector3 {
67  Vector3() : x(0), y(0), z(0) {}
68  Vector3(T nx, T ny) : x(nx), y(ny), z(0) {}
69  Vector3(T nx, T ny, T nz) : x(nx), y(ny), z(nz) {}
70  template <typename X>
71  Vector3(const Vector3<X> &r) : x(r.x), y(r.y), z(r.z) {}
72  template <typename X>
73  Vector3(const X n[3]) : x(n[0]), y(n[1]), z(n[2]) {}
74  T x; T y; T z;
75 
76  bool operator==(const Vector3 &s1) const
77  {return ((x == s1.x) && (y == s1.y) && (z == s1.z));}
78  template<typename X>
79  Vector3 &operator+=(const Vector3<X> &s1) {
80  x += s1.x; y += s1.y; z += s1.z;
81  return *this;
82  }
83  template<typename X>
84  Vector3 &operator-=(const Vector3<X> &s1) {
85  x -= s1.x; y -= s1.y; z -= s1.z;
86  return *this;
87  }
88  template<typename X>
89  Vector3 &operator*=(const X &k) {
90  x *= k; y *= k; z *= k;
91  return *this;
92  }
93  //! square of distance between this and a point
94  T distance2(const Vector3<T> &s1) const {
95  T x1 = x - s1.x;
96  T y1 = y - s1.y;
97  T z1 = z - s1.z;
98  return x1*x1 + y1*y1 + z1*z1;
99  }
100  //! square of distance between this and a line from s1 to s2
101  T distance2(const Vector3<T> &s1, const Vector3<T> &s2) const {
102  T x1 = x - s1.x;
103  T y1 = y - s1.y;
104  T z1 = z - s1.z;
105  T x2 = s2.x - s1.x;
106  T y2 = s2.y - s1.y;
107  T z2 = s2.z - s1.z;
108  T zbab = x1*x2 + y1*y2 + z1*z2;
109  T ab2 = x2*x2 + y2*y2 + z2*z2;
110  T zb2 = x1*x1 + y1*y1 + z1*z1;
111  return (zb2*ab2 - zbab*zbab) / ab2;
112  }
113  void normalize() {
114  T ir = (T)1.0 / sqrt(x*x + y*y + z*z);
115  x *= ir; y *= ir; z *= ir;
116  }
117  Vector3 &vectorProduct(const Vector3 &s1) {
118  Vector3 s2;
119  s2.x = y * s1.z - z * s1.y;
120  s2.y = z * s1.x - x * s1.z;
121  s2.z = x * s1.y - y * s1.x;
122  *this = s2;
123  return *this;
124  }
125  T innerProduct(const Vector3 &s1) const {
126  return x * s1.x + y * s1.y + z * s1.z;
127  }
128  T abs() const {
129  return sqrt(x*x+y*y+z*z);
130  }
131  };
132 
133  MonteCarlo(int num_threads);
134  ~MonteCarlo();
135 
136  //! \return Delta U [J/A site].
137  //! \param flips # of flipping to be performed. # done is returned.
138  //! \param tests Min # of tests to be performed. # done is returned.
139  double exec(double temp, Vector3<double> field,
140  int *flips, long double *tests, double *DUav, Vector3<double> *Mav);
141  //! randomize spins
142  void randomize();
143  //! [mu_B/A site]
144  Vector3<double> magnetization();
145  //! [mu_B/site]
146  struct Quartet {
147  Quartet() {
148  sites[0] = 0.0;
149  sites[1] = 0.0;
150  sites[2] = 0.0;
151  sites[3] = 0.0;
152  twotwo = 0.0;
153  onethree = 0.0;
154  }
155  double sites[4];
156  //! icerule probability.
157  double twotwo;
158  //! 1-in,3-out or 1-out,3-in probability.
159  double onethree;
160  };
161  Quartet siteMagnetization();
162  //! internal energy U [J/A site]
163  double internalEnergy();
164  //! prepare interactions.
165  //! \param size # of lattices for one direction.
166  //! \param dfactor Bulk demagnetization factor D (0 < D < 1).
167  //! \param cutoff_real [L.U.].
168  //! \param cutoff_rec [2pi/L].
169  //! \param alpha Ewald convergence factor [1/L].
170  //! \return # of interactions.
171  static int setupField(int size, double dfactor,
172  double cutoff_real, double cutoff_rec, double alpha);
173  //! read snapshot.
174  void read(std::istream &);
175  void read(const char *spins, double temp, Vector3<double> field);
176  //! write snapshot.
177  void write(std::ostream &);
178  void write(char *spins,
179  double *fields = 0, double *probabilities = 0);
180  void write_bsite(Vector3<double> *fields);
181  void write_8asite(Vector3<double> *fields);
182  void write_48fsite(Vector3<double> *fields);
183  struct FlipHistory {int lidx; int site; float delta; double tests;};
184  void write_flips(std::deque<FlipHistory> &buf);
185 
186  static int length() {
187  return s_L;
188  }
189 
190  //! true if user interrupts.
191  static volatile bool s_bAborting;
192 
193 private:
194  //! thread pool.
195  volatile bool m_bTerminated;
196 
197  XCondition m_thread_pool_cond;
198  XCondition m_hint_site2_last_cond;
199  void execute();
200  //! target spin for concurrent calc. of interactions.
201  atomic<int> m_hint_site2_left, m_hint_site2_not_done;
202  int m_hint_spin1_site;
203  int m_hint_spin1_lattice_index;
204  //! store calculated fields.
205  double m_hint_fields[16];
206  int m_hint_sec_cache_miss[16];
207 
208  //! Accelerate flipping.
209  //! \return tests to flip.
210  long double accelFlipping();
211  int m_last_probability_buffer;
212  int m_last_flipped_site;
213  int m_last_flipped_lattice_index;
214  bool m_play_back_buffer;
215  std::vector<double> m_probability_buffers[2][16];
216 
217  //! Cache systems
218  //! Primary cache: field at the target site.
219  //! Secondary cache: field from a certain site at the target site.
220  //! Third cache : field from a certain site with real space calc. at the target site.
222  bool m_sec_cache_enabled, m_third_cache_enabled;
223  bool m_sec_cache_firsttime, m_third_cache_firsttime;
224  //! total hittings to caches.
226  atomic<long> m_third_cache_hit;
227  //! cached interaction energy.
228  std::vector<double> m_field_pri_cached[16];
229  //! true if cached data is valid.
230  std::vector<uint16_t> m_field_pri_cached_sane;
231  //! cached interaction energy.
232  std::vector<double> m_field_sec_cached[16][16];
233  //! true if cached data is valid.
234  std::vector<uint16_t> m_field_sec_cached_sane[16];
235  //! cached interaction energy.
236  std::vector<double> m_field_third_cached[16][16];
237  //! true if cached data is valid.
238  std::vector<uint16_t> m_field_third_cached_sane[16];
239 
240  //! many tests until fixed number of flipping is performed.
241  //! \sa exec()
242  void doTests(int *flips, long double tests);
243  void flipSpin(int site, int lidx, double du, long double tests_after_check);
244  inline double flippingProbability(int site, int lidx, double field, double *du);
245 
246  typedef Vector3<int> VectorInt;
247  //! unit is 1/4 lattice const.
248  static inline VectorInt distance(int site1, int site2, int di, int dj, int dk);
249  //! max interaction distance for real space.
250  static int s_cutoff_real;
251  static double s_cutoff_real_radius;
252  //! For reciprocal space. i.e. Ewald term.
253  static int s_cutoff_rec;
254  static double s_cutoff_rec_radius;
255  //! Ewald convergence factor [1/m].
256  static double s_alpha;
257  //! Demagnetization D factor.
258  static double s_dfactor;
259  //! \return true if included.
260  static int dipoleFieldReal(const Vector3<double> &dist_times_4, int site2, Vector3<double> *ret);
261  static int dipoleFieldRec(const Vector3<double> &k, int site2, Vector3<double> *ret);
262 
263  typedef float Spin;
264 
265  static inline int lattice_index(int i, int j, int k);
266  //! For real space calculations. Particle part.
267  //! field along ising axis when spin is +1.
268  //! index is given by distance_index()
269  //! [T]
270 #ifdef PACK_4FLOAT
271  struct PackedSpin {
272  PackedSpin() {
273  for(int i = 0; i < 4; i++) x[i] = 0.0;
274  }
275  PackedSpin(const PackedSpin &v) {
276  for(int i = 0; i < 4; i++) x[i] = v.x[i];
277  }
278  Spin x[4];
279  Spin sum() const {
280  float h = 0.0;
281  for(int i = 0; i < 4; i++) h += x[i];
282  return h;
283  }
284  PackedSpin &operator+=(const PackedSpin &v) {
285  for(int i = 0; i < 4; i++) x[i] += v.x[i];
286  return *this;
287  }
288  PackedSpin &operator*=(const PackedSpin &v) {
289  for(int i = 0; i < 4; i++) x[i] *= v.x[i];
290  return *this;
291  }
292  }
293 #if defined __GNUC__ || defined __clang__
294  __attribute__((__aligned__(16)))
295 #endif
296  ;
297  struct FieldRealArray {std::vector<PackedSpin> align[4];};
298 #else
299  typedef std::vector<Spin> FieldRealArray;
300 #endif
301  static FieldRealArray s_fields_real[16][16];
302  static FieldRealArray s_fields_real_B[16][16][3];
303  static FieldRealArray s_fields_real_8a[8][16][3];
304  static FieldRealArray s_fields_real_48f[48][16][3];
305  static void addFieldsReal(MonteCarlo::Spin v, FieldRealArray& array, int di, int dj, int dk);
306  //! For reciprocal space. i.e. Ewald term.
307  static std::vector<Spin> s_fields_rec[16][16];
308  static std::vector<Vector3<Spin> > s_fields_rec_generic[16];
309  //! For self-energy caclulation.
310  static double s_fields_rec_sum;
311  static std::vector<std::complex<MonteCarlo::Spin> > s_exp_ph[16];
312  static inline int reciprocal_index(int kx, int ky, int kz);
313  //! spin orientations. in real space.
314  //! images are repeated outside boundary along x.
315 #ifdef PACK_4FLOAT
316  std::vector<PackedSpin> m_spins_real[16];
317 #else
318  std::vector<Spin> m_spins_real[16];
319 #endif
320  static inline int spins_real_index(int i, int j, int k);
321  static inline int spins_real_index(int lidx);
322  inline Spin readSpin(int site, int sidx);
323  inline void writeSpin(Spin v, int site, int sidx);
324  //! For reciprocal space. with q-cutoff.
325  std::vector<std::complex<Spin> > m_spins_rec[16];
326  void makeReciprocalImage();
327  //! \param diff e.g. -2, -1, 1, 2.
328  inline void modifyReciprocalImage(Spin diff, int site, int i, int j, int k);
329 
330  //! internal field from surrounding spins along ising axis [T].
331  inline double hinteraction(int site, int lidx);
332  double hinteraction_miscache(int sec_cache_miss_cnt, int site, int lidx);
333  inline double iterate_interactions(int site1, int lidx, int site2);
334  Vector3<double> iterate_real_generic(const FieldRealArray[16][3], int i, int j, int k);
335  inline double iterate_real_redirected(int cnt, const FieldRealArray &, int i, int j, int k, int site2);
336  double iterate_real(int site1, int i, int j, int k, int site2);
337  Vector3<double> iterate_rec_generic(Vector3<double> pos1, int i, int j, int k);
338  Vector3<double> iterate_rec_generic(Vector3<double> pos1, int i, int j, int k, int site2);
339  inline double iterate_rec_redirected(int cutoff, int site1, int i, int j, int k, int site2);
340  double iterate_rec(int site1, int i, int j, int k, int site2);
341 
342  //! temperature. 1/k_B T [1/J].
343  double m_beta;
344  //! Along Ising direction [T]
345  double m_ext_field[16];
346  //! size of lattices
347  static int s_L;
348  //! # of spins
349  static int s_num_spins;
350  //! Delta U [J]
351  long double m_DeltaU;
352  void takeThermalAverage(long double tests_after_check);
353  //! Sum Delta U [J]
354  long double m_SumDeltaU;
355  //! Sum Spin Polarization
356  long double m_SumSpin[16];
357  long double m_SumTests;
358  long double m_SumTestsAtLastFlip;
359  //! 4*r^2 to nth neighbor.
360  static std::vector<int> s_4r2_neighbor;
361 
362  std::deque<pthread_t> m_threads;
363  static void * xthread_start_routine(void *);
364 
365  static Vector3<double> s_ASiteIsingVector[16];
366 
367  std::deque<FlipHistory> m_flipHistory;
368 };
369 
370 //inline functions.
371 //! unit is 1/4 lattice const.
372 static const int cg_ASitePositions[16][3] = {
373  {0,0,0}, {1,1,0}, {1,0,1}, {0,1,1},
374  {2,2,0}, {3,3,0}, {3,2,1}, {2,3,1},
375  {0,2,2}, {1,3,2}, {1,2,3}, {0,3,3},
376  {2,0,2}, {3,1,2}, {3,0,3}, {2,1,3}
377 };
378 //! unit is 1/4 lattice const.
379 static const int cg_BSitePositions[16][3] = {
380  {2,2,2}, {1,3,0}, {3,0,1}, {0,1,3},
381  {0,0,2}, {3,1,0}, {1,2,1}, {2,3,3},
382  {2,0,0}, {1,1,2}, {3,2,3}, {0,3,1},
383  {0,2,0}, {3,3,2}, {1,0,3}, {2,1,1}
384 };
385 //! unit is 1/8 lattice const.
386 static const int cg_8aSitePositions[8][3] = {
387  {1,1,1}, {5,5,1}, {1,5,5}, {5,1,5},
388  {7,3,3}, {3,7,3}, {7,7,7}, {3,3,7}
389 };
390 #define OX (0.4201*8)
391 //! unit is 1/8 lattice const.
392 static const double cg_48fSitePositions[48][3] = {
393  {OX,1,1}, {OX+4,5,1}, {OX,5,5}, {OX+4,1,5},
394  {1,OX,1}, {5,OX+4,1}, {1,OX+4,5}, {5,OX,5},
395  {1,1,OX}, {5,5,OX}, {1,5,OX+4}, {5,1,OX+4},
396  {-OX+6,1,5}, {-OX+10,5,5}, {-OX+6,5,1}, {-OX+10,1,1},
397  {5,-OX+6,1}, {1,-OX+10,1}, {5,-OX+10,5}, {1,-OX+6,5},
398  {1,5,-OX+6}, {5,1,-OX+6}, {1,1,-OX+10}, {5,5,-OX+10},
399  {7,OX+2,3}, {3,OX-2,3}, {7,OX-2,7}, {3,OX+2,7},
400  {OX-2,3,3}, {OX+2,7,3}, {OX-2,7,7}, {OX+2,3,7},
401  {3,3,OX-2}, {7,7,OX-2}, {3,7,OX+2}, {7,3,OX+2},
402  {7,-OX+8,7}, {3,-OX+4,7}, {7,-OX+4,3}, {3,-OX+8,3},
403  {-OX+4,7,3}, {-OX+8,3,3}, {-OX+4,3,7}, {-OX+8,7,7},
404  {7,3,-OX+4}, {3,7,-OX+4}, {7,7,-OX+8}, {3,3,-OX+8}
405 };
406 
407 //! Ising axes. to "in" direction.
408 static const int cg_ASiteIsingAxes[16][3] = {
409  {1,1,1}, {-1,-1,1}, {-1,1,-1}, {1,-1,-1},
410  {1,1,1}, {-1,-1,1}, {-1,1,-1}, {1,-1,-1},
411  {1,1,1}, {-1,-1,1}, {-1,1,-1}, {1,-1,-1},
412  {1,1,1}, {-1,-1,1}, {-1,1,-1}, {1,-1,-1}
413 };
414 inline int
415 MonteCarlo::reciprocal_index(int kx, int ky, int kz) {
416  return (2*s_cutoff_rec + 1)*((2*s_cutoff_rec + 1)*kz + ky + s_cutoff_rec) + kx + s_cutoff_rec;
417 }
418 inline int
419 MonteCarlo::lattice_index(int i, int j, int k) {
420  return s_L*(s_L*k + j) + i;
421 }
422 #ifdef PACK_4FLOAT
423 inline int
424 MonteCarlo::spins_real_index(int i, int j, int k) {
425  int l = ((3 * s_L - 1) / 4 + 1) * 4;
426  return 3*l*(s_L*k + j) + s_L + i;
427 }
428 inline int
429 MonteCarlo::spins_real_index(int lidx) {
430  int l = ((3 * s_L - 1) / 4 + 1) * 4;
431  return 3*l*(lidx / s_L) + s_L + (lidx % s_L);
432 }
433 inline MonteCarlo::Spin
434 MonteCarlo::readSpin(int site, int sidx) {
435  int r = sidx / 4;
436  int c = sidx % 4;
437  return m_spins_real[site][r].x[c];
438 }
439 inline void
440 MonteCarlo::writeSpin(Spin v, int site, int sidx) {
441  m_spins_real[site][sidx / 4].x[sidx % 4] = v;
442  m_spins_real[site][(sidx - s_L) / 4].x[(sidx - s_L) % 4] = v;
443  m_spins_real[site][(sidx + s_L) / 4].x[(sidx + s_L) % 4] = v;
444 }
445 #else
446 inline int
447 MonteCarlo::spins_real_index(int i, int j, int k) {
448  return 3*s_L*(s_L*k + j) + i + s_L;
449 }
450 inline int
451 MonteCarlo::spins_real_index(int lidx) {
452  return lidx * 3 - (lidx % s_L) * 2 + s_L;
453 }
454 inline MonteCarlo::Spin
455 MonteCarlo::readSpin(int site, int sidx) {
456  return m_spins_real[site][sidx];
457 }
458 inline void
459 MonteCarlo::writeSpin(Spin v, int site, int sidx) {
460  m_spins_real[site][sidx - s_L] = v;
461  m_spins_real[site][sidx] = v;
462  m_spins_real[site][sidx + s_L] = v;
463 }
464 #endif
465 //! unit is 1/4 lattice const.
467 MonteCarlo::distance(int site1, int site2, int di, int dj, int dk)
468 {
469  VectorInt v;
470  v.x = 4*di + cg_ASitePositions[site2][0] - cg_ASitePositions[site1][0];
471  v.y = 4*dj + cg_ASitePositions[site2][1] - cg_ASitePositions[site1][1];
472  v.z = 4*dk + cg_ASitePositions[site2][2] - cg_ASitePositions[site1][2];
473  return v;
474 }
475 inline double
476 MonteCarlo::iterate_interactions(int site1, int lidx, int site2)
477 {
478  int n = lidx;
479  int i = n % s_L;
480  n /= s_L;
481  int j = n % s_L;
482  n /= s_L;
483  int k = n;
484 
485  double h = iterate_rec(site1, i, j, k, site2);
486 
487  if(m_third_cache_enabled &&
488  (m_field_third_cached_sane[site2][lidx] & (1u << site1))) {
489  ++m_third_cache_hit;
490  h += m_field_third_cached[site1][site2][lidx];
491  }
492  else {
493  double hreal = iterate_real(site1, i, j, k, site2);
494  if(m_third_cache_enabled) {
495  m_field_third_cached[site1][site2][lidx] = hreal;
496  m_field_third_cached_sane[site2][lidx] |= 1u << site1;
497  }
498  h += hreal;
499  }
500 
501  if(m_sec_cache_enabled) {
502  m_field_sec_cached[site1][site2][lidx] = h;
503  m_field_sec_cached_sane[site2][lidx] |= 1u << site1;
504  }
505 
506  return h;
507 }
508 
509 inline double
510 MonteCarlo::hinteraction(int site1, int lidx)
511 {
512  if(m_field_pri_cached_sane[lidx] & (1u << site1)) {
513  return m_field_pri_cached[site1][lidx];
514  }
515 
517 
518  double h = 0.0;
519  int sec_cache_miss_cnt = 0;
520  for(int site2 = 0; site2 < 16; site2++) {
521  if(m_sec_cache_enabled &&
522  (m_field_sec_cached_sane[site2][lidx] & (1u << site1))) {
523  m_sec_cache_hit++;
524  h += m_field_sec_cached[site1][site2][lidx];
525  }
526  else {
527  m_hint_sec_cache_miss[sec_cache_miss_cnt++] = site2;
528  }
529  }
530 
531  if(sec_cache_miss_cnt <= 8) {
532  // Inefficient case for threading.
533  for(int miss = 0; miss < sec_cache_miss_cnt; miss++) {
534  int site2 = m_hint_sec_cache_miss[miss];
535  h += iterate_interactions(site1, lidx, site2);
536  }
537  }
538  else
539  h += hinteraction_miscache(sec_cache_miss_cnt, site1, lidx);
540 
541  // contribution from this spin must not be counted.
542  // cache result.
543  m_field_pri_cached[site1][lidx] = h;
544  m_field_pri_cached_sane[lidx] |= 1u << site1;
545  return h;
546 }
547 
548 #endif /*MONTECARLO_H_*/

Generated for KAME4 by  doxygen 1.8.3