#include #include CPS_START_NAMESPACE //------------------------------------------------------------------ // // alg_action_rational.C // // AlgActionRational is a bilinear action where the matrix is represented // by a rational approximation. // //------------------------------------------------------------------ CPS_END_NAMESPACE #include #include #include #include #include #include #include #include #include #include CPS_START_NAMESPACE //!< Dummy contructor - does nothing AlgActionRational::AlgActionRational() : AlgActionBilinear() { cname = "AlgActionRational"; } //!< Constructor called by AlgActionRationalQuotient AlgActionRational::AlgActionRational(AlgMomentum &mom, ActionBilinearArg &bi_arg) : AlgActionBilinear(mom,bi_arg) { cname = "AlgActionRational"; } //!< Need to add restart method or similar so do not need to //reconstruct actions - add calls to restart methods to hmc class AlgActionRational::AlgActionRational(AlgMomentum &mom, ActionRationalArg &r_arg, int traj_num) : AlgActionBilinear(mom, r_arg.bi_arg) { cname = "AlgActionRational"; char *fname = "AlgActionRational()"; VRB.Func(cname,fname); int_type = INT_RATIONAL; rat_arg = &r_arg; //!< First check n_masses bilinear = n_masses rational if (rat_arg->rationals.rationals_len != rat_arg->bi_arg.bilinears.bilinears_len) ERR.General(cname, fname, "Inconsistency between RationalArg and BilinearArg n_masses"); // Rational force term not implemented dim < 4 if( fermion == F_CLASS_ASQTAD && (GJP.XnodeSites()==2 || GJP.YnodeSites()==2 || GJP.ZnodeSites()==2 || GJP.TnodeSites()==2 ) ) ERR.General(cname,fname, "Force not implemented for Fasqtad with any dimension < 4\n"); //!< Allocate memory for the fermion CG arguments. if(n_masses > 0){ //!< construct approximation if necessary generateApprox(mass, &remez_arg_md, &remez_arg_mc, rat_arg->rationals.rationals_val); //!< Allocate memory for the fermion CG arguments. generateCgArg(mass, &frm_cg_arg_fg, &frm_cg_arg_md, &frm_cg_arg_mc, "frm_cg_arg", rat_arg->rationals.rationals_val); max_size = 0; total_size = 0; for (int i=0; ieigen.eigen_measure == EIGEN_MEASURE_YES) generateEigArg(rat_arg->eigen); } void AlgActionRational::init(int traj_num) { char *fname = "init(int)" ; VRB.Func(cname,fname); AlgActionBilinear::init(); evolved = 1; heatbathEval = 0; energyEval = 0; // traj = traj_num-1; VRB.FuncEnd(cname,fname); } AlgActionRational::~AlgActionRational() { char *fname = "~AlgActionRational()" ; VRB.Func(cname,fname); //!< Free memory for timescale split partial fraction if (n_masses > 0 && int_type == INT_RATIONAL) { //!< Free splitCheck parameters for (int i=0; ieigen.eigen_measure == EIGEN_MEASURE_YES) destroyEigArg(); } } //!< Heat Bath for the pseudo-fermions (phi) void AlgActionRational::heatbath() { char *fname = "heatbath()"; //!< Only evaluate heatbath if necessary if (!heatbathEval) { if(!UniqueID()) printf("AlgActionRational::heatbath\n"); //!< Create an appropriate lattice Lattice &lat = LatticeFactory::Create(fermion, G_CLASS_NONE); h_init = 0.0; for(int i=0; i=GJP.Xnodes()*GJP.XnodeSites()/2 && gy>=GJP.Ynodes()*GJP.YnodeSites()/2){ int pos[5] = {x,y,z,t,s}; int f_off = lat.FsiteOffsetChkb(pos) * lat.SpinComponents(); for(int spn=0;spn VecEqualsVecTimesEquFloat(frmn[0], remez_arg_mc[i].norm_inv, f_size); cg_iter = lat.FmatEvlMInv(phi+i, frmn[0], remez_arg_mc[i].pole_inv, remez_arg_mc[i].degree, 0, frm_cg_arg_mc[i], CNV_FRM_NO, SINGLE, remez_arg_mc[i].residue_inv); {//for testing Float norm = dotProduct((IFloat *)phi[i],(IFloat *)phi[i],f_size); if(GJP.Gparity1fY()) norm/=2; glb_sum_five(&norm); if(!UniqueID()) printf("phi %d norm %f\n",i,norm); } updateCgStats(frm_cg_arg_mc[i][0]); } LatticeFactory::Destroy(); evolved = 0; heatbathEval = 1; energyEval = 0; } // traj++; } // Calculate rhmc fermion contribution to the Hamiltonian Float AlgActionRational::energy() { char *fname="energy()"; if (energyEval) { return 0.0; } else if (!evolved) { energyEval = 1; return h_init; } else { int shift = 0; Float h = 0.0; //!< Before energy is measured, do we want to check bounds? if (rat_arg->eigen.eigen_measure == EIGEN_MEASURE_YES) checkApprox(mass, remez_arg_mc, rat_arg->eigen); //!< Create an appropriate lattice Lattice &lat = LatticeFactory::Create(fermion, G_CLASS_NONE); for (int i=0; i VecEqualsVecTimesEquFloat(phi[i],remez_arg_mc[i].norm,f_size); cg_iter = lat.FmatEvlMInv(frmn, phi[i], remez_arg_mc[i].pole, remez_arg_mc[i].degree, 0, frm_cg_arg_mc[i], CNV_FRM_NO, SINGLE, remez_arg_mc[i].residue); updateCgStats(frm_cg_arg_mc[i][0]); // shift this evaluation into minvcg? h += lat.FhamiltonNode(frmn[0], frmn[0]); } { Float hlat = h; glb_sum_five(&hlat); if(!UniqueID()) printf("AlgActionRational energy %f\n",hlat); } LatticeFactory::Destroy(); energyEval = 1; return h; } } void AlgActionRational::evolve(Float dt, int nsteps) { evolve(dt, nsteps, fractionSplit); } void AlgActionRational::prepare_fg(Matrix * force, Float dt_ratio) { char * fname = "prepare_fg(M*,F)"; Lattice &lat = LatticeFactory::Create(fermion, G_CLASS_NONE); //!< Variables required for ASQTAD partial fraction splitting int total_split_degree = 0; for (int i=0; i 0) { cg_iter = lat.FmatEvlMInv(frmn+shift+isz, phi[i], remez_arg_md[i].pole+isz, deg, isz, frm_cg_arg_fg[i]+isz, CNV_FRM_NO, frmn_d+shift+isz); updateCgStats(frm_cg_arg_fg[i][isz]); if (force_measure == FORCE_MEASURE_YES || (fermion != F_CLASS_ASQTAD && fermion != F_CLASS_P4) ) { Fdt = lat.RHMC_EvolveMomFforce(force, frmn+shift+isz, deg, isz, remez_arg_md[i].residue+isz, mass[i], dt_ratio, frmn_d+shift+isz, force_measure); if (force_measure == FORCE_MEASURE_YES) { char label[200]; sprintf(label, "%s total, mass = %e:", force_label, mass[i]); Fdt.print(dt_ratio, label); } } else { //!< Do appropriate pointer arithmetic for asqtad/p4 for (int j=0; j 0 && force_measure == FORCE_MEASURE_NO ) { Fdt = lat.RHMC_EvolveMomFforce(force, frmn_tmp, total_split_degree, 0, all_res, 0.0, dt_ratio, frmn_d, force_measure); if (force_measure == FORCE_MEASURE_YES) { char label[200]; sprintf(label, "%s total:", force_label); Fdt.print(dt_ratio, label); } } LatticeFactory::Destroy(); } //!< run method evolves the integrator void AlgActionRational::evolve(Float dt, int nsteps, int **fractionSplit) { char *fname = "evolve(Float, int, int **)"; if (n_masses <= 0) return; Float trueMass; if(!UniqueID()) printf("Entered AlgActionRational::evolve\n"); //!< Variables required for ASQTAD partial fraction splitting int total_split_degree = 0; for (int i=0; i 0) { { unsigned int gcsum = lat.CheckSum(); if(GJP.Gparity() && GJP.Gparity1f2fComparisonCode()){ gcsum += lat.CheckSum(lat.GaugeField() + 4*GJP.VolNodeSites()); } QioControl qc; gcsum = qc.globalSumUint(gcsum); if(UniqueID()==0) printf("AlgActionRational::evolve step %d lattice checksum %u\n",steps,gcsum); } cg_iter = lat.FmatEvlMInv(frmn+shift+isz, phi[i], remez_arg_md[i].pole+isz, deg, isz, frm_cg_arg_md[i]+isz, CNV_FRM_NO, frmn_d+shift+isz); {//for testing Float norm1 = dotProduct((IFloat *)phi[i],(IFloat *)phi[i],f_size); glb_sum_five(&norm1); Float norm2 = dotProduct((IFloat *)frmn[shift+isz],(IFloat *)frmn[shift+isz],f_size); glb_sum_five(&norm2); if(!UniqueID()) printf("AlgActionRational::evolve step %d, phi[%d] norm %f, out norm %f\n",steps,i,norm1,norm2); } updateCgStats(frm_cg_arg_md[i][isz]); if (force_measure == FORCE_MEASURE_YES || (fermion != F_CLASS_ASQTAD && fermion != F_CLASS_P4) ) { Fdt = lat.RHMC_EvolveMomFforce(mom, frmn+shift+isz, deg, isz, remez_arg_md[i].residue+isz, mass[i], dt, frmn_d+shift+isz, force_measure); if (force_measure == FORCE_MEASURE_YES) { char label[200]; sprintf(label, "%s total, mass = %e:", force_label, mass[i]); Fdt.print(dt, label); } } else { //!< Do appropriate pointer arithmetic for asqtad/p4 for (int j=0; j 0 && force_measure == FORCE_MEASURE_NO ) { Fdt = lat.RHMC_EvolveMomFforce(mom, frmn_tmp, total_split_degree, 0, all_res, 0.0, dt, frmn_d, force_measure); if (force_measure == FORCE_MEASURE_YES) { char label[200]; sprintf(label, "%s total:", force_label); Fdt.print(dt, label); } } evolved = 1; heatbathEval = 0; energyEval = 0; md_steps++; } LatticeFactory::Destroy(); } //!< Generate the optimal rational approximation for rational representation // Need to add boson/fermion optimisation - requires extra space for FIRat. void AlgActionRational::generateApprox(Float *mass, RemezArg **remez_arg_md, RemezArg **remez_arg_mc, RationalDescr *rat) { char *fname = "generateApprox(F*,RA*,RA*,RD*)"; *remez_arg_md = new RemezArg[n_masses]; *remez_arg_mc = new RemezArg[n_masses]; for(int i=0; imass = mass[i]; //CK: added for twisted mass fermions if(epsilon) (*cg_arg_fg)[i][j]->epsilon = epsilon[i]; (*cg_arg_fg)[i][j]->max_num_iter = max_num_iter[i]; (*cg_arg_fg)[i][j]->stop_rsd = rat[i].stop_rsd_fg_mult * rat[i].md_approx.stop_rsd.stop_rsd_val[j]; // (*cg_arg_md)[i][j] = (CgArg*)smalloc(sizeof(CgArg),md_label_ij,fname,cname); (*cg_arg_md)[i][j] = new CgArg; (*cg_arg_md)[i][j]->mass = mass[i]; //CK: added for twisted mass fermions if(epsilon) (*cg_arg_md)[i][j]->epsilon = epsilon[i]; (*cg_arg_md)[i][j]->max_num_iter = max_num_iter[i]; (*cg_arg_md)[i][j]->stop_rsd = rat[i].md_approx.stop_rsd.stop_rsd_val[j]; } for (int j=0; jmass = mass[i]; //CK: added for twisted mass fermions if(epsilon) (*cg_arg_mc)[i][j]->epsilon = epsilon[i]; (*cg_arg_mc)[i][j]->max_num_iter = max_num_iter[i]; (*cg_arg_mc)[i][j]->stop_rsd = rat[i].mc_approx.stop_rsd.stop_rsd_val[j]; } } } void AlgActionRational::destroyCgArg(CgArg ***cg_arg_fg, CgArg ***cg_arg_md, CgArg ***cg_arg_mc, const char *label, RemezArg *remez_arg_md, RemezArg *remez_arg_mc) { char *fname = "destroyCgArg(Cg***, Cg***,Cg***,char*,RemezArg*,RemezArg*)"; char fg_label[100], fg_label_i[100], fg_label_ij[100]; char md_label[100], md_label_i[100], md_label_ij[100]; char mc_label[100], mc_label_i[100], mc_label_ij[100]; sprintf(fg_label, "%s_fg", label); sprintf(fg_label_i, "%s_fg[i]", label); sprintf(fg_label_ij, "%s_fg[i][j]", label); sprintf(md_label, "%s_md", label); sprintf(md_label_i, "%s_md[i]", label); sprintf(md_label_ij, "%s_md[i][j]", label); sprintf(mc_label, "%s_mc", label); sprintf(mc_label_i, "%s_mc[i]", label); sprintf(mc_label_ij, "%s_mc[i][j]", label); for (int i=0; in_masses) ERR.General(cname, fname, "Invalid mass\n"); if (j<0 || j>=remez_arg_md[i].degree) ERR.General(cname, fname, "Invalid split parameters: mass %d\n",i); if (!splitCheck[i][j]) splitCheck[i][j] = 1; else ERR.General(cname, fname, "Mass %d, pole %d has already been included\n", i, j); } //!< Check that all of the partial fractions have been accounted for void AlgActionRational::checkSplit() { const char *fname = "checkSplit()"; for (int i=0; i %e\n", i, mass[i], lambda_low[0][i], remez_arg[i].lambda_low); } } } { //!< Measure the highest eigenvalue sprintf(eig_file,"%s.%d",eigen.eig_hi_stem,traj_num); eig_arg.fname = eig_file; eig_arg.RitzMatOper = NEG_MATPCDAG_MATPC; AlgEig eig(lat,&ca_eig,&eig_arg); eig.run(lambda_high); for (int i=0; i remez_arg[i].lambda_high) { ERR.General(cname, fname, "Upper bound exceeded: mass[%d] = %f, %e > %e\n", i, mass[i], lambda_high[0][i], remez_arg[i].lambda_high); } else { VRB.Result(cname,fname,"Upper bound valid: mass[%d] = %f, %e < %e\n", i, mass[i], lambda_high[0][i], remez_arg[i].lambda_high); } } } LatticeFactory::Destroy(); } CPS_END_NAMESPACE