GenerateQuenched

Generate pure gauge configurations with the Wilson gauge action by applying heat bath and over relaxation updates.



/*
 * main_generateQuenched.cpp
 *
 * Luis Altenkort, 2 Apr 2019
 *
 */

#include "../simulateqcd.h"
#include "../modules/gauge_updates/pureGaugeUpdates.h"
#include "../modules/observables/polyakovLoop.h"

#include <chrono>

#define PREC double
#define ONDEVICE true

struct generateQuenchedParameters : LatticeParameters {
    Parameter<std::string> output_dir;
    Parameter<int> nconfs;
    Parameter<int> nsweeps_ORperHB;
    Parameter<int> nsweeps_HBwithOR;
    Parameter<std::string> start;
    Parameter<int> nsweeps_thermal_HB_only;
    Parameter<int> nsweeps_thermal_HBwithOR;
    Parameter<int64_t> seed;
    Parameter<std::string> prev_conf;
    Parameter<std::string> prev_rand;

    // constructor
    generateQuenchedParameters() {
        addDefault(output_dir, "output_dir", std::string("."));
        addDefault(nconfs, "nconfs", 1000);
        addDefault(nsweeps_ORperHB, "nsweeps_ORperHB", 4);
        addDefault(nsweeps_HBwithOR, "nsweeps_HBwithOR", 500);
        addOptional(start, "start"); //valid options: one, fixed_random, all_random
        addOptional(nsweeps_thermal_HB_only, "nsweeps_thermal_HB_only"); //thermalization e.g. 500
        addOptional(nsweeps_thermal_HBwithOR, "nsweeps_thermal_HBwithOR"); //thermalization e.g. 4000
        addOptional(seed, "seed"); //default: time since unix epoch in milliseconds (see below)
        addOptional(prev_conf, "prev_conf");
        addOptional(prev_rand, "prev_rand");
    }
};

void set_seed( CommunicationBase &commBase, Parameter<int64_t> &seed ){
    if ( not seed.isSet() ) {
        int64_t root_seed = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()).count();
        commBase.root2all(root_seed);
        seed.set(root_seed);
        rootLogger.info("No seed was specified. Using time since epoch in milliseconds.");
    }
    rootLogger.info("Seed for random numbers is " ,  seed());
    return;
}


