class IsingSimulation : public alps::scheduler::MCRun
{
public:
IsingSimulation(const alps::ProcessList&,const alps::Parameters&,int);
void save(alps::ODump&) const;
void load(alps::IDump&);
void dostep();
bool is_thermalized() const;
double work_done() const;
bool change_parameter(const std::string& name, const alps::StringValue& value);
private:
uint32_t length; // the system size
double beta; // the inverse temperatre
uint32_t sweeps; // the number of sweeps done
uint32_t thermalization_sweeps; // the number of sweeps to be done for equilibration
uint32_t total_sweeps; // the total number of sweeps to be done after equilibration
std::vector<int> spins; // the vector to store the spins
};
typedef alps::scheduler::SimpleMCFactory<IsingSimulation> IsingFactory;
int main(int argc, char** argv)
{
try {
return alps::scheduler::start(argc,argv,IsingFactory());
}
catch (std::exception& exc) {
return -1;
}
}
IsingSimulation::IsingSimulation(const alps::ProcessList& w,const alps::Parameters& p,int node)
: scheduler::MCRun(0,w,p,node),
length(static_cast<uint32_t>(parms["L"])),
beta(1./static_cast<double>(parms["T"])),
thermalization_sweeps(static_cast<uint32_t>(parms["THERMALIZATION"])),
total_sweeps(static_cast<uint32_t>(parms["SWEEPS"])),
sweeps(0),
spins(where.empty() ? 0 : length)
{
// initialize random spin configuration
for(int i=0;i<spins.size();i++)
spins[i]=(random_real() < 0.5 ? 1 : -1);
// create measurement objects
measurements << alea::RealObservable("Energy");
measurements << alea::RealObservable("Magnetization");
}
If the object is just created to evaluate the simulation but not to perform actual simulations, the where data member of the simulation, specifying the processes on which a simulation will performed, will be empty. In that case the spins vectoring, storing the spins of the simulation can be resized to zero.
void IsingSimulation::save(alps::ODump& dump) const
{
dump << sweeps << spins;
}
saves the simulation data into a checkpoint.
void IsingSimulation::load(alps::IDump& dump)
{
dump >> sweeps;
if(!where.empty()) // skip reading the spins if we are just evaluating
dump >> spins;
}
This loads the simulation data from a checkpoint. If the object is just loaded to evaluate the simulation but not to perform actual simulations, the where data member of the simulation, specifying the processes on which a simulation will performed, will be empty. In that case reading the spin configuration can be omitted to save memory.
bool IsingSimulation::change_parameter(const std::string& name, const alps::StringValue& value)
{
if(name=="SWEEPS") {
total_sweeps=static_cast<uint32_t>(value);
return true; // can do it.
}
else
return false; // cannot do it.
}
is called when the user tries to change a parameter while the simulation is running. In this example we only allow changes to the total number of sweeps.
Note:The implementation of this function is optional.
bool IsingSimulation::is_thermalized() const
{
return (sweeps >= thermalization_sweeps);
}
determines thermalization. Here the simulation is thermalized when a certain number of sweeps, given by the user has been performed.
double IsingSimulation::work_done() const
{
return (is_thermalized() ? (sweeps-thermalization_sweeps)/double(total_sweeps) :0.);
}
returns the fraction of total work performed.
void IsingSimulation::dostep()
{
// increment sweep count
sweeps++;
// perform updates
for (int j=0;j<length;j++) {
// choose a random site and determine the neighbors
int i = int(double(length)*random_real());
int right=(i+1 < length ? i+1 : 0);
int left=( i-1 < 0 ? length-1 : i-1);
// calculate change in the weight of the configuration
double p=exp(2.*beta*spins[i]*(spins[right]+spins[left]));
// Metropolis updating: accept if random number is smaller than p
if (p>=1. || random_real() < p)
spins[i]=-spins[i];
}
// perform measurements
int tmag=0;
int ten=0;
for (int i=0;i<length;i++) {
int right=(i +1 < length ? i+1 : 0);
tmag += spins[i];
ten += -spins[i]*spins[right];
}
// normalize measurements and add them to the observables
measurements.get<alea::RealObservable>("Energy") << double(ten)/length;
measurements.get<alea::RealObservable>("Magnetization") << double(tmag)/length;
}
performs the actual simulations and measurements.
can be overridden to perform extra tasks when the simulation is started and halted (e.g. opening and closing of files or (de)allocation of extra resources.void MCRun::start() const; void MCRun::halt() const;