Beispiel #1
0
void maxwell(real temp)
{ 
   int         k;
   vektor      tot_impuls;
   int         nactive_x, nactive_y, nactive_z;
   static long dummy = 0;
   int slice;
#ifdef DAMP
   real tmp1,tmp2,tmp3,f,maxax,maxax2;
#endif
#ifdef LASER
   real depth;
#endif

#ifdef UNIAX
   real xisq;
   real xi0;
   real xi1;
   real xi2;
   real dot;
   real norm;
   real osq;
#endif
   real   TEMP;
   real   scale, xx, tmp;
   int    num, nhalf, typ;

   TEMP = temp;
   tot_impuls.x = 0.0;   nactive_x = 0;
   tot_impuls.y = 0.0;   nactive_y = 0;
#ifndef TWOD
   tot_impuls.z = 0.0;   nactive_z = 0;
#endif

   /* set temperature */
   for (k=0; k<NCELLS; ++k) {

      int i;
      cell *p;
      vektor *rest;

      p = CELLPTR(k);

      for (i=0; i<p->n; ++i) {
#ifdef LASER
	 depth =   laser_dir.x * ORT(p,i,X)
		 + laser_dir.y * ORT(p,i,Y)
#ifndef TWOD
		 + laser_dir.z * ORT(p,i,Z)
#endif
	 ;
	 depth -= laser_offset;
         if (depth < 0) {
	   depth=0; /* we don't want to exceed laser_delta_temp */
         }
	 
	 TEMP =  laser_delta_temp * exp(-laser_mu * depth);
         TEMP += temperature; /* add base temperature of sample */

#endif /* LASER */

#ifdef DAMP
            /* Calculate stadium function f */
         maxax = MAX(MAX(stadium.x,stadium.y),stadium.z);
         maxax2 = MAX(MAX(stadium2.x,stadium2.y),stadium2.z);

         tmp1 = (stadium2.x == 0) ? 0 : SQR((ORT(p,i,X)-center.x)/(2.0*stadium2.x));
         tmp2 = (stadium2.y == 0) ? 0 : SQR((ORT(p,i,Y)-center.y)/(2.0*stadium2.y));
         tmp3 = (stadium2.z == 0) ? 0 : SQR((ORT(p,i,Z)-center.z)/(2.0*stadium2.z));

         f    = (tmp1+tmp2+tmp3-SQR(maxax/(2.0*maxax2)))/\
             (.25- SQR(maxax/(2.0*maxax2)));

         if (f<= 0.0)
             f = 0.0;
         else if (f>1.0)
             f = 1.0;

      /* we smooth the stadium function: to get a real bath tub !
        fully damped atoms have temp=0, temperature gradient determined
          by bath tub */
         if (f !=0)
             TEMP = damptemp * (1.0 - 0.5 * (1 + sin(-M_PI/2.0 + M_PI*f)));
         else TEMP= temp;

#endif

#ifdef FTG
	  /* calc slice and set TEMP  */
	 tmp = ORT(p,i,X) / box_x.x;
	 slice = (int) nslices * tmp;
	 if (slice<0)        slice = 0;
	 if (slice>=nslices) slice = nslices -1;;
	 
	 TEMP=  Tleft + (Tright-Tleft)*(slice-nslices_Left+1) /
	   (real) (nslices-nslices_Left-nslices_Right+1);
    
	 if (slice>=nslices-nslices_Right) TEMP = Tright;
	 if (slice<nslices_Left)           TEMP=  Tleft;
#endif
         
	 tmp  = sqrt(TEMP * MASSE(p,i));
         rest = restrictions + VSORTE(p,i);
#ifndef RIGID
         IMPULS(p,i,X) = imd_gaussian(tmp) * rest->x;
         IMPULS(p,i,Y) = imd_gaussian(tmp) * rest->y;
#ifndef TWOD
         IMPULS(p,i,Z) = imd_gaussian(tmp) * rest->z;
#endif
#else
	 /* superatoms get velocity zero */
	 if (superatom[VSORTE(p,i)]>-1) {
	   IMPULS(p,i,X) = 0.0;
	   IMPULS(p,i,Y) = 0.0;
#ifndef TWOD
	   IMPULS(p,i,Z) = 0.0;
#endif
	 }
#endif
         nactive_x += (int) rest->x;
         nactive_y += (int) rest->y;
#ifndef TWOD
         nactive_z += (int) rest->z;
#endif
         tot_impuls.x += IMPULS(p,i,X);
         tot_impuls.y += IMPULS(p,i,Y);
#ifndef TWOD
         tot_impuls.z += IMPULS(p,i,Z);
#endif

#ifdef UNIAX

         /* angular velocities for uniaxial molecules */

         /* choose a random vector in space */

         do {
           xi1 = 2.0 * drand48() - 1.0 ;
           xi2 = 2.0 * drand48() - 1.0 ;
           xisq = xi1 * xi1 + xi2 * xi2 ;
         } while ( xisq >= 1.0 );

         xi0 = sqrt( 1.0 - xisq ) ;

         DREH_IMPULS(p,i,X) = 2.0 * xi1 * xi0 ;
         DREH_IMPULS(p,i,Y) = 2.0 * xi2 * xi0 ;
         DREH_IMPULS(p,i,Z) = 1.0 - 2.0 * xisq ;

        /* constrain the vector to be perpendicular to the molecule */

        dot = SPRODN(DREH_IMPULS,p,i,ACHSE,p,i);

        DREH_IMPULS(p,i,X) -= dot * ACHSE(p,i,X) ; 
        DREH_IMPULS(p,i,Y) -= dot * ACHSE(p,i,Y) ; 
        DREH_IMPULS(p,i,Z) -= dot * ACHSE(p,i,Z) ; 

        /* renormalize vector */	   

        osq = SPRODN(DREH_IMPULS,p,i,DREH_IMPULS,p,i);
        norm = SQRT( osq );

        DREH_IMPULS(p,i,X) /= norm ;
        DREH_IMPULS(p,i,Y) /= norm ;
        DREH_IMPULS(p,i,Z) /= norm ;

        /* choose the magnitude of the angular momentum */

        osq = - 2.0 * uniax_inert * TEMP * log( drand48() ) ;
        norm = sqrt( osq );

        DREH_IMPULS(p,i,X) *= norm ;
        DREH_IMPULS(p,i,Y) *= norm ;
        DREH_IMPULS(p,i,Z) *= norm ;

#endif /* UNIAX */

#ifdef SHOCK
	/* plate against bulk */
	 if (shock_mode == 1) {
	   if ( ORT(p,i,X) < shock_strip ) 
	       IMPULS(p,i,X) += shock_speed * MASSE(p,i);
	 }
	 /* two halves against one another */
	 if (shock_mode == 2) {
	   if ( ORT(p,i,X) < box_x.x*0.5 ) 
	     IMPULS(p,i,X) += shock_speed * MASSE(p,i);
	   else
	     IMPULS(p,i,X) -= shock_speed * MASSE(p,i);
	 }
	 /* bulk against wall */
	 if (shock_mode == 3) IMPULS(p,i,X) += shock_speed * MASSE(p,i);
#endif
      }
   }

#ifdef CLONE

   /* compute the total momentum afresh */
   tot_impuls.x = 0.0;
   tot_impuls.y = 0.0;
#ifndef TWOD
   tot_impuls.z = 0.0;
#endif

   /* set velocities of clones equal */
   for (k=0; k<NCELLS; k++) {

      int i, j;
      cell *p;
      p = CELLPTR(k);

      for (i=0; i<p->n; i+=nclones) {

        tot_impuls.x += nclones * IMPULS(p,i,X);
        tot_impuls.y += nclones * IMPULS(p,i,Y);
#ifndef TWOD
        tot_impuls.z += nclones * IMPULS(p,i,Z);
#endif
	for (j=1; j<nclones; j++) {
          IMPULS(p,i+j,X) = IMPULS(p,i,X);
          IMPULS(p,i+j,Y) = IMPULS(p,i,Y);
#ifndef TWOD
          IMPULS(p,i+j,Z) = IMPULS(p,i,Z);
#endif
        }
      }
   }

#endif /* CLONE */

   tot_impuls.x = nactive_x == 0 ? 0.0 : tot_impuls.x / nactive_x;
   tot_impuls.y = nactive_y == 0 ? 0.0 : tot_impuls.y / nactive_y;
#ifndef TWOD
   tot_impuls.z = nactive_z == 0 ? 0.0 : tot_impuls.z / nactive_z;
#endif

   /* correct center of mass momentum */
   for (k=0; k<NCELLS; ++k) {
      int i;
      cell *p;
      vektor *rest;
      p = CELLPTR(k);
      for (i=0; i<p->n; ++i) {
         rest = restrictions + VSORTE(p,i);
         IMPULS(p,i,X) -= tot_impuls.x * rest->x;
         IMPULS(p,i,Y) -= tot_impuls.y * rest->y;
#ifndef TWOD
         IMPULS(p,i,Z) -= tot_impuls.z * rest->z;
#endif
      }
   }

} 
Beispiel #2
0
/* This is laser_rescale_mode == 4 */
void laser_rescale_ttm()
{
  /* This function just writes the exponential source term into the FD net.
   * Heating of the electrons occurs later,
   * in the numerical solution of the pdeq.                              */

  int i,j,k;
  real exp_gauss_time_etc, gauss_time_squared, gauss_time_squared1, depth;
  
  gauss_time_squared = timestep * steps - laser_t_0;
  gauss_time_squared *= gauss_time_squared;
  exp_gauss_time_etc = exp(-gauss_time_squared/laser_sigma_t_squared/2.0)
    * laser_p_peak ;/*  * fd_h.x*fd_h.y*fd_h.z not needed */
  if (laser_t_1>0) {
    gauss_time_squared1 = timestep * steps - laser_t_1;
    gauss_time_squared1 *= gauss_time_squared1;
    exp_gauss_time_etc += exp(-gauss_time_squared1/laser_sigma_t1_squared/2.0)
      * laser_p_peak1;/*  * fd_h.x*fd_h.y*fd_h.z not needed */
  }

  /* loop over all FD cells, excluding ghost layers */
  
  for(i=1; i<local_fd_dim.x-1; ++i)
  {
    for(j=1; j<local_fd_dim.y-1; ++j)
    {
      for(k=1; k<local_fd_dim.z-1; ++k)
      {
	depth = ttm_calc_depth(i,j,k); 
        l2[i][j][k].source = l1[i][j][k].source
	                   = exp(-laser_mu*depth) * exp_gauss_time_etc; 
      }
    }
  }

#ifdef PDECAY

  for (k=0; k<NCELLS; k++) {
    cell *p;
    p = CELLPTR(k);
    int i;
    for (i=0; i < p->n; i++) {
	if( ORT(p,i,X) > ramp_start )
	  {
	    switch ( pdecay_mode){
	    case 0:
	      {
		double m = 1 / ( (ramp_end - ramp_start ) ) ;
		double b = - ramp_start / ( ramp_end - ramp_start );
		
		double xia = ORT(p,i,X) *m + b ;
	
		IMPULS(p,i,X) *= 1.0- ( ORT(p,i,X) *m + b)  ;
		
		if(steps==-1)
		  printf(" %f %f \n",  ORT(p,i,X),1.0 - ( ORT(p,i,X) * m + b) );
		break;
	      }
	    case 1:	      
	      {
		double a = 1.0 / ( ramp_start - ramp_end);
		a *= a;
	
		IMPULS(p,i,X) *= a * ( ORT(p,i,X) - ramp_end ) * ( ORT(p,i,X) - ramp_end );

		if(steps==-1)
		  printf("%f %f \n",  ORT(p,i,X), a * ( ORT(p,i,X) - ramp_end ) * ( ORT(p,i,X) - ramp_end ));
		break;
	      }
	      break;
	    case 2:
	      {
		double m = 1 / ( (ramp_end - ramp_start ) ) ;
		double b = - ramp_start / ( ramp_end - ramp_start );
		
		KRAFT(p,i,X) -=  ( IMPULS(p,i,X)/MASSE(p,i)) * ( ORT(p,i,X) *m + b  ) * xipdecay;
		
		
		if(steps==-1)
		  printf(" %f %f \n",  ORT(p,i,X),ORT(p,i,X) *m + b);
		break;
	      }
	      break;
	    case 3:
	      {
		double a = 1.0 / ( ramp_end - ramp_start);
		a *= a;
			
		 KRAFT(p,i,X) -=  ( IMPULS(p,i,X)/MASSE(p,i)) * xipdecay * a * ( ORT(p,i,X) - ramp_start ) * ( ORT(p,i,X) - ramp_start );

		if(steps==-1)
		  printf("%f %f \n",  ORT(p,i,X), a * ( ORT(p,i,X) - ramp_start ) * ( ORT(p,i,X) - ramp_start ) );
		break;
	      }
	      break;
	    default:
	      error("Illegal value for parameter pdecay_mode.\n");
	      break;
	    }
	  }

    }
  }
#endif 

}
Beispiel #3
0
void laser_rescale_1()
{ /* Rescale all atom velocities so that exactly the same amount of
     kinetic energy is added to the atoms at a given depth.
     The direction of the momentum vectors remains unchanged, except for
     zero-velocity atoms, which will be given a random direction.*/

  real exp_gauss_time_etc, gauss_time_squared, gauss_time_squared1;
  int k;
  real cosph, sinph, theta, costh, sinth;

  gauss_time_squared = timestep * steps - laser_t_0;
  gauss_time_squared *= gauss_time_squared;
  exp_gauss_time_etc = exp(-gauss_time_squared/laser_sigma_t_squared/2.0)
                       * laser_p_peak * timestep * laser_atom_vol;
  if (laser_t_1>0) {
    gauss_time_squared1 = timestep * steps - laser_t_1;
    gauss_time_squared1 *= gauss_time_squared1;
    exp_gauss_time_etc += exp(-gauss_time_squared1/laser_sigma_t1_squared/2.0)
                       * laser_p_peak1 * timestep * laser_atom_vol;
  }


  for (k=0; k<NCELLS; k++) {
    cell *p;
    p = CELLPTR(k);
    int i;
    for (i=0; i < p->n; i++) {
      real p_0_square; /* square of initial atom momentum */
      real de; /* Kinetic energy to be added to the atom */
      real depth; /* Distance from origin along laser_dir */
      real tmpx, tmpy, tmpsqr;
#ifndef TWOD
      real tmpz;
#endif
      real scale_p; /* Scale factor for atom momentum */

      p_0_square = SPRODN(IMPULS,p,i,IMPULS,p,i);
      depth = laser_calc_depth(p,i);

#ifdef PDECAY
	if( ORT(p,i,X) > ramp_start )
	  {
	    switch ( pdecay_mode){
	    case 0:
	      {
		/* y= m * x + b */
		double m = 1 / ( (ramp_end - ramp_start ) ) ;
		double b = - ramp_start / ( ramp_end - ramp_start );
		
		double xia = ORT(p,i,X) *m + b ;
	
		IMPULS(p,i,X) *= 1.0 - ( ORT(p,i,X) *m + b)  ;
		
		if(steps==-1)
		  printf(" %f %f \n",  ORT(p,i,X),1.0 - ( ORT(p,i,X) * m + b) );
		break;
	      }
	    case 1:	      
	      {
		double a = 1.0 / ( ramp_start - ramp_end);
		a *= a;
	
		IMPULS(p,i,X) *= a * ( ORT(p,i,X) - ramp_end ) * ( ORT(p,i,X) - ramp_end );

		if(steps==-1)
		  printf("%f %f \n",  ORT(p,i,X), a * ( ORT(p,i,X) - ramp_end ) * ( ORT(p,i,X) - ramp_end ));
		break;
	      }
	      break;
	    case 2:
	      {
		double m = 1 / ( (ramp_end - ramp_start ) ) ;
		double b = - ramp_start / ( ramp_end - ramp_start );
		
		KRAFT(p,i,X) -=  ( IMPULS(p,i,X)/MASSE(p,i)) * ( ORT(p,i,X) *m + b  ) * xipdecay;
		
		
		if(steps==-1)
		  printf(" %f %f \n",  ORT(p,i,X),ORT(p,i,X) *m + b);
		break;
	      }
	      break;
	    case 3:
	      {
		double a = 1.0 / ( ramp_end - ramp_start);
		a *= a;
			
		 KRAFT(p,i,X) -=  ( IMPULS(p,i,X)/MASSE(p,i)) * xipdecay * a * ( ORT(p,i,X) - ramp_start ) * ( ORT(p,i,X) - ramp_start );

		if(steps==-1)
		  printf("%f %f \n",  ORT(p,i,X), a * ( ORT(p,i,X) - ramp_start ) * ( ORT(p,i,X) - ramp_start ) );
		break;
	      }
	      break;
	    default:
	      error("Illegal value for parameter pdecay_mode.\n");
	      break;
	    }
	  }
#endif 


#ifdef LASERYZ  /* spacial dependence of laser beam */    
    
     
      double x = ORT(p,i,X);
      double y = ORT(p,i,Y);
      double z = ORT(p,i,Z);
   
      
     
      de = exp( -laser_mu*depth ) * exp_gauss_time_etc * laser_intensity_profile(x,y,z);     
  
    

#else
      de = exp(-laser_mu*depth) * exp_gauss_time_etc;
       
#endif         

       if ( p_0_square == 0.0 ) { /* we need a direction for the momentum. */
#ifndef TWOD
        /* find random 3d unit vector */
        rand_uvec_3d(&tmpx, &tmpy, &tmpz);
#else
        /* find random 2d unit vector */
        rand_uvec_2d(&tmpx, &tmpy);      
#endif
        scale_p = sqrt( de * 2.0 * MASSE(p,i) );
        IMPULS(p,i,X) = tmpx * scale_p;
        IMPULS(p,i,Y) = tmpy * scale_p;
#ifndef TWOD
        IMPULS(p,i,Z) = tmpz * scale_p;
#endif
      } else { /* rescale present momentum */

        scale_p = sqrt( de * 2.0 * MASSE(p,i) / p_0_square + 1.0 );
        IMPULS(p,i,X) *= scale_p;
        IMPULS(p,i,Y) *= scale_p;
#ifndef TWOD
        IMPULS(p,i,Z) *= scale_p;
#endif

      }
    }
  }
} /* void laser_rescale_1()*/
Beispiel #4
0
void laser_rescale_2()
/* Instead of just rescaling, add the momentum increment in random direction.
   Only thereafter rescale so the right amount of energy gets absorbed.
   Involves several square roots, probably slower
*/ 
{

  real exp_gauss_time_etc, gauss_time_squared, gauss_time_squared1;
  int k;

  gauss_time_squared = timestep * steps - laser_t_0;
  gauss_time_squared *= gauss_time_squared;
  exp_gauss_time_etc = exp(-gauss_time_squared/laser_sigma_t_squared/2.0)
                       * laser_p_peak * timestep * laser_atom_vol;
  if (laser_t_1>0) {
    gauss_time_squared1 = timestep * steps - laser_t_1;
    gauss_time_squared1 *= gauss_time_squared1;
    exp_gauss_time_etc += exp(-gauss_time_squared1/laser_sigma_t1_squared/2.0)
                       * laser_p_peak1 * timestep * laser_atom_vol;
  }

  for (k=0; k<NCELLS; k++) {
    cell *p;
    p = CELLPTR(k);
    int i;
    for (i=0; i < p->n; i++) {
      real p_0_square; /* square of initial atom momentum */
      real p_0;
      real de; /* Kinetic energy to be added to the atom */
      real dp;
      real depth; /* Distance from origin along laser_dir */
      real tmpx, tmpy, tmpsqr;
#ifndef TWOD
      real tmpz;
#endif
      real scale_p; /* Scale factor for atom momentum */

      p_0_square = SPRODN(IMPULS,p,i,IMPULS,p,i);
      p_0=sqrt(p_0_square);

      depth = laser_calc_depth(p,i);

#ifdef LASERYZ  /* spacial dependence of laser beam */    
    
    
      double x = ORT(p,i,X);
      double y = ORT(p,i,Y);
      double z = ORT(p,i,Z);
      de = exp( -laser_mu*depth ) * exp_gauss_time_etc * laser_intensity_profile(x,y,z);   

#else
      de = exp(-laser_mu*depth) * exp_gauss_time_etc;
    
#endif
      dp = sqrt( p_0_square + 2*de*MASSE(p,i) ) - p_0;
    

      /* Momentum increment is to point in a random direction... */
#ifndef TWOD
      rand_uvec_3d(&tmpx, &tmpy, &tmpz);
#else
      rand_uvec_2d(&tmpx, &tmpy);
#endif
      IMPULS(p,i,X) += tmpx * dp;
      IMPULS(p,i,Y) += tmpy * dp;
#ifndef TWOD
      IMPULS(p,i,Z) += tmpz * dp;
#endif

      /* rescale present momentum to an absolute value of dp + p_0 */
      scale_p = (p_0 + dp) / SQRT( SPRODN(IMPULS,p,i,IMPULS,p,i) );
      IMPULS(p,i,X) *= scale_p;
      IMPULS(p,i,Y) *= scale_p;
#ifndef TWOD
      IMPULS(p,i,Z) *= scale_p;
#endif
    
    }
  }
} /* void laser_rescale_2()*/
Beispiel #5
0
void init_fcs(void) {

  FCSResult res;
  fcs_int srf = 1;
  char *method;

  fcs_int   pbc [3] = { pbc_dirs.x, pbc_dirs.y, pbc_dirs.z };
  fcs_float BoxX[3] = { box_x.x, box_x.y, box_x.z };
  fcs_float BoxY[3] = { box_y.x, box_y.y, box_y.z };
  fcs_float BoxZ[3] = { box_z.x, box_z.y, box_z.z };
  fcs_float off [3] = { 0.0, 0.0, 0.0 };

  /* subtract CM momentum */
  if (0 == imdrestart) {
    int i, k; real ptot[4], ptot_2[4], px, py, pz;
    ptot[0] = 0.0; ptot[1] = 0.0; ptot[2] = 0.0, ptot[3] = 0.0; 
    for (k=0; k<NCELLS; ++k) { /* loop over all cells */
      cell *p = CELLPTR(k);
      for (i=0; i<p->n; i++) {
        ptot[0] += IMPULS(p,i,X);
        ptot[1] += IMPULS(p,i,Y);
        ptot[2] += IMPULS(p,i,Z);
        ptot[3] += MASSE(p,i);
      }
    }
#ifdef MPI
    MPI_Allreduce( ptot, ptot_2, 4, REAL, MPI_SUM, cpugrid);
    ptot[0] = ptot_2[0];
    ptot[1] = ptot_2[1]; 
    ptot[2] = ptot_2[2]; 
    ptot[3] = ptot_2[3]; 
#endif
    px = ptot[0]/ptot[3];
    py = ptot[1]/ptot[3];
    pz = ptot[2]/ptot[3];
    for (k=0; k<NCELLS; ++k) { /* loop over all cells */
      cell *p = CELLPTR(k);
      for (i=0; i<p->n; i++) {
        IMPULS(p,i,X) -= px * MASSE(p,i);
        IMPULS(p,i,Y) -= py * MASSE(p,i);
        IMPULS(p,i,Z) -= pz * MASSE(p,i);
      }
    }
  }

  switch (fcs_method) {
    case FCS_METH_DIRECT: method = "direct"; break;
    case FCS_METH_PEPC:   method = "pepc";   break;
    case FCS_METH_FMM:    method = "fmm";    break;
    case FCS_METH_P3M:    method = "p3m";    srf = fcs_near_field_flag; break;
    case FCS_METH_P2NFFT: method = "p2nfft"; srf = fcs_near_field_flag; break;
    case FCS_METH_VMG:    method = "vmg";    break;
    case FCS_METH_PP3MG:  method = "pp3mg";  break;
  }

  /* initialize handle and set common parameters */
  res = fcs_init(&handle, method, cpugrid); 
  ASSERT_FCS(res);
  res = fcs_set_common(handle, srf, BoxX, BoxY, BoxZ, off, pbc, natoms);
  ASSERT_FCS(res);
  res = fcs_require_virial(handle, 1);
  ASSERT_FCS(res);

  /* set method specific parameters */
  switch (fcs_method) {
#ifdef FCS_ENABLE_DIRECT
    case FCS_METH_DIRECT:
      /* nothing to do */
      break;
#endif
#ifdef FCS_ENABLE_PEPC
    case FCS_METH_PEPC:
      res = fcs_pepc_setup(handle, (fcs_float)fcs_pepc_eps, 
            (fcs_float)fcs_pepc_theta );
      ASSERT_FCS(res);
      res = fcs_pepc_set_num_walk_threads( handle, (fcs_int)fcs_pepc_nthreads );
      ASSERT_FCS(res);
      break;
#endif
#ifdef FCS_ENABLE_FMM
    case FCS_METH_FMM:
      res = fcs_fmm_set_absrel(handle, (fcs_int)fcs_fmm_absrel);
      ASSERT_FCS(res);
      res = fcs_fmm_set_tolerance_energy(handle, (fcs_float)fcs_tolerance);
      ASSERT_FCS(res);
      break;
#endif
#ifdef FCS_ENABLE_P3M
    case FCS_METH_P3M:
      if (0==srf) {
        res = fcs_p3m_set_r_cut(handle, (fcs_float)fcs_rcut);
        ASSERT_FCS(res);
      }
      res = fcs_set_tolerance(handle, FCS_TOLERANCE_TYPE_FIELD,
                              (fcs_float)fcs_tolerance);
      ASSERT_FCS(res);
      if (fcs_grid_dim.x) 
        res = fcs_p3m_set_grid(handle, (fcs_int)fcs_grid_dim.x);
      ASSERT_FCS(res);
      break;
#endif
#ifdef FCS_ENABLE_P2NFFT
    case FCS_METH_P2NFFT:
      if (0==srf) {
        res = fcs_p2nfft_set_r_cut(handle, (fcs_float)fcs_rcut);
        ASSERT_FCS(res);
      }
      res = fcs_set_tolerance(handle, FCS_TOLERANCE_TYPE_FIELD,
                              (fcs_float)fcs_tolerance);
      ASSERT_FCS(res);
      if (fcs_grid_dim.x) { 
        res = fcs_p2nfft_set_grid(handle, (fcs_int)fcs_grid_dim.x,
              (fcs_int)fcs_grid_dim.y, (fcs_int)fcs_grid_dim.z);
        ASSERT_FCS(res);
      }
      if (fcs_p2nfft_intpol_order) {
        res = fcs_p2nfft_set_pnfft_interpolation_order(handle, 
              (fcs_int)fcs_p2nfft_intpol_order);
        ASSERT_FCS(res);
      }
      if (fcs_p2nfft_epsI) {
        res = fcs_p2nfft_set_epsI(handle, (fcs_float)fcs_p2nfft_epsI);
        ASSERT_FCS(res);
      }
      //res = fcs_p2nfft_set_pnfft_window_by_name(handle, "bspline");
      //ASSERT_FCS(res);
      break;
#endif
#ifdef FCS_ENABLE_VMG
    case FCS_METH_VMG:
      if (fcs_vmg_near_field_cells) {
        res = fcs_vmg_set_near_field_cells(handle, (fcs_int)fcs_vmg_near_field_cells);
        ASSERT_FCS(res);
      }
      if (fcs_vmg_interpol_order) {
        res = fcs_vmg_set_interpolation_order(handle, (fcs_int)fcs_vmg_interpol_order);
        ASSERT_FCS(res);
      }
      if (fcs_vmg_discr_order) {
        res = fcs_vmg_set_discretization_order(handle, (fcs_int)fcs_vmg_discr_order);
        ASSERT_FCS(res);
      }
      if (fcs_iter_tolerance > 0) {
        res = fcs_vmg_set_precision(handle, (fcs_float)fcs_iter_tolerance);
        ASSERT_FCS(res);
      }
      break;
#endif
#ifdef FCS_ENABLE_PP3MG
    case FCS_METH_PP3MG:
      /* use default values, if not specified otherwise */
      if (fcs_grid_dim.x) {
        res = fcs_pp3mg_set_cells_x(handle, (fcs_int)fcs_grid_dim.x);
        ASSERT_FCS(res);
        res = fcs_pp3mg_set_cells_y(handle, (fcs_int)fcs_grid_dim.y);
        ASSERT_FCS(res);
        res = fcs_pp3mg_set_cells_z(handle, (fcs_int)fcs_grid_dim.z);
        ASSERT_FCS(res);
      }
      if (fcs_pp3mg_ghosts) {
        res = fcs_pp3mg_set_ghosts(handle, (fcs_int)fcs_pp3mg_ghosts);
        ASSERT_FCS(res);
      }
      if (fcs_pp3mg_degree) {
        res = fcs_pp3mg_set_degree(handle, (fcs_int)fcs_pp3mg_degree);
        ASSERT_FCS(res);
      }
      if (fcs_pp3mg_max_part) { 
        res = fcs_pp3mg_set_max_particles(handle, (fcs_int)fcs_pp3mg_max_part);
        ASSERT_FCS(res);
      }
      if (fcs_max_iter) { 
        res = fcs_pp3mg_set_max_iterations(handle,(fcs_int)fcs_max_iter);
        ASSERT_FCS(res);
      }
      if (fcs_iter_tolerance > 0) {
        res = fcs_pp3mg_set_tol(handle, (fcs_float)fcs_iter_tolerance);
        ASSERT_FCS(res);
      }      
break;
#endif
    default: 
      error("FCS method unknown or not implemented"); 
      break;
  }
  pack_fcs();
  res = fcs_tune(handle, nloc, nloc_max, pos, chg);
  ASSERT_FCS(res);

  /* inform about tuned parameters */
  switch (fcs_method) {
    fcs_int grid_dim[3];
    fcs_float r_cut;
#ifdef FCS_ENABLE_P3M
    case FCS_METH_P3M:
      res = fcs_p3m_get_r_cut(handle, &r_cut);
      ASSERT_FCS(res);
      res = fcs_p3m_get_grid(handle, grid_dim);
      ASSERT_FCS(res);
      if (0==myid) 
        printf("FCS: Tuned grid dimensions, cutoff: %d %d %d, %f\n",
               grid_dim[0], grid_dim[1], grid_dim[2], r_cut);
      break;
#endif
#ifdef FCS_ENABLE_P2NFFT
    case FCS_METH_P2NFFT:
      res = fcs_p2nfft_get_grid(handle, grid_dim, grid_dim+1, grid_dim+2);
      ASSERT_FCS(res);
      res = fcs_p2nfft_get_r_cut(handle, &r_cut);
      ASSERT_FCS(res);
      if (0==myid) 
        printf("FCS: Tuned grid dimensions, cutoff: %d %d %d, %f\n",
               grid_dim[0], grid_dim[1], grid_dim[2], r_cut);
      break;
#endif
#ifdef FCS_ENABLE_PP3MG
    case FCS_METH_PP3MG:
      res = fcs_pp3mg_get_cells_x(handle, grid_dim  );
      ASSERT_FCS(res);
      res = fcs_pp3mg_get_cells_y(handle, grid_dim+1);
      ASSERT_FCS(res);
      res = fcs_pp3mg_get_cells_z(handle, grid_dim+2);
      if (0==myid) 
        printf("FCS: Tuned grid dimensions: %d %d %d\n",
               grid_dim[0], grid_dim[1], grid_dim[2]);
      ASSERT_FCS(res);
      break;
#endif
    default: 
      break;
  }

  /* add near-field potential, after fcs_tune */
  if (0==srf) fcs_update_pottab();
}