int main(int argc, char* argv[]) {

    const size_t HaloDepth = 1;
    typedef GIndexer<All,HaloDepth> GInd;
    stdLogger.setVerbosity(INFO);
    generateQuenchedParameters              lp;
    CommunicationBase                       commBase(&argc, &argv);
    lp.readfile(commBase, "../parameter/applications/generateQuenched.param", argc, argv);
    commBase.init(lp.nodeDim());
    StopWatch<true> timer;
    initIndexer(HaloDepth,lp,commBase);
    Gaugefield<PREC,ONDEVICE,HaloDepth>     gauge(commBase);
    GaugeAction<PREC,ONDEVICE,HaloDepth>    gaugeAction(gauge);
    GaugeUpdate<PREC,ONDEVICE,HaloDepth>    gaugeUpdate(gauge);
    PolyakovLoop<PREC,true,HaloDepth>       pLoop(gauge);


    grnd_state<false> host_state;
    grnd_state<true> dev_state;

    ///Start new stream or continue existing one?
    if ( lp.prev_conf.isSet()
        and not lp.nsweeps_thermal_HB_only.isSet()
        and not lp.nsweeps_thermal_HBwithOR.isSet()
        and lp.confnumber.isSet()) {
        rootLogger.info("Resuming previous run.");

        gauge.readconf_nersc(lp.prev_conf());
        gauge.updateAll();

        ///Initialize RNG for resuming
        if ( lp.prev_rand.isSet() ) {
            host_state.read_from_file(lp.prev_rand(), commBase);
        } else {
            rootLogger.warn("No prev_rand was specified!");
            set_seed(commBase, lp.seed);
            host_state.make_rng_state(lp.seed());
        }
        dev_state = host_state;

        lp.confnumber.set(lp.confnumber() + lp.nsweeps_HBwithOR());
        rootLogger.info("Next conf_number will be " ,  lp.confnumber());

    } else if ( not lp.prev_conf.isSet()
                and not lp.prev_rand.isSet()
                and lp.start.isSet()
                and lp.nsweeps_thermal_HB_only.isSet()
                and lp.nsweeps_thermal_HBwithOR.isSet()
                and not lp.confnumber.isSet()) {
        rootLogger.info("Starting new stream.");

        /// Initialize RNG for new stream
        set_seed(commBase, lp.seed);
        host_state.make_rng_state(lp.seed());
        dev_state = host_state;

        ///Initialize gaugefield
        if ( lp.start() == "fixed_random" ) {
            rootLogger.info("Starting with all U = some single arbitrary SU3");
            gSite first_site; //by default = 0 0 0 0
            SU3<PREC> some_SU3;
            some_SU3.random(host_state.getElement(first_site));
            gauge.iterateWithConst(some_SU3);
        } else if ( lp.start() == "all_random"  ) {
            rootLogger.info("Starting with some random configuration");
            gauge.random(host_state.state);
        } else if ( lp.start() == "one" ) {
            rootLogger.info("Starting with all U = 1");
            gauge.one();
        } else {
            throw std::runtime_error(stdLogger.fatal("Error! Choose from 'start = {one, fixed_random, all_random}!"));
        }

        rootLogger.info("On stream " ,  lp.streamName());

        lp.confnumber.set(lp.nsweeps_HBwithOR());
        rootLogger.info("Start thermalization. Doing " ,  lp.nsweeps_thermal_HB_only() ,  " pure HB sweeps.");
        for (int i = 0; i < lp.nsweeps_thermal_HB_only(); ++i) {
            gaugeUpdate.updateHB(dev_state.state,lp.beta());
        }
        rootLogger.info("Now do " ,  lp.nsweeps_thermal_HBwithOR() ,  " HB sweeps with " ,  lp.nsweeps_ORperHB() ,
                            " OR sweeps per HB.");
        for (int i = 0; i < lp.nsweeps_thermal_HBwithOR(); ++i) {
            gaugeUpdate.updateHB(dev_state.state,lp.beta());
            for (int j = 0; j < lp.nsweeps_ORperHB(); j++) {
                gaugeUpdate.updateOR();
            }
        }
        rootLogger.info("Thermalization finished");
    } else {
        throw std::runtime_error(stdLogger.fatal("Error! Parameters unclear. To start a new stream, specify nsweeps_thermal_HB_only,"
                       "nsweeps_thermal_HBwithOR and start (one, fixed_random or all_random). To continue "
                       "existing stream, specify"
                       "(previous) conf_nr, prev_conf and (optionally) prev_rand. Do not specify unused"
                       "parameters."));
    }

    rootLogger.info("Generating up to " ,  lp.nconfs() ,  " confs with a separation of " ,
                        lp.nsweeps_HBwithOR() ,  " HBOR sweeps (OR/HB = " ,  lp.nsweeps_ORperHB() ,  ") ...");
    for (int i = 0; i < lp.nconfs(); i++ ){
        rootLogger.info("======================================================================");
        rootLogger.info("Start sweeping...");
        ///do separation sweeps
        timer.start();
        for (int i = 0; i < lp.nsweeps_HBwithOR(); ++i) {
            gaugeUpdate.updateHB(dev_state.state, lp.beta());
            for (int j = 0; j < lp.nsweeps_ORperHB(); j++) {
                gaugeUpdate.updateOR();
            }
        }
        timer.stop();
        rootLogger.info("It took " ,  timer.seconds() ,  " seconds to do " ,  lp.nsweeps_HBwithOR() ,  " HBOR "
                             "sweeps.");
        timer.reset();

        rootLogger.info("Plaquette = " ,  gaugeAction.plaquette());
        rootLogger.info("Polyakov loop = " ,  pLoop.getPolyakovLoop());

        std::string conf_path = lp.output_dir()+"/conf"+lp.fileExt();
        std::string rand_path = lp.output_dir()+"/rand"+lp.fileExt();

        rootLogger.info("Writing conf to disk...");
        timer.start();
        gauge.writeconf_nersc(conf_path, 2, 2);
        host_state = dev_state;
        host_state.write_to_file(rand_path, commBase);
        timer.stop();

        rootLogger.info("Writing to disk took " ,  timer.seconds() ,  " seconds");
        timer.reset();
        lp.confnumber.set(lp.confnumber() + lp.nsweeps_HBwithOR());
    }

    return 0;
}