The Heisenberg Example. But threaded!

The O(3) Heisenberg model is a slightly more advanced model on a continuous state space. This demo also gives an example of how to inject a self-defined Wolff Cluster update for your self-defined model into MARQOV. Additionally we show in this example how to use the MARQOV scheduler in order to have automatic scheduling of the jobs derived from your parameter space sampling.

  1#include <iostream>
  2#include <array>
  3#include <tuple>
  4#include <vector>
  5
  6//include the MARQOV library
  7#undef MPIMARQOV
  8#include "libmarqov.h"
  9
 10//include the RegularLattice
 11#include "../src/lattice/regular_hypercubic.h"
 12
 13//include some predefined observables, e.g. the magnetization and the energy
 14#include "../src/hamiltonian/util/observables.h"
 15
 16
 17// Define interaction term for the Heisenberg model
 18class MyHeisenberg_interaction
 19{
 20	public:
 21		MyHeisenberg_interaction(const double J) : J(J) {}
 22		std::array<double, 3> get (const std::array<double, 3>& phi) {return phi;};
 23        const double J;
 24};
 25
 26class MySimpleHeisenberg
 27{
 28	public:
 29		
 30		// The spin dimension of the Heisenberg or O(3) model
 31		constexpr static int SymD = 3;
 32
 33		// Define the state vector that this model will use.
 34		// For the Heisenberg model this is a three-dimensional unit vector
 35		typedef std::array<double, SymD> StateVector;
 36
 37		// Parameters
 38		double J; // The coupling constant
 39		const std::string name; // every Hamiltonian MUST have a name, this is required for the HDF5 output
 40
 41		// Hamiltonian terms
 42		// here this is only the canonical O(3) interaction, defined above
 43		std::array<MyHeisenberg_interaction*, 1> interactions = {new MyHeisenberg_interaction(J)};
 44        
 45		// Constructor
 46		MySimpleHeisenberg(double J) : J(J), name("MySimpleHeisenberg"), obs_e(*this){}
 47		~MySimpleHeisenberg() {delete interactions[0];}
 48
 49		// Observables
 50		Magnetization  obs_m;
 51		Energy<MySimpleHeisenberg>  obs_e{*this};
 52                std::pair<Magnetization, Energy<MySimpleHeisenberg> > observables{obs_m, obs_e};
 53};
 54
 55namespace MARQOV
 56{
 57    template <class Lattice>
 58    struct Wolff<MySimpleHeisenberg, Lattice>
 59    {
 60        std::vector<int> cstack = std::vector<int>(4096/sizeof(int), 0);///< the size of the stack is meant to be preserved across different cluster processes.
 61        
 62        template <class RNG, class StateSpace>
 63        inline int move(const MySimpleHeisenberg& ham, const Lattice& grid, StateSpace& statespace, RNG& rng, double beta, int rsite)
 64        {
 65            typedef MySimpleHeisenberg Hamiltonian;
 66            typedef typename Hamiltonian::StateVector StateVector;
 67            constexpr static int SymD = Hamiltonian::SymD;
 68            
 69            int q = 0;
 70            auto& seed = statespace[rsite];
 71            cstack[q] = rsite;
 72            
 73            int rdir = rng.integer(SymD); // random Cartesian direction
 74            seed[rdir] *= -1;
 75            
 76            int clustersize = 1;
 77            int current = 0;
 78            
 79            // plain Heisenberg model has only one interaction term
 80            const auto gcpl = ham.interactions[0]->J; 
 81            
 82            while (q>=0)
 83            {
 84                current = cstack[q];
 85                q--;
 86                
 87                const auto nbrs = grid.nbrs(0, current);
 88                if(q + nbrs.size() > cstack.size()) 
 89                    cstack.resize(2*cstack.size());
 90                for (std::size_t i = 0; i < nbrs.size(); ++i)
 91                {
 92                    const auto currentnbr = nbrs[i];
 93                    StateVector& candidate = statespace[currentnbr];
 94                    
 95                    const auto lcpl = statespace[current][rdir] * candidate[rdir];
 96                    const auto cpl  = gcpl*lcpl;
 97                    
 98                    if (wolff_update_accepted(cpl, beta, rng))
 99                    {
100                        q++;
101                        clustersize++;
102                        cstack[q] = currentnbr;
103                        candidate[rdir] = -candidate[rdir];
104                    }
105                }
106            }
107            return clustersize;
108        }
109    };
110}
111
112using namespace std;
113using namespace MARQOV;
114
115int main()
116{
117	std::cout<<"Welcome to the MARQOV Heisenberg test case! ";
118	std::cout<<"This test is the minimum example that features a self-defined Heisenberg model and utlizes ";
119	std::cout<<"the multithread scheduler."<<std::endl;
120    // Initialize the lattice
121	int L = 64;
122	int dim = 3;
123    RegularHypercubic mylatt(L, dim);
124
125	// Set Monte Carlo parameters using MARQOV::Config
126	MARQOV::Config mp("./"); // output path 
127	mp.setnmetro(5); // number of Metropolis sweeps per EMCS
128	mp.setncluster(10); // number of Wolff updates per EMCS
129	mp.setwarmupsteps(5); // number of EMCS for warmup
130	mp.setgameloopsteps(3); // number of EMCS for production
131	mp.setloglevel(RELEASE); // set the log level
132
133	// Set the Hamiltonian parameters, J, and the inverse temperature beta
134    double beta = 0.66;
135    double J = -1;
136    auto hp = make_tuple(beta, J);
137
138    // Let's create some parameters tuples, a temperature scan for the scheduler to work on
139
140    // Prepare an array of parameter tuples
141    auto args = make_tuple(std::ref(mylatt), mp, hp);
142    vector<decltype(args)> v;
143
144	// Fill
145    for(int j = 0; j < 4; ++j)
146    {
147        hp = make_tuple(beta+j*0.1, J);
148        v.push_back(make_tuple(std::ref(mylatt), mp, hp));
149    }
150
151    // Set up the MARQOV schedular
152    auto sched = makeScheduler<MySimpleHeisenberg, RegularHypercubic>(args, 10);
153    sched.setloglevel(RELEASE);
154	// Feed parameters to the scheduler which creates the simulations
155    for(auto p : v)
156		sched.createSimfromParameter(p);
157	// Run
158    sched.start();
159}