Пример #1
0
int nl_spectrum( Real vmass, field_offset temp1, field_offset temp2 ) { 
  /* return the C.G. iteration number */
  double *piprop,*pi2prop,*rhoprop,*rho2prop,*barprop;
  double *nlpiprop,*nlpi2prop,*ckpiprop,*ckpi2prop;
  double *delprop,*ckbarprop;
  Real vmass_x2;
  site* s;
  register complex cc;
  Real finalrsq;
  register int i,x,y,z,t,icol,cgn;
  register int t_source,t_off;
  int dir,isrc;

  msg_tag *mtag[16];

  piprop = (double *)malloc( nt*sizeof(double) );
  pi2prop = (double *)malloc( nt*sizeof(double) );
  rhoprop = (double *)malloc( nt*sizeof(double) );
  rho2prop = (double *)malloc( nt*sizeof(double) );
  barprop = (double *)malloc( nt*sizeof(double) );
  nlpiprop = (double *)malloc( nt*sizeof(double) );
  nlpi2prop = (double *)malloc( nt*sizeof(double) );
  ckpiprop = (double *)malloc( nt*sizeof(double) );
  ckpi2prop = (double *)malloc( nt*sizeof(double) );
  delprop = (double *)malloc( nt*sizeof(double) );
  ckbarprop = (double *)malloc( nt*sizeof(double) );

  for( t=0; t<nt; t++ ){
    piprop[t]=0.0; pi2prop[t]=0.0; rhoprop[t]=0.0; rho2prop[t]=0.0;
    nlpiprop[t]=0.0; nlpi2prop[t]=0.0;
    ckpiprop[t]=0.0; ckpi2prop[t]=0.0;
    barprop[t]=0.0; delprop[t]=0.0; ckbarprop[t]=0.0;
  }

  vmass_x2 = 2.*vmass;
  cgn=0;

  /* Fix TUP Coulomb gauge - gauge links only*/
  rephase( OFF );
  gaugefix(TUP,(Real)1.8,500,(Real)GAUGE_FIX_TOL);
  rephase( ON );
#ifdef FN
  invalidate_all_ferm_links(&fn_links);
#endif

  /* Unlike spectrum.c, here we calculate only with wall sources */
  for(t_source=source_start, isrc=0; t_source<2*nt && isrc < n_sources;
        ++isrc, t_source += source_inc ) {
      
      /* Only work for even source slices */
      if( t_source%2 != 0 ){
	printf("DUMMY:  Use even time slices for nl_spectrum()\n");
	terminate(0);
      }

      /* Compute propagator from even wall sites */
      /* Sources are normalized to 1/8 to make them comparable to */
      /* propagators from a wall with ones on the cube origin. */
      /* Put result in propmat */
      
      for(icol=0; icol<3; icol++) {
	  
	  /* initialize temp1 and temp2 */
	  clear_latvec( temp1, EVEN);
	  clear_latvec( temp2, EVEN);
	  
	  for(x=0;x<nx;x++)for(y=0;y<ny;y++)for(z=0;z<nz;z++) {
	      if((x+y+z) % 2 == 0) {
		  if( node_number(x,y,z,t_source) != mynode() )continue;
		  i=node_index(x,y,z,t_source);
		  ((su3_vector *)(F_PT(&lattice[i],temp1)))->c[icol].real = 
		    -0.25;
		}
	    }
	  
	  /* do a C.G. */
	  load_ferm_links(&fn_links);
	  cgn += congrad(niter,rsqprop,EVEN,&finalrsq, &fn_links);
	  /* Multiply by -Madjoint */
	  dslash_site( temp2, temp2, ODD, &fn_links);
	  scalar_mult_latvec( temp2, -vmass_x2, temp2, EVEN);
	  
	  /* fill the hadron matrix */
	  copy_latvec( temp2, F_OFFSET(propmat[icol]), EVENANDODD);
	} /* end loop on icol */
      
      
      /* Compute propagator from odd wall sites */
      /* Put result in propmat2 */
      
      for(icol=0; icol<3; icol++) {
	  
	  /* initialize temp1 and temp2 */
	  clear_latvec( temp1, ODD);
	  clear_latvec( temp2, ODD);
	  for(x=0;x<nx;x++)for(y=0;y<ny;y++)for(z=0;z<nz;z++) {
	      if((x+y+z) % 2 == 1) {
		  if( node_number(x,y,z,t_source) != mynode() )continue;
		  i=node_index(x,y,z,t_source);
		  ((su3_vector *)(F_PT(&lattice[i],temp1)))->c[icol].real = 
		    -0.25;
		}
	    }
	  
	  /* do a C.G. */
	  load_ferm_links(&fn_links);
	  cgn += congrad(niter,rsqprop,ODD,&finalrsq,&fn_links);
	  /* Multiply by -Madjoint */
	  dslash_site( temp2, temp2, EVEN, &fn_links);
	  scalar_mult_latvec( temp2, -vmass_x2, temp2, ODD);
	  
	  /* fill the hadron matrix */
	  copy_latvec( temp2, F_OFFSET(propmat2[icol]), EVENANDODD);
	} /* end loop on icol */
      
      /* cgn now gives the sum for both inversions */
      
      
      /* measure the meson propagator for the E wall source */
      for(t=0; t<nt; t++) {
	  /* define the time value offset t from t_source */
	  t_off = (t+t_source)%nt;
	  
	  for(x=0;x<nx;x++)for(y=0;y<ny;y++)for(z=0;z<nz;z++)
	    for(icol=0;icol<3;icol++) {
		if( node_number(x,y,z,t_off) != mynode() )continue;
		i=node_index(x,y,z,t_off);
		cc = su3_dot( &lattice[i].propmat[icol],
			     &lattice[i].propmat[icol] );
		
		piprop[t] += cc.real;
		/* (rhoprop and rho2prop are not generated by this source) */
		
		if( (x+y+z)%2==0)pi2prop[t] += cc.real;
		else	     pi2prop[t] -= cc.real;
		
	      }
	  
	} /* nt-loop */
      
      /* measure the baryon propagator for the E wall source */
      for(t=0; t<nt; t++) {
	  /* define the time value offset t from t_source */
	  t_off = (t+t_source)%nt;
	  
	  for(x=0;x<nx;x+=2)for(y=0;y<ny;y+=2)for(z=0;z<nz;z+=2) {
	      if( node_number(x,y,z,t_off) != mynode() )continue;
	      i=node_index(x,y,z,t_off);
	      cc = det_su3( (su3_matrix *)(lattice[i].propmat) );
	      barprop[t] += cc.real;
	  }
	  
	  /* must get sign right.  This looks to see if we have
	     wrapped around the lattice.  "t" is the distance
	     from the source to the measurement, so we are
	     trying to find out if t_source+t is greater than
	     or equal to nt. */
	  if( (((t+t_source)/nt-t_source/nt)%2) == 1 )barprop[t] *= -1.0;
	  /* change sign because antiperiodic b.c.  sink point
	     should really be in a copy of the lattice */
	} /* nt-loop */
      
      
      /* Measure nonlocal (and some local for checking) propagators    */
      /* These propagators include the delta and some nonlocal mesons  */
      /* The method for the delta is described in M.F.L. Golterman and */
      /* J. Smit, Nucl. Phys. B 255, 328 (1985)                        */
      /* Equation (6.3) defines the sink operator for the delta        */
      /* The method for the mesons is described in M.F.L. Golterman    */
      /* Nucl. Phys. B 273, 663 (1986)                                 */
      /* The treatment of the source wall is described in Gupta,       */
      /* Guralnik, Kilcup, and Sharpe, (GGKS) NSF-ITP-90-172 (1990)    */
      /* To get the delta propagator, we take the "q" propagator       */
      /* matrices for each of the wall colors and antisymmetrize over  */
      /* wall color as well as s                    */
      
      /* First construct the "q" and "o" propagators                   */
      /* Put q = E + O in propmat and o = E - O in propmat2 */
      
      FORALLSITES(i,s) {
	  for(icol=0; icol<3; icol++) {
	      add_su3_vector (&(s->propmat[icol]), &(s->propmat2[icol]), 
			      (su3_vector *)(s->tempmat1.e[icol]) );
	      sub_su3_vector (&(s->propmat[icol]), &(s->propmat2[icol]), 
			      &(s->propmat2[icol]) );
	      su3vec_copy( (su3_vector *)(s->tempmat1.e[icol]),
		&(s->propmat[icol]) );
	    }
	}
      
      
      
      /* Next gather the propagators in preparation for calculating   */
      /* shifted propagators Dq and Do                                */
      
      FORALLUPDIRBUT(TUP,dir) {
	  /* Start bringing "q" = propmat from forward sites    */
	  
	  mtag[dir] = start_gather_site(F_OFFSET(propmat[0]), 
		   sizeof(su3_matrix), dir, EVENANDODD, gen_pt[dir]);
	  
	  /* Start bringing "q" from backward neighbors       */
	  
	  mtag[dir+4] = start_gather_site(F_OFFSET(propmat[0]), 
		   sizeof(su3_matrix), OPP_DIR(dir), EVENANDODD,
		   gen_pt[dir+4]);
	  wait_gather(mtag[dir]);
	  wait_gather(mtag[dir+4]);
	  
	  /* Start bringing "o" = propmat2 from forward sites   */
	  
	  mtag[8+dir] = start_gather_site(F_OFFSET(propmat2[0]), 
		   sizeof(su3_matrix), dir, EVENANDODD, gen_pt[8+dir]);
	  
	      /* Start bringing "o" from backward neighbors       */
	  
	  mtag[8+dir+4] = start_gather_site(F_OFFSET(propmat2[0]), 
		    sizeof(su3_matrix), OPP_DIR(dir), EVENANDODD,
		    gen_pt[8+dir+4]);
	  wait_gather(mtag[8+dir]);
	  wait_gather(mtag[8+dir+4]);
	  
	}
      
      
      /* Calculate and dump delta propagator */
      for(t=0; t<nt; t++) {
	  /* define the time value offset t from t_source */
	  t_off = (t+t_source)%nt;
	  
	  /* Calculate contribution for each permutation of source color */
	  delta_prop (0,1,2, 1, t_off, &delprop[t]);
	  delta_prop (1,2,0, 1, t_off, &delprop[t]);
	  delta_prop (2,0,1, 1, t_off, &delprop[t]);
	  delta_prop (1,0,2,-1, t_off, &delprop[t]);
	  delta_prop (0,2,1,-1, t_off, &delprop[t]);
	  delta_prop (2,1,0,-1, t_off, &delprop[t]);
	  
	  if( (((t+t_source)/nt-t_source/nt)%2) == 1 ) delprop[t] *= -1;
	} /* nt-loop */
      
      /* Calculate the "q" source nucleon as a check */
      
      /* Calculate and dump nucleon check propagator */
      for(t=0; t<nt; t++) {
	  /* define the time value offset t from t_source */
	  t_off = (t+t_source)%nt;
	  
	  for(x=0;x<nx;x+=2)for(y=0;y<ny;y+=2)for(z=0;z<nz;z+=2) {
	      if( node_number(x,y,z,t_off) != mynode() )continue;
	      i=node_index(x,y,z,t_off);
	      /* The q propagator is in propmat */
	      cc = det_su3( (su3_matrix *)(lattice[i].propmat) );
	      ckbarprop[t] += cc.real;
	    }
	  
	  if( (((t+t_source)/nt-t_source/nt)%2) == 1 )ckbarprop[t]*= -1.0;
	  /* change sign because antiperiodic b.c.  sink point
	     should really be in a copy of the lattice */
	} /* nt-loop */
      
      /* Calculate nonlocal meson propagators and local check */
      for(t=0; t<nt; t++) {
	  /* Calculate two nonlocal pion propagators */
	  /* These are pi_1 and pi_1 tilde of Gupta et al */
	  /* Also calculate two local propagators as a check */
	  
	  /* define the time value offset t from t_source */
	  t_off = (t+t_source)%nt;
	  
	  nl_meson_prop(t_off,&nlpiprop[t],&nlpi2prop[t],&ckpiprop[t],
	     &ckpi2prop[t]);
	  
	} /* nt-loop */
      
      /* Clean up gathers */
      FORALLUPDIRBUT(TUP,dir) {
	  cleanup_gather(mtag[dir]);
	  cleanup_gather(mtag[dir+4]);
	  cleanup_gather(mtag[8+dir]);
	  cleanup_gather(mtag[8+dir+4]);
	}
Пример #2
0
OBSOLETE!  See update_rhmc.c
/********** update_rhmc_omelyan.c ******************************************/
/* MIMD version 7 */

/*
 See Takaishi and de Forcrand hep-lat/-0505020
 Update lattice.
    compute PHI for both factors in fermion determinant at beginning
	update U by (epsilon/2)*lambda
	compute X for light and strange quarks for each term in rational 
		function (or "both factors in det")
	update H, by epsilon
	update U by epsilon * (2-lambda)
	compute X for light and strange quarks for each term in rational 
		function
	update H, by epsilon
	update U by (epsilon/2)*lambda

 This routine does not refresh the antihermitian momenta.
 This routine begins at "integral" time, with H and U evaluated
 at same time.
  "lambda" is adjustable parameter.  At lambda=1 this is just two
  leapfrog steps of length epsilon. Note my lambda is 4X the lambda in
  Takaishi and de Forcrand and my epsilon is 1/2 theirs.  This makes
  epsilon the same as for the leapfrog algorithm.
  Omelyan "optimum lambda" is 4*0.1932
*/
#include "ks_imp_includes.h"	/* definitions files and prototypes */

#define mat_invert mat_invert_uml
/**#define mat_invert mat_invert_cg**/

int update()  {
  int step, iters=0;
  double startaction,endaction;
  Real xrandom;
  int i;
  su3_vector **multi_x;
  su3_vector *sumvec;
  Real lambda;
  int iphi;
  
  lambda = 0.8;
  node0_printf("Omelyan integration, steps= %d eps= %e lambda= %e\n",steps,epsilon,lambda);
  if (steps %2 != 0 ){
    node0_printf("BONEHEAD! need even number of steps\n");
    exit(0);
  }
  
  /* allocate space for multimass solution vectors */
  multi_x = (su3_vector **)malloc(max_rat_order*sizeof(su3_vector *));
  if(multi_x == NULL){
    printf("update: No room for multi_x\n");
    terminate(1);
  }
  for(i=0;i<max_rat_order;i++) 
    multi_x[i]=(su3_vector *)malloc( sizeof(su3_vector)*sites_on_node );
  sumvec = (su3_vector *)malloc( sizeof(su3_vector)*sites_on_node );
  
  /* refresh the momenta */
  ranmom();
  
  /* generate a pseudofermion configuration only at start*/
  for(iphi = 0; iphi < n_pseudo; iphi++){
    grsource_imp_rhmc( F_OFFSET(phi[iphi]), &(rparam[iphi].GR), EVEN,
		       multi_x,sumvec, rsqmin_gr[iphi], niter_gr[iphi]);
  }
  
  /* find action */
  startaction=d_action_rhmc(multi_x,sumvec);
  /* copy link field to old_link */
  gauge_field_copy( F_OFFSET(link[0]), F_OFFSET(old_link[0]));
  
  /* do "steps" microcanonical steps (one "step" = one force evaluation)"  */
  for(step=2; step <= steps; step+=2){
    
    /* update U's and H's - see header comment */
    update_u(0.5*epsilon*lambda);
    update_h_rhmc( epsilon, multi_x);
    update_u(epsilon*(2.0-lambda));
    update_h_rhmc( epsilon, multi_x);
    update_u(0.5*epsilon*lambda);
    
    /* reunitarize the gauge field */
    rephase( OFF );
    reunitarize();
    rephase( ON );
    /*TEMP - monitor action*/ //if(step%6==0)d_action_rhmc(multi_x,sumvec);
    
  }	/* end loop over microcanonical steps */
  
  /* find action */
  /* do conjugate gradient to get (Madj M)inverse * phi */
  endaction=d_action_rhmc(multi_x,sumvec);
  /* decide whether to accept, if not, copy old link field back */
  /* careful - must generate only one random number for whole lattice */
#ifdef HMC
  if(this_node==0)xrandom = myrand(&node_prn);
  broadcast_float(&xrandom);
  if( exp( (double)(startaction-endaction) ) < xrandom ){
    if(steps > 0)
      gauge_field_copy( F_OFFSET(old_link[0]), F_OFFSET(link[0]) );
#ifdef FN
    invalidate_all_ferm_links(&fn_links);
    invalidate_all_ferm_links(&fn_links_dmdu0);
#endif
    node0_printf("REJECT: delta S = %e\n", (double)(endaction-startaction));
  }
  else {
    node0_printf("ACCEPT: delta S = %e\n", (double)(endaction-startaction));
  }
#else // not HMC
  node0_printf("CHECK: delta S = %e\n", (double)(endaction-startaction));
#endif // HMC
  
  /* free multimass solution vector storage */
  for(i=0;i<max_rat_order;i++)free(multi_x[i]);
  free(sumvec);
  
  if(steps > 0)return (iters/steps);
  else return(-99);
}
Пример #3
0
int main( int argc, char **argv ){
  register site *s;
  int i,si;
  int prompt;
  double dtime;
  su3_vector **eigVec ;
  su3_vector *tmp ;
  double *eigVal ;
  int total_R_iters ;
  double chirality ;

  initialize_machine(&argc,&argv);
#ifdef HAVE_QDP
  QDP_initialize(&argc, &argv);
#ifndef QDP_PROFILE
  QDP_profcontrol(0);
#endif
#endif
  /* Remap standard I/O */
  if(remap_stdio_from_args(argc, argv) == 1)terminate(1);

  g_sync();
  /* set up */
  prompt = setup();

  /* loop over input sets */
  while( readin(prompt) == 0){
    
    dtime = -dclock();
    invalidate_all_ferm_links(&fn_links);
    make_path_table(&ks_act_paths, &ks_act_paths_dmdu0);
    /* Load fat and long links for fermion measurements if needed */
    load_ferm_links(&fn_links, &ks_act_paths);
    /* call fermion_variable measuring routines */
    /* results are printed in output file */
    f_meas_imp( F_OFFSET(phi), F_OFFSET(xxx), mass,
		&fn_links, &fn_links_dmdu0);
    eigVal = (double *)malloc(Nvecs*sizeof(double));
    eigVec = (su3_vector **)malloc(Nvecs*sizeof(su3_vector*));
    for(i=0;i<Nvecs;i++)
      eigVec[i]=
	(su3_vector*)malloc(sites_on_node*sizeof(su3_vector));
    
    total_R_iters=Kalkreuter(eigVec, eigVal, eigenval_tol, 
			     error_decr, Nvecs, MaxIter, Restart, 
			     Kiters, EVEN, &fn_links) ;
    tmp = (su3_vector*)malloc(sites_on_node*sizeof(su3_vector));
    for(i=0;i<Nvecs;i++)
      { 
	/* Construct to odd part of the vector.                 *
	 * Note that the true odd part of the eigenvector is    *
	 *  i/sqrt(eigVal) Dslash Psi. But since I only compute *
	 * the chirality the i factor is irrelevant (-i)*i=1!!  */
	dslash_fn_field(eigVec[i], tmp, ODD, &fn_links) ;
	FORSOMEPARITY(si,s,ODD){ 
	  scalar_mult_su3_vector( &(tmp[si]),
				  1.0/sqrt(eigVal[i]), 
				  &(eigVec[i][si]) ) ;
	}
	
	measure_chirality(eigVec[i], &chirality, EVENANDODD);
	/* Here I divide by 2 since the EVEN vector is normalized to
	 * 1. The EVENANDODD vector is normalized to 2. I could have
	 * normalized the EVENANDODD vector to 1 and then not devide
	 * by to.  The measure_chirality routine assumes vectors
	 * normalized to 1.  */
	node0_printf("Chirality(%i): %g\n",i,chirality/2) ;
      }
    free(tmp);
    /**
       for(i=0;i<Nvecs;i++)
       {
       sprintf(label,"DENSITY(%i)",i) ;
       print_densities(eigVec[i], label, ny/2,nz/2,nt/2, EVEN) ;
       }
    **/
    for(i=0;i<Nvecs;i++)
      free(eigVec[i]) ;
    free(eigVec) ;
    free(eigVal) ;
#ifdef FN
    invalidate_all_ferm_links(&fn_links);
#endif
    fflush(stdout);
    
    node0_printf("RUNNING COMPLETED\n"); fflush(stdout);
    dtime += dclock();
    if(this_node==0){
      printf("Time = %e seconds\n",dtime);
      printf("total_iters = %d\n",total_iters);
      printf("total Rayleigh iters = %d\n",total_R_iters);
    }
    fflush(stdout);
  }
Пример #4
0
/* For compatibility with fermion_links_hisq.c */
void
invalidate_fn_links(ferm_links_t *fn)
{
  invalidate_all_ferm_links(fn);
}
Пример #5
0
int
main( int argc, char **argv )
{
  int meascount,traj_done;
  int prompt;
  int s_iters, avs_iters, avspect_iters, avbcorr_iters;
  double dtime, dclock();
  
  initialize_machine(&argc,&argv);
#ifdef HAVE_QDP
  QDP_initialize(&argc, &argv);
#endif
  /* Remap standard I/O */
  if(remap_stdio_from_args(argc, argv) == 1)terminate(1);
  
  g_sync();
  /* set up */
  prompt = setup();

//  restore_random_state_scidac_to_site("randsave", F_OFFSET(site_prn));
//  restore_color_vector_scidac_to_site("xxx1save", F_OFFSET(xxx1),1);
//  restore_color_vector_scidac_to_site("xxx2save", F_OFFSET(xxx2),1);

  /* loop over input sets */
  while( readin(prompt) == 0) {
    
    /* perform warmup trajectories */
    dtime = -dclock();
    for( traj_done=0; traj_done < warms; traj_done++ ){
      update();
    }
    node0_printf("WARMUPS COMPLETED\n"); fflush(stdout);
    
    /* perform measuring trajectories, reunitarizing and measuring 	*/
    meascount=0;		/* number of measurements 		*/
    avspect_iters = avs_iters = avbcorr_iters = 0;
    for( traj_done=0; traj_done < trajecs; traj_done++ ){ 
      
      /* do the trajectories */
      s_iters=update();
      
      /* measure every "propinterval" trajectories */
      if( (traj_done%propinterval)==(propinterval-1) ){
	
	/* call gauge_variable fermion_variable measuring routines */
	/* results are printed in output file */
	rephase(OFF);
	g_measure( );
	rephase(ON);

	/* Load fat and long links for fermion measurements */
	load_ferm_links(&fn_links, &ks_act_paths);
#ifdef DM_DU0
	load_ferm_links(&fn_links_dmdu0, &ks_act_paths_dmdu0);
#endif

	/* Measure pbp, etc */
#ifdef ONEMASS
	f_meas_imp(F_OFFSET(phi),F_OFFSET(xxx),mass, &fn_links, 
		   &fn_links_dmdu0);
#else
	f_meas_imp( F_OFFSET(phi1), F_OFFSET(xxx1), mass1, 
		    &fn_links, &fn_links_dmdu0);
	f_meas_imp( F_OFFSET(phi2), F_OFFSET(xxx2), mass2,
		    &fn_links, &fn_links_dmdu0);
#endif

	/* Measure derivatives wrto chemical potential */
#ifdef D_CHEM_POT
#ifdef ONEMASS
	Deriv_O6( F_OFFSET(phi1), F_OFFSET(xxx1), F_OFFSET(xxx2), mass,
		  &fn_links, &fn_links_dmdu0);
#else
	Deriv_O6( F_OFFSET(phi1), F_OFFSET(xxx1), F_OFFSET(xxx2), mass1,
		  &fn_links, &fn_links_dmdu0);
	Deriv_O6( F_OFFSET(phi1), F_OFFSET(xxx1), F_OFFSET(xxx2), mass2,
		  &fn_links, &fn_links_dmdu0);
#endif
#endif

#ifdef SPECTRUM 
	/* Fix TUP Coulomb gauge - gauge links only*/
	rephase( OFF );
	gaugefix(TUP,(Real)1.8,500,(Real)GAUGE_FIX_TOL);
	rephase( ON );
#ifdef FN
	invalidate_all_ferm_links(&fn_links);
#ifdef DM_DU0
	invalidate_all_ferm_links(&fn_links_dmdu0);
#endif
#endif
	/* Load fat and long links for fermion measurements */
	load_ferm_links(&fn_links, &ks_act_paths);
#ifdef DM_DU0
	load_ferm_links(&fn_links_dmdu0, &ks_act_paths_dmdu0);
#endif	
	if(strstr(spectrum_request,",spectrum,") != NULL){
#ifdef ONEMASS
	  avspect_iters += spectrum2(mass,F_OFFSET(phi),F_OFFSET(xxx),
				     &fn_links);
#else
	  avspect_iters += spectrum2( mass1, F_OFFSET(phi1),
				      F_OFFSET(xxx1), &fn_links);
	  avspect_iters += spectrum2( mass2, F_OFFSET(phi1),
				      F_OFFSET(xxx1), &fn_links);
#endif
	}
	
	if(strstr(spectrum_request,",spectrum_point,") != NULL){
#ifdef ONEMASS
	  avspect_iters += spectrum_fzw(mass,F_OFFSET(phi),F_OFFSET(xxx),
					&fn_links);
#else
	  avspect_iters += spectrum_fzw( mass1, F_OFFSET(phi1),
					 F_OFFSET(xxx1), &fn_links);
	  avspect_iters += spectrum_fzw( mass2, F_OFFSET(phi1),
					 F_OFFSET(xxx1), &fn_links);
#endif
	}
	
	if(strstr(spectrum_request,",nl_spectrum,") != NULL){
#ifdef ONEMASS
	  avspect_iters += nl_spectrum(mass,F_OFFSET(phi),F_OFFSET(xxx),
				       F_OFFSET(tempmat1),F_OFFSET(staple),
				       &fn_links);
#else
	  avspect_iters += nl_spectrum( mass1, F_OFFSET(phi1), 
		F_OFFSET(xxx1), F_OFFSET(tempmat1),F_OFFSET(staple),
					&fn_links);
#endif
	}
	
	if(strstr(spectrum_request,",spectrum_mom,") != NULL){
#ifdef ONEMASS
	  avspect_iters += spectrum_mom(mass,mass,F_OFFSET(phi),5e-3,
					&fn_links);
#else
	  avspect_iters += spectrum_mom( mass1, mass1, 
					 F_OFFSET(phi1), 1e-1,
					 &fn_links);
#endif
	}
	
	if(strstr(spectrum_request,",spectrum_multimom,") != NULL){
#ifdef ONEMASS
	  avspect_iters += spectrum_multimom(mass,
					     spectrum_multimom_low_mass,
					     spectrum_multimom_mass_step,
					     spectrum_multimom_nmasses,
					     5e-3, &fn_links);
#else
	  avspect_iters += spectrum_multimom(mass1,
					     spectrum_multimom_low_mass,
					     spectrum_multimom_mass_step,
					     spectrum_multimom_nmasses,
					     5e-3, &fn_links);

#endif
	}
	
#ifndef ONEMASS
	if(strstr(spectrum_request,",spectrum_nd,") != NULL){
	  avspect_iters += spectrum_nd( mass1, mass2, 1e-1,
					&fn_links);
	}
#endif
	if(strstr(spectrum_request,",spectrum_nlpi2,") != NULL){
#ifdef ONEMASS
	  avspect_iters += spectrum_nlpi2(mass,mass,F_OFFSET(phi),5e-3,
					  &fn_links );
#else
	  avspect_iters += spectrum_nlpi2( mass1, mass1, 
					   F_OFFSET(phi1),1e-1,
					   &fn_links );
	  avspect_iters += spectrum_nlpi2( mass2, mass2, 
					   F_OFFSET(phi1),1e-1,
					   &fn_links );
#endif
	}
	
	if(strstr(spectrum_request,",spectrum_singlets,") != NULL){
#ifdef ONEMASS
	  avspect_iters += spectrum_singlets(mass, 5e-3, F_OFFSET(phi),
					     &fn_links);
#else
	  avspect_iters += spectrum_singlets(mass1, 5e-3, F_OFFSET(phi1),
					     &fn_links );
	  avspect_iters += spectrum_singlets(mass2, 5e-3, F_OFFSET(phi1),
					     &fn_links );
#endif
	}

	if(strstr(spectrum_request,",fpi,") != NULL)
	  {
	    avspect_iters += fpi_2( fpi_mass, fpi_nmasses, 2e-3,
				    &fn_links );
	  }
	
#ifdef HYBRIDS
	if(strstr(spectrum_request,",spectrum_hybrids,") != NULL){
#ifdef ONEMASS
	  avspect_iters += spectrum_hybrids( mass,F_OFFSET(phi),1e-1,
					     &fn_links);
#else
	  avspect_iters += spectrum_hybrids( mass1, F_OFFSET(phi1), 5e-3,
					     &fn_links);
	  avspect_iters += spectrum_hybrids( mass2, F_OFFSET(phi1), 2e-3,
					     &fn_links);
#endif
	}
#endif
	if(strstr(spectrum_request,",hvy_pot,") != NULL){
	  rephase( OFF );
	  hvy_pot( F_OFFSET(link[XUP]) );
	  rephase( ON );
	}
#endif /* SPECTRUM */
	avs_iters += s_iters;
	++meascount;
	fflush(stdout);
      }
    }	/* end loop over trajectories */
    
    node0_printf("RUNNING COMPLETED\n"); fflush(stdout);
    if(meascount>0)  {
      node0_printf("average cg iters for step= %e\n",
		   (double)avs_iters/meascount);
#ifdef SPECTRUM
      node0_printf("average cg iters for spectrum = %e\n",
		   (double)avspect_iters/meascount);
#endif
    }
    
    dtime += dclock();
    if(this_node==0){
      printf("Time = %e seconds\n",dtime);
      printf("total_iters = %d\n",total_iters);
    }
    fflush(stdout);
    
    /* save lattice if requested */
    if( saveflag != FORGET ){
      rephase( OFF );
      save_lattice( saveflag, savefile, stringLFN );
      rephase( ON );
#ifdef HAVE_QIO
//       save_random_state_scidac_from_site("randsave", "Dummy file XML",
//        "Random number state", QIO_SINGLEFILE, F_OFFSET(site_prn));
//       save_color_vector_scidac_from_site("xxx1save", "Dummy file XML",
//        "xxx vector", QIO_SINGLEFILE, F_OFFSET(xxx1),1);
//       save_color_vector_scidac_from_site("xxx2save", "Dummy file XML",
//        "xxx vector", QIO_SINGLEFILE, F_OFFSET(xxx2),1);
#endif
    }
  }
#ifdef HAVE_QDP
  QDP_finalize();
#endif  
  normal_exit(0);
  return 0;
}
Пример #6
0
OBSOLETE!! multi_x is no longer sized correctly for more than one pseudofermion
/********** update_omelyan.c ****************************************************/
/* MIMD version 7 */

/*
 See Takaishi and de Forcrand hep-lat/-0505020
 Update lattice.
 Two gauge steps for one fermion force step ("epsilon" is time for one fermion step)
	update U to epsilon*(1/4-alpha/2)
	Update H by epsilon*1/2*gauge_force
	update U to epsilon*(1/2-beta)
	Update H by epsilon*fermion_force
	update U to epsilon*(3/4+alpha/2)
	Update H by epsilon*1/2*gauge_force

	update U to epsilon*(5/4-alpha/2)
	Update H by epsilon*1/2*gauge_force
	update U to epsilon*(3/2+beta)
	Update H by epsilon*fermion_force
	update U to epsilon*(7/4+alpha/2)
	Update H by epsilon*1/2*gauge_force
	update U to epsilon*(2)

 This routine does not refresh the antihermitian momenta.
 This routine begins at "integral" time, with H and U evaluated
 at same time.
  "alpha" and "beta" are adjustable parameters.  At alpha=beta=0 this
   is just leapfrog integration.
  Omelyan "optimum alpha" is 2*(0.25-0.1932) ~ 0.1
*/
#include "ks_imp_includes.h"	/* definitions files and prototypes */

#define mat_invert mat_invert_uml
/**#define mat_invert mat_invert_cg**/

int update()  {
  int step, iters=0;
  Real final_rsq;
  double startaction,endaction,d_action();
  Real xrandom;
  int i,j; site *s;
  su3_vector *multi_x[MAX_RAT_ORDER];
  su3_vector *sumvec;
  Real alpha,beta;
  int iphi;
  
  alpha = 0.1;
  beta = 0.1;
  node0_printf("Omelyan integration, 2 gauge for one 1 fermion step, steps= %d eps= %e alpha= %e beta= %e\n",
	       steps,epsilon,alpha,beta);
  if (steps %2 != 0 ){
    node0_printf("BONEHEAD! need even number of steps\n");
    exit(0);
  }
  
  /* allocate space for multimass solution vectors */
  for(i=0;i<MAX_RAT_ORDER;i++) multi_x[i]=(su3_vector *)malloc( sizeof(su3_vector)*sites_on_node );
  sumvec = (su3_vector *)malloc( sizeof(su3_vector)*sites_on_node );
  
  /* refresh the momenta */
  ranmom();
  
  /* generate a pseudofermion configuration only at start*/
  for(iphi = 0; iphi < nphi; iphi++){
    grsource_imp_rhmc( F_OFFSET(phi[iphi]), &(rparam[iphi].GR), EVEN,
		       multi_x,sumvec, rsqmin_gr[iphi], niter_gr[iphi]);
  }

  /* find action */
  startaction=d_action_rhmc(multi_x,sumvec);
  /* copy link field to old_link */
  gauge_field_copy( F_OFFSET(link[0]), F_OFFSET(old_link[0]));
  
  /* do "steps" microcanonical steps (one "step" = one force evaluation)"  */
  for(step=2; step <= steps; step+=2){
    
    /* update U's and H's - see header comment */
    update_u( epsilon*( (0.25-0.5*alpha) ) );
    update_h_gauge( 0.5*epsilon);
    update_u( epsilon*( (0.5-beta)-(0.25-0.5*alpha) ) );
    update_h_fermion( epsilon, multi_x);
    update_u( epsilon*( (0.75+0.5*alpha)-(0.5-beta) ) );
    update_h_gauge( 0.5*epsilon);
    
    update_u( epsilon*( (1.25-0.5*alpha)-(0.75+0.5*alpha) ) );
    update_h_gauge( 0.5*epsilon);
    update_u( epsilon*( (1.5+beta)-(1.25-0.5*alpha) ) );
    update_h_fermion( epsilon, multi_x);
    update_u( epsilon*( (1.75+0.5*alpha)-(1.5+beta) ) );
    update_h_gauge( 0.5*epsilon);
    update_u( epsilon*( (2.0)-(1.75+0.5*alpha) ) );
    
    /* reunitarize the gauge field */
    rephase( OFF );
    reunitarize();
    rephase( ON );
    /*TEMP - monitor action*/ //if(step%6==0)d_action_rhmc(multi_x,sumvec);
    
  }	/* end loop over microcanonical steps */
  
  /* find action */
  /* do conjugate gradient to get (Madj M)inverse * phi */
  endaction=d_action_rhmc(multi_x,sumvec);
  /* decide whether to accept, if not, copy old link field back */
  /* careful - must generate only one random number for whole lattice */
#ifdef HMC
  if(this_node==0)xrandom = myrand(&node_prn);
  broadcast_float(&xrandom);
  if( exp( (double)(startaction-endaction) ) < xrandom ){
    if(steps > 0)
      gauge_field_copy( F_OFFSET(old_link[0]), F_OFFSET(link[0]) );
#ifdef FN
  invalidate_all_ferm_links(&fn_links);
  invalidate_all_ferm_links(&fn_links_dmdu0);
#endif
    node0_printf("REJECT: delta S = %e\n", (double)(endaction-startaction));
  }
  else {
    node0_printf("ACCEPT: delta S = %e\n", (double)(endaction-startaction));
  }
#else // not HMC
  node0_printf("CHECK: delta S = %e\n", (double)(endaction-startaction));
#endif // HMC
  
  /* free multimass solution vector storage */
  for(i=0;i<MAX_RAT_ORDER;i++)free(multi_x[i]);
  free(sumvec);
  
  if(steps > 0)return (iters/steps);
    else return(-99);
}
Пример #7
0
int
main( int argc, char **argv )
{
  int meascount,traj_done,i;
  int prompt;
  int s_iters, avs_iters, avspect_iters, avbcorr_iters;
  double dtime, dclock();
  
  initialize_machine(&argc,&argv);
#ifdef HAVE_QDP
  QDP_initialize(&argc, &argv);
#ifndef QDP_PROFILE
  QDP_profcontrol(0);
#endif
#endif
  /* Remap standard I/O */
  if(remap_stdio_from_args(argc, argv) == 1)terminate(1);
  
  g_sync();
  /* set up */
  prompt = setup();

  /* loop over input sets */
  while( readin(prompt) == 0) {
    
    /* perform warmup trajectories */
#ifdef MILC_GLOBAL_DEBUG
    global_current_time_step = 0;
#endif /* MILC_GLOBAL_DEBUG */

    dtime = -dclock();
    for( traj_done=0; traj_done < warms; traj_done++ ){
      update();
    }
    node0_printf("WARMUPS COMPLETED\n"); fflush(stdout);
    
    /* perform measuring trajectories, reunitarizing and measuring 	*/
    meascount=0;		/* number of measurements 		*/
    avspect_iters = avs_iters = avbcorr_iters = 0;

    for( traj_done=0; traj_done < trajecs; traj_done++ ){ 
#ifdef MILC_GLOBAL_DEBUG
#ifdef HISQ_REUNITARIZATION_DEBUG
  {
  int isite, idir;
  site *s;
  FORALLSITES(isite,s) {
    for( idir=XUP;idir<=TUP;idir++ ) {
      lattice[isite].on_step_Y[idir] = 0;
      lattice[isite].on_step_W[idir] = 0;
      lattice[isite].on_step_V[idir] = 0;
    }
  }
  }
#endif /* HISQ_REUNITARIZATION_DEBUG */
#endif /* MILC_GLOBAL_DEBUG */
      /* do the trajectories */
      s_iters=update();

      /* measure every "propinterval" trajectories */
      if( (traj_done%propinterval)==(propinterval-1) ){
	
	/* call gauge_variable fermion_variable measuring routines */
	/* results are printed in output file */
	rephase(OFF);
	g_measure( );
	rephase(ON);
#ifdef MILC_GLOBAL_DEBUG
#ifdef HISQ
        g_measure_plaq( );
#endif
#ifdef MEASURE_AND_TUNE_HISQ
        g_measure_tune( );
#endif /* MEASURE_AND_TUNE_HISQ */
#endif /* MILC_GLOBAL_DEBUG */

	/************************************************************/
	/* WARNING: The spectrum code below is under revision       */
	/* It works only in special cases                           */
	/* For the asqtad spectrum, please create the lattice first */
	/* and then run the appropriate executable in ks_imp_dyn.   */
	/************************************************************/
	/* Do some fermion measurements */
#ifdef SPECTRUM 
	/* Fix TUP Coulomb gauge - gauge links only*/
	rephase( OFF );
	gaugefix(TUP,(Real)1.8,500,(Real)GAUGE_FIX_TOL);
	rephase( ON );

	invalidate_all_ferm_links(&fn_links);
#ifdef DM_DU0
	invalidate_all_ferm_links(&fn_links_dmdu0);
#endif
#endif


	for(i=0;i<n_dyn_masses;i++){
	  // Remake the path table if the fermion coeffs change for this mass
// DT IT CAN"T BE RIGHT TO CALL IT WITH dyn_mass
	  //if(make_path_table(&ks_act_paths, &ks_act_paths_dmdu0,dyn_mass[i]))
//AB: NOT SURE IF WE ARE DOING THIS RIGHT HERE
//    HAVE TO THINK THROUGH HOW LINKS ARE LOADED FOR MEASUREMENTS
//    AND WHERE NAIK CORRECTION CAN EVER POSSIBLY ENTER
//	  if(make_path_table(&ks_act_paths, &ks_act_paths_dmdu0,   0.0/*TEMP*/   ))
	    {
	      // If they change, invalidate only fat and long links
	      //node0_printf("INVALIDATE\n");
	      invalidate_all_ferm_links(&fn_links);
#ifdef DM_DU0
	      invalidate_all_ferm_links(&fn_links_dmdu0);
#endif
	    }
	    /* Load fat and long links for fermion measurements if needed */
#ifdef HISQ
//AB: QUICK FIX TO USE NAIK EPSILON FOR SPECTRUM MEASUREMENTS,
//    WORKS ONLY IF IN THE RATIONAL FUNCTION FILE naik_term_epsilon IS NON-ZERO
//    FOR LAST PSEUDO-FIELD
//    IT IS ASSUMED THAT THIS CORRECTION CORRESPONDS TO LAST DYNAMICAL MASS
//AB: OLD WAY OF INITIALIZING THE LINKS:  fn_links.hl.current_X_set = 0;
//    INSTEAD WE DO:
////	    if(n_dyn_masses-1==i) { // last dynamical mass, assumed to be c-quark
////	      fn_links.hl.current_X_set = n_naiks-1;
//DT CHARM QUARK NEEDS SMALLER RESIDUAL
////	      node0_printf("TEMP: reset rsqprop from %e to %e\n",rsqprop,1e-8*rsqprop);
////	      rsqprop *= 1e-8;
////	    }
////	    else { // light quarks
	      fn_links.hl.current_X_set = 0;
////	    }
#endif
	    load_ferm_links(&fn_links, &ks_act_paths);
#ifdef DM_DU0
#ifdef HISQ
	    fn_links_dmdu0.hl.current_X_set = 0;
#endif
	    load_ferm_links(&fn_links_dmdu0, &ks_act_paths_dmdu0);
#endif
	    
	    f_meas_imp( F_OFFSET(phi1), F_OFFSET(xxx1), dyn_mass[i],
			&fn_links, &fn_links_dmdu0);
	    /* Measure derivatives wrto chemical potential */
#ifdef D_CHEM_POT
	    Deriv_O6( F_OFFSET(phi1), F_OFFSET(xxx1), F_OFFSET(xxx2), 
		      dyn_mass[i], &fn_links, &fn_links_dmdu0);
#endif
	    
#ifdef SPECTRUM 

	    // DT: At the moment spectrum_nd does only the first two masses
	    // this only makes sense to get the kaon, and only works if
	    // eps_naik is the same for both the first two quarks
            if( strstr(spectrum_request,",spectrum_nd,") != NULL && i==0 )
              avspect_iters += spectrum_nd( dyn_mass[0], dyn_mass[1],  1e-2, &fn_links);

	    // AB: spectrum() is used only for the charm quark,
	    // i.e., last dynamical mass
	    if(strstr(spectrum_request,",spectrum,") != NULL && n_dyn_masses-1==i)
	      avspect_iters += spectrum2( dyn_mass[i], F_OFFSET(phi1),
					  F_OFFSET(xxx1), &fn_links);
	    
	    if(strstr(spectrum_request,",spectrum_point,") != NULL)
	      avspect_iters += spectrum_fzw( dyn_mass[i], F_OFFSET(phi1),
					     F_OFFSET(xxx1), &fn_links);
	    
	    // AB: nl_spectrum is used only for strange,
	    // i.e., second mass
	    if(strstr(spectrum_request,",nl_spectrum,") != NULL && 1==i)
	      avspect_iters += nl_spectrum( dyn_mass[i], F_OFFSET(phi1), 
					    F_OFFSET(xxx1), 
					    F_OFFSET(tempmat1),
					    F_OFFSET(staple),
					    &fn_links);
	    
	    // AB: spectrum_mom is used only for charm,
	    // i.e., last mass
	    if(strstr(spectrum_request,",spectrum_mom,") != NULL && n_dyn_masses-1==i)
	      avspect_iters += spectrum_mom( dyn_mass[i], dyn_mass[i], 
					     F_OFFSET(phi1), 1e-1,
					     &fn_links);
	    
	    // For now we can't do the off-diagonal spectrum if Dirac operators
            // depend on masses.  We need two propagators
	    // if(strstr(spectrum_request,",spectrum_multimom,") != NULL)
	    //     avspect_iters += spectrum_multimom(dyn_mass[i],
	    //				 spectrum_multimom_low_mass,
	    //				 spectrum_multimom_mass_step,
	    //				 spectrum_multimom_nmasses,
	    //				 5e-3, &fn_links);

	    // For now we can't do the off-diagonal spectrum if Dirac operators
            // depend on masses.  We need two propagators
	    //	    if(strstr(spectrum_request,",spectrum_nd,") != NULL){
	    //	      avspect_iters += spectrum_nd( mass1, mass2, 1e-1,
	    //					    &fn_links);

	    // AB: spectrum_nlpi2 is used only for up/down,
	    // i.e., first mass
	    if(strstr(spectrum_request,",spectrum_nlpi2,") != NULL && 0==i)
	      avspect_iters += spectrum_nlpi2( dyn_mass[i], dyn_mass[i],
					       F_OFFSET(phi1),1e-1,
					       &fn_links );
	
	    if(strstr(spectrum_request,",spectrum_singlets,") != NULL)
	      avspect_iters += spectrum_singlets(dyn_mass[i], 5e-3, 
						 F_OFFSET(phi1), &fn_links );

	    // For now we can't do the off-diagonal spectrum if Dirac operators
            // depend on masses.  We need two propagators
	    // if(strstr(spectrum_request,",fpi,") != NULL)
	    // avspect_iters += fpi_2( fpi_mass, fpi_nmasses, 2e-3,
	    //			    &fn_links );
	
#ifdef HYBRIDS
	  if(strstr(spectrum_request,",spectrum_hybrids,") != NULL)
	    avspect_iters += spectrum_hybrids( dyn_mass[i], F_OFFSET(phi1), 
					       5e-3, &fn_links);
#endif
	  if(strstr(spectrum_request,",hvy_pot,") != NULL){
	    rephase( OFF );
	    hvy_pot( F_OFFSET(link[XUP]) );
	    rephase( ON );
	  }
#endif
//	    if(n_dyn_masses-1==i) { // last dynamical mass, assumed to be c-quark
//DT CHARM QUARK NEEDS SMALLER RESIDUAL
//AB NEED TO RETURN RESIDUAL TO THE ORIGINAL VALUE
//	      node0_printf("TEMP: reset rsqprop from %e to %e\n",rsqprop,1e+8*rsqprop);
//	      rsqprop *= 1e+8;
//	    }
	}
	avs_iters += s_iters;
	++meascount;
	fflush(stdout);
      }
    }	/* end loop over trajectories */
    
    node0_printf("RUNNING COMPLETED\n"); fflush(stdout);
    if(meascount>0)  {
      node0_printf("average cg iters for step= %e\n",
		   (double)avs_iters/meascount);
    }
    
    dtime += dclock();
    if(this_node==0){
      printf("Time = %e seconds\n",dtime);
      printf("total_iters = %d\n",total_iters);
    }
    fflush(stdout);
    
    /* save lattice if requested */
    if( saveflag != FORGET ){
      rephase( OFF );
      save_lattice( saveflag, savefile, stringLFN );
      rephase( ON );
    }
  }
#ifdef HAVE_QDP
  QDP_finalize();
#endif  
  normal_exit(0);
  return 0;
}
Пример #8
0
OBSOLETE!  See update_rhmc.c
/********** update.c ****************************************************/
/* MIMD version 7 */

/*
 Update lattice.
     compute PHI for both factors in fermion determinant at beginning
	update U by (epsilon/2)
	compute X for light and strange quarks for each term in rational 
		function ( or "both factors in det.")
	update H, full step
	update U to next time needed

 This routine does not refresh the antihermitian momenta.
 This routine begins at "integral" time, with H and U evaluated
 at same time.
*/
#include "ks_imp_includes.h"	/* definitions files and prototypes */

#define mat_invert mat_invert_uml
/**#define mat_invert mat_invert_cg**/

int update()  {
  int step, iters=0;
  double startaction,endaction;
#ifdef HMC
  Real xrandom;
#endif
  int i;
  su3_vector **multi_x;
  su3_vector *sumvec;
  int iphi;

  node0_printf("Leapfrog integration, steps= %d eps= %e\n",steps,epsilon);
  
  /* allocate space for multimass solution vectors */

  multi_x = (su3_vector **)malloc(max_rat_order*sizeof(su3_vector *));
  if(multi_x == NULL){
    printf("update: No room for multi_x\n");
    terminate(1);
  }
  for(i=0;i<max_rat_order;i++){
    multi_x[i]=(su3_vector *)malloc( sizeof(su3_vector)*sites_on_node );
    if(multi_x[i] == NULL){
      printf("update: No room for multi_x\n");
      terminate(1);
    }
  }

  sumvec = (su3_vector *)malloc( sizeof(su3_vector)*sites_on_node );
  
  /* refresh the momenta */
  ranmom();
  
  /* generate a pseudofermion configuration only at start*/
  // NOTE used to clear xxx here.  May want to clear all solutions for reversibility
  for(iphi = 0; iphi < n_pseudo; iphi++){
    grsource_imp_rhmc( F_OFFSET(phi[iphi]), &(rparam[iphi].GR), EVEN,
		       multi_x,sumvec, rsqmin_gr[iphi], niter_gr[iphi]);
  }

  /* find action */
  startaction=d_action_rhmc(multi_x,sumvec);
  /* copy link field to old_link */
  gauge_field_copy( F_OFFSET(link[0]), F_OFFSET(old_link[0]));
  
  /* do "steps" microcanonical steps"  */
  for(step=1; step <= steps; step++){
    
    /* update U's to middle of interval */
    update_u(0.5*epsilon);
    
    /* now update H by full time interval */
    update_h_rhmc( epsilon, multi_x);
    
    /* update U's by half time step to get to even time */
    update_u(epsilon*0.5);
    
    /* reunitarize the gauge field */
    rephase( OFF );
    reunitarize();
    rephase( ON );
    /*TEMP - monitor action*/if(step%4==0)d_action_rhmc(multi_x,sumvec);
    
  }	/* end loop over microcanonical steps */
  
  /* find action */
  /* do conjugate gradient to get (Madj M)inverse * phi */
  endaction=d_action_rhmc(multi_x,sumvec);
  /* decide whether to accept, if not, copy old link field back */
  /* careful - must generate only one random number for whole lattice */
#ifdef HMC
  if(this_node==0)xrandom = myrand(&node_prn);
  broadcast_float(&xrandom);
  if( exp( (double)(startaction-endaction) ) < xrandom ){
    if(steps > 0)
      gauge_field_copy( F_OFFSET(old_link[0]), F_OFFSET(link[0]) );
#ifdef FN
    invalidate_all_ferm_links(&fn_links);
    invalidate_all_ferm_links(&fn_links_dmdu0);
#endif
    node0_printf("REJECT: delta S = %e\n", (double)(endaction-startaction));
  }
  else {
    node0_printf("ACCEPT: delta S = %e\n", (double)(endaction-startaction));
  }
#else  // not HMC
  node0_printf("CHECK: delta S = %e\n", (double)(endaction-startaction));
#endif // HMC
  
  /* free multimass solution vector storage */
  for(i=0;i<max_rat_order;i++)free(multi_x[i]);
  free(sumvec);
  
  if(steps > 0)return (iters/steps);
  else return(-99);
}