diff --git a/exercises/ex10_solution/Makefile b/exercises/ex10_solution/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..7bd55db609488df0034ed1d355941ab3ba3589e6 --- /dev/null +++ b/exercises/ex10_solution/Makefile @@ -0,0 +1,4 @@ +include $(ALPS_ROOT)/share/alps/include.mk + +ising: ising.cpp + $(CXX) -Wall $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $(LIBS) -o ising ising.cpp diff --git a/exercises/ex10_solution/classical_ising-mag.pdf b/exercises/ex10_solution/classical_ising-mag.pdf new file mode 100755 index 0000000000000000000000000000000000000000..7964e9e202347ff6610101e715a9ac8f1c82fed7 Binary files /dev/null and b/exercises/ex10_solution/classical_ising-mag.pdf differ diff --git a/exercises/ex10_solution/classical_ising-mag2.pdf b/exercises/ex10_solution/classical_ising-mag2.pdf new file mode 100755 index 0000000000000000000000000000000000000000..30c7457e9fa9d905afd3453a15b8f7adfb64ca20 Binary files /dev/null and b/exercises/ex10_solution/classical_ising-mag2.pdf differ diff --git a/exercises/ex10_solution/classical_ising-mag_error.pdf b/exercises/ex10_solution/classical_ising-mag_error.pdf new file mode 100755 index 0000000000000000000000000000000000000000..da2ef9ce5c21acba312108676b8e10a01be5583d Binary files /dev/null and b/exercises/ex10_solution/classical_ising-mag_error.pdf differ diff --git a/exercises/ex10_solution/classical_ising-mag_tau.pdf b/exercises/ex10_solution/classical_ising-mag_tau.pdf new file mode 100755 index 0000000000000000000000000000000000000000..59a4905418d4dc10e82e47d3c20b81b4f88fef50 Binary files /dev/null and b/exercises/ex10_solution/classical_ising-mag_tau.pdf differ diff --git a/exercises/ex10_solution/data/run_classical.sh b/exercises/ex10_solution/data/run_classical.sh new file mode 100755 index 0000000000000000000000000000000000000000..55e055b953dbd156eb7c1b9986a9d7b8d9afe77f --- /dev/null +++ b/exercises/ex10_solution/data/run_classical.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +L=16 +N=1000000 + +for J in 0.1 0.2 0.3 0.4 0.44 0.5 0.6 0.7 0.8 0.9 +do + time ../ising $L $L $J $J $N & + time ../ising $L $L $J $J $N local & + wait +done diff --git a/exercises/ex10_solution/ising.cpp b/exercises/ex10_solution/ising.cpp new file mode 100755 index 0000000000000000000000000000000000000000..0b301f58b26f478536bcb0c33b79bcc02d37d4cc --- /dev/null +++ b/exercises/ex10_solution/ising.cpp @@ -0,0 +1,344 @@ +/***************************************************************************** + * + * Copyright (C) 2010 - 2012 Jan Gukelberger + * Copyright (C) 2010 Brigitte Surer + * + * This software is based on the ALPS Code-02 tutorial, published under the ALPS + * Library License; you can use, redistribute it and/or modify it under + * the terms of the license, either version 1 or (at your option) any later + * version. + * + * You should have received a copy of the ALPS Library License along with + * the ALPS Libraries; see the file LICENSE.txt. If not, the license is also + * available from http://alps.comp-phys.org/. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#include <alps/scheduler/montecarlo.h> +#include <alps/alea.h> +#include <boost/random.hpp> +#include <boost/multi_array.hpp> +#include <iostream> +#include <sstream> +#include <vector> +#include <map> +#include <cmath> +using namespace std; + + +class Simulation +{ +public: + Simulation(double Jy, double Jx, size_t M, size_t L, std::string output_file, bool local) + : eng_(42) + , rng_(eng_, dist_) + , localUpdates_(local) + , spins_(boost::extents[M][L]) + , energy_("E") + , magnetization_("m") + , abs_magnetization_("|m|") + , m2_("m^2") + , m4_("m^4") + , filename_(output_file) + { + L_[0] = M ; L_[1] = L ; + J_[0] = Jy; J_[1] = Jx; + exp2j_[0] = exp(-2*Jy); + exp2j_[1] = exp(-2*Jx); + + // Init random spin configuration + for(unsigned i = 0; i < L_[0]; ++i) + { + for(unsigned j = 0; j < L_[1]; ++j) + spin(make_pair(i,j)) = 2 * randint(2) - 1; + } + } + + void run(size_t ntherm,size_t n) + { + thermalization_ = ntherm; + sweeps_=n; + // Thermalize for ntherm steps + while(ntherm--) + step(); + + // Run n steps + while(n--) + { + step(); + measure(); + } + + //save the observables + save(filename_); + + // Print observables + // std::cout << abs_magnetization_; + std::cout << abs_magnetization_.name() << ":\t" << abs_magnetization_.mean() + << " +- " << abs_magnetization_.error() << ";\ttau = " << abs_magnetization_.tau() + << ";\tconverged: " << alps::convergence_to_text(abs_magnetization_.converged_errors()) + << std::endl; + std::cout << energy_.name() << ":\t" << energy_.mean() + << " +- " << energy_.error() << ";\ttau = " << energy_.tau() + << ";\tconverged: " << alps::convergence_to_text(energy_.converged_errors()) + << std::endl; + std::cout << magnetization_.name() << ":\t" << magnetization_.mean() + << " +- " << magnetization_.error() << ";\ttau = " << magnetization_.tau() + << ";\tconverged: " << alps::convergence_to_text(magnetization_.converged_errors()) + << std::endl; + } + + void step() + { + switch( localUpdates_ ) + { + case false: cluster_step(); + case true: local_sweep(); + } + } + + void cluster_step() + { + // printSpins(); + vector<TodoItem> todo; + set<Site> flipped; + + // Pick random site k=(i,j) + Site x = randsite(); + Spin s = spin(x); + flip(x); + flipped.insert(x); + addNeighbors(x,todo); + + while( !todo.empty() ) + { + TodoItem t = todo.back(); + todo.pop_back(); + + if( spin(t.x) != s || flipped.count(t.x) ) continue; // do not do anything if the spins where not parallel or if the potential one (t) is already added to the cluster + + if( rng_() > exp2j_[t.dir] ) + { + flip(t.x); + flipped.insert(t.x); + addNeighbors(t.x,todo); + } + } + } + + void local_sweep() + { + for( size_t i = 0; i < nsites(); ++i ) + { + // Pick random site k=(i,j) + Site x = randsite(); + Spin s = spin(x); + + // Measure local energy e = -s_k * sum_{l nn k} s_l + Site l(x.first,(x.second+L_[1]-1)%L_[1]), d((x.first+L_[0]-1)%L_[0],x.second), + r(x.first,(x.second +1)%L_[1]), u((x.first +1)%L_[0],x.second); + int ey = s * (spin(u) + spin(d)); // up + down + int ex = s * (spin(l) + spin(r)); // left + right + double p = 1; + switch( ey ) + { + case -2: p /= (exp2j_[0]*exp2j_[0]); break; + case +2: p *= (exp2j_[0]*exp2j_[0]); break; + default: break; + } + switch( ex ) + { + case -2: p /= (exp2j_[1]*exp2j_[1]); break; + case +2: p *= (exp2j_[1]*exp2j_[1]); break; + default: break; + } + + // Flip s_k with probability exp(2 beta e) + if(p > 1 || rng_() < p) + flip(x); + } + } + + void measure() + { + int E = 0; // energy + int M = 0; // magnetization + for(size_t i = 0; i < L_[0]; ++i) + { + for(size_t j = 0; j < L_[1]; ++j) + { + E -= J_[0]*spins_[i][j]*spins_[(i+1)%L_[0]][j] + J_[1]*spins_[i][j]*spins_[i][(j+1)%L_[1]]; + M += spins_[i][j]; + } + } + + // Add sample to observables + energy_ << E/double(nsites()); + double m = M/double(nsites()); + magnetization_ << m; + abs_magnetization_ << fabs(m); + m2_ << m*m; + m4_ << m*m*m*m; + } + + void save(std::string const & filename){ + alps::hdf5::archive ar(filename,alps::hdf5::archive::REPLACE); + ar << alps::make_pvp("/parameters/L", L_[1]); + ar << alps::make_pvp("/parameters/M", L_[0]); + ar << alps::make_pvp("/parameters/Jx", J_[1]); + ar << alps::make_pvp("/parameters/Jy", J_[0]); + ar << alps::make_pvp("/parameters/SWEEPS", sweeps_); + ar << alps::make_pvp("/parameters/THERMALIZATION", thermalization_); + + ar << alps::make_pvp("/simulation/results/"+energy_.representation(), energy_); + ar << alps::make_pvp("/simulation/results/"+magnetization_.representation(), magnetization_); + ar << alps::make_pvp("/simulation/results/"+abs_magnetization_.representation(), abs_magnetization_); + ar << alps::make_pvp("/simulation/results/"+m2_.representation(), m2_); + ar << alps::make_pvp("/simulation/results/"+m4_.representation(), m4_); + + alps::RealObsevaluator m = abs_magnetization_; + alps::RealObsevaluator m2 = m2_; + alps::RealObsevaluator m4 = m4_; + + alps::RealObsevaluator u2("Binder Cumulant U2"); + u2 = m2/(m*m); + ar << alps::make_pvp("/simulation/results/"+u2.name(), u2); + + alps::RealObsevaluator chi("Connected Susceptibility"); + chi=nsites()*(m2-m*m); + ar << alps::make_pvp("/simulation/results/"+chi.name(), chi); + + alps::RealObsevaluator u4("Binder Cumulant"); + u4 = m4/(m2*m2); + ar << alps::make_pvp("/simulation/results/"+u4.name(), u4); + } + +protected: + typedef signed char Spin; + typedef std::pair<unsigned,unsigned> Site; + typedef unsigned Direction; + struct TodoItem { Site x; Direction dir; TodoItem(unsigned i=0, unsigned j=0, Direction d=0) : x(i,j), dir(d) {} }; + + // Random int from the interval [0,max) + int randint(int max) const + { + return static_cast<int>(max * rng_()); + } + Site randsite() const + { + return Site(randint(L_[0]),randint(L_[1])); + } + size_t nsites() const + { + return L_[0]*L_[1]; + } + Spin& spin(Site x) + { + return spins_[x.first][x.second]; + } + const Spin& spin(Site x) const + { + return spins_[x.first][x.second]; + } + void flip(Site x) + { + spin(x) *= -1; + } + void addNeighbors(Site x, vector<TodoItem>& n) const + { + n.push_back(TodoItem(x.first,(x.second+L_[1]-1)%L_[1],1)); // left + n.push_back(TodoItem(x.first,(x.second +1)%L_[1],1)); // right + n.push_back(TodoItem((x.first+L_[0]-1)%L_[0],x.second,0)); // down + n.push_back(TodoItem((x.first +1)%L_[0],x.second,0)); // up + } + + void printSpins() const + { + for( unsigned i = 0; i < L_[0]; ++i ) + { + for( unsigned j = 0; j < L_[1]; ++j ) + cout << (int(spins_[i][j]) > 0 ? 'x' : '.'); + cout << "\n"; + } + cout << endl; + } + +private: + typedef boost::mt19937 engine_type; + typedef boost::uniform_real<> distribution_type; + typedef boost::variate_generator<engine_type&, distribution_type> rng_type; + engine_type eng_; + distribution_type dist_; + mutable rng_type rng_; + + static const unsigned DIMENSIONS = 2; + size_t L_[DIMENSIONS]; + double J_[DIMENSIONS]; + size_t sweeps_; + size_t thermalization_; + bool localUpdates_; + + boost::multi_array<Spin,DIMENSIONS> spins_; + double exp2j_[DIMENSIONS]; + + alps::RealObservable energy_; + alps::RealObservable magnetization_; + alps::RealObservable abs_magnetization_; + alps::RealObservable m2_; + alps::RealObservable m4_; + + std::string filename_; +}; + +string usage(const std::string& prog) +{ + return "usage: " + prog + " M L Jy Jx N"; +} +int main(int argc, const char** argv) +{ + if( argc != 6 && argc != 7 ) + { + cerr << usage(argv[0]) << endl; + return -1; + } + + size_t M, L, N; + double Jy, Jx; + bool local = false; + try + { + using boost::lexical_cast; + M = lexical_cast<size_t>(argv[1]); // Linear lattice sizes + L = lexical_cast<size_t>(argv[2]); // + Jy = lexical_cast<double>(argv[3]); // coupling constants + Jx = lexical_cast<double>(argv[4]); // + N = lexical_cast<size_t>(argv[5]); // # of simulation steps + if( argc > 6 && argv[6] == string("local") ) + local = true; + } + catch(...) + { + cerr << usage(argv[0]) << endl; + return -1; + } + + + std::cout << "# M: " << M << " L: " << L << " Jy: " << Jy << " Jx: " << Jx << " N: " << N << " local: " << local << std::endl; + + std::stringstream output_name; + output_name << "ising_M" << M << "_L" << L << "_Jy" << Jy << "_Jx" << Jx; + if( local ) output_name << "_local"; + output_name <<".h5"; + Simulation sim(Jy, Jx, M, L, output_name.str(), local); + sim.run(N/5,N); + + return 0; +} diff --git a/exercises/ex10_solution/plot_classical.py b/exercises/ex10_solution/plot_classical.py new file mode 100755 index 0000000000000000000000000000000000000000..1c3f9695ece4d55922f6f4c75abebd31307cd2ef --- /dev/null +++ b/exercises/ex10_solution/plot_classical.py @@ -0,0 +1,53 @@ +import sys, os, re + +import numpy as np +import matplotlib.pyplot as plt +import pyalps +from pyalps.plot import plot + +files = pyalps.getResultFiles(dirname='data') +data = pyalps.loadMeasurements(files , ['|m|','m^2']) + +for d in pyalps.flatten(data): + if re.search(r'_local\.h5$',d.props['filename']): + d.props['update'] = 'local' + else: + d.props['update'] = 'cluster' + + +m = pyalps.collectXY(data, 'Jx', '|m|', foreach=['update']) +m2 = pyalps.collectXY(data, 'Jx', 'm^2', foreach=['update']) + +plt.figure() +plot(m) +plt.xlabel('$\\beta J$') +plt.ylabel('|magnetization|') +plt.legend(loc='best', frameon=False) +plt.savefig('classical_ising-mag.pdf',transparent=True) + + +plt.figure() +plot(m2) +plt.xlabel('$\\beta J$') +plt.ylabel('|magnetization|^2') +plt.legend(loc='best', frameon=False) +plt.savefig('classical_ising-mag2.pdf',transparent=True) + +plt.figure() +for d in m: + plt.plot(d.x,[y.error for y in d.y],label=d.props['label']) +plt.xlabel('$\\beta J$') +plt.ylabel('error') +plt.legend(loc='best', frameon=False) +plt.savefig('classical_ising-mag_error.pdf',transparent=True) + +plt.figure() +for d in m: + plt.plot(d.x,[y.tau for y in d.y],label=d.props['label']) +plt.xlabel('$\\beta J$') +plt.ylabel('autocorrelation time') +plt.legend(loc='best', frameon=False) +plt.savefig('classical_ising-mag_tau.pdf',transparent=True) + + +plt.show()