Exemple #1
0
void do_neighbour_tables(cell *p, cell *q, vektor pbc)
{
  int i, j;
  int jstart;
  int q_typ, p_typ;
  vektor d, tmp_d;
  real radius;

  /* For each atom in first cell */
  for (i=0; i<p->n; ++i) {

    /* Compute only neighbour tables for existing atoms */
    if ( p->del[i] == 0 ) {

      /* All atoms are white */ 
      p->color[i]    = -1;

      tmp_d.x = p->ort[i].x - pbc.x;
      tmp_d.y = p->ort[i].y - pbc.y;
#ifndef TWOD
      tmp_d.z = p->ort[i].z - pbc.z;
#endif
      p_typ   = p->sorte[i];

      jstart = (p==q ? i+1 : 0);
    
      /* For each atom in neighbouring cell */
      for (j = jstart; j < q->n; ++j) {

	if ( q->del[j] == 0 ) {
	  q_typ = q->sorte[j];
	  
	  /* Calculate distance  */
	  d.x = q->ort[j].x - tmp_d.x;
	  d.y = q->ort[j].y - tmp_d.y;
#ifndef TWOD
	  d.z = q->ort[j].z - tmp_d.z;
#endif

	  radius = sqrt(SPROD(d,d));

	  /* Make neighbour tables */
#ifdef TERSOFF
	  if (radius <= ter_r_cut[p_typ][q_typ])
#else
	    if (radius <= r_max)
#endif 
	    {        
	      neightab *neigh;

	      /* Update neighbour table of particle i */
	      if ( first == 0 )
		neigh = &p->neightab_array[i];
	      else 
		neigh = &p->perm_neightab_array[i];

	      if (neigh->n_max <= neigh->n ) {
		error("Neighbour table too small, increase neigh_len");
	      }

	      neigh->typ[neigh->n] = q_typ;
	      neigh->cl [neigh->n] = q;
	      neigh->num[neigh->n] = j;

	      neigh->n++;

	      /* Update neighbour table of particle j */
	      if ( first == 0 )
		neigh = &q->neightab_array[j];
	      else
		neigh = &q->perm_neightab_array[j];

	      if (neigh->n_max <= neigh->n ) {
		error("Neighbour table too small, increase neigh_len");
	      }

	      neigh->typ[neigh->n] = p_typ;
	      neigh->cl [neigh->n] = p;
	      neigh->num[neigh->n] = i;

	      neigh->n++;
	    }
	}
      } /* for j */
    }
  } /* for i */

}
Exemple #2
0
void calc_extpot(void)
{
  int k, i, n;
  int isinx,isiny,isinz;
  real tmpvec1[4], tmpvec2[4];

  vektor d,addforce,totaddforce;
  real   dd,cc;
  real   dn,ddn,ee;
  
  vektor force;
  real tmp_virial;
#ifdef P_AXIAL
  vektor tmp_vir_vect;
#endif
      
  real pot_zwi, pot_grad;
  int col, is_short=0;
  

  
  for (k=0; k<ep_n; k++) {
    ep_fext[k] = 0.0;
    ep_xmax[k] = 0.0;
    ep_ymax[k] = 0.0;
    ep_atomsincontact[k]=0;
    ep_xmin[k] = 1.e8;
    ep_ymin[k] = 1.e8;
  }
  
  if(ep_key == 0) {   /* default: original harmonic potential */
    for (k=0; k<NCELLS; ++k) {
      cell *p = CELLPTR(k);
      for (i=0; i<p->n; ++i) {
	for (n=0; n<ep_n; ++n) {
	  
	
	  isinx= ep_dir[n].x;                  
	  isiny= ep_dir[n].y;                  
	  isinz= ep_dir[n].z;                  
	
	  d.x = ep_pos[n].x - ORT(p,i,X); 
	  d.y = ep_pos[n].y - ORT(p,i,Y); 
	  d.z = ep_pos[n].z - ORT(p,i,Z); 
	  dn  = SPROD(d,ep_dir[n]);
	  
	  /* spherical indentor*/
	  if (n<ep_nind) {
	    if (dn > -ep_rcut) {
	      real d2 = SPROD(d,d);
	      real d1 = SQRT(d2);
	      dd = ep_rcut - d1;
	      if (dd > 0.0) {
		real f = ep_a * dd * dd / d1;   /* force on atoms and indentor */
		KRAFT(p,i,X) -= f * d.x; 
		KRAFT(p,i,Y) -= f * d.y; 
		KRAFT(p,i,Z) -= f * d.z;
		ep_fext[n]   += f * ABS(dn); /* normal force on indentor */

		ep_atomsincontact[n]++;

		/* for determination of contact area */
		if(isinz)
		  {				  
		    ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		    ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Y) );    
		    ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		    ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Y) );    
		  }
		else if(isiny)
		  {
		    ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		    ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		    ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		    ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		  }
		else
		  {
		    ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,Y) );    
		    ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		    ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,Y) );    
		    ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		  }
	      }
	    }
	  }          
	  /*  potential wall */
	  else {  
	    if (dn*dn < ep_rcut*ep_rcut) {
	      real d1 = (dn>0) ? dn : -1*dn ;
	      dd = ep_rcut - d1;
	      if (dd > 0.0) {
		ep_atomsincontact[n]++;
		real f = ep_a * dd * dd / d1;   /* force on atoms and indentor */
		KRAFT(p,i,X) += f * ep_dir[n].x;
		KRAFT(p,i,Y) += f * ep_dir[n].y;
		KRAFT(p,i,Z) += f * ep_dir[n].z;
		ep_fext[n]   += f;  /* magnitude of force on wall */
	      }
	    } 
	  }
	}
      }
    }
  }
  else if(ep_key == 1) /* Ju Li's spherical indenter, see PRB 67, 104105 */
    {
 
      totaddforce.x=0.0;
      totaddforce.y=0.0;
      totaddforce.z=0.0;
      
      for (k=0; k<NCELLS; ++k) {
	cell *p = CELLPTR(k);
	for (i=0; i<p->n; ++i) {
	  for (n=0; n<ep_n; ++n) {
	    
	
	    isinx= ep_dir[n].x;                  
	    isiny= ep_dir[n].y;                  
	    isinz= ep_dir[n].z;      
	    
	    if (n<ep_nind) {	    
	      d.x =   ORT(p,i,X)-ep_pos[n].x; 
	      d.y =   ORT(p,i,Y)-ep_pos[n].y; 
	      d.z =   ORT(p,i,Z)-ep_pos[n].z; 
	      dn  = SPROD(d,ep_dir[n]);
	      dd  = SPROD(d,d);
	      
	      if ( dd < ep_rcut*ep_rcut)
		{
		  ep_atomsincontact[n]++;
		  /* for the determination of the contact area */
		  if(isinz)
		    {				  
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Y) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Y) );    
		    }
		  else if(isiny)
		    {
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		    }
		  else
		    {
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,Y) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,Y) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		  }
		  
		  if(have_extpotfile == 1){
		    PAIR_INT3(pot_zwi, pot_grad, ext_pot, n, ep_nind, dd, is_short);
		    tot_pot_energy += pot_zwi;
		    force.x = -1.0* pot_grad * d.x; 
		    force.y = -1.0* pot_grad * d.y; 
		    force.z = -1.0* pot_grad * d.z; 
		    KRAFT(p,i,X) += force.x;
		    KRAFT(p,i,Y) += force.y;
		    KRAFT(p,i,Z) += force.z;
		      
		    totaddforce.x += force.x;
		    totaddforce.y += force.y;
		    totaddforce.z += force.z;
		    
		    ep_fext[n]   += -pot_grad * ABS(dn); /* normal force on indentor */
		    
#ifdef P_AXIAL
		    tmp_vir_vect.x -= d.x * force.x;
		    tmp_vir_vect.y -= d.y * force.y;
#ifndef TWOD
		    tmp_vir_vect.z -= d.z * force.z;
#endif
#else
		    tmp_virial     -= dd * pot_grad;
#endif

#ifdef STRESS_TENS
		    if (do_press_calc) {
		      PRESSTENS(p,i,xx) -= d.x * force.x;
		      PRESSTENS(p,i,yy) -= d.y * force.y;
		      PRESSTENS(p,i,xy) -= d.x * force.y;
#ifndef TWOD
		      PRESSTENS(p,i,zz) -= d.z * force.z;
		      PRESSTENS(p,i,yz) -= d.y * force.z;
		      PRESSTENS(p,i,zx) -= d.z * force.x;
#endif
		      }
#endif
		    }

		   
	      /* old version of extpot, kept for downwards compatibility */
		  else{
		    ddn= sqrt(dd);
		    cc = (ep_rcut - ddn)/ep_a;
		    if (cc > UPPER_EXP) cc = UPPER_EXP;
		    if (cc < LOWER_EXP) cc = LOWER_EXP;
		    ee = exp(cc - 1.0/cc);
		    
		    tot_pot_energy += ee;
		    POTENG(p,i) += ee;
		    
		    ee = ee / ep_a / ddn * (1.0 + 1.0 /(cc*cc));
                        
		    KRAFT(p,i,X) += ee * d.x; 
		    KRAFT(p,i,Y) += ee * d.y; 
		    KRAFT(p,i,Z) += ee * d.z;
		    
		    totaddforce.x += ee * d.x;
		    totaddforce.y += ee * d.y;
		    totaddforce.z += ee * d.z; 
		    
		    ep_fext[n]   += ee * ABS(dn); /* normal force on indentor */
		  }
		}
	    } 
	  }
	}
      }
      
#ifdef MPI
      tmpvec1[0] =  totaddforce.x ;
      tmpvec1[1] =  totaddforce.y ;
      tmpvec1[2] =  totaddforce.z ;
      //    printf("before totaddforcereduce allreduce\n");fflush(stdout);
      MPI_Allreduce( tmpvec1, tmpvec2, 4, REAL, MPI_SUM, cpugrid);
      // printf("after totaddforce allreduce\n");fflush(stdout);
      totaddforce.x = tmpvec2[0];
      totaddforce.y = tmpvec2[1];
      totaddforce.z = tmpvec2[2];      
#endif
      /* no need for a wall as the total additional impuls is substracted */
      
      totaddforce.x *= 1.0/nactive_vect[0];
      totaddforce.y *= 1.0/nactive_vect[1];
      totaddforce.z *= 1.0/nactive_vect[2];
      
      
      for (k=0; k<NCELLS; ++k) {
	cell *p = CELLPTR(k);
	for (i=0; i<p->n; ++i) {
	  KRAFT(p,i,X) -= totaddforce.x;
	  KRAFT(p,i,Y) -= totaddforce.y;
	  KRAFT(p,i,Z) -= totaddforce.z;
	}
      }
    }
  

  else if(ep_key == 2) 
    /* Ju Li's spherical indenter made flat, see PRB 67, 104105
       with subtraction of total additional impulse
       works only with indentation directions parallel to box vectors*/ 
    {
      //      vektor d,addforce,totaddforce;
      //real   dd,cc;
      //real   dn,ddn,ee;
      
      totaddforce.x=0.0;
      totaddforce.y=0.0;
      totaddforce.z=0.0;
      
      
      for (k=0; k<NCELLS; ++k) {
	cell *p = CELLPTR(k);
	for (i=0; i<p->n; ++i) {
	  for (n=0; n<ep_n; ++n) {

	    isinx= ep_dir[n].x;                  
	    isiny= ep_dir[n].y;                  
	    isinz= ep_dir[n].z;      
	    
	    //  vektor d;
	    // real   dn;
	    d.x =  (ep_dir[n].x==0)  ? 0 : (ORT(p,i,X)-ep_pos[n].x); 
	    d.y =  (ep_dir[n].y==0)  ? 0 : (ORT(p,i,Y)-ep_pos[n].y); 
	    d.z =  (ep_dir[n].z==0)  ? 0 : (ORT(p,i,Z)-ep_pos[n].z); 
	    dn  = SPROD(d,ep_dir[n]);
	    dd  = SPROD(d,d);
		
	    if ( dd < ep_rcut*ep_rcut)
	      {
		/* for the determination of the contact area */
		ep_atomsincontact[n]++;
		if(isinz)
		    {				  
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Y) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Y) );    
		    }
		  else if(isiny)
		    {
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		    }
		  else
		    {
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,Y) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,Y) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		    }


		  
		if(have_extpotfile == 1){
		  PAIR_INT3(pot_zwi, pot_grad, ext_pot, n, ep_nind, dd, is_short);
		  tot_pot_energy += pot_zwi;
		  force.x = -1.0* pot_grad * d.x; 
		  force.y = -1.0* pot_grad * d.y; 
		  force.z = -1.0* pot_grad * d.z; 
		  KRAFT(p,i,X) += force.x;
		  KRAFT(p,i,Y) += force.y;
		  KRAFT(p,i,Z) += force.z;
		  
		  totaddforce.x += force.x;
		  totaddforce.y += force.y;
		  totaddforce.z += force.z;
		  
		  ep_fext[n]   += -pot_grad * ABS(dn); /* normal force on indentor */
		  
#ifdef P_AXIAL
		  tmp_vir_vect.x -= d.x * force.x;
		  tmp_vir_vect.y -= d.y * force.y;
#ifndef TWOD
		  tmp_vir_vect.z -= d.z * force.z;
#endif
#else
		  tmp_virial     -= dd * pot_grad;
#endif
		  
#ifdef STRESS_TENS
		  if (do_press_calc) {
		    PRESSTENS(p,i,xx) -= d.x * force.x;
		    PRESSTENS(p,i,yy) -= d.y * force.y;
		    PRESSTENS(p,i,xy) -= d.x * force.y;
#ifndef TWOD
		    PRESSTENS(p,i,zz) -= d.z * force.z;
		    PRESSTENS(p,i,yz) -= d.y * force.z;
		    PRESSTENS(p,i,zx) -= d.z * force.x;
#endif
		  }
#endif
		}
		
		   
		/* old version of extpot, kept for downwards compatibility */
		else{
		  ddn= sqrt(dd);
		  cc = (ep_rcut - ddn)/ep_a;
		  if (cc > UPPER_EXP) cc = UPPER_EXP;
		  if (cc < LOWER_EXP) cc = LOWER_EXP;
		  ee = exp(cc - 1.0/cc);
		    
		  tot_pot_energy += ee;
		  POTENG(p,i) += ee;
		  
		  ee = ee / ep_a / ddn * (1.0 + 1.0 /(cc*cc));
		  
		  KRAFT(p,i,X) += ee * d.x; 
		  KRAFT(p,i,Y) += ee * d.y; 
		  KRAFT(p,i,Z) += ee * d.z;
		  
		  totaddforce.x += ee * d.x;
		  totaddforce.y += ee * d.y;
		  totaddforce.z += ee * d.z; 
                    
		  ep_fext[n]   += ee * ABS(dn); /* normal force on indentor */
                    
		}
	      }
	  } 
	      
	}
      }
      
      
#ifdef MPI
      tmpvec1[0] =  totaddforce.x ;
      tmpvec1[1] =  totaddforce.y ;
      tmpvec1[2] =  totaddforce.z ;
      //    printf("before totaddforcereduce allreduce\n");fflush(stdout);
      MPI_Allreduce( tmpvec1, tmpvec2, 4, REAL, MPI_SUM, cpugrid);
      // printf("after totaddforce allreduce\n");fflush(stdout);
      totaddforce.x = tmpvec2[0];
      totaddforce.y = tmpvec2[1];
      totaddforce.z = tmpvec2[2];      
#endif
      /* no need for a wall as the total additional impuls is substracted */
      
      totaddforce.x *= 1.0/nactive_vect[0];
      totaddforce.y *= 1.0/nactive_vect[1];
      totaddforce.z *= 1.0/nactive_vect[2];
      
      
      for (k=0; k<NCELLS; ++k) {
	cell *p = CELLPTR(k);
	for (i=0; i<p->n; ++i) {
	  KRAFT(p,i,X) -= totaddforce.x;
	  KRAFT(p,i,Y) -= totaddforce.y;
	  KRAFT(p,i,Z) -= totaddforce.z;
	}
      }
    }

  else if(ep_key == 3) 
    /* Ju Li's spherical indenter made flat, see PRB 67, 104105
       without subtraction of the total additional impulse
       works only with indentation directions parallel to box vectors*/ 
    {
      //    vektor d,addforce,totaddforce;
      //      real   dd,cc;
      //      real   dn,ddn,ee;
      
      totaddforce.x=0.0;
      totaddforce.y=0.0;
      totaddforce.z=0.0;
      
      
      for (k=0; k<NCELLS; ++k) {
	cell *p = CELLPTR(k);
	for (i=0; i<p->n; ++i) {
	  for (n=0; n<ep_n; ++n) {
	    
	 
	    isinx= ep_dir[n].x;                  
	    isiny= ep_dir[n].y;                  
	    isinz= ep_dir[n].z;      
	    
	    vektor d;
	    real   dn;
	    d.x =  (ep_dir[n].x==0)  ? 0 : (ORT(p,i,X)-ep_pos[n].x) ; 
	    d.y =   (ep_dir[n].y==0)  ? 0 : (ORT(p,i,Y)-ep_pos[n].y); 
	    d.z =   (ep_dir[n].z==0)  ? 0 : (ORT(p,i,Z)-ep_pos[n].z); 
	    dn  = SPROD(d,ep_dir[n]);
	    dd  = SPROD(d,d);
		
	    if ( dd < ep_rcut*ep_rcut)
	      {
		/* for the determination of the contact area */
		ep_atomsincontact[n]++;
		if(isinz)
		    {				  
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Y) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Y) );    
		    }
		  else if(isiny)
		    {
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,X) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,X) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		    }
		  else
		    {
		      ep_xmax[n] = MAX(ep_xmax[n], ORT(p,i,Y) );    
		      ep_ymax[n] = MAX(ep_ymax[n], ORT(p,i,Z) );    
		      ep_xmin[n] = MIN(ep_xmin[n], ORT(p,i,Y) );    
		      ep_ymin[n] = MIN(ep_ymin[n], ORT(p,i,Z) );    
		    }

		  
		if(have_extpotfile == 1){
		  PAIR_INT3(pot_zwi, pot_grad, ext_pot, n, ep_nind, dd, is_short);
		  tot_pot_energy += pot_zwi;
		  force.x = - pot_grad * d.x; 
		  force.y = - pot_grad * d.y; 
		  force.z = - pot_grad * d.z; 
		  KRAFT(p,i,X) += force.x;
		  KRAFT(p,i,Y) += force.y;
		  KRAFT(p,i,Z) += force.z;
		  
		  totaddforce.x += force.x;
		  totaddforce.y += force.y;
		  totaddforce.z += force.z;
		  
		  ep_fext[n]   += -pot_grad * ABS(dn); /* normal force on indentor */
		  
#ifdef P_AXIAL
		  tmp_vir_vect.x -= d.x * force.x;
		  tmp_vir_vect.y -= d.y * force.y;
#ifndef TWOD
		  tmp_vir_vect.z -= d.z * force.z;
#endif
#else
		  tmp_virial     -= dd * pot_grad;
#endif
		  
#ifdef STRESS_TENS
		  if (do_press_calc) {
		    PRESSTENS(p,i,xx) -= d.x * force.x;
		    PRESSTENS(p,i,yy) -= d.y * force.y;
		    PRESSTENS(p,i,xy) -= d.x * force.y;
#ifndef TWOD
		    PRESSTENS(p,i,zz) -= d.z * force.z;
		    PRESSTENS(p,i,yz) -= d.y * force.z;
		    PRESSTENS(p,i,zx) -= d.z * force.x;
#endif
		  }
#endif
		}
		
		   
		/* old version of extpot, kept for downwards compatibility */
		else{
		ddn= sqrt(dd);
		cc = (ep_rcut - ddn)/ep_a;
		if (cc > UPPER_EXP) cc = UPPER_EXP;
		if (cc < LOWER_EXP) cc = LOWER_EXP;
		ee = exp(cc - 1.0/cc);
		    
		tot_pot_energy += ee;
		POTENG(p,i) += ee;
		    
		ee = ee / ep_a / ddn * (1.0 + 1.0 /(cc*cc));
		
		KRAFT(p,i,X) += ee * d.x; 
		KRAFT(p,i,Y) += ee * d.y; 
		KRAFT(p,i,Z) += ee * d.z;
		ep_fext[n]   += ee * ABS(dn); /* normal force on indentor */
		}
	      }	    
	  } 
	}
      }     
    }
  
  else
    {
      error("Error: external potential ep_key not defined.\n");
    }
#ifdef P_AXIAL
vir_xx += tmp_vir_vect.x;
vir_yy += tmp_vir_vect.y;
virial += tmp_vir_vect.x;
virial += tmp_vir_vect.y;
#ifndef TWOD
vir_zz += tmp_vir_vect.z;
virial += tmp_vir_vect.z;
#endif
#else
virial += tmp_virial;
#endif 
}
Exemple #3
0
void calc_strain(void)
{
  cell *p,*q;
  int i,j,k;
  int l,m,n;
  int r,s,t;
  int u,v,w;
  int g,h;
  int number;                          /* number of neighbours */ 
  int totalnumber = 0;                 /* number of neighbours of all atoms */
  int emptynumber = 0;                 /* number of atoms with less than 3 neighbours */ 
  int maxnumber = 0, minnumber = 1000; /* maximal and minimal number of neighbours occuring */
  int num = 4;
  vektor pbc;
  vektor *d, *du, *tmp;
  real a[3][3], b[3][3];
  real radius;
  real det;

  /* Allocate memory for temporary variables */
  d   = (vektor *) malloc( num * sizeof(vektor));
  du  = (vektor *) malloc( num * sizeof(vektor));
  tmp = (vektor *) malloc( num * sizeof(vektor));


  /* Initialization */

  /* for each cell */
  for (i=0; i < cell_dim.x; ++i)
    for (j=0; j < cell_dim.y; ++j)
#ifndef TWOD
      for (k=0; k < cell_dim.z; ++k)
#endif
	{
#ifdef TWOD
	  p = PTR_2D_V(cell_array,i,j  ,cell_dim);
#else
	  p = PTR_3D_V(cell_array,i,j,k,cell_dim);
#endif
	  /* For each atom in this cell */
	  for (u=0; u < p->n; ++u)
	    { 
	      p->strain[u].x        = 0.0;
	      p->strain[u].y        = 0.0;
#ifndef TWOD
	      p->strain[u].z        = 0.0;
#endif
	      p->strain_offdia[u].x = 0.0;
#ifndef TWOD
	      p->strain_offdia[u].y = 0.0;
	      p->strain_offdia[u].z = 0.0;
#endif
	      p->empty[u]           = 0;
	    }
	}

  /* Compute strain tensor */

  /* For each cell */
  for (i=0; i < cell_dim.x; ++i)
    for (j=0; j < cell_dim.y; ++j)
#ifndef TWOD
      for (k=0; k < cell_dim.z; ++k)
#endif
	{
#ifdef TWOD
	  p = PTR_2D_V(cell_array,i,j  ,cell_dim);
#else
	  p = PTR_3D_V(cell_array,i,j,k,cell_dim);
#endif

	  /* For each atom in this first cell */
	  for (u=0; u<p->n; ++u)
	    {

	      number = 0;
	      
	      /* For the neighbours of the first cell */
	      for (l=-1; l <= 1; ++l)
		for (m=-1; m <= 1; ++m)
#ifndef TWOD
		  for (n=-1; n <= 1; ++n)
#endif
		    {
	      /* Calculate Indices of Neighbour */
	      r = i+l;  pbc.x = 0;
	      s = j+m;  pbc.y = 0;
#ifndef TWOD
	      t = k+n;  pbc.z = 0;
#endif
              /* Deal with periodic boundary conditions if necessary */
              if (r<0) {
                if (pbc_dirs.x==1) {
                  r = cell_dim.x-1; 
                  pbc.x -= box_x.x;      
                  pbc.y -= box_x.y;
#ifndef TWOD
                  pbc.z -= box_x.z;
#endif
                } else continue;
              }
              if (s<0) {
                if (pbc_dirs.y==1) {
                  s = cell_dim.y-1;
                  pbc.x -= box_y.x;      
                  pbc.y -= box_y.y;
#ifndef TWOD
                  pbc.z -= box_y.z;
#endif
                } else continue;
              }
#ifndef TWOD
              if (t<0) {
                if (pbc_dirs.z==1) {
                  t = cell_dim.z-1;
                  pbc.x -= box_z.x;      
                  pbc.y -= box_z.y;
                  pbc.z -= box_z.z;
                } else continue;
              }
#endif
              if (r>cell_dim.x-1) {
                if (pbc_dirs.x==1) {
                  r = 0; 
                  pbc.x += box_x.x;      
                  pbc.y += box_x.y;
#ifndef TWOD
                  pbc.z += box_x.z;
#endif
                } else continue;
              }
              if (s>cell_dim.y-1) {
                if (pbc_dirs.y==1) {
                  s = 0; 
                  pbc.x += box_y.x;      
                  pbc.y += box_y.y;
#ifndef TWOD
                  pbc.z += box_y.z;
#endif
                } else continue;
              }
#ifndef TWOD
              if (t>cell_dim.z-1) {
                if (pbc_dirs.z==1) {
                  t = 0; 
                  pbc.x += box_z.x;      
                  pbc.y += box_z.y;
                  pbc.z += box_z.z;
                } else continue;
              }
#endif

	      /* Neighbour cell (note that p==q ist possible) */
#ifdef TWOD
              q = PTR_2D_V(cell_array,r,s,cell_dim);
#else
              q = PTR_3D_V(cell_array,r,s,t,cell_dim);
#endif

	      /* For each atom in the second cell */

	      for( v=0; v<q->n; ++v)
		{
		  /* Check whether there is enough memory for tmp variables */
		  if( number >= num) {
			++num;
			d    = (vektor *) realloc( d,   num * sizeof(vektor)); 
			du   = (vektor *) realloc( du,  num * sizeof(vektor));
			tmp  = (vektor *) realloc( tmp, num * sizeof(vektor)); 
		      }
		  
		  /* Calculate distance */
		  d[number].x = q->ort[v].x - q->dsp[v].x - p->ort[u].x + p->dsp[u].x + pbc.x;
		  d[number].y = q->ort[v].y - q->dsp[v].y - p->ort[u].y + p->dsp[u].y + pbc.y;
#ifndef TWOD
		  d[number].z = q->ort[v].z - q->dsp[v].z - p->ort[u].z + p->dsp[u].z + pbc.z;
#endif

		  radius = sqrt( (double)(SPROD(d[number],d[number])) );

		  if ( radius > 0.01 && radius < r_max ) 
		    {

		      /* Calculate differences of displacements */
		      du[number].x = q->dsp[v].x - p->dsp[u].x;
		      du[number].y = q->dsp[v].y - p->dsp[u].y;
#ifndef TWOD
		      du[number].z = q->dsp[v].z - p->dsp[u].z;
#endif

		      ++number; /* Number of neighbours*/

		    }
		} /* v */
	    } /* Neighbours of p */
	      
	      /* Calculate transformation matrix of du */

	      /* a = dx * dxT */

	      totalnumber += number;
	      maxnumber    = (number>maxnumber) ? number : maxnumber;
	      minnumber    = (number<minnumber) ? number : minnumber;

	      /* At least 3 neighbour atoms are required */
	      if (number < 3) { 
		p->empty[u] = 1;
		++emptynumber;
	      }
	      else
#ifdef TWOD
		{
	  for(g=0; g<2; ++g)
	    for(h=0; h<2; ++h)
	       a[g][h] = 0.0;

	  for (w=0; w<number; ++w) 
	    {
	      a[0][0] += d[w].x * d[w].x;  a[0][1] += d[w].x * d[w].y; 
	      a[1][0] += d[w].y * d[w].x;  a[1][1] += d[w].y * d[w].y;
	    }

	  /* b = Inverse of a */

	  det = a[0][0] * a[1][1] - a[0][1] * a[1][0];

	  if (det == 0.0) error("Transformation matrix zero.");

	  b[0][0] =  a[1][1] / det;
	  b[0][1] = -a[0][1] / det;
	  b[1][0] = -a[1][0] / det;
	  b[1][1] =  a[0][0] / det;

	  /* tmp = dx * b  */

	  for (w=0; w<number; ++w)
	    {
	      tmp[w].x = d[w].x * b[0][0] + d[w].y * b[1][0];
	      tmp[w].y = d[w].x * b[0][1] + d[w].y * b[1][1]; 
	    }

	  /* strain = (symmetrized) du * tmp  */

	  for (w=0; w<number; ++w)
	    {
	      p->strain[u].x        += du[w].x * tmp[w].x;
	      p->strain[u].y        += du[w].y * tmp[w].y;
	      
	      p->strain_offdia[u].x += ( du[w].y * tmp[w].x + du[w].x * tmp[w].y ) / 2;
	    }
#else /* 3D */
	{

	  for (g=0; g<3; ++g)
	    for (h=0; h<3; ++h)
	      a[g][h] = 0.0;

	  for (w=0; w<number; ++w) 
	    {
	      a[0][0] += d[w].x * d[w].x;  a[0][1] += d[w].x * d[w].y;  a[0][2] += d[w].x * d[w].z;
	      a[1][0] += d[w].y * d[w].x;  a[1][1] += d[w].y * d[w].y;  a[1][2] += d[w].y * d[w].z;
	      a[2][0] += d[w].z * d[w].x;  a[2][1] += d[w].z * d[w].y;  a[2][2] += d[w].z * d[w].z;
	    }

	  /* b = Inverse of a */

	  det = a[0][0] * a[1][1] * a[2][2] +
	        a[0][1] * a[1][2] * a[2][0] +
	        a[0][2] * a[1][0] * a[2][1] -
	        a[2][0] * a[1][1] * a[0][2] -
	        a[2][1] * a[1][2] * a[0][0] -
	        a[2][2] * a[1][0] * a[0][1];

	  if (det == 0.0) error("Transformation matrix singular.");

	  b[0][0] = ( a[1][1] * a[2][2] - a[1][2] * a[2][1] ) / det;
	  b[0][1] = ( a[2][1] * a[0][2] - a[0][1] * a[2][2] ) / det;
	  b[0][2] = ( a[0][1] * a[1][2] - a[1][1] * a[0][2] ) / det;

	  b[1][0] = ( a[1][2] * a[2][0] - a[1][0] * a[2][2] ) / det;
	  b[1][1] = ( a[0][0] * a[2][2] - a[2][0] * a[0][2] ) / det;
	  b[1][2] = ( a[0][2] * a[1][0] - a[0][0] * a[1][2] ) / det;
	  
	  b[2][0] = ( a[1][0] * a[2][1] - a[1][1] * a[2][0] ) / det;
	  b[2][1] = ( a[0][1] * a[2][0] - a[0][0] * a[2][1] ) / det;
	  b[2][2] = ( a[0][0] * a[1][1] - a[0][1] * a[1][0] ) / det;

	  /* tmp = dx * b  */

	  for (w=0; w<number; ++w)
	    {
	      tmp[w].x = d[w].x * b[0][0] + d[w].y * b[1][0] + d[w].z * b[2][0];
	      tmp[w].y = d[w].x * b[0][1] + d[w].y * b[1][1] + d[w].z * b[2][1];
	      tmp[w].z = d[w].x * b[0][2] + d[w].y * b[1][2] + d[w].z * b[2][2];
	    }

	  /* strain = (symmetrized) du * tmp  */

	  for (w=0; w<number; ++w)
	    {
	      p->strain[u].x += du[w].x * tmp[w].x;
	      p->strain[u].y += du[w].y * tmp[w].y;
	      p->strain[u].z += du[w].z * tmp[w].z;

	      p->strain_offdia[u].x += ( du[w].y * tmp[w].z + du[w].z * tmp[w].y ) / 2;
	      p->strain_offdia[u].y += ( du[w].x * tmp[w].z + du[w].z * tmp[w].x ) / 2;
	      p->strain_offdia[u].z += ( du[w].x * tmp[w].y + du[w].y * tmp[w].x ) / 2;
	    }
#endif	 /* Not TWOD */
	  
	} /* number > 2 */

		} /* u */

	    } /* First cell */

	  /* Statistics */
	  printf("Maximal number of neighbour atoms: %d\n", maxnumber);
	  printf("Minimal number of neighbour atoms: %d\n", minnumber);
	  printf("Average number of neighbour atoms: %f\n", (float) totalnumber/natoms );
	  if(emptynumber>0)
	    printf("Number of omitted atoms: %d (%.2f %%)\n", emptynumber, (float) emptynumber/natoms );

}
Exemple #4
0
void do_elco_eam(cell *p, cell *q, vektor pbc)
{
  int i, j, jstart;
  vektor tmp_d, d;
  int same_cell;
  int p_typ, q_typ, col1, col2;
  real r2, eam_energy, pref1, pref2, tmp;
  real f_i_strich, f_i_zweistrich, f_i_dreistrich;
  real f_j_strich, f_j_zweistrich, f_j_dreistrich;
  real rho_j_strich, rho_j_zweistrich, rho_j_dreistrich;
  real rho_i_strich, rho_i_zweistrich, rho_i_dreistrich;
  int is_short=0, inc=ntypes*ntypes;
  real xx, xy, yy, yz, zz, zx;

  /* for each atom in first cell */
  for (i=0; i<p->n; ++i) {

    tmp_d.x = p->ort[i].x - pbc.x;
    tmp_d.y = p->ort[i].y - pbc.y;
#ifndef TWOD
    tmp_d.z = p->ort[i].z - pbc.z;
#endif
    p_typ   = p->sorte[i];

#ifdef TWOD
    same_cell = ((p==q) && (pbc.x==0) && (pbc.y==0));
#else
    same_cell = ((p==q) && (pbc.x==0) && (pbc.y==0) && (pbc.z==0));
#endif

    if (same_cell) {
      PAIR_INT4(eam_energy, f_i_strich, f_i_zweistrich, f_i_dreistrich, 
	       embed_pot, p_typ, ntypes, EAM_RHO(p,i), is_short)

      epot += eam_energy;

      xx = p->eam_stress[i].xx;
      xy = p->eam_stress[i].xy;
      yy = p->eam_stress[i].yy;
#ifndef TWOD
      yz = p->eam_stress[i].yz;
      zz = p->eam_stress[i].zz;
      zx = p->eam_stress[i].zx;
#endif

      p->stress[i].xx += f_i_strich * xx;
      sigma.xx        += f_i_strich * xx;
      p->stress[i].xy += f_i_strich * xy;
      sigma.xy        += f_i_strich * xy;
      p->stress[i].yy += f_i_strich * yy;
      sigma.yy        += f_i_strich * yy;
#ifndef TWOD
      p->stress[i].yz += f_i_strich * yz;
      sigma.yz        += f_i_strich * yz;
      p->stress[i].zz += f_i_strich * zz;
      sigma.zz        += f_i_strich * zz;
      p->stress[i].zx += f_i_strich * zx;
      sigma.zx        += f_i_strich * zx;
#endif

      p->elco[i].c11  += f_i_zweistrich * xx * xx;
      c.c11           += f_i_zweistrich * xx * xx;
      p->elco[i].c12  += f_i_zweistrich * xx * yy;
      c.c12           += f_i_zweistrich * xx * yy;
      p->elco[i].c66  += f_i_zweistrich * xy * xy;
      c.c66           += f_i_zweistrich * xy * xy;
      p->elco[i].c22  += f_i_zweistrich * yy * yy;
      c.c22           += f_i_zweistrich * yy * yy;
#ifndef TWOD
      p->elco[i].c13  += f_i_zweistrich * xx * zz;
      c.c13           += f_i_zweistrich * xx * zz;
      p->elco[i].c55  += f_i_zweistrich * zx * zx;
      c.c55           += f_i_zweistrich * zx * zx;
      p->elco[i].c23  += f_i_zweistrich * yy * zz;
      c.c23           += f_i_zweistrich * yy * zz;
      p->elco[i].c44  += f_i_zweistrich * yz * yz;
      c.c44           += f_i_zweistrich * yz * yz;
      p->elco[i].c33  += f_i_zweistrich * zz * zz;
      c.c33           += f_i_zweistrich * zz * zz;
      p->elco[i].c45  += f_i_zweistrich * yz * zx;
      c.c45           += f_i_zweistrich * yz * zx;
      p->elco[i].c46  += f_i_zweistrich * yz * xy;
      c.c46           += f_i_zweistrich * yz * xy;
      p->elco[i].c25  += f_i_zweistrich * yy * zx;
      c.c25           += f_i_zweistrich * yy * zx;
      p->elco[i].c56  += f_i_zweistrich * zx * xy;
      c.c56           += f_i_zweistrich * zx * xy;
      p->elco[i].c14  += f_i_zweistrich * xx * yz;
      c.c14           += f_i_zweistrich * xx * yz;
      p->elco[i].c15  += f_i_zweistrich * xx * zx;
      c.c15           += f_i_zweistrich * xx * zx;
#endif
      p->elco[i].c16  += f_i_zweistrich * xx * xy;
      c.c16           += f_i_zweistrich * xx * xy;
      p->elco[i].c26  += f_i_zweistrich * yy * xy;
      c.c26           += f_i_zweistrich * yy * xy;
#ifndef TWOD
      p->elco[i].c24  += f_i_zweistrich * yy * yz;
      c.c24           += f_i_zweistrich * yy * yz;
      p->elco[i].c34  += f_i_zweistrich * zz * yz;
      c.c34           += f_i_zweistrich * zz * yz;
      p->elco[i].c35  += f_i_zweistrich * zz * zx;
      c.c35           += f_i_zweistrich * zz * zx;
      p->elco[i].c36  += f_i_zweistrich * zz * xy;
      c.c36           += f_i_zweistrich * zz * xy;
#endif
      press           += f_i_strich * p->eam_press[i];

      bulkm           += f_i_zweistrich * p->eam_press[i] * p->eam_press[i]
	                   + f_i_strich * p->eam_bulkm[i];

      dbulkm_dp       += f_i_dreistrich 
	                 * p->eam_press[i] * p->eam_press[i] * p->eam_press[i]
			   + 3.0 * f_i_zweistrich 
			     * p->eam_press[i] * p->eam_bulkm[i]
			       + f_i_strich * p->eam_dbulkm[i];
    } 
    else {      
      DERIV_FUNC(f_i_strich, f_i_zweistrich, f_i_dreistrich, 
		 embed_pot, p_typ, ntypes, EAM_RHO(p,i), is_short)
    }

    jstart = (same_cell ? i+1 : 0);

    /* for each atom in neighbouring cell */
    for (j=jstart; j<q->n; ++j) {

      /* calculate distance */ 
      d.x = q->ort[j].x - tmp_d.x;
      d.y = q->ort[j].y - tmp_d.y;
#ifndef TWOD
      d.z = q->ort[j].z - tmp_d.z;
#endif
      q_typ = q->sorte[j];
      r2    = SPROD(d,d);
      col1  = q_typ * ntypes + p_typ;
      col2  = p_typ * ntypes + q_typ;

      if ((r2 < rho_h_tab.end[col1]) || (r2 < rho_h_tab.end[col2])) {

        DERIV_FUNC(f_j_strich, f_j_zweistrich, f_j_dreistrich, 
		   embed_pot, q_typ, ntypes, EAM_RHO(q,j), is_short);

        DERIV_FUNC(rho_i_strich, rho_i_zweistrich, rho_i_dreistrich, 
		   rho_h_tab, col1, inc, r2, is_short);

        if ( col1 == col2 ) {
          rho_j_strich     = rho_i_strich;
          rho_j_zweistrich = rho_i_zweistrich;
	} else {

          DERIV_FUNC(rho_j_strich, rho_j_zweistrich, rho_j_dreistrich, 
		     rho_h_tab, col2, inc, r2, is_short);
	}

	pref1 = 2.0 * 
	  ( f_i_strich * rho_j_zweistrich + f_j_strich * rho_i_zweistrich );

	pref2 = f_i_strich * rho_j_strich + f_j_strich * rho_i_strich;

	tmp = d.x * d.x * d.x * d.x * pref1 + d.x * d.x * pref2;
	p->elco[i].c11 += tmp;
	q->elco[j].c11 += tmp;
	c.c11          += 2.0 * tmp;
	tmp = d.x * d.x * d.y * d.y * pref1;
	p->elco[i].c12 += tmp;
	q->elco[j].c12 += tmp;
	c.c12          += 2.0 * tmp;
	tmp += 0.5 * ( d.x * d.x + d.y * d.y ) * pref2;
	p->elco[i].c66 += tmp;
	q->elco[j].c66 += tmp;
	c.c66          += 2.0 * tmp;
	tmp = d.y * d.y * d.y * d.y * pref1 + d.y * d.y * pref2;
	p->elco[i].c22 += tmp;
	q->elco[j].c22 += tmp;
	c.c22          += 2.0 * tmp;
#ifndef TWOD
	tmp = d.x * d.x * d.z * d.z * pref1;
	p->elco[i].c13 += tmp;
	q->elco[j].c13 += tmp;
	c.c13          += 2.0 * tmp;
	tmp += 0.5 * ( d.x * d.x + d.z * d.z ) * pref2; 
	p->elco[i].c55 += tmp;
	q->elco[j].c55 += tmp;
	c.c55          += 2.0 * tmp;
	tmp = d.y * d.y * d.z * d.z * pref1;
	p->elco[i].c23 += tmp;
	q->elco[j].c23 += tmp;
	c.c23          += 2.0 * tmp;
	tmp += 0.5 * ( d.y * d.y + d.z * d.z ) * pref2; 
	p->elco[i].c44 += tmp;
	q->elco[j].c44 += tmp;
	c.c44          += 2.0 * tmp;
	tmp = d.z * d.z * d.z * d.z * pref1 + d.z * d.z * pref2;
	p->elco[i].c33 += tmp;
	q->elco[j].c33 += tmp;
	c.c33          += 2.0 * tmp;
	tmp = d.x * d.y * d.z * d.z * pref1 + 0.25 * d.x * d.y * pref2;
	p->elco[i].c45 += tmp;
	q->elco[j].c45 += tmp;
	c.c45          += 2.0 * tmp;
	tmp = d.x * d.y * d.y * d.z * pref1 + 0.25 * d.x * d.z * pref2;
	p->elco[i].c46 += tmp;
	q->elco[j].c46 += tmp;
	c.c46          += 2.0 * tmp;
	tmp -= 0.25 * d.x * d.z * pref2;
	p->elco[i].c25 += tmp;
	q->elco[j].c25 += tmp;
	c.c25          += 2.0 * tmp;
	tmp = d.x * d.x * d.y * d.z * pref1 + 0.25 * d.y * d.z * pref2;
	p->elco[i].c56 += tmp;
	q->elco[j].c56 += tmp;
	c.c56          += 2.0 * tmp;
	tmp -= 0.25 * d.y * d.z * pref2;
	p->elco[i].c14 += tmp;
	q->elco[j].c14 += tmp;
	c.c14          += 2.0 * tmp;
	tmp = d.x * d.x * d.x * d.z * pref1 + 0.5 * d.x * d.z * pref2;
	p->elco[i].c15 += tmp;
	q->elco[j].c15 += tmp;
	c.c15          += 2.0 * tmp;
#endif
	tmp = d.x * d.x * d.x * d.y * pref1 + 0.5 * d.x * d.y * pref2;
	p->elco[i].c16 += tmp;
	q->elco[j].c16 += tmp;
	c.c16          += 2.0 * tmp;
	tmp = d.x * d.y * d.y * d.y * pref1 + 0.5 * d.x * d.y * pref2;
	p->elco[i].c26 += tmp;
	q->elco[j].c26 += tmp;
	c.c26          += 2.0 * tmp;
#ifndef TWOD
	tmp = d.y * d.y * d.y * d.z * pref1 + 0.5 * d.y * d.z * pref2;
	p->elco[i].c24 += tmp;
	q->elco[j].c24 += tmp;
	c.c24          += 2.0 * tmp;
	tmp = d.y * d.z * d.z * d.z * pref1 + 0.5 * d.y * d.z * pref2;
	p->elco[i].c34 += tmp;
	q->elco[j].c34 += tmp;
	c.c34          += 2.0 * tmp;
	tmp = d.x * d.z * d.z * d.z * pref1 + 0.5 * d.x * d.z * pref2;
	p->elco[i].c35 += tmp;
	q->elco[j].c35 += tmp;
	c.c35          += 2.0 * tmp;
	tmp = d.x * d.y * d.z * d.z * pref1;
	p->elco[i].c36 += tmp;
	q->elco[j].c36 += tmp;
	c.c36          += 2.0 * tmp;
#endif
      }
    }
  }
}
Exemple #5
0
double calc_forces(double* xi_opt, double* forces, int flag)
{
  double tmpsum = 0.0;
  double sum = 0.0;
  int first = 0;
  int col = 0;
  int ne = 0;
  int size = 0;
  int i = flag;
  double* xi = NULL;
  apot_table_t* apt = &g_pot.apot_table;
  double charge[g_param.ntypes];
  double sum_charges;
  double dp_kappa;

#if defined(DIPOLE)
  double dp_alpha[g_param.ntypes];
  double dp_b[apt->number];
  double dp_c[apt->number];
#endif  // DIPOLE

  switch (g_pot.format_type) {
    case POTENTIAL_FORMAT_UNKNOWN:
      break;
    case POTENTIAL_FORMAT_ANALYTIC:
      xi = g_pot.calc_pot.table;
      break;
    case POTENTIAL_FORMAT_TABULATED_EQ_DIST:
    case POTENTIAL_FORMAT_TABULATED_NON_EQ_DIST:
      xi = xi_opt;
      break;
  }

  ne = g_pot.apot_table.total_ne_par;
  size = apt->number;

  /* This is the start of an infinite loop */
  while (1) {
    tmpsum = 0.0; /* sum of squares of local process */

#if defined(APOT) && !defined(MPI)
    if (g_pot.format_type == POTENTIAL_FORMAT_ANALYTIC) {
      apot_check_params(xi_opt);
      update_calc_table(xi_opt, xi, 0);
    }
#endif  // APOT && !MPI

#if defined(MPI)
/* exchange potential and flag value */
#if !defined(APOT)
    MPI_Bcast(xi, g_pot.calc_pot.len, MPI_DOUBLE, 0, MPI_COMM_WORLD);
#endif  // !APOT
    MPI_Bcast(&flag, 1, MPI_INT, 0, MPI_COMM_WORLD);

    if (flag == 1)
      break; /* Exception: flag 1 means clean up */

#if defined(APOT)
    if (g_mpi.myid == 0)
      apot_check_params(xi_opt);
    MPI_Bcast(xi_opt, g_calc.ndimtot, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    if (g_pot.format_type == POTENTIAL_FORMAT_ANALYTIC)
      update_calc_table(xi_opt, xi, 0);
#else   // APOT
    /* if flag==2 then the potential parameters have changed -> sync */
    if (flag == 2)
      potsync();
#endif  // APOT
#endif  // MPI

    /* local arrays for electrostatic parameters */
    sum_charges = 0;
    for (i = 0; i < g_param.ntypes - 1; i++) {
      if (xi_opt[2 * size + ne + i]) {
        charge[i] = xi_opt[2 * size + ne + i];
        sum_charges += apt->ratio[i] * charge[i];
      } else {
        charge[i] = 0.0;
      }
    }
    apt->last_charge = -sum_charges / apt->ratio[g_param.ntypes - 1];
    charge[g_param.ntypes - 1] = apt->last_charge;
    if (xi_opt[2 * size + ne + g_param.ntypes - 1]) {
      dp_kappa = xi_opt[2 * size + ne + g_param.ntypes - 1];
    } else {
      dp_kappa = 0.0;
    }

#if defined(DIPOLE)
    for (i = 0; i < g_param.ntypes; i++) {
      if (xi_opt[2 * size + ne + g_param.ntypes + i]) {
        dp_alpha[i] = xi_opt[2 * size + ne + g_param.ntypes + i];
      } else {
        dp_alpha[i] = 0.0;
      }
    }
    for (i = 0; i < size; i++) {
      if (xi_opt[2 * size + ne + 2 * g_param.ntypes + i]) {
        dp_b[i] = xi_opt[2 * size + ne + 2 * g_param.ntypes + i];
      } else {
        dp_b[i] = 0.0;
      }
      if (xi_opt[3 * size + ne + 2 * g_param.ntypes + i]) {
        dp_c[i] = xi_opt[3 * size + ne + 2 * g_param.ntypes + i];
      } else {
        dp_c[i] = 0.0;
      }
    }
#endif  // DIPOLE

    /* init second derivatives for splines */
    for (col = 0; col < g_calc.paircol; col++) {
      first = g_pot.calc_pot.first[col];
      switch (g_pot.format_type) {
        case POTENTIAL_FORMAT_UNKNOWN:
          error(1, "Unknown potential format detected! (%s:%d)\n", __FILE__,
                __LINE__);
        case POTENTIAL_FORMAT_ANALYTIC:
        case POTENTIAL_FORMAT_TABULATED_EQ_DIST: {
          spline_ed(g_pot.calc_pot.step[col], xi + first,
                    g_pot.calc_pot.last[col] - first + 1, *(xi + first - 2),
                    0.0, g_pot.calc_pot.d2tab + first);
          break;
        }
        case POTENTIAL_FORMAT_TABULATED_NON_EQ_DIST: {
          spline_ne(g_pot.calc_pot.xcoord + first, xi + first,
                    g_pot.calc_pot.last[col] - first + 1, *(xi + first - 2),
                    0.0, g_pot.calc_pot.d2tab + first);
        }
      }
    }

#if !defined(MPI)
    g_mpi.myconf = g_config.nconf;
#endif  // MPI

    /* region containing loop over configurations,
       also OMP-parallelized region */
    {
      int self;
      vector tmp_force;
      int h, j, type1, type2, uf;
#if defined(STRESS)
      int us, stresses;
#endif  // STRESS
      int n_i, n_j;
      double fnval, grad, fnval_tail, grad_tail, grad_i, grad_j;
#if defined(DIPOLE)
      double p_sr_tail;
#endif  // DIPOLE
      atom_t* atom;
      neigh_t* neigh;

      /* loop over configurations: M A I N LOOP CONTAINING ALL ATOM-LOOPS */
      for (h = g_mpi.firstconf; h < g_mpi.firstconf + g_mpi.myconf; h++) {
        uf = g_config.conf_uf[h - g_mpi.firstconf];
#if defined(STRESS)
        us = g_config.conf_us[h - g_mpi.firstconf];
#endif  // STRESS
        /* reset energies and stresses */
        forces[g_calc.energy_p + h] = 0.0;
#if defined(STRESS)
        stresses = g_calc.stress_p + 6 * h;
        for (i = 0; i < 6; i++)
          forces[stresses + i] = 0.0;
#endif  // STRESS

#if defined(DIPOLE)
        /* reset dipoles and fields: LOOP Z E R O */
        for (i = 0; i < g_config.inconf[h]; i++) {
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          atom->E_stat.x = 0.0;
          atom->E_stat.y = 0.0;
          atom->E_stat.z = 0.0;
          atom->p_sr.x = 0.0;
          atom->p_sr.y = 0.0;
          atom->p_sr.z = 0.0;
        }
#endif  // DIPOLE

        /* F I R S T LOOP OVER ATOMS: reset forces, dipoles */
        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          n_i = 3 * (g_config.cnfstart[h] + i);
          if (uf) {
            forces[n_i + 0] = -g_config.force_0[n_i + 0];
            forces[n_i + 1] = -g_config.force_0[n_i + 1];
            forces[n_i + 2] = -g_config.force_0[n_i + 2];
          } else {
            forces[n_i + 0] = 0.0;
            forces[n_i + 1] = 0.0;
            forces[n_i + 2] = 0.0;
          }
        } /* end F I R S T LOOP */

        /* S E C O N D loop: calculate short-range and monopole forces,
           calculate static field- and dipole-contributions */
        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          type1 = atom->type;
          n_i = 3 * (g_config.cnfstart[h] + i);
          for (j = 0; j < atom->num_neigh; j++) { /* neighbors */
            neigh = atom->neigh + j;
            type2 = neigh->type;
            col = neigh->col[0];

            /* updating tail-functions - only necessary with variing kappa */
            if (!apt->sw_kappa)
              elstat_shift(neigh->r, dp_kappa, &neigh->fnval_el,
                           &neigh->grad_el, &neigh->ggrad_el);

            /* In small cells, an atom might interact with itself */
            self = (neigh->nr == i + g_config.cnfstart[h]) ? 1 : 0;

            /* calculate short-range forces */
            if (neigh->r < g_pot.calc_pot.end[col]) {
              if (uf) {
                fnval = splint_comb_dir(&g_pot.calc_pot, xi, neigh->slot[0],
                                        neigh->shift[0], neigh->step[0], &grad);
              } else {
                fnval = splint_dir(&g_pot.calc_pot, xi, neigh->slot[0],
                                   neigh->shift[0], neigh->step[0]);
              }

              /* avoid double counting if atom is interacting with a
                 copy of itself */
              if (self) {
                fnval *= 0.5;
                grad *= 0.5;
              }
              forces[g_calc.energy_p + h] += fnval;

              if (uf) {
                tmp_force.x = neigh->dist_r.x * grad;
                tmp_force.y = neigh->dist_r.y * grad;
                tmp_force.z = neigh->dist_r.z * grad;
                forces[n_i + 0] += tmp_force.x;
                forces[n_i + 1] += tmp_force.y;
                forces[n_i + 2] += tmp_force.z;
                /* actio = reactio */
                n_j = 3 * neigh->nr;
                forces[n_j + 0] -= tmp_force.x;
                forces[n_j + 1] -= tmp_force.y;
                forces[n_j + 2] -= tmp_force.z;

#if defined(STRESS)
                /* calculate pair stresses */
                if (us) {
                  forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
                  forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
                  forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
                  forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
                  forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
                  forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
                }
#endif  // STRESS
              }
            }

            /* calculate monopole forces */
            if (neigh->r < g_config.dp_cut &&
                (charge[type1] || charge[type2])) {
              fnval_tail = neigh->fnval_el;
              grad_tail = neigh->grad_el;

              grad_i = charge[type2] * grad_tail;
              if (type1 == type2) {
                grad_j = grad_i;
              } else {
                grad_j = charge[type1] * grad_tail;
              }
              fnval = charge[type1] * charge[type2] * fnval_tail;
              grad = charge[type1] * grad_i;

              if (self) {
                grad_i *= 0.5;
                grad_j *= 0.5;
                fnval *= 0.5;
                grad *= 0.5;
              }

              forces[g_calc.energy_p + h] += fnval;

              if (uf) {
                tmp_force.x = neigh->dist.x * grad;
                tmp_force.y = neigh->dist.y * grad;
                tmp_force.z = neigh->dist.z * grad;
                forces[n_i + 0] += tmp_force.x;
                forces[n_i + 1] += tmp_force.y;
                forces[n_i + 2] += tmp_force.z;
                /* actio = reactio */
                n_j = 3 * neigh->nr;
                forces[n_j + 0] -= tmp_force.x;
                forces[n_j + 1] -= tmp_force.y;
                forces[n_j + 2] -= tmp_force.z;
#if defined(STRESS)
                /* calculate coulomb stresses */
                if (us) {
                  forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
                  forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
                  forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
                  forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
                  forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
                  forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
                }
#endif  // STRESS
              }
#if defined(DIPOLE)
              /* calculate static field-contributions */
              atom->E_stat.x += neigh->dist.x * grad_i;
              atom->E_stat.y += neigh->dist.y * grad_i;
              atom->E_stat.z += neigh->dist.z * grad_i;

              g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_stat.x -=
                  neigh->dist.x * grad_j;
              g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_stat.y -=
                  neigh->dist.y * grad_j;
              g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_stat.z -=
                  neigh->dist.z * grad_j;

              /* calculate short-range dipoles */
              if (dp_alpha[type1] && dp_b[col] && dp_c[col]) {
                p_sr_tail = grad_tail * neigh->r *
                            shortrange_value(neigh->r, dp_alpha[type1],
                                             dp_b[col], dp_c[col]);
                atom->p_sr.x += charge[type2] * neigh->dist_r.x * p_sr_tail;
                atom->p_sr.y += charge[type2] * neigh->dist_r.y * p_sr_tail;
                atom->p_sr.z += charge[type2] * neigh->dist_r.z * p_sr_tail;
              }
              if (dp_alpha[type2] && dp_b[col] && dp_c[col] && !self) {
                p_sr_tail = grad_tail * neigh->r *
                            shortrange_value(neigh->r, dp_alpha[type2],
                                             dp_b[col], dp_c[col]);
                g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_sr.x -=
                    charge[type1] * neigh->dist_r.x * p_sr_tail;
                g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_sr.y -=
                    charge[type1] * neigh->dist_r.y * p_sr_tail;
                g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_sr.z -=
                    charge[type1] * neigh->dist_r.z * p_sr_tail;
              }
#endif  // DIPOLE
            }

          } /* loop over neighbours */
        }   /* end S E C O N D loop over atoms */

#if defined(DIPOLE)
        /* T H I R D loop: calculate whole dipole moment for every atom */
        double rp, dp_sum;
        int dp_converged = 0, dp_it = 0;
        double max_diff = 10;

        while (dp_converged == 0) {
          dp_sum = 0;
          for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
            atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                   g_mpi.firstatom;
            type1 = atom->type;
            if (dp_alpha[type1]) {
              if (dp_it) {
                /* note: mixing parameter is different from that on in IMD */
                atom->E_tot.x = (1 - g_config.dp_mix) * atom->E_ind.x +
                                g_config.dp_mix * atom->E_old.x +
                                atom->E_stat.x;
                atom->E_tot.y = (1 - g_config.dp_mix) * atom->E_ind.y +
                                g_config.dp_mix * atom->E_old.y +
                                atom->E_stat.y;
                atom->E_tot.z = (1 - g_config.dp_mix) * atom->E_ind.z +
                                g_config.dp_mix * atom->E_old.z +
                                atom->E_stat.z;
              } else {
                atom->E_tot.x = atom->E_ind.x + atom->E_stat.x;
                atom->E_tot.y = atom->E_ind.y + atom->E_stat.y;
                atom->E_tot.z = atom->E_ind.z + atom->E_stat.z;
              }

              atom->p_ind.x = dp_alpha[type1] * atom->E_tot.x + atom->p_sr.x;
              atom->p_ind.y = dp_alpha[type1] * atom->E_tot.y + atom->p_sr.y;
              atom->p_ind.z = dp_alpha[type1] * atom->E_tot.z + atom->p_sr.z;

              atom->E_old.x = atom->E_ind.x;
              atom->E_old.y = atom->E_ind.y;
              atom->E_old.z = atom->E_ind.z;

              atom->E_ind.x = 0.0;
              atom->E_ind.y = 0.0;
              atom->E_ind.z = 0.0;
            }
          }

          for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
            atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                   g_mpi.firstatom;
            type1 = atom->type;
            for (j = 0; j < atom->num_neigh; j++) { /* neighbors */
              neigh = atom->neigh + j;
              type2 = neigh->type;
              col = neigh->col[0];
              /* In small cells, an atom might interact with itself */
              self = (neigh->nr == i + g_config.cnfstart[h]) ? 1 : 0;

              if (neigh->r < g_config.dp_cut && dp_alpha[type1] &&
                  dp_alpha[type2]) {
                rp = SPROD(
                    g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind,
                    neigh->dist_r);
                atom->E_ind.x +=
                    neigh->grad_el *
                    (3 * rp * neigh->dist_r.x -
                     g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.x);
                atom->E_ind.y +=
                    neigh->grad_el *
                    (3 * rp * neigh->dist_r.y -
                     g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.y);
                atom->E_ind.z +=
                    neigh->grad_el *
                    (3 * rp * neigh->dist_r.z -
                     g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.z);

                if (!self) {
                  rp = SPROD(atom->p_ind, neigh->dist_r);
                  g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_ind.x +=
                      neigh->grad_el *
                      (3 * rp * neigh->dist_r.x - atom->p_ind.x);
                  g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_ind.y +=
                      neigh->grad_el *
                      (3 * rp * neigh->dist_r.y - atom->p_ind.y);
                  g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_ind.z +=
                      neigh->grad_el *
                      (3 * rp * neigh->dist_r.z - atom->p_ind.z);
                }
              }
            }
          }

          for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
            atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                   g_mpi.firstatom;
            type1 = atom->type;
            if (dp_alpha[type1]) {
              dp_sum +=
                  dsquare(dp_alpha[type1] * (atom->E_old.x - atom->E_ind.x));
              dp_sum +=
                  dsquare(dp_alpha[type1] * (atom->E_old.y - atom->E_ind.y));
              dp_sum +=
                  dsquare(dp_alpha[type1] * (atom->E_old.z - atom->E_ind.z));
            }
          }

          dp_sum /= 3 * g_config.inconf[h];
          dp_sum = sqrt(dp_sum);

          if (dp_it) {
            if ((dp_sum > max_diff) || (dp_it > 50)) {
              dp_converged = 1;
              for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
                atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                       g_mpi.firstatom;
                type1 = atom->type;
                if (dp_alpha[type1]) {
                  atom->p_ind.x =
                      dp_alpha[type1] * atom->E_stat.x + atom->p_sr.x;
                  atom->p_ind.y =
                      dp_alpha[type1] * atom->E_stat.y + atom->p_sr.y;
                  atom->p_ind.z =
                      dp_alpha[type1] * atom->E_stat.z + atom->p_sr.z;
                  atom->E_ind.x = atom->E_stat.x;
                  atom->E_ind.y = atom->E_stat.y;
                  atom->E_ind.z = atom->E_stat.z;
                }
              }
            }
          }

          if (dp_sum < g_config.dp_tol)
            dp_converged = 1;

          dp_it++;
        } /* end T H I R D loop over atoms */

        /* F O U R T H  loop: calculate monopole-dipole and dipole-dipole forces
         */
        double rp_i, rp_j, pp_ij, tmp_1, tmp_2;
        double grad_1, grad_2, srval, srgrad, srval_tail, srgrad_tail,
            fnval_sum, grad_sum;
        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          type1 = atom->type;
          n_i = 3 * (g_config.cnfstart[h] + i);
          for (j = 0; j < atom->num_neigh; j++) { /* neighbors */
            neigh = atom->neigh + j;
            type2 = neigh->type;
            col = neigh->col[0];

            /* In small cells, an atom might interact with itself */
            self = (neigh->nr == i + g_config.cnfstart[h]) ? 1 : 0;
            if (neigh->r < g_config.dp_cut &&
                (dp_alpha[type1] || dp_alpha[type2])) {
              fnval_tail = -neigh->grad_el;
              grad_tail = -neigh->ggrad_el;

              if (dp_b[col] && dp_c[col]) {
                shortrange_term(neigh->r, dp_b[col], dp_c[col], &srval_tail,
                                &srgrad_tail);
                srval = fnval_tail * srval_tail;
                srgrad = fnval_tail * srgrad_tail + grad_tail * srval_tail;
              }

              if (self) {
                fnval_tail *= 0.5;
                grad_tail *= 0.5;
              }

              /* monopole-dipole contributions */
              if (charge[type1] && dp_alpha[type2]) {
                if (dp_b[col] && dp_c[col]) {
                  fnval_sum = fnval_tail + srval;
                  grad_sum = grad_tail + srgrad;
                } else {
                  fnval_sum = fnval_tail;
                  grad_sum = grad_tail;
                }

                rp_j = SPROD(
                    g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind,
                    neigh->dist_r);
                fnval = charge[type1] * rp_j * fnval_sum * neigh->r;
                grad_1 = charge[type1] * rp_j * grad_sum * neigh->r2;
                grad_2 = charge[type1] * fnval_sum;

                forces[g_calc.energy_p + h] -= fnval;

                if (uf) {
                  tmp_force.x =
                      neigh->dist_r.x * grad_1 +
                      g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.x *
                          grad_2;
                  tmp_force.y =
                      neigh->dist_r.y * grad_1 +
                      g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.y *
                          grad_2;
                  tmp_force.z =
                      neigh->dist_r.z * grad_1 +
                      g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.z *
                          grad_2;
                  forces[n_i + 0] -= tmp_force.x;
                  forces[n_i + 1] -= tmp_force.y;
                  forces[n_i + 2] -= tmp_force.z;
                  /* actio = reactio */
                  n_j = 3 * neigh->nr;
                  forces[n_j + 0] += tmp_force.x;
                  forces[n_j + 1] += tmp_force.y;
                  forces[n_j + 2] += tmp_force.z;
#if defined(STRESS)
                  /* calculate stresses */
                  if (us) {
                    forces[stresses + 0] += neigh->dist.x * tmp_force.x;
                    forces[stresses + 1] += neigh->dist.y * tmp_force.y;
                    forces[stresses + 2] += neigh->dist.z * tmp_force.z;
                    forces[stresses + 3] += neigh->dist.x * tmp_force.y;
                    forces[stresses + 4] += neigh->dist.y * tmp_force.z;
                    forces[stresses + 5] += neigh->dist.z * tmp_force.x;
                  }
#endif  // STRESS
                }
              }

              /* dipole-monopole contributions */
              if (dp_alpha[type1] && charge[type2]) {
                if (dp_b[col] && dp_c[col]) {
                  fnval_sum = fnval_tail + srval;
                  grad_sum = grad_tail + srgrad;
                } else {
                  fnval_sum = fnval_tail;
                  grad_sum = grad_tail;
                }

                rp_i = SPROD(atom->p_ind, neigh->dist_r);
                fnval = charge[type2] * rp_i * fnval_sum * neigh->r;
                grad_1 = charge[type2] * rp_i * grad_sum * neigh->r2;
                grad_2 = charge[type2] * fnval_sum;

                forces[g_calc.energy_p + h] += fnval;

                if (uf) {
                  tmp_force.x =
                      neigh->dist_r.x * grad_1 + atom->p_ind.x * grad_2;
                  tmp_force.y =
                      neigh->dist_r.y * grad_1 + atom->p_ind.y * grad_2;
                  tmp_force.z =
                      neigh->dist_r.z * grad_1 + atom->p_ind.z * grad_2;
                  forces[n_i + 0] += tmp_force.x;
                  forces[n_i + 1] += tmp_force.y;
                  forces[n_i + 2] += tmp_force.z;
                  /* actio = reactio */
                  n_j = 3 * neigh->nr;
                  forces[n_j + 0] -= tmp_force.x;
                  forces[n_j + 1] -= tmp_force.y;
                  forces[n_j + 2] -= tmp_force.z;
#if defined(STRESS)
                  /* calculate stresses */
                  if (us) {
                    forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
                    forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
                    forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
                    forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
                    forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
                    forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
                  }
#endif  // STRESS
                }
              }

              /* dipole-dipole contributions */
              if (dp_alpha[type1] && dp_alpha[type2]) {
                pp_ij = SPROD(
                    atom->p_ind,
                    g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind);
                tmp_1 = 3 * rp_i * rp_j;
                tmp_2 = 3 * fnval_tail / neigh->r2;

                fnval = -(tmp_1 - pp_ij) * fnval_tail;
                grad_1 = (tmp_1 - pp_ij) * grad_tail;
                grad_2 = 2 * rp_i * rp_j;

                forces[g_calc.energy_p + h] += fnval;

                if (uf) {
                  tmp_force.x =
                      grad_1 * neigh->dist.x -
                      tmp_2 *
                          (grad_2 * neigh->dist.x -
                           rp_i * neigh->r *
                               g_config.conf_atoms[neigh->nr - g_mpi.firstatom]
                                   .p_ind.x -
                           rp_j * neigh->r * atom->p_ind.x);
                  tmp_force.y =
                      grad_1 * neigh->dist.y -
                      tmp_2 *
                          (grad_2 * neigh->dist.y -
                           rp_i * neigh->r *
                               g_config.conf_atoms[neigh->nr - g_mpi.firstatom]
                                   .p_ind.y -
                           rp_j * neigh->r * atom->p_ind.y);
                  tmp_force.z =
                      grad_1 * neigh->dist.z -
                      tmp_2 *
                          (grad_2 * neigh->dist.z -
                           rp_i * neigh->r *
                               g_config.conf_atoms[neigh->nr - g_mpi.firstatom]
                                   .p_ind.z -
                           rp_j * neigh->r * atom->p_ind.z);
                  forces[n_i + 0] -= tmp_force.x;
                  forces[n_i + 1] -= tmp_force.y;
                  forces[n_i + 2] -= tmp_force.z;
                  /* actio = reactio */
                  n_j = 3 * neigh->nr;
                  forces[n_j + 0] += tmp_force.x;
                  forces[n_j + 1] += tmp_force.y;
                  forces[n_j + 2] += tmp_force.z;

#if defined(STRESS)
                  /* calculate stresses */
                  if (us) {
                    forces[stresses + 0] += neigh->dist.x * tmp_force.x;
                    forces[stresses + 1] += neigh->dist.y * tmp_force.y;
                    forces[stresses + 2] += neigh->dist.z * tmp_force.z;
                    forces[stresses + 3] += neigh->dist.x * tmp_force.y;
                    forces[stresses + 4] += neigh->dist.y * tmp_force.z;
                    forces[stresses + 5] += neigh->dist.z * tmp_force.x;
                  }
#endif  // STRESS
                }
              }
            }
          } /* loop over neighbours */
        }   /* end F O U R T H loop over atoms */
#endif      // DIPOLE

        /* F I F T H  loop: self energy contributions and sum-up force
         * contributions */
        double qq;
#if defined(DIPOLE)
        double pp;
#endif                                             // DIPOLE
        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          type1 = atom->type;
          n_i = 3 * (g_config.cnfstart[h] + i);

          /* self energy contributions */
          if (charge[type1]) {
            qq = charge[type1] * charge[type1];
            fnval = DP_EPS * dp_kappa * qq / sqrt(M_PI);
            forces[g_calc.energy_p + h] -= fnval;
          }
#if defined(DIPOLE)
          if (dp_alpha[type1]) {
            pp = SPROD(atom->p_ind, atom->p_ind);
            fnval = pp / (2 * dp_alpha[type1]);
            forces[g_calc.energy_p + h] += fnval;
          }
/* alternative dipole self energy including kappa-dependence */
// if (dp_alpha[type1]) {
// pp = SPROD(atom->p_ind, atom->p_ind);
// fnval = kkk * pp / sqrt(M_PI);
// forces[energy_p + h] += fnval;
//}
#endif  // DIPOLE

          /* sum-up: whole force contributions flow into tmpsum */
          if (uf) {
#if defined(FWEIGHT)
            /* Weigh by absolute value of force */
            forces[n_i + 0] /= FORCE_EPS + atom->absforce;
            forces[n_i + 1] /= FORCE_EPS + atom->absforce;
            forces[n_i + 2] /= FORCE_EPS + atom->absforce;
#endif  // FWEIGHT
#if defined(CONTRIB)
            if (atom->contrib)
#endif  // CONTRIB
              tmpsum += g_config.conf_weight[h] *
                        (dsquare(forces[n_i + 0]) + dsquare(forces[n_i + 1]) +
                         dsquare(forces[n_i + 2]));
          }
        } /* end F I F T H loop over atoms */

        /* whole energy contributions flow into tmpsum */
        forces[g_calc.energy_p + h] /= (double)g_config.inconf[h];
        forces[g_calc.energy_p + h] -= g_config.force_0[g_calc.energy_p + h];
        tmpsum += g_config.conf_weight[h] * g_param.eweight *
                  dsquare(forces[g_calc.energy_p + h]);

#if defined(STRESS)
        /* whole stress contributions flow into tmpsum */
        if (uf && us) {
          for (i = 0; i < 6; i++) {
            forces[stresses + i] /= g_config.conf_vol[h - g_mpi.firstconf];
            forces[stresses + i] -= g_config.force_0[stresses + i];
            tmpsum += g_config.conf_weight[h] * g_param.sweight *
                      dsquare(forces[stresses + i]);
          }
        }
#endif  // STRESS
      } /* end M A I N loop over configurations */
    }   /* parallel region */

/* dummy constraints (global) */
#if defined(APOT)
    /* add punishment for out of bounds (mostly for powell_lsq) */
    if (g_mpi.myid == 0) {
      tmpsum += apot_punish(xi_opt, forces);
    }
#endif  // APOT

#if defined(MPI)
    /* reduce global sum */
    sum = 0.0;
    MPI_Reduce(&tmpsum, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    /* gather forces, energies, stresses */
    if (g_mpi.myid == 0) { /* root node already has data in place */
      /* forces */
      MPI_Gatherv(MPI_IN_PLACE, g_mpi.myatoms, g_mpi.MPI_VECTOR, forces,
                  g_mpi.atom_len, g_mpi.atom_dist, g_mpi.MPI_VECTOR, 0,
                  MPI_COMM_WORLD);
      /* energies */
      MPI_Gatherv(MPI_IN_PLACE, g_mpi.myconf, MPI_DOUBLE,
                  forces + g_calc.energy_p, g_mpi.conf_len, g_mpi.conf_dist,
                  MPI_DOUBLE, 0, MPI_COMM_WORLD);
#if defined(STRESS)
      /* stresses */
      MPI_Gatherv(MPI_IN_PLACE, g_mpi.myconf, g_mpi.MPI_STENS,
                  forces + g_calc.stress_p, g_mpi.conf_len, g_mpi.conf_dist,
                  g_mpi.MPI_STENS, 0, MPI_COMM_WORLD);
#endif  // STRESS
    } else {
      /* forces */
      MPI_Gatherv(forces + g_mpi.firstatom * 3, g_mpi.myatoms, g_mpi.MPI_VECTOR,
                  forces, g_mpi.atom_len, g_mpi.atom_dist, g_mpi.MPI_VECTOR, 0,
                  MPI_COMM_WORLD);
      /* energies */
      MPI_Gatherv(forces + g_calc.energy_p + g_mpi.firstconf, g_mpi.myconf,
                  MPI_DOUBLE, forces + g_calc.energy_p, g_mpi.conf_len,
                  g_mpi.conf_dist, MPI_DOUBLE, 0, MPI_COMM_WORLD);
#if defined(STRESS)
      /* stresses */
      MPI_Gatherv(forces + g_calc.stress_p + 6 * g_mpi.firstconf, g_mpi.myconf,
                  g_mpi.MPI_STENS, forces + g_calc.stress_p, g_mpi.conf_len,
                  g_mpi.conf_dist, g_mpi.MPI_STENS, 0, MPI_COMM_WORLD);
#endif  // STRESS
    }
#else
    sum = tmpsum; /* global sum = local sum  */
#endif  // MPI

    /* root process exits this function now */
    if (g_mpi.myid == 0) {
      g_calc.fcalls++; /* Increase function call counter */
      if (isnan(sum)) {
#if defined(DEBUG)
        printf("\n--> Force is nan! <--\n\n");
#endif  // DEBUG
        return 10e10;
      } else
        return sum;
    }
  }

  /* once a non-root process arrives here, all is done. */
  return -1.0;
}
Exemple #6
0
double calc_forces_elstat(double *xi_opt, double *forces, int flag)
{
  double tmpsum, sum = 0.;
  int   first, col, ne, size, i;
  double *xi = NULL;
  apot_table_t *apt = &apot_table;
  double charge[ntypes];
  double sum_charges;
  double dp_kappa;

#ifdef DIPOLE
  double dp_alpha[ntypes];
  double dp_b[apt->number];
  double dp_c[apt->number];
#endif /* DIPOLE */

  switch (format) {
      case 0:
	xi = calc_pot.table;
	break;
      case 3:			/* fall through */
      case 4:
	xi = xi_opt;		/* calc-table is opt-table */
	break;
      case 5:
	xi = calc_pot.table;	/* we need to update the calc-table */
  }

  ne = apot_table.total_ne_par;
  size = apt->number;

  /* This is the start of an infinite loop */
  while (1) {
    tmpsum = 0.;		/* sum of squares of local process */

#if defined APOT && !defined MPI
    if (format == 0) {
      apot_check_params(xi_opt);
      update_calc_table(xi_opt, xi, 0);
    }
#endif /* APOT && !MPI */

#ifdef MPI
    /* exchange potential and flag value */
#ifndef APOT
    MPI_Bcast(xi, calc_pot.len, MPI_DOUBLE, 0, MPI_COMM_WORLD);
#endif /* APOT */
    MPI_Bcast(&flag, 1, MPI_INT, 0, MPI_COMM_WORLD);

    if (flag == 1)
      break;			/* Exception: flag 1 means clean up */

#ifdef APOT
    if (myid == 0)
      apot_check_params(xi_opt);
    MPI_Bcast(xi_opt, ndimtot, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    if (format == 0)
      update_calc_table(xi_opt, xi, 0);
#else /* APOT */
    /* if flag==2 then the potential parameters have changed -> sync */
    if (flag == 2)
      potsync();
#endif /* APOT */
#endif /* MPI */

    /* local arrays for electrostatic parameters */
    sum_charges = 0;
    for (i = 0; i < ntypes - 1; i++) {
      if (xi_opt[2 * size + ne + i]) {
	charge[i] = xi_opt[2 * size + ne + i];
	sum_charges += apt->ratio[i] * charge[i];
      } else {
	charge[i] = 0.;
      }
    }
    apt->last_charge = -sum_charges / apt->ratio[ntypes - 1];
    charge[ntypes - 1] = apt->last_charge;
    if (xi_opt[2 * size + ne + ntypes - 1]) {
      dp_kappa = xi_opt[2 * size + ne + ntypes - 1];
    } else {
      dp_kappa = 0.;
    }

#ifdef DIPOLE
    for (i = 0; i < ntypes; i++) {
      if (xi_opt[2 * size + ne + ntypes + i]) {
	dp_alpha[i] = xi_opt[2 * size + ne + ntypes + i];
      } else {
	dp_alpha[i] = 0.;
      }
    }
    for (i = 0; i < size; i++) {
      if (xi_opt[2 * size + ne + 2 * ntypes + i]) {
	dp_b[i] = xi_opt[2 * size + ne + 2 * ntypes + i];
      } else {
	dp_b[i] = 0.;
      }
      if (xi_opt[3 * size + ne + 2 * ntypes + i]) {
	dp_c[i] = xi_opt[3 * size + ne + 2 * ntypes + i];
      } else {
	dp_c[i] = 0.;
      }
    }
#endif /* DIPOLE */

    /* init second derivatives for splines */
    for (col = 0; col < paircol; col++) {
      first = calc_pot.first[col];
      if (format == 3 || format == 0) {
	spline_ed(calc_pot.step[col], xi + first,
	  calc_pot.last[col] - first + 1, *(xi + first - 2), 0.0, calc_pot.d2tab + first);
      } else {			/* format >= 4 ! */
	spline_ne(calc_pot.xcoord + first, xi + first,
	  calc_pot.last[col] - first + 1, *(xi + first - 2), 0.0, calc_pot.d2tab + first);
      }
    }

#ifndef MPI
    myconf = nconf;
#endif /* MPI */

    /* region containing loop over configurations,
       also OMP-parallelized region */
    {
      int   self;
      vector tmp_force;
      int   h, j, type1, type2, uf, us, stresses;
      int   n_i, n_j;
      double fnval, grad, fnval_tail, grad_tail, grad_i, grad_j;
#ifdef DIPOLE
      double p_sr_tail;
#endif /* DIPOLE */
      atom_t *atom;
      neigh_t *neigh;

      /* loop over configurations: M A I N LOOP CONTAINING ALL ATOM-LOOPS */
      for (h = firstconf; h < firstconf + myconf; h++) {
	uf = conf_uf[h - firstconf];
#ifdef STRESS
	us = conf_us[h - firstconf];
#endif /* STRESS */
	/* reset energies and stresses */
	forces[energy_p + h] = 0.0;
#ifdef STRESS
	stresses = stress_p + 6 * h;
	for (i = 0; i < 6; i++)
	  forces[stresses + i] = 0.0;
#endif /* STRESS */

#ifdef DIPOLE
	/* reset dipoles and fields: LOOP Z E R O */
	for (i = 0; i < inconf[h]; i++) {
	  atom = conf_atoms + i + cnfstart[h] - firstatom;
	  atom->E_stat.x = 0.0;
	  atom->E_stat.y = 0.0;
	  atom->E_stat.z = 0.0;
	  atom->p_sr.x = 0.0;
	  atom->p_sr.y = 0.0;
	  atom->p_sr.z = 0.0;
	}
#endif /* DIPOLE */

	/* F I R S T LOOP OVER ATOMS: reset forces, dipoles */
	for (i = 0; i < inconf[h]; i++) {	/* atoms */
	  n_i = 3 * (cnfstart[h] + i);
	  if (uf) {
	    forces[n_i + 0] = -force_0[n_i + 0];
	    forces[n_i + 1] = -force_0[n_i + 1];
	    forces[n_i + 2] = -force_0[n_i + 2];
	  } else {
	    forces[n_i + 0] = 0.0;
	    forces[n_i + 1] = 0.0;
	    forces[n_i + 2] = 0.0;
	  }
	}			/* end F I R S T LOOP */

	/* S E C O N D loop: calculate short-range and monopole forces,
	   calculate static field- and dipole-contributions */
	for (i = 0; i < inconf[h]; i++) {	/* atoms */
	  atom = conf_atoms + i + cnfstart[h] - firstatom;
	  type1 = atom->type;
	  n_i = 3 * (cnfstart[h] + i);
	  for (j = 0; j < atom->num_neigh; j++) {	/* neighbors */
	    neigh = atom->neigh + j;
	    type2 = neigh->type;
	    col = neigh->col[0];

	    /* updating tail-functions - only necessary with variing kappa */
	    if (!apt->sw_kappa)
	      elstat_shift(neigh->r, dp_kappa, &neigh->fnval_el, &neigh->grad_el, &neigh->ggrad_el);

	    /* In small cells, an atom might interact with itself */
	    self = (neigh->nr == i + cnfstart[h]) ? 1 : 0;

	    /* calculate short-range forces */
	    if (neigh->r < calc_pot.end[col]) {

	      if (uf) {
		fnval =
		  splint_comb_dir(&calc_pot, xi, neigh->slot[0], neigh->shift[0], neigh->step[0], &grad);
	      } else {
		fnval = splint_dir(&calc_pot, xi, neigh->slot[0], neigh->shift[0], neigh->step[0]);
	      }

	      /* avoid double counting if atom is interacting with a
	         copy of itself */
	      if (self) {
		fnval *= 0.5;
		grad *= 0.5;
	      }
	      forces[energy_p + h] += fnval;

	      if (uf) {
		tmp_force.x = neigh->dist_r.x * grad;
		tmp_force.y = neigh->dist_r.y * grad;
		tmp_force.z = neigh->dist_r.z * grad;
		forces[n_i + 0] += tmp_force.x;
		forces[n_i + 1] += tmp_force.y;
		forces[n_i + 2] += tmp_force.z;
		/* actio = reactio */
		n_j = 3 * neigh->nr;
		forces[n_j + 0] -= tmp_force.x;
		forces[n_j + 1] -= tmp_force.y;
		forces[n_j + 2] -= tmp_force.z;

#ifdef STRESS
		/* calculate pair stresses */
		if (us) {
		  forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
		  forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
		  forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
		  forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
		  forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
		  forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
		}
#endif /* STRESS */
	      }
	    }

	    /* calculate monopole forces */
	    if (neigh->r < dp_cut && (charge[type1] || charge[type2])) {

	      fnval_tail = neigh->fnval_el;
	      grad_tail = neigh->grad_el;

	      grad_i = charge[type2] * grad_tail;
	      if (type1 == type2) {
		grad_j = grad_i;
	      } else {
		grad_j = charge[type1] * grad_tail;
	      }
	      fnval = charge[type1] * charge[type2] * fnval_tail;
	      grad = charge[type1] * grad_i;

	      if (self) {
		grad_i *= 0.5;
		grad_j *= 0.5;
		fnval *= 0.5;
		grad *= 0.5;
	      }

	      forces[energy_p + h] += fnval;

	      if (uf) {
		tmp_force.x = neigh->dist.x * grad;
		tmp_force.y = neigh->dist.y * grad;
		tmp_force.z = neigh->dist.z * grad;
		forces[n_i + 0] += tmp_force.x;
		forces[n_i + 1] += tmp_force.y;
		forces[n_i + 2] += tmp_force.z;
		/* actio = reactio */
		n_j = 3 * neigh->nr;
		forces[n_j + 0] -= tmp_force.x;
		forces[n_j + 1] -= tmp_force.y;
		forces[n_j + 2] -= tmp_force.z;
#ifdef STRESS
		/* calculate coulomb stresses */
		if (us) {
		  forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
		  forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
		  forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
		  forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
		  forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
		  forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
		}
#endif /* STRESS */
	      }
#ifdef DIPOLE
	      /* calculate static field-contributions */
	      atom->E_stat.x += neigh->dist.x * grad_i;
	      atom->E_stat.y += neigh->dist.y * grad_i;
	      atom->E_stat.z += neigh->dist.z * grad_i;

	      conf_atoms[neigh->nr - firstatom].E_stat.x -= neigh->dist.x * grad_j;
	      conf_atoms[neigh->nr - firstatom].E_stat.y -= neigh->dist.y * grad_j;
	      conf_atoms[neigh->nr - firstatom].E_stat.z -= neigh->dist.z * grad_j;

	      /* calculate short-range dipoles */
	      if (dp_alpha[type1] && dp_b[col] && dp_c[col]) {
		p_sr_tail =
		  grad_tail * neigh->r * shortrange_value(neigh->r, dp_alpha[type1], dp_b[col], dp_c[col]);
		atom->p_sr.x += charge[type2] * neigh->dist_r.x * p_sr_tail;
		atom->p_sr.y += charge[type2] * neigh->dist_r.y * p_sr_tail;
		atom->p_sr.z += charge[type2] * neigh->dist_r.z * p_sr_tail;
	      }
	      if (dp_alpha[type2] && dp_b[col] && dp_c[col] && !self) {
		p_sr_tail =
		  grad_tail * neigh->r * shortrange_value(neigh->r, dp_alpha[type2], dp_b[col], dp_c[col]);
		conf_atoms[neigh->nr - firstatom].p_sr.x -= charge[type1] * neigh->dist_r.x * p_sr_tail;
		conf_atoms[neigh->nr - firstatom].p_sr.y -= charge[type1] * neigh->dist_r.y * p_sr_tail;
		conf_atoms[neigh->nr - firstatom].p_sr.z -= charge[type1] * neigh->dist_r.z * p_sr_tail;
	      }
#endif /* DIPOLE */

	    }

	  }			/* loop over neighbours */
	}			/* end S E C O N D loop over atoms */

#ifdef DIPOLE
	/* T H I R D loop: calculate whole dipole moment for every atom */
	double rp, dp_sum;
	int   dp_converged = 0, dp_it = 0;
	double max_diff = 10;

	while (dp_converged == 0) {
	  dp_sum = 0;
	  for (i = 0; i < inconf[h]; i++) {	/* atoms */
	    atom = conf_atoms + i + cnfstart[h] - firstatom;
	    type1 = atom->type;
	    if (dp_alpha[type1]) {

	      if (dp_it) {
		/* note: mixing parameter is different from that on in IMD */
		atom->E_tot.x = (1 - dp_mix) * atom->E_ind.x + dp_mix * atom->E_old.x + atom->E_stat.x;
		atom->E_tot.y = (1 - dp_mix) * atom->E_ind.y + dp_mix * atom->E_old.y + atom->E_stat.y;
		atom->E_tot.z = (1 - dp_mix) * atom->E_ind.z + dp_mix * atom->E_old.z + atom->E_stat.z;
	      } else {
		atom->E_tot.x = atom->E_ind.x + atom->E_stat.x;
		atom->E_tot.y = atom->E_ind.y + atom->E_stat.y;
		atom->E_tot.z = atom->E_ind.z + atom->E_stat.z;
	      }

	      atom->p_ind.x = dp_alpha[type1] * atom->E_tot.x + atom->p_sr.x;
	      atom->p_ind.y = dp_alpha[type1] * atom->E_tot.y + atom->p_sr.y;
	      atom->p_ind.z = dp_alpha[type1] * atom->E_tot.z + atom->p_sr.z;

	      atom->E_old.x = atom->E_ind.x;
	      atom->E_old.y = atom->E_ind.y;
	      atom->E_old.z = atom->E_ind.z;

	      atom->E_ind.x = 0.;
	      atom->E_ind.y = 0.;
	      atom->E_ind.z = 0.;
	    }
	  }

	  for (i = 0; i < inconf[h]; i++) {	/* atoms */
	    atom = conf_atoms + i + cnfstart[h] - firstatom;
	    type1 = atom->type;
	    for (j = 0; j < atom->num_neigh; j++) {	/* neighbors */
	      neigh = atom->neigh + j;
	      type2 = neigh->type;
	      col = neigh->col[0];
	      /* In small cells, an atom might interact with itself */
	      self = (neigh->nr == i + cnfstart[h]) ? 1 : 0;

	      if (neigh->r < dp_cut && dp_alpha[type1] && dp_alpha[type2]) {

		rp = SPROD(conf_atoms[neigh->nr - firstatom].p_ind, neigh->dist_r);
		atom->E_ind.x +=
		  neigh->grad_el * (3 * rp * neigh->dist_r.x - conf_atoms[neigh->nr - firstatom].p_ind.x);
		atom->E_ind.y +=
		  neigh->grad_el * (3 * rp * neigh->dist_r.y - conf_atoms[neigh->nr - firstatom].p_ind.y);
		atom->E_ind.z +=
		  neigh->grad_el * (3 * rp * neigh->dist_r.z - conf_atoms[neigh->nr - firstatom].p_ind.z);

		if (!self) {
		  rp = SPROD(atom->p_ind, neigh->dist_r);
		  conf_atoms[neigh->nr - firstatom].E_ind.x +=
		    neigh->grad_el * (3 * rp * neigh->dist_r.x - atom->p_ind.x);
		  conf_atoms[neigh->nr - firstatom].E_ind.y +=
		    neigh->grad_el * (3 * rp * neigh->dist_r.y - atom->p_ind.y);
		  conf_atoms[neigh->nr - firstatom].E_ind.z +=
		    neigh->grad_el * (3 * rp * neigh->dist_r.z - atom->p_ind.z);
		}
	      }
	    }
	  }

	  for (i = 0; i < inconf[h]; i++) {	/* atoms */
	    atom = conf_atoms + i + cnfstart[h] - firstatom;
	    type1 = atom->type;
	    if (dp_alpha[type1]) {
	      dp_sum += dsquare(dp_alpha[type1] * (atom->E_old.x - atom->E_ind.x));
	      dp_sum += dsquare(dp_alpha[type1] * (atom->E_old.y - atom->E_ind.y));
	      dp_sum += dsquare(dp_alpha[type1] * (atom->E_old.z - atom->E_ind.z));
	    }
	  }

	  dp_sum /= 3 * inconf[h];
	  dp_sum = sqrt(dp_sum);

	  if (dp_it) {
	    if ((dp_sum > max_diff) || (dp_it > 50)) {
	      dp_converged = 1;
	      for (i = 0; i < inconf[h]; i++) {	/* atoms */
		atom = conf_atoms + i + cnfstart[h] - firstatom;
		type1 = atom->type;
		if (dp_alpha[type1]) {
		  atom->p_ind.x = dp_alpha[type1] * atom->E_stat.x + atom->p_sr.x;
		  atom->p_ind.y = dp_alpha[type1] * atom->E_stat.y + atom->p_sr.y;
		  atom->p_ind.z = dp_alpha[type1] * atom->E_stat.z + atom->p_sr.z;
		  atom->E_ind.x = atom->E_stat.x;
		  atom->E_ind.y = atom->E_stat.y;
		  atom->E_ind.z = atom->E_stat.z;
		}
	      }
	    }
	  }

	  if (dp_sum < dp_tol) {
	    dp_converged = 1;
	  }

	  dp_it++;
	}			/* end T H I R D loop over atoms */


	/* F O U R T H  loop: calculate monopole-dipole and dipole-dipole forces */
	double rp_i, rp_j, pp_ij, tmp_1, tmp_2;
	double grad_1, grad_2, srval, srgrad, srval_tail, srgrad_tail, fnval_sum, grad_sum;
	for (i = 0; i < inconf[h]; i++) {	/* atoms */
	  atom = conf_atoms + i + cnfstart[h] - firstatom;
	  type1 = atom->type;
	  n_i = 3 * (cnfstart[h] + i);
	  for (j = 0; j < atom->num_neigh; j++) {	/* neighbors */
	    neigh = atom->neigh + j;
	    type2 = neigh->type;
	    col = neigh->col[0];

	    /* In small cells, an atom might interact with itself */
	    self = (neigh->nr == i + cnfstart[h]) ? 1 : 0;
	    if (neigh->r < dp_cut && (dp_alpha[type1] || dp_alpha[type2])) {

	      fnval_tail = -neigh->grad_el;
	      grad_tail = -neigh->ggrad_el;

	      if (dp_b[col] && dp_c[col]) {
		shortrange_term(neigh->r, dp_b[col], dp_c[col], &srval_tail, &srgrad_tail);
		srval = fnval_tail * srval_tail;
		srgrad = fnval_tail * srgrad_tail + grad_tail * srval_tail;
	      }

	      if (self) {
		fnval_tail *= 0.5;
		grad_tail *= 0.5;
	      }

	      /* monopole-dipole contributions */
	      if (charge[type1] && dp_alpha[type2]) {

		if (dp_b[col] && dp_c[col]) {
		  fnval_sum = fnval_tail + srval;
		  grad_sum = grad_tail + srgrad;
		} else {
		  fnval_sum = fnval_tail;
		  grad_sum = grad_tail;
		}

		rp_j = SPROD(conf_atoms[neigh->nr - firstatom].p_ind, neigh->dist_r);
		fnval = charge[type1] * rp_j * fnval_sum * neigh->r;
		grad_1 = charge[type1] * rp_j * grad_sum * neigh->r2;
		grad_2 = charge[type1] * fnval_sum;

		forces[energy_p + h] -= fnval;

		if (uf) {
		  tmp_force.x = neigh->dist_r.x * grad_1 + conf_atoms[neigh->nr - firstatom].p_ind.x * grad_2;
		  tmp_force.y = neigh->dist_r.y * grad_1 + conf_atoms[neigh->nr - firstatom].p_ind.y * grad_2;
		  tmp_force.z = neigh->dist_r.z * grad_1 + conf_atoms[neigh->nr - firstatom].p_ind.z * grad_2;
		  forces[n_i + 0] -= tmp_force.x;
		  forces[n_i + 1] -= tmp_force.y;
		  forces[n_i + 2] -= tmp_force.z;
		  /* actio = reactio */
		  n_j = 3 * neigh->nr;
		  forces[n_j + 0] += tmp_force.x;
		  forces[n_j + 1] += tmp_force.y;
		  forces[n_j + 2] += tmp_force.z;
#ifdef STRESS
		  /* calculate stresses */
		  if (us) {
		    forces[stresses + 0] += neigh->dist.x * tmp_force.x;
		    forces[stresses + 1] += neigh->dist.y * tmp_force.y;
		    forces[stresses + 2] += neigh->dist.z * tmp_force.z;
		    forces[stresses + 3] += neigh->dist.x * tmp_force.y;
		    forces[stresses + 4] += neigh->dist.y * tmp_force.z;
		    forces[stresses + 5] += neigh->dist.z * tmp_force.x;
		  }
#endif /* STRESS */
		}
	      }

	      /* dipole-monopole contributions */
	      if (dp_alpha[type2] && charge[type2]) {

		if (dp_b[col] && dp_c[col]) {
		  fnval_sum = fnval_tail + srval;
		  grad_sum = grad_tail + srgrad;
		} else {
		  fnval_sum = fnval_tail;
		  grad_sum = grad_tail;
		}

		rp_i = SPROD(atom->p_ind, neigh->dist_r);
		fnval = charge[type2] * rp_i * fnval_sum * neigh->r;
		grad_1 = charge[type2] * rp_i * grad_sum * neigh->r2;
		grad_2 = charge[type2] * fnval_sum;

		forces[energy_p + h] += fnval;

		if (uf) {
		  tmp_force.x = neigh->dist_r.x * grad_1 + atom->p_ind.x * grad_2;
		  tmp_force.y = neigh->dist_r.y * grad_1 + atom->p_ind.y * grad_2;
		  tmp_force.z = neigh->dist_r.z * grad_1 + atom->p_ind.z * grad_2;
		  forces[n_i + 0] += tmp_force.x;
		  forces[n_i + 1] += tmp_force.y;
		  forces[n_i + 2] += tmp_force.z;
		  /* actio = reactio */
		  n_j = 3 * neigh->nr;
		  forces[n_j + 0] -= tmp_force.x;
		  forces[n_j + 1] -= tmp_force.y;
		  forces[n_j + 2] -= tmp_force.z;
#ifdef STRESS
		  /* calculate stresses */
		  if (us) {
		    forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
		    forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
		    forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
		    forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
		    forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
		    forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
		  }
#endif /* STRESS */
		}
	      }


	      /* dipole-dipole contributions */
	      if (dp_alpha[type1] && dp_alpha[type2]) {

		pp_ij = SPROD(atom->p_ind, conf_atoms[neigh->nr - firstatom].p_ind);
		tmp_1 = 3 * rp_i * rp_j;
		tmp_2 = 3 * fnval_tail / neigh->r2;

		fnval = -(tmp_1 - pp_ij) * fnval_tail;
		grad_1 = (tmp_1 - pp_ij) * grad_tail;
		grad_2 = 2 * rp_i * rp_j;

		forces[energy_p + h] += fnval;

		if (uf) {
		  tmp_force.x =
		    grad_1 * neigh->dist.x -
		    tmp_2 * (grad_2 * neigh->dist.x -
		    rp_i * neigh->r * conf_atoms[neigh->nr - firstatom].p_ind.x -
		    rp_j * neigh->r * atom->p_ind.x);
		  tmp_force.y =
		    grad_1 * neigh->dist.y - tmp_2 * (grad_2 * neigh->dist.y -
		    rp_i * neigh->r * conf_atoms[neigh->nr - firstatom].p_ind.y -
		    rp_j * neigh->r * atom->p_ind.y);
		  tmp_force.z =
		    grad_1 * neigh->dist.z - tmp_2 * (grad_2 * neigh->dist.z -
		    rp_i * neigh->r * conf_atoms[neigh->nr - firstatom].p_ind.z -
		    rp_j * neigh->r * atom->p_ind.z);
		  forces[n_i + 0] -= tmp_force.x;
		  forces[n_i + 1] -= tmp_force.y;
		  forces[n_i + 2] -= tmp_force.z;
		  /* actio = reactio */
		  n_j = 3 * neigh->nr;
		  forces[n_j + 0] += tmp_force.x;
		  forces[n_j + 1] += tmp_force.y;
		  forces[n_j + 2] += tmp_force.z;

#ifdef STRESS
		  /* calculate stresses */
		  if (us) {
		    forces[stresses + 0] += neigh->dist.x * tmp_force.x;
		    forces[stresses + 1] += neigh->dist.y * tmp_force.y;
		    forces[stresses + 2] += neigh->dist.z * tmp_force.z;
		    forces[stresses + 3] += neigh->dist.x * tmp_force.y;
		    forces[stresses + 4] += neigh->dist.y * tmp_force.z;
		    forces[stresses + 5] += neigh->dist.z * tmp_force.x;
		  }
#endif /* STRESS */
		}
	      }
	    }
	  }			/* loop over neighbours */
	}			/* end F O U R T H loop over atoms */
#endif /* DIPOLE */


	/* F I F T H  loop: self energy contributions and sum-up force contributions */
	double qq;
#ifdef DIPOLE
	double pp;
#endif /* DIPOLE */
	for (i = 0; i < inconf[h]; i++) {	/* atoms */
	  atom = conf_atoms + i + cnfstart[h] - firstatom;
	  type1 = atom->type;
	  n_i = 3 * (cnfstart[h] + i);

	  /* self energy contributions */
	  if (charge[type1]) {
	    qq = charge[type1] * charge[type1];
	    fnval = dp_eps * dp_kappa * qq / sqrt(M_PI);
	    forces[energy_p + h] -= fnval;
	  }
#ifdef DIPOLE
	  if (dp_alpha[type1]) {
	    pp = SPROD(atom->p_ind, atom->p_ind);
	    fnval = pp / (2 * dp_alpha[type1]);
	    forces[energy_p + h] += fnval;
	  }
	  /* alternative dipole self energy including kappa-dependence */
	  //if (dp_alpha[type1]) {
	  // pp = SPROD(atom->p_ind, atom->p_ind);
	  // fnval = kkk * pp / sqrt(M_PI);
	  // forces[energy_p + h] += fnval;
	  //}
#endif /* DIPOLE */


	  /* sum-up: whole force contributions flow into tmpsum */
	  if (uf) {
#ifdef FWEIGHT
	    /* Weigh by absolute value of force */
	    forces[n_i + 0] /= FORCE_EPS + atom->absforce;
	    forces[n_i + 1] /= FORCE_EPS + atom->absforce;
	    forces[n_i + 2] /= FORCE_EPS + atom->absforce;
#endif /* FWEIGHT */
#ifdef CONTRIB
	    if (atom->contrib)
#endif /* CONTRIB */
	      tmpsum +=
		conf_weight[h] * (dsquare(forces[n_i + 0]) + dsquare(forces[n_i + 1]) + dsquare(forces[n_i +
		    2]));
	  }
	}			/* end F I F T H loop over atoms */


	/* whole energy contributions flow into tmpsum */
	forces[energy_p + h] /= (double)inconf[h];
	forces[energy_p + h] -= force_0[energy_p + h];
	tmpsum += conf_weight[h] * eweight * dsquare(forces[energy_p + h]);

#ifdef STRESS
	/* whole stress contributions flow into tmpsum */
	if (uf && us) {
	  for (i = 0; i < 6; i++) {
	    forces[stresses + i] /= conf_vol[h - firstconf];
	    forces[stresses + i] -= force_0[stresses + i];
	    tmpsum += conf_weight[h] * sweight * dsquare(forces[stresses + i]);
	  }
	}
#endif /* STRESS */
      }				/* end M A I N loop over configurations */
    }				/* parallel region */

    /* dummy constraints (global) */
#ifdef APOT
    /* add punishment for out of bounds (mostly for powell_lsq) */
    if (myid == 0) {
      tmpsum += apot_punish(xi_opt, forces);
    }
#endif /* APOT */

    sum = tmpsum;		/* global sum = local sum  */

#ifdef MPI
    /* reduce global sum */
    sum = 0.;
    MPI_Reduce(&tmpsum, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    /* gather forces, energies, stresses */
    if (myid == 0) {		/* root node already has data in place */
      /* forces */
      MPI_Gatherv(MPI_IN_PLACE, myatoms, MPI_VECTOR, forces, atom_len,
	atom_dist, MPI_VECTOR, 0, MPI_COMM_WORLD);
      /* energies */
      MPI_Gatherv(MPI_IN_PLACE, myconf, MPI_DOUBLE, forces + natoms * 3,
	conf_len, conf_dist, MPI_DOUBLE, 0, MPI_COMM_WORLD);
      /* stresses */
      MPI_Gatherv(MPI_IN_PLACE, myconf, MPI_STENS, forces + natoms * 3 + nconf,
	conf_len, conf_dist, MPI_STENS, 0, MPI_COMM_WORLD);
    } else {
      /* forces */
      MPI_Gatherv(forces + firstatom * 3, myatoms, MPI_VECTOR, forces, atom_len,
	atom_dist, MPI_VECTOR, 0, MPI_COMM_WORLD);
      /* energies */
      MPI_Gatherv(forces + natoms * 3 + firstconf, myconf, MPI_DOUBLE,
	forces + natoms * 3, conf_len, conf_dist, MPI_DOUBLE, 0, MPI_COMM_WORLD);
      /* stresses */
      MPI_Gatherv(forces + natoms * 3 + nconf + 6 * firstconf, myconf, MPI_STENS,
	forces + natoms * 3 + nconf, conf_len, conf_dist, MPI_STENS, 0, MPI_COMM_WORLD);
    }
#endif /* MPI */

    /* root process exits this function now */
    if (myid == 0) {
      fcalls++;			/* Increase function call counter */
      if (isnan(sum)) {
#ifdef DEBUG
	printf("\n--> Force is nan! <--\n\n");
#endif /* DEBUG */
	return 10e10;
      } else
	return sum;
    }

  }

  /* once a non-root process arrives here, all is done. */
  return -1.;
}
Exemple #7
0
void calc_forces_neb(void)
{
  real dl2=0.0, dr2=0.0, drl=0.0, d2=0.0, f2=0.0, f2max=0.0, drlmax=0.0,df=0.0;
  real tmp,tmp1,tmp2, cosphi, fphi, src[3], dest[3], *d=pos;
  real kr,kl;
  int k, i;
  int var_k=0;
 
  int myimage,maximage;
  real V_previous, V_actual, V_next;
  real deltaVmin,deltaVmax;
  real normdr,normdl,inormd;
  real Eref,Emax,Emin,delta_E;
  real ratio_plus,ratio_minus,abs_next,abs_previous ;
  real k_sum, k_diff,tmpl,tmpr;
  real tmp_neb_ks[NEB_MAXNREP] INIT(zero100);
  real felastfact=0.0;

  myimage = myrank;

  /* get info about the energies of the different images */
  neb_image_energies[ myimage]=tot_pot_energy;
  MPI_Allreduce(neb_image_energies , neb_epot_im, NEB_MAXNREP, REAL, MPI_SUM, MPI_COMM_WORLD);
  Emax=-999999999999999;
  Emin=999999999999999;
  for(i=0;i<neb_nrep;i++)
    {
      if(neb_epot_im[i]>=Emax)
	{
	  Emax=neb_epot_im[i];
	  maximage=i;
	}
      if(neb_epot_im[i]<=Emin)
	{
	  Emin=neb_epot_im[i];
	}
    }
  if(steps == neb_cineb_start)
    {
      if(neb_climbing_image > 0)
	{
	  if(myrank==0)
	    {
	      if( neb_climbing_image == maximage)
		printf("Starting climbing image = %d (= max_Epot = %lf)\n",neb_climbing_image, Emax);
	      else
		printf("Starting climbing image = %d \n WARNING: %d != %d with max_Epot = %lf)\n", \
		       neb_climbing_image,neb_climbing_image,maximage, Emax);
	    }
	}
      else
	{
	  neb_climbing_image = maximage;
	  if(myrank==0)
	    {
	      printf("Starting climbing image, image set to %d (= max_Epot = %lf)\n",maximage, Emax);
	    }
	}

    }

  /* determine variable spring constants (jcp113 p. 9901) */

  tmp_neb_ks[myimage]=0;

  if(myrank != 0 && myrank != neb_nrep-1)
  { 

    V_previous = neb_epot_im[myimage-1];
    V_actual   = neb_epot_im[myimage];
    V_next     = neb_epot_im[myimage+1];	

    if ( neb_kmax > 0 & neb_kmin >0 &&  steps > neb_vark_start)
      {
	var_k=1;
	k_sum  = neb_kmax + neb_kmin;
	k_diff = neb_kmax - neb_kmin;    
	delta_E = Emax - Emin;
	if (delta_E > 1.0e-12)
	  {
	    tmp_neb_ks[myimage] = 0.5 *(k_sum - k_diff * cos(3.141592653589793238*( neb_epot_im[myimage] - Emin )/delta_E ));
	  }
      }
    else
      {
	tmp_neb_ks[myimage] = neb_k;
      }
  }
  MPI_Allreduce(tmp_neb_ks , neb_ks, NEB_MAXNREP, REAL, MPI_SUM, MPI_COMM_WORLD); 

  /* exchange positions with neighbor replicas */
  neb_sendrecv_pos();
   
  /* determine tangent vector and the elastic spring force */
  if(myrank != 0 && myrank != neb_nrep-1)
  { 
      dl2=0.0;d2=0.0;dr2=0.0;
      
      kr = 0.5 * (neb_ks[myimage]+neb_ks[myimage+1]);
      kl = 0.5 * (neb_ks[myimage]+neb_ks[myimage-1]);

      /* preparation: calculate distance to left and right immage */
       for (i=0; i<DIM*natoms; i+=DIM) {
	 vektor dr,dl;	
	 real x;
	 dl.x = pos  [i  ] - pos_l[i  ];
	 dl.y = pos  [i+1] - pos_l[i+1];
	 dl.z = pos  [i+2] - pos_l[i+2];
	 dr.x = pos_r[i  ] - pos  [i  ];
	 dr.y = pos_r[i+1] - pos  [i+1];
	 dr.z = pos_r[i+2] - pos  [i+2];
	 
	    /* apply periodic boundary conditions */
	 if (1==pbc_dirs.x) {
	   x = - round( SPROD(dl,tbox_x) );
	   dl.x += x * box_x.x;
	   dl.y += x * box_x.y;
	   dl.z += x * box_x.z;
	   x = - round( SPROD(dr,tbox_x) );
	   dr.x += x * box_x.x;
	   dr.y += x * box_x.y;
	   dr.z += x * box_x.z;
	 }
	 if (1==pbc_dirs.y) {
	   x = - round( SPROD(dl,tbox_y) );
	   dl.x += x * box_y.x;
	   dl.y += x * box_y.y;
	   dl.z += x * box_y.z;
	   x = - round( SPROD(dr,tbox_y) );
	   dr.x += x * box_y.x;
	   dr.y += x * box_y.y;
	   dr.z += x * box_y.z;
	 }
	 if (1==pbc_dirs.z) {
	   x = - round( SPROD(dl,tbox_z) );
	   dl.x += x * box_z.x;
	   dl.y += x * box_z.y;
	   dl.z += x * box_z.z;
	   x = - round( SPROD(dr,tbox_z) );
	   dr.x += x * box_z.x;
	   dr.y += x * box_z.y;
	   dr.z += x * box_z.z;
	 }
	 dRleft[i  ] = dl.x; 
	 dRleft[i+1] = dl.y; 
	 dRleft[i+2] = dl.z; 
	 dRright[i  ] = dr.x; 
	 dRright[i+1] = dr.y; 
	 dRright[i+2] = dr.z; 
 	    
       }

      /* computation of the tangent requires 2 steps: determination of the direction and then normalization */
      /* here we use only the improved tangent method */

      if ( ( V_next > V_actual ) && ( V_actual > V_previous ) )
	{

	  for (i=0; i<DIM*natoms; i+=DIM) {
	    tau[i  ] = dRright[i  ];
	    tau[i+1] = dRright[i+1];
	    tau[i+2] = dRright[i+2];
	    d2  += dRright[i  ]*dRright[i  ];
	    d2  += dRright[i+1]*dRright[i+1];
	    d2  += dRright[i+2]*dRright[i+2];
	  }
	  
	  tmp=1.0/sqrt(d2);
	  for (i=0; i<DIM*natoms; i+=DIM) {
	    tau[i  ] *= tmp;
	    tau[i+1] *= tmp;
	    tau[i+2] *= tmp;
	    	 
	    if (var_k==1)
	      {
		felastfact += tau[i  ] * ( -kr *dRright[i  ] + kl * dRleft[i  ]);
		felastfact += tau[i+1] * ( -kr *dRright[i+1] + kl * dRleft[i+1]);
		felastfact += tau[i+2] * ( -kr *dRright[i+2] + kl * dRleft[i+2]);
	      }
	    else 
	      {
		felastfact +=  tau[i  ] * ( - dRright[i  ] + dRleft[i  ]);
		felastfact +=  tau[i+1] * ( - dRright[i+1] + dRleft[i+1]);
		felastfact +=  tau[i+2] * ( - dRright[i+2] + dRleft[i+2]);
	      }
	  }
	}
      else if ( ( V_next < V_actual ) && ( V_actual < V_previous ) ) 
	{
	  for (i=0; i<DIM*natoms; i+=DIM) {
	    tau[i  ] = dRleft[i  ];
	    tau[i+1] = dRleft[i+1];
	    tau[i+2] = dRleft[i+2];
	    d2  += dRleft[i  ]*dRleft[i  ];
	    d2  += dRleft[i+1]*dRleft[i+1];
	    d2  += dRleft[i+2]*dRleft[i+2];
	  }
	  
	  tmp=1.0/sqrt(d2);
	  for (i=0; i<DIM*natoms; i+=DIM) {
	    tau[i  ] *= tmp;
	    tau[i+1] *= tmp;
	    tau[i+2] *= tmp;
	    	  

	    if (var_k==1)
	      {
		felastfact += tau[i  ] * ( -kr *dRright[i  ] + kl * dRleft[i  ]);
		felastfact += tau[i+1] * ( -kr *dRright[i+1] + kl * dRleft[i+1]);
		felastfact += tau[i+2] * ( -kr *dRright[i+2] + kl * dRleft[i+2]);
	      }
	    else 
	      {
		felastfact +=  tau[i  ] * ( - dRright[i  ] + dRleft[i  ]);
		felastfact +=  tau[i+1] * ( - dRright[i+1] + dRleft[i+1]);
		felastfact +=  tau[i+2] * ( - dRright[i+2] + dRleft[i+2]);

	
	      }
	  }
	}      
      else
	{
	  abs_next     = FABS( V_next     - V_actual );
	  abs_previous = FABS( V_previous - V_actual );
	  deltaVmax    = MAX( abs_next, abs_previous );
	  deltaVmin    = MIN( abs_next, abs_previous );

	  for (i=0; i<DIM*natoms; i+=DIM) {
	    dr2  += dRright[i  ]*dRright[i  ];
	    dr2  += dRright[i+1]*dRright[i+1];
	    dr2  += dRright[i+2]*dRright[i+2];
	    dl2  += dRleft[i  ]*dRleft[i  ];
	    dl2  += dRleft[i+1]*dRleft[i+1];
	    dl2  += dRleft[i+2]*dRleft[i+2];
	  }
	  tmpl=1.0/sqrt(dl2);
	  tmpr=1.0/sqrt(dr2);

	  for (i=0; i<DIM*natoms; i+=DIM) {
	    vektor dl, dr;
	    dr.x =  dRright[i  ]*tmpr;
	    dr.y =  dRright[i+1]*tmpr;
	    dr.z =  dRright[i+2]*tmpr;

	    dl.x =  dRleft[i  ]*tmpl;
	    dl.y =  dRleft[i+1]*tmpl;
	    dl.z =  dRleft[i+2]*tmpl;

	    if (V_next > V_previous ) 
	      {
		tau[i  ] = dr.x * deltaVmax + dl.x * deltaVmin ;
		tau[i+1] = dr.y * deltaVmax + dl.y * deltaVmin;
		tau[i+2] = dr.z * deltaVmax + dl.z * deltaVmin;
	      }
	    else if ( V_next < V_previous ) 
	      {
		tau[i  ] = dr.x * deltaVmin + dl.x * deltaVmax ;
		tau[i+1] = dr.y * deltaVmin + dl.y * deltaVmax;
		tau[i+2] = dr.z * deltaVmin + dl.z * deltaVmax;
	      }
	    else
	      {
		tau[i  ] = dr.x + dl.x;
		tau[i+1] = dr.y + dl.y;
		tau[i+2] = dr.z + dl.z;
	      }
	    d2  += tau[i  ]*tau[i  ];
	    d2  += tau[i+1]*tau[i+1];
	    d2  += tau[i+2]*tau[i+2];
	  }
	  tmp=1.0/sqrt(d2);
	  for (i=0; i<DIM*natoms; i+=DIM) {	 
	    tau[i  ] *= tmp;
	    tau[i+1] *= tmp;
	    tau[i+2] *= tmp;
	    	   
	    if (var_k==1)
	      {
		felastfact += tau[i  ] * ( -kr *dRright[i  ] + kl * dRleft[i  ]);
		felastfact += tau[i+1] * ( -kr *dRright[i+1] + kl * dRleft[i+1]);
		felastfact += tau[i+2] * ( -kr *dRright[i+2] + kl * dRleft[i+2]);
	      }
	    else 
	      {
		felastfact +=  tau[i  ] * ( - dRright[i  ] + dRleft[i  ]);
		felastfact +=  tau[i+1] * ( - dRright[i+1] + dRleft[i+1]);
		felastfact +=  tau[i+2] * ( - dRright[i+2] + dRleft[i+2]);	
	      }
	    

	  }
	}

      /* finally construct the spring force */
      for (i=0; i<DIM*natoms; i+=DIM) {
	if (var_k==1)
	  {
	    f[i  ] = - tau[i  ] *felastfact;
	    f[i+1] = - tau[i+1] *felastfact;
	    f[i+2] = - tau[i+2] *felastfact;
	  }
	else
	  {
	    f[i  ] = - neb_k * tau[i  ] *felastfact;
	    f[i+1] = - neb_k * tau[i+1] *felastfact;
	    f[i+2] = - neb_k * tau[i+2] *felastfact;
	  }
      }
  }// end  if(myrank != 0 && mrank != neb_nrep-1)


  /* calculate the neb-force */
 if(myrank != 0 && myrank != neb_nrep-1)
  {

    // first scalar product of -force and tangent vector 
      tmp = 0.0;
      for (k=0; k<NCELLS; k++) {
	cell *p = CELLPTR(k);
	for (i=0; i<p->n; i++) { 
	  int n = NUMMER(p,i);
	  tmp -= tau X(n) * KRAFT(p,i,X);
	  tmp -= tau Y(n) * KRAFT(p,i,Y);
	  tmp -= tau Z(n) * KRAFT(p,i,Z);
	}
      }
     
      // add tmp times the tangent vector
      // and the spring force
      for (k=0; k<NCELLS; k++) {
	cell *p = CELLPTR(k);
	for (i=0; i<p->n; i++) { 
	  int n = NUMMER(p,i);
	  if(myimage == neb_climbing_image && (steps >= neb_cineb_start))
	    {
	      KRAFT(p,i,X) += 2.0*tmp * tau X(n);
	      KRAFT(p,i,Y) += 2.0*tmp * tau Y(n);
	      KRAFT(p,i,Z) += 2.0*tmp * tau Z(n);
	    }
	  else
	    {
	      KRAFT(p,i,X) += tmp * tau X(n) + f X(n);
	      KRAFT(p,i,Y) += tmp * tau Y(n) + f Y(n);
	      KRAFT(p,i,Z) += tmp * tau Z(n) + f Z(n);
	    }

	  
	}
      }
      
  } //  if(myrank != 0 && mrank != neb_nrep-1)
  
}
Exemple #8
0
void do_elco_pair(cell *p, cell *q, vektor pbc)
{
  int i, j;
  vektor d;
  int  p_typ, q_typ, col1, inc = ntypes * ntypes, is_short = 0;
  real r2, tmp, phi, dphi, ddphi, dddphi;
#ifdef EAM
  real rho_h;
  int col2;
  real rho_i_strich, rho_i_zweistrich, rho_i_dreistrich;
  real rho_j_strich, rho_j_zweistrich, rho_j_dreistrich;
#endif

  /* For each atom in first cell */
  for (i=0; i<p->n; ++i) 
    /* For each atom in neighbouring cell */
    for (j=((p==q) ? i+1 : 0); j<q->n; ++j) {
      
      /* Calculate distance */
      d.x = q->ort[j].x - p->ort[i].x + pbc.x;
      d.y = q->ort[j].y - p->ort[i].y + pbc.y;
#ifndef TWOD
      d.z = q->ort[j].z - p->ort[i].z + pbc.z;
#endif
      r2    = SPROD(d,d);

      p_typ = p->sorte[i];
      q_typ = q->sorte[j];
      col1  = p_typ * ntypes + q_typ;

      if ( r2 <= pair_pot.end[col1] ) {

	PAIR_INT4(phi, dphi, ddphi, dddphi, pair_pot, col1, inc, r2, is_short)

	/* Compute potential energy */
	epot += phi;

	/* Compute stress and elastic constants */
	tmp = d.x * d.x * dphi; 
	p->stress[i].xx += tmp;
	q->stress[j].xx += tmp;
	sigma.xx        += 2.0 * tmp;
	tmp = d.x * d.y * dphi; 
	p->stress[i].xy += tmp;
	q->stress[j].xy += tmp;
	sigma.xy        += 2.0 * tmp;
	tmp = d.y * d.y * dphi; 
	p->stress[i].yy += tmp;
	q->stress[j].yy += tmp;
	sigma.yy        += 2.0 * tmp;
#ifndef TWOD
	tmp = d.y * d.z * dphi; 
	p->stress[i].yz += tmp;
	q->stress[j].yz += tmp;
	sigma.yz        += 2.0 * tmp;
	tmp = d.z * d.z * dphi; 
	p->stress[i].zz += tmp;
	q->stress[j].zz += tmp;
	sigma.zz        += 2.0 * tmp;
	tmp = d.z * d.x * dphi; 
	p->stress[i].zx += tmp;
	q->stress[j].zx += tmp;
	sigma.zx        += 2.0 * tmp;
#endif

	tmp = 2.0 * d.x * d.x * d.x * d.x * ddphi + d.x * d.x * dphi;
	p->elco[i].c11 += tmp;
	q->elco[j].c11 += tmp;
	c.c11          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.x * d.y * d.y * ddphi;
	p->elco[i].c12 += tmp;
	q->elco[j].c12 += tmp;
	c.c12          += 2.0 * tmp;
	tmp += 0.5 * ( d.x * d.x + d.y * d.y ) * dphi; 
	p->elco[i].c66 += tmp;
	q->elco[j].c66 += tmp;
	c.c66          += 2.0 * tmp;
	tmp = 2.0 * d.y * d.y * d.y * d.y * ddphi + d.y * d.y * dphi;
	p->elco[i].c22 += tmp;
	q->elco[j].c22 += tmp;
	c.c22          += 2.0 * tmp;
#ifndef TWOD
	tmp = 2.0 * d.x * d.x * d.z * d.z * ddphi;
	p->elco[i].c13 += tmp;
	q->elco[j].c13 += tmp;
	c.c13          += 2.0 * tmp;
	tmp += 0.5 * ( d.x * d.x + d.z * d.z ) * dphi; 
	p->elco[i].c55 += tmp;
	q->elco[j].c55 += tmp;
	c.c55          += 2.0 * tmp;
	tmp = 2.0 * d.y * d.y * d.z * d.z * ddphi;
	p->elco[i].c23 += tmp;
	q->elco[j].c23 += tmp;
	c.c23          += 2.0 * tmp;
	tmp += 0.5 * ( d.y * d.y + d.z * d.z ) * dphi; 
	p->elco[i].c44 += tmp;
	q->elco[j].c44 += tmp;
	c.c44          += 2.0 * tmp;
	tmp = 2.0 * d.z * d.z * d.z * d.z * ddphi + d.z * d.z * dphi;
	p->elco[i].c33 += tmp;
	q->elco[j].c33 += tmp;
	c.c33          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.y * d.z * d.z * ddphi + 0.25 * d.x * d.y * dphi;
	p->elco[i].c45 += tmp;
	q->elco[j].c45 += tmp;
	c.c45          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.y * d.y * d.z * ddphi + 0.25 * d.x * d.z * dphi;
	p->elco[i].c46 += tmp;
	q->elco[j].c46 += tmp;
	c.c46          += 2.0 * tmp;
	tmp -= 0.25 * d.x * d.z * dphi;
	p->elco[i].c25 += tmp;
	q->elco[j].c25 += tmp;
	c.c25          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.x * d.y * d.z * ddphi + 0.25 * d.y * d.z * dphi;
	p->elco[i].c56 += tmp;
	q->elco[j].c56 += tmp;
	c.c56          += 2.0 * tmp;
	tmp -= 0.25 * d.y * d.z * dphi;
	p->elco[i].c14 += tmp;
	q->elco[j].c14 += tmp;
	c.c14          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.x * d.x * d.z * ddphi + 0.5 * d.x * d.z * dphi;
	p->elco[i].c15 += tmp;
	q->elco[j].c15 += tmp;
	c.c15          += 2.0 * tmp;
#endif
	tmp = 2.0 * d.x * d.x * d.x * d.y * ddphi + 0.5 * d.x * d.y * dphi;
	p->elco[i].c16 += tmp;
	q->elco[j].c16 += tmp;
	c.c16          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.y * d.y * d.y * ddphi + 0.5 * d.x * d.y * dphi;
	p->elco[i].c26 += tmp;
	q->elco[j].c26 += tmp;
	c.c26          += 2.0 * tmp;
#ifndef TWOD
	tmp = 2.0 * d.y * d.y * d.y * d.z * ddphi + 0.5 * d.y * d.z * dphi;
	p->elco[i].c24 += tmp;
	q->elco[j].c24 += tmp;
	c.c24          += 2.0 * tmp;
	tmp = 2.0 * d.y * d.z * d.z * d.z * ddphi + 0.5 * d.y * d.z * dphi;
	p->elco[i].c34 += tmp;
	q->elco[j].c34 += tmp;
	c.c34          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.z * d.z * d.z * ddphi + 0.5 * d.x * d.z * dphi;
	p->elco[i].c35 += tmp;
	q->elco[j].c35 += tmp;
	c.c35          += 2.0 * tmp;
	tmp = 2.0 * d.x * d.y * d.z * d.z * ddphi;
	p->elco[i].c36 += tmp;
	q->elco[j].c36 += tmp;
	c.c36          += 2.0 * tmp;
#endif
	press          +=   2.0 * dphi * r2;

	bulkm          += ( 2.0 * ddphi * r2 + dphi ) * 2.0 * r2;

	dbulkm_dp      += ( 2.0 * dddphi * r2 + 3.0 * ddphi ) * 4.0 * r2 * r2;

      }

#ifdef EAM
      col2  = q_typ * ntypes + p_typ;

      /* compute host electron density */
      if ( r2 < rho_h_tab.end[col1] )  {
        VAL_FUNC(rho_h, rho_h_tab, col1,  inc, r2, is_short);
        EAM_RHO(p,i) += rho_h; 
      }
      if ( p_typ == q_typ ) {
        if ( r2 < rho_h_tab.end[col1] ) 
	  EAM_RHO(q,j) += rho_h; 
      } else {
        if ( r2 < rho_h_tab.end[col2] ) {
          VAL_FUNC(rho_h, rho_h_tab, col2, inc, r2, is_short);
          EAM_RHO(q,j) += rho_h; 
        }
      }

      /* Compute stress for EAM potential */
      if ( (r2 < rho_h_tab.end[col1]) || (r2 < rho_h_tab.end[col2]) ) {

        DERIV_FUNC(rho_i_strich, rho_i_zweistrich, rho_i_dreistrich, 
		   rho_h_tab, col2, inc, r2, is_short);

	q->eam_stress[j].xx += 2.0 * rho_i_strich * d.x * d.x;
	q->eam_stress[j].xy += 2.0 * rho_i_strich * d.x * d.y;
	q->eam_stress[j].yy += 2.0 * rho_i_strich * d.y * d.y;
#ifndef TWOD
	q->eam_stress[j].yz += 2.0 * rho_i_strich * d.y * d.z;
	q->eam_stress[j].zz += 2.0 * rho_i_strich * d.z * d.z;
	q->eam_stress[j].zx += 2.0 * rho_i_strich * d.z * d.x;
#endif
	q->eam_press[j]     +=   2.0 * rho_i_strich * r2; 
	q->eam_bulkm[j]     += ( 2.0 * rho_i_zweistrich * r2 + rho_i_strich )
	                         * 2.0 * r2; 
	q->eam_dbulkm[j]    += ( 2.0 * rho_i_dreistrich * r2 
				+ 3.0 * rho_i_zweistrich ) 
	                         * 4.0 * r2 * r2;

        if ( col1 == col2 ) {
          rho_j_strich     = rho_i_strich;
          rho_j_zweistrich = rho_i_zweistrich;
	  rho_j_dreistrich = rho_i_dreistrich;
	} 
	else {

          DERIV_FUNC(rho_j_strich, rho_j_zweistrich, rho_j_dreistrich, 
		     rho_h_tab, col1, inc, r2, is_short);
	}

	p->eam_stress[i].xx += 2.0 * rho_j_strich * d.x * d.x;
	p->eam_stress[i].xy += 2.0 * rho_j_strich * d.x * d.y;
	p->eam_stress[i].yy += 2.0 * rho_j_strich * d.y * d.y;
#ifndef TWOD
	p->eam_stress[i].yz += 2.0 * rho_j_strich * d.y * d.z;
	p->eam_stress[i].zz += 2.0 * rho_j_strich * d.z * d.z;
	p->eam_stress[i].zx += 2.0 * rho_j_strich * d.z * d.x;
#endif
	p->eam_press[i]     +=   2.0 * rho_j_strich * r2; 
	p->eam_bulkm[i]     += ( 2.0 * rho_j_zweistrich * r2 + rho_j_strich )
	                         * 2.0 * r2; 
	p->eam_dbulkm[i]    += ( 2.0 * rho_j_dreistrich * r2 
				+ 3.0 * rho_j_zweistrich )
	                         * 4.0 * r2 * r2;
      }
#endif /* EAM */
    }
}
Exemple #9
0
void do_angle(cell *p, cell *q, cell *r, cell *s,
              vektor pbc_q, vektor pbc_r, vektor pbc_s)
{
    int i, j, k, l;
    int ang;
    int temp;
    vektor d_ij, d_ik, d_jk, d_il, d_jl, d_kl;
    vektor v_k, v_l;
    real radius_ij, radius_ik, radius_jk, radius_il, radius_jl, radius_kl;
    real phi;
    real betrag_v_k, betrag_v_l;
    double sprod;
    int p_typ, q_typ, r_typ, s_typ;

    /*
                        l
                       /
                      /
               i-----j
              /
             /
            k

      */

    /* For each atom in cell p */
    for (i = 0; i < p->n; ++i)
        /* For each atom in neighbouring cell q */
        for (j = (p == q ? i+1 : 0); j < q->n; ++j)
            /* For each atom in neighbouring cell r of p */
            for (k = 0; k < r->n; ++k)
                /* for each atom in neighbouring cell s of q */
                for (l = 0; l < s->n; ++l)
                {

                    /* Calculate distance vectors */
                    d_ij.x = q->ort[j].x - p->ort[i].x + pbc_q.x;
                    d_ij.y = q->ort[j].y - p->ort[i].y + pbc_q.y;
                    d_ij.z = q->ort[j].z - p->ort[i].z + pbc_q.z;

                    d_ik.x = r->ort[k].x - p->ort[i].x + pbc_r.x;
                    d_ik.y = r->ort[k].y - p->ort[i].y + pbc_r.y;
                    d_ik.z = r->ort[k].z - p->ort[i].z + pbc_r.z;

                    d_jl.x = s->ort[l].x - q->ort[j].x + pbc_s.x;
                    d_jl.y = s->ort[l].y - q->ort[j].y + pbc_s.y;
                    d_jl.z = s->ort[l].z - q->ort[j].z + pbc_s.z;

                    d_jk.x = d_ik.x - d_ij.x;
                    d_jk.y = d_ik.y - d_ij.y;
                    d_jk.z = d_ik.z - d_ij.z;

                    d_il.x = d_ij.x + d_jl.x;
                    d_il.y = d_ij.y + d_jl.y;
                    d_il.z = d_ij.z + d_jl.z;

                    d_kl.x = d_jl.x - d_jk.x;
                    d_kl.y = d_jl.y - d_jk.y;
                    d_kl.z = d_jl.z - d_jk.z;

                    radius_ij = sqrt( (double)(SPROD(d_ij,d_ij)) );
                    radius_ik = sqrt( (double)(SPROD(d_ik,d_ik)) );
                    radius_jl = sqrt( (double)(SPROD(d_jl,d_jl)) );
                    radius_jk = sqrt( (double)(SPROD(d_jk,d_jk)) );
                    radius_il = sqrt( (double)(SPROD(d_il,d_il)) );
                    radius_kl = sqrt( (double)(SPROD(d_kl,d_kl)) );

                    /* v_k = d_ik x d_jk */
                    v_k.x = d_ik.y * d_jk.z - d_ik.z * d_jk.y;
                    v_k.y = d_ik.z * d_jk.x - d_ik.x * d_jk.z;
                    v_k.z = d_ik.x * d_jk.y - d_ik.y * d_jk.x;

                    betrag_v_k = sqrt( (double)(SPROD(v_k,v_k)) );

                    /* v_l = d_il x d_jl */
                    v_l.x = d_il.y * d_jl.z - d_il.z * d_jl.y;
                    v_l.y = d_il.z * d_jl.x - d_il.x * d_jl.z;
                    v_l.z = d_il.x * d_jl.y - d_il.y * d_jl.x;

                    betrag_v_l = sqrt( (double)(SPROD(v_l,v_l)) );

                    /* Calculate torsion angles */
                    if ( (radius_ij < r_max) && (radius_ik < r_max)
                            && (radius_jl < r_max)
                            && (radius_ij*radius_ik*radius_jl*radius_jk*radius_il*radius_kl > 0.0) && (betrag_v_k > 0.0) && (betrag_v_l > 0.0) )
                    {
                        ++nangles;
                        sprod = (double)( SPROD(v_k,v_l)/( betrag_v_k * betrag_v_l ));
                        if (sprod < -1.0) sprod = -1.0;

                        phi = (double) (acos(sprod));

                        ang = (int) ( slots * phi / 3.141592654 );

                        p_typ = p->sorte[i];
                        q_typ = q->sorte[j];
                        r_typ = r->sorte[k];
                        s_typ = s->sorte[l];


                        if (p_typ == q_typ) {
                            if ( r_typ > s_typ ) {
                                temp = s_typ;
                                s_typ = r_typ;
                                r_typ = temp;
                            }
                        }
                        else if (p_typ > q_typ) {
                            temp = q_typ;
                            q_typ = p_typ;
                            p_typ = temp;
                            temp = s_typ;
                            s_typ = r_typ;
                            r_typ = temp;
                        }

                        if ((ang >= 0) && (ang < slots))
                            ++*PTR_5D_V(histogram, ang , p_typ, q_typ, r_typ, s_typ, hist_dim);
                    }
                }

}
Exemple #10
0
void do_forces(cell *p, cell *q, vektor pbc, real *Epot, real *Virial, 
               real *Vir_xx, real *Vir_yy, real *Vir_zz,
               real *Vir_yz, real *Vir_zx, real *Vir_xy)
{
  int i, j ;
  int jstart ;

  real tmp_virial ;
  vektor tmp_vir_vect ; 
  vektor tmp_r12 ;

  vektor r12 ;
  vektor e1 ;
  vektor e2 ;
  real rsqr ;

  real pot12 ;
  vektor force12 ;
  vektor torque12 ;
  vektor torque21 ;

  /* actual pair virial and virial components */
  
  tmp_virial     = 0.0;
  tmp_vir_vect.x = 0.0;
  tmp_vir_vect.y = 0.0;
  tmp_vir_vect.z = 0.0;
    
  /* For each atom in first cell */
  for (i = 0;i < p->n; ++i) {
    /* For each atom in neighbouring cell */
    /* Some compilers don't find the expressions that are invariant 
       to the inner loop. I'll have to define my own temp variables. */

    tmp_r12.x = ORT(p,i,X) - pbc.x;
    tmp_r12.y = ORT(p,i,Y) - pbc.y;
    tmp_r12.z = ORT(p,i,Z) - pbc.z;

    e1.x = ACHSE(p,i,X);
    e1.y = ACHSE(p,i,Y);
    e1.z = ACHSE(p,i,Z);

#ifdef TWOD
    jstart = (((p==q) && (pbc.x==0) && (pbc.y==0))               ? i+1 : 0);
#else
    jstart = (((p==q) && (pbc.x==0) && (pbc.y==0) && (pbc.z==0)) ? i+1 : 0);
#endif
    
    for (j = jstart; j < q->n; ++j) {
      
      /* Calculate distance */

      r12.x = tmp_r12.x - ORT(q,j,X);
      r12.y = tmp_r12.y - ORT(q,j,Y);
      r12.z = tmp_r12.z - ORT(q,j,Z);

      rsqr = SPROD(r12,r12);

      e2.x = ACHSE(q,j,X);
      e2.y = ACHSE(q,j,Y);
      e2.z = ACHSE(q,j,Z);

#ifndef NODBG_DIST
      if (0==rsqr) 
	{ 
	  char msgbuf[256];
	  sprintf(msgbuf,"Distance is zero: i=%d, j=%d\n",i,j);
	  error(msgbuf);
	}
#else
      if (0==rsqr) error("Distance is zero.");
#endif

      if (rsqr <= uniax_r2_cut) {

	/* calculate interactions, if distance smaller than cutoff radius */ 

	gay_berne( r12, e1, e2, rsqr, uniax_sig, uniax_eps, &pot12,
		   &force12, &torque12, &torque21) ;
	
        /* accumulate forces */

	KRAFT(p,i,X) += force12.x;
	KRAFT(p,i,Y) += force12.y;
	KRAFT(p,i,Z) += force12.z;

	KRAFT(q,j,X) -= force12.x;
	KRAFT(q,j,Y) -= force12.y;
	KRAFT(q,j,Z) -= force12.z;

        /* accumulate torques */

	DREH_MOMENT(p,i,X) += torque12.x;
	DREH_MOMENT(p,i,Y) += torque12.y;
	DREH_MOMENT(p,i,Z) += torque12.z;

	DREH_MOMENT(q,j,X) += torque21.x;
	DREH_MOMENT(q,j,Y) += torque21.y;
	DREH_MOMENT(q,j,Z) += torque21.z;

        *Epot       += pot12;
        pot12       *= 0.5;   /* avoid double counting */
	POTENG(p,i) += pot12;
	POTENG(q,j) += pot12;

        tmp_vir_vect.x += r12.x * force12.x ;
        tmp_vir_vect.y += r12.y * force12.y ;
        tmp_vir_vect.z += r12.z * force12.z ;
	tmp_virial += r12.x * force12.x
	  + r12.y * force12.y + r12.z * force12.z ;

      }; /* if */

    }; /* for j */

  }; /* for i */

  *Vir_xx += tmp_vir_vect.x;
  *Vir_yy += tmp_vir_vect.y;
  *Vir_zz += tmp_vir_vect.z;
  *Virial += tmp_virial ;

} /* do_forces_uniax */
Exemple #11
0
double calc_forces(double* xi_opt, double* forces, int flag)
{
  double tmpsum, sum = 0.0;
  int first, col, ne, size, i = flag;
  double* xi = NULL;
  apot_table_t* apt = &g_pot.apot_table;
  double charge[g_param.ntypes];
  double sum_charges;
  double dp_kappa;

#if defined(DIPOLE)
  double dp_alpha[g_param.ntypes];
  double dp_b[g_calc.paircol];
  double dp_c[g_calc.paircol];
#endif  // DIPOLE

  static double rho_sum_loc, rho_sum;
  rho_sum_loc = rho_sum = 0.0;

  switch (g_pot.format_type) {
    case POTENTIAL_FORMAT_UNKNOWN:
      error(1, "Unknown potential format detected! (%s:%d)\n", __FILE__, __LINE__);
    case POTENTIAL_FORMAT_ANALYTIC:
      xi = g_pot.calc_pot.table;
      break;
    case POTENTIAL_FORMAT_TABULATED_EQ_DIST:
    case POTENTIAL_FORMAT_TABULATED_NON_EQ_DIST:
      xi = xi_opt;
      break;
    case POTENTIAL_FORMAT_KIM:
      error(1, "KIM format is not supported by EAM elstat force routine!");
  }

#if !defined(MPI)
  g_mpi.myconf = g_config.nconf;
#endif  // MPI

  ne = g_pot.apot_table.total_ne_par;
  size = apt->number;

  /* This is the start of an infinite loop */
  while (1) {
    tmpsum = 0.0; /* sum of squares of local process */
    rho_sum_loc = 0.0;

#if defined APOT && !defined MPI
    if (g_pot.format_type == POTENTIAL_FORMAT_ANALYTIC) {
      apot_check_params(xi_opt);
      update_calc_table(xi_opt, xi, 0);
    }
#endif  // APOT && !MPI

#if defined(MPI)
/* exchange potential and flag value */
#if !defined(APOT)
    MPI_Bcast(xi, g_pot.calc_pot.len, MPI_DOUBLE, 0, MPI_COMM_WORLD);
#endif  // APOT
    MPI_Bcast(&flag, 1, MPI_INT, 0, MPI_COMM_WORLD);

    if (flag == 1)
      break; /* Exception: flag 1 means clean up */

#if defined(APOT)
    if (g_mpi.myid == 0)
      apot_check_params(xi_opt);
    MPI_Bcast(xi_opt, g_calc.ndimtot, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    if (g_pot.format_type == POTENTIAL_FORMAT_ANALYTIC)
      update_calc_table(xi_opt, xi, 0);
#else   /* APOT */
    /* if flag==2 then the potential parameters have changed -> sync */
    if (flag == 2)
      potsync();
#endif  // APOT
#endif  // MPI

    /* local arrays for electrostatic parameters */
    sum_charges = 0;
    for (i = 0; i < g_param.ntypes - 1; i++) {
      if (xi_opt[2 * size + ne + i]) {
        charge[i] = xi_opt[2 * size + ne + i];
        sum_charges += apt->ratio[i] * charge[i];
      } else {
        charge[i] = 0.0;
      }
    }
    apt->last_charge = -sum_charges / apt->ratio[g_param.ntypes - 1];
    charge[g_param.ntypes - 1] = apt->last_charge;
    if (xi_opt[2 * size + ne + g_param.ntypes - 1]) {
      dp_kappa = xi_opt[2 * size + ne + g_param.ntypes - 1];
    } else {
      dp_kappa = 0.0;
    }

#if defined(DIPOLE)
    for (i = 0; i < g_param.ntypes; i++) {
      if (xi_opt[2 * size + ne + g_param.ntypes + i]) {
        dp_alpha[i] = xi_opt[2 * size + ne + g_param.ntypes + i];
      } else {
        dp_alpha[i] = 0.0;
      }
    }
    for (i = 0; i < g_calc.paircol; i++) {
      if (xi_opt[2 * size + ne + 2 * g_param.ntypes + i]) {
        dp_b[i] = xi_opt[2 * size + ne + 2 * g_param.ntypes + i];
      } else {
        dp_b[i] = 0.0;
      }
      if (xi_opt[2 * size + ne + 2 * g_param.ntypes + g_calc.paircol + i]) {
        dp_c[i] =
            xi_opt[2 * size + ne + 2 * g_param.ntypes + g_calc.paircol + i];
      } else {
        dp_c[i] = 0.0;
      }
    }
#endif  // DIPOLE

    /* init second derivatives for splines */

    /* pair potentials & rho */
    for (col = 0; col < g_calc.paircol + g_param.ntypes; col++) {
      first = g_pot.calc_pot.first[col];

      switch (g_pot.format_type) {
        case POTENTIAL_FORMAT_UNKNOWN:
          error(1, "Unknown potential format detected! (%s:%d)\n", __FILE__,
                __LINE__);
        case POTENTIAL_FORMAT_ANALYTIC:
        case POTENTIAL_FORMAT_TABULATED_EQ_DIST: {
          spline_ed(g_pot.calc_pot.step[col], xi + first,
                    g_pot.calc_pot.last[col] - first + 1, *(xi + first - 2),
                    0.0, g_pot.calc_pot.d2tab + first);
          break;
        }
        case POTENTIAL_FORMAT_TABULATED_NON_EQ_DIST: {
          spline_ne(g_pot.calc_pot.xcoord + first, xi + first,
                    g_pot.calc_pot.last[col] - first + 1, *(xi + first - 2),
                    0.0, g_pot.calc_pot.d2tab + first);
        }
        case POTENTIAL_FORMAT_KIM:
          error(1, "KIM format is not supported by EAM elstat force routine!");
      }
    }

    /* F */
    for (col = g_calc.paircol + g_param.ntypes;
         col < g_calc.paircol + 2 * g_param.ntypes; col++) {
      first = g_pot.calc_pot.first[col];
      /* gradient at left boundary matched to square root function,
         when 0 not in domain(F), else natural spline */
      switch (g_pot.format_type) {
        case POTENTIAL_FORMAT_UNKNOWN:
          error(1, "Unknown potential format detected! (%s:%d)\n", __FILE__,
                __LINE__);
        case POTENTIAL_FORMAT_ANALYTIC:
        case POTENTIAL_FORMAT_TABULATED_EQ_DIST: {
          spline_ed(g_pot.calc_pot.step[col], xi + first,
                    g_pot.calc_pot.last[col] - first + 1, *(xi + first - 2),
                    *(xi + first - 1), g_pot.calc_pot.d2tab + first);
          break;
        }
        case POTENTIAL_FORMAT_TABULATED_NON_EQ_DIST: {
          spline_ne(g_pot.calc_pot.xcoord + first, xi + first,
                    g_pot.calc_pot.last[col] - first + 1, *(xi + first - 2),
                    *(xi + first - 1), g_pot.calc_pot.d2tab + first);
        }
        case POTENTIAL_FORMAT_KIM:
          error(1, "KIM format is not supported by EAM elstat force routine!");
      }
    }

    /* region containing loop over configurations */
    {
      int self;
      vector tmp_force;
      int h, j, type1, type2, uf;
#if defined(STRESS)
      int us = 0;
      int stresses = 0;
#endif
      int n_i, n_j;
      double fnval, grad, fnval_tail, grad_tail, grad_i, grad_j;
#if defined(DIPOLE)
      double p_sr_tail = 0.0;
#endif
      atom_t* atom;
      neigh_t* neigh;
      double r;
      int col_F;
      double eam_force;
      double rho_val, rho_grad, rho_grad_j;

      /* loop over configurations: M A I N LOOP CONTAINING ALL ATOM-LOOPS */
      for (h = g_mpi.firstconf; h < g_mpi.firstconf + g_mpi.myconf; h++) {
        uf = g_config.conf_uf[h - g_mpi.firstconf];
#if defined(STRESS)
        us = g_config.conf_us[h - g_mpi.firstconf];
#endif  // STRESS
        /* reset energies and stresses */
        forces[g_calc.energy_p + h] = 0.0;
#if defined(STRESS)
        stresses = g_calc.stress_p + 6 * h;
        for (i = 0; i < 6; i++)
          forces[stresses + i] = 0.0;
#endif  // STRESS

        /* set limiting constraints */
        forces[g_calc.limit_p + h] = -g_config.force_0[g_calc.limit_p + h];

#if defined(DIPOLE)
        /* reset dipoles and fields: LOOP Z E R O */
        for (i = 0; i < g_config.inconf[h]; i++) {
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          atom->E_stat.x = 0.0;
          atom->E_stat.y = 0.0;
          atom->E_stat.z = 0.0;
          atom->p_sr.x = 0.0;
          atom->p_sr.y = 0.0;
          atom->p_sr.z = 0.0;
        }
#endif  // DIPOLE

        /* F I R S T LOOP OVER ATOMS: reset forces, dipoles */
        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          n_i = 3 * (g_config.cnfstart[h] + i);
          if (uf) {
            forces[n_i + 0] = -g_config.force_0[n_i + 0];
            forces[n_i + 1] = -g_config.force_0[n_i + 1];
            forces[n_i + 2] = -g_config.force_0[n_i + 2];
          } else {
            forces[n_i + 0] = 0.0;
            forces[n_i + 1] = 0.0;
            forces[n_i + 2] = 0.0;
          }
          /* reset atomic density */
          g_config.conf_atoms[g_config.cnfstart[h] - g_mpi.firstatom + i].rho =
              0.0;
        } /* end F I R S T LOOP */

        /* S E C O N D loop: calculate short-range and monopole forces,
           calculate static field- and dipole-contributions,
           calculate atomic densities */
        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          type1 = atom->type;
          n_i = 3 * (g_config.cnfstart[h] + i);
          for (j = 0; j < atom->num_neigh; j++) { /* neighbors */
            neigh = atom->neigh + j;
            type2 = neigh->type;
            col = neigh->col[0];

            /* updating tail-functions - only necessary with variing kappa */
            if (!apt->sw_kappa)
#if defined(DSF)
              elstat_dsf(neigh->r, dp_kappa, &neigh->fnval_el,
                           &neigh->grad_el, &neigh->ggrad_el);
#else
              elstat_shift(neigh->r, dp_kappa, &neigh->fnval_el,
                           &neigh->grad_el, &neigh->ggrad_el);
#endif // DSF

            /* In small cells, an atom might interact with itself */
            self = (neigh->nr == i + g_config.cnfstart[h]) ? 1 : 0;

            /* calculate short-range forces */
            if (neigh->r < g_pot.calc_pot.end[col]) {
              if (uf) {
                fnval = splint_comb_dir(&g_pot.calc_pot, xi, neigh->slot[0],
                                        neigh->shift[0], neigh->step[0], &grad);
              } else {
                fnval = splint_dir(&g_pot.calc_pot, xi, neigh->slot[0],
                                   neigh->shift[0], neigh->step[0]);
              }

              /* avoid double counting if atom is interacting with a copy of
               * itself */
              if (self) {
                fnval *= 0.5;
                grad *= 0.5;
              }
              forces[g_calc.energy_p + h] += fnval;

              if (uf) {
                tmp_force.x = neigh->dist_r.x * grad;
                tmp_force.y = neigh->dist_r.y * grad;
                tmp_force.z = neigh->dist_r.z * grad;
                forces[n_i + 0] += tmp_force.x;
                forces[n_i + 1] += tmp_force.y;
                forces[n_i + 2] += tmp_force.z;
                /* actio = reactio */
                n_j = 3 * neigh->nr;
                forces[n_j + 0] -= tmp_force.x;
                forces[n_j + 1] -= tmp_force.y;
                forces[n_j + 2] -= tmp_force.z;
#if defined(STRESS)
                /* calculate pair stresses */
                if (us) {
                  forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
                  forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
                  forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
                  forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
                  forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
                  forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
                }
#endif  // STRESS
              }
            }

            /* calculate monopole forces */
            if (neigh->r < g_config.dp_cut &&
                (charge[type1] || charge[type2])) {
              fnval_tail = neigh->fnval_el;
              grad_tail = neigh->grad_el;

              grad_i = charge[type2] * grad_tail;
              if (type1 == type2) {
                grad_j = grad_i;
              } else {
                grad_j = charge[type1] * grad_tail;
              }
              fnval = charge[type1] * charge[type2] * fnval_tail;
              grad = charge[type1] * grad_i;

              if (self) {
                grad_i *= 0.5;
                grad_j *= 0.5;
                fnval *= 0.5;
                grad *= 0.5;
              }

              forces[g_calc.energy_p + h] += fnval;

              if (uf) {
                tmp_force.x = neigh->dist.x * grad;
                tmp_force.y = neigh->dist.y * grad;
                tmp_force.z = neigh->dist.z * grad;
                forces[n_i + 0] += tmp_force.x;
                forces[n_i + 1] += tmp_force.y;
                forces[n_i + 2] += tmp_force.z;
                /* actio = reactio */
                n_j = 3 * neigh->nr;
                forces[n_j + 0] -= tmp_force.x;
                forces[n_j + 1] -= tmp_force.y;
                forces[n_j + 2] -= tmp_force.z;
#if defined(STRESS)
                /* calculate coulomb stresses */
                if (us) {
                  forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
                  forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
                  forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
                  forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
                  forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
                  forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
                }
#endif  // STRESS
              }
#if defined(DIPOLE)
              /* calculate static field-contributions */
              atom->E_stat.x += neigh->dist.x * grad_i;
              atom->E_stat.y += neigh->dist.y * grad_i;
              atom->E_stat.z += neigh->dist.z * grad_i;

              g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_stat.x -=
                  neigh->dist.x * grad_j;
              g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_stat.y -=
                  neigh->dist.y * grad_j;
              g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_stat.z -=
                  neigh->dist.z * grad_j;

              /* calculate short-range dipoles */
              if (dp_alpha[type1] && dp_b[col] && dp_c[col]) {
                p_sr_tail = grad_tail * neigh->r *
                            shortrange_value(neigh->r, dp_alpha[type1],
                                             dp_b[col], dp_c[col]);
                atom->p_sr.x += charge[type2] * neigh->dist_r.x * p_sr_tail;
                atom->p_sr.y += charge[type2] * neigh->dist_r.y * p_sr_tail;
                atom->p_sr.z += charge[type2] * neigh->dist_r.z * p_sr_tail;
              }
              if (dp_alpha[type2] && dp_b[col] && dp_c[col] && !self) {
                p_sr_tail = grad_tail * neigh->r *
                            shortrange_value(neigh->r, dp_alpha[type2],
                                             dp_b[col], dp_c[col]);
                g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_sr.x -=
                    charge[type1] * neigh->dist_r.x * p_sr_tail;
                g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_sr.y -=
                    charge[type1] * neigh->dist_r.y * p_sr_tail;
                g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_sr.z -=
                    charge[type1] * neigh->dist_r.z * p_sr_tail;
              }
#endif  // DIPOLE
            }

            /* calculate atomic densities */
            if (atom->type == neigh->type) {
              /* then transfer(a->b)==transfer(b->a) */
              if (neigh->r < g_pot.calc_pot.end[neigh->col[1]]) {
                rho_val = splint_dir(&g_pot.calc_pot, xi, neigh->slot[1],
                                     neigh->shift[1], neigh->step[1]);
                atom->rho += rho_val;
                /* avoid double counting if atom is interacting with a
                   copy of itself */
                if (!self) {
                  g_config.conf_atoms[neigh->nr - g_mpi.firstatom].rho +=
                      rho_val;
                }
              }
            } else {
              /* transfer(a->b)!=transfer(b->a) */
              if (neigh->r < g_pot.calc_pot.end[neigh->col[1]]) {
                atom->rho += splint_dir(&g_pot.calc_pot, xi, neigh->slot[1],
                                        neigh->shift[1], neigh->step[1]);
              }
              /* cannot use slot/shift to access splines */
              if (neigh->r < g_pot.calc_pot.end[g_calc.paircol + atom->type])
                g_config.conf_atoms[neigh->nr - g_mpi.firstatom].rho +=
                    (*g_splint)(&g_pot.calc_pot, xi,
                                g_calc.paircol + atom->type, neigh->r);
            }

          } /* loop over neighbours */

          col_F =
              g_calc.paircol + g_param.ntypes + atom->type; /* column of F */
          if (atom->rho > g_pot.calc_pot.end[col_F]) {
            /* then punish target function -> bad potential */
            forces[g_calc.limit_p + h] +=
                DUMMY_WEIGHT * 10.0 *
                dsquare(atom->rho - g_pot.calc_pot.end[col_F]);
            atom->rho = g_pot.calc_pot.end[col_F];
          }

          if (atom->rho < g_pot.calc_pot.begin[col_F]) {
            /* then punish target function -> bad potential */
            forces[g_calc.limit_p + h] +=
                DUMMY_WEIGHT * 10.0 *
                dsquare(g_pot.calc_pot.begin[col_F] - atom->rho);
            atom->rho = g_pot.calc_pot.begin[col_F];
          }

/* embedding energy, embedding gradient */
/* contribution to cohesive energy is F(n) */
#if defined(NORESCALE)
          if (atom->rho < g_pot.calc_pot.begin[col_F]) {
            /* linear extrapolation left */
            rho_val = splint_comb(&calc_pot, xi, col_F,
                                  g_pot.calc_pot.begin[col_F], &atom->gradF);
            forces[energy_p + h] +=
                rho_val +
                (atom->rho - g_pot.calc_pot.begin[col_F]) * atom->gradF;
#if defined(APOT)
            forces[limit_p + h] += DUMMY_WEIGHT * 10.0 *
                                   dsquare(calc_pot.begin[col_F] - atom->rho);
#endif  // APOT
          } else if (atom->rho > g_pot.calc_pot.end[col_F]) {
            /* and right */
            rho_val = splint_comb(
                &calc_pot, xi, col_F,
                g_pot.calc_pot.end[col_F] - 0.5 * g_pot.calc_pot.step[col_F],
                &atom->gradF);
            forces[energy_p + h] +=
                rho_val + (atom->rho - g_pot.calc_pot.end[col_F]) * atom->gradF;
#if defined(APOT)
            forces[limit_p + h] +=
                DUMMY_WEIGHT * 10.0 *
                dsquare(atom->rho - g_pot.calc_pot.end[col_F]);
#endif  // APOT
          }
          /* and in-between */
          else {
            forces[energy_p + h] +=
                splint_comb(&calc_pot, xi, col_F, atom->rho, &atom->gradF);
          }
#else
          forces[g_calc.energy_p + h] += (*g_splint_comb)(
              &g_pot.calc_pot, xi, col_F, atom->rho, &atom->gradF);
#endif  // NORESCALE
          /* sum up rho */
          rho_sum_loc += atom->rho;

        } /* end S E C O N D loop over atoms */

#if defined(DIPOLE)
        /* T H I R D loop: calculate whole dipole moment for every atom */
        double rp, dp_sum;
        int dp_converged = 0, dp_it = 0;
        double max_diff = 10;

        while (dp_converged == 0) {
          dp_sum = 0;
          for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
            atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                   g_mpi.firstatom;
            type1 = atom->type;
            if (dp_alpha[type1]) {
              if (dp_it) {
                /* note: mixing parameter is different from that on in IMD */
                atom->E_tot.x = (1 - g_config.dp_mix) * atom->E_ind.x +
                                g_config.dp_mix * atom->E_old.x +
                                atom->E_stat.x;
                atom->E_tot.y = (1 - g_config.dp_mix) * atom->E_ind.y +
                                g_config.dp_mix * atom->E_old.y +
                                atom->E_stat.y;
                atom->E_tot.z = (1 - g_config.dp_mix) * atom->E_ind.z +
                                g_config.dp_mix * atom->E_old.z +
                                atom->E_stat.z;
              } else {
                atom->E_tot.x = atom->E_ind.x + atom->E_stat.x;
                atom->E_tot.y = atom->E_ind.y + atom->E_stat.y;
                atom->E_tot.z = atom->E_ind.z + atom->E_stat.z;
              }

              atom->p_ind.x = dp_alpha[type1] * atom->E_tot.x + atom->p_sr.x;
              atom->p_ind.y = dp_alpha[type1] * atom->E_tot.y + atom->p_sr.y;
              atom->p_ind.z = dp_alpha[type1] * atom->E_tot.z + atom->p_sr.z;

              atom->E_old.x = atom->E_ind.x;
              atom->E_old.y = atom->E_ind.y;
              atom->E_old.z = atom->E_ind.z;

              atom->E_ind.x = 0.0;
              atom->E_ind.y = 0.0;
              atom->E_ind.z = 0.0;
            }
          }

          for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
            atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                   g_mpi.firstatom;
            type1 = atom->type;
            for (j = 0; j < atom->num_neigh; j++) { /* neighbors */
              neigh = atom->neigh + j;
              type2 = neigh->type;
              col = neigh->col[0];
              /* In small cells, an atom might interact with itself */
              self = (neigh->nr == i + g_config.cnfstart[h]) ? 1 : 0;

              if (neigh->r < g_config.dp_cut && dp_alpha[type1] &&
                  dp_alpha[type2]) {
                rp = SPROD(
                    g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind,
                    neigh->dist_r);
                atom->E_ind.x +=
                    neigh->grad_el *
                    (3 * rp * neigh->dist_r.x -
                     g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.x);
                atom->E_ind.y +=
                    neigh->grad_el *
                    (3 * rp * neigh->dist_r.y -
                     g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.y);
                atom->E_ind.z +=
                    neigh->grad_el *
                    (3 * rp * neigh->dist_r.z -
                     g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.z);

                if (!self) {
                  rp = SPROD(atom->p_ind, neigh->dist_r);
                  g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_ind.x +=
                      neigh->grad_el *
                      (3 * rp * neigh->dist_r.x - atom->p_ind.x);
                  g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_ind.y +=
                      neigh->grad_el *
                      (3 * rp * neigh->dist_r.y - atom->p_ind.y);
                  g_config.conf_atoms[neigh->nr - g_mpi.firstatom].E_ind.z +=
                      neigh->grad_el *
                      (3 * rp * neigh->dist_r.z - atom->p_ind.z);
                }
              }
            }
          }

          for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
            atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                   g_mpi.firstatom;
            type1 = atom->type;
            if (dp_alpha[type1]) {
              dp_sum +=
                  dsquare(dp_alpha[type1] * (atom->E_old.x - atom->E_ind.x));
              dp_sum +=
                  dsquare(dp_alpha[type1] * (atom->E_old.y - atom->E_ind.y));
              dp_sum +=
                  dsquare(dp_alpha[type1] * (atom->E_old.z - atom->E_ind.z));
            }
          }

          dp_sum /= 3 * g_config.inconf[h];
          dp_sum = sqrt(dp_sum);

          if (dp_it) {
            if ((dp_sum > max_diff) || (dp_it > 50)) {
              dp_converged = 1;
              for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
                atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                       g_mpi.firstatom;
                type1 = atom->type;
                if (dp_alpha[type1]) {
                  atom->p_ind.x =
                      dp_alpha[type1] * atom->E_stat.x + atom->p_sr.x;
                  atom->p_ind.y =
                      dp_alpha[type1] * atom->E_stat.y + atom->p_sr.y;
                  atom->p_ind.z =
                      dp_alpha[type1] * atom->E_stat.z + atom->p_sr.z;
                  atom->E_ind.x = atom->E_stat.x;
                  atom->E_ind.y = atom->E_stat.y;
                  atom->E_ind.z = atom->E_stat.z;
                }
              }
            }
          }

          if (dp_sum < g_config.dp_tol)
            dp_converged = 1;

          dp_it++;
        } /* end T H I R D loop over atoms */

        /* F O U R T H  loop: calculate monopole-dipole and dipole-dipole forces
         */
        double rp_i, rp_j, pp_ij, tmp_1, tmp_2;
        double grad_1, grad_2, srval, srgrad, srval_tail, srgrad_tail,
            fnval_sum, grad_sum;

        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          type1 = atom->type;
          n_i = 3 * (g_config.cnfstart[h] + i);
          for (j = 0; j < atom->num_neigh; j++) { /* neighbors */
            neigh = atom->neigh + j;
            type2 = neigh->type;
            col = neigh->col[0];

            /* In small cells, an atom might interact with itself */
            self = (neigh->nr == i + g_config.cnfstart[h]) ? 1 : 0;
            if (neigh->r < g_config.dp_cut &&
                (dp_alpha[type1] || dp_alpha[type2])) {
              fnval_tail = -neigh->grad_el;
              grad_tail = -neigh->ggrad_el;

              if (dp_b[col] && dp_c[col]) {
                shortrange_term(neigh->r, dp_b[col], dp_c[col], &srval_tail,
                                &srgrad_tail);
                srval = fnval_tail * srval_tail;
                srgrad = fnval_tail * srgrad_tail + grad_tail * srval_tail;
              }

              if (self) {
                fnval_tail *= 0.5;
                grad_tail *= 0.5;
              }

              /* monopole-dipole contributions */
              if (charge[type1] && dp_alpha[type2]) {
                if (dp_b[col] && dp_c[col]) {
                  fnval_sum = fnval_tail + srval;
                  grad_sum = grad_tail + srgrad;
                } else {
                  fnval_sum = fnval_tail;
                  grad_sum = grad_tail;
                }

                rp_j = SPROD(
                    g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind,
                    neigh->dist_r);
                fnval = charge[type1] * rp_j * fnval_sum * neigh->r;
                grad_1 = charge[type1] * rp_j * grad_sum * neigh->r2;
                grad_2 = charge[type1] * fnval_sum;

                forces[g_calc.energy_p + h] -= fnval;

                if (uf) {
                  tmp_force.x =
                      neigh->dist_r.x * grad_1 +
                      g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.x *
                          grad_2;
                  tmp_force.y =
                      neigh->dist_r.y * grad_1 +
                      g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.y *
                          grad_2;
                  tmp_force.z =
                      neigh->dist_r.z * grad_1 +
                      g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind.z *
                          grad_2;
                  forces[n_i + 0] -= tmp_force.x;
                  forces[n_i + 1] -= tmp_force.y;
                  forces[n_i + 2] -= tmp_force.z;
                  /* actio = reactio */
                  n_j = 3 * neigh->nr;
                  forces[n_j + 0] += tmp_force.x;
                  forces[n_j + 1] += tmp_force.y;
                  forces[n_j + 2] += tmp_force.z;

#if defined(STRESS)
                  /* calculate stresses */
                  if (us) {
                    forces[stresses + 0] += neigh->dist.x * tmp_force.x;
                    forces[stresses + 1] += neigh->dist.y * tmp_force.y;
                    forces[stresses + 2] += neigh->dist.z * tmp_force.z;
                    forces[stresses + 3] += neigh->dist.x * tmp_force.y;
                    forces[stresses + 4] += neigh->dist.y * tmp_force.z;
                    forces[stresses + 5] += neigh->dist.z * tmp_force.x;
                  }
#endif  // STRESS
                }
              }

              /* dipole-monopole contributions */
              if (dp_alpha[type2] && charge[type2]) {
                if (dp_b[col] && dp_c[col]) {
                  fnval_sum = fnval_tail + srval;
                  grad_sum = grad_tail + srgrad;
                } else {
                  fnval_sum = fnval_tail;
                  grad_sum = grad_tail;
                }

                rp_i = SPROD(atom->p_ind, neigh->dist_r);
                fnval = charge[type2] * rp_i * fnval_sum * neigh->r;
                grad_1 = charge[type2] * rp_i * grad_sum * neigh->r2;
                grad_2 = charge[type2] * fnval_sum;

                forces[g_calc.energy_p + h] += fnval;

                if (uf) {
                  tmp_force.x =
                      neigh->dist_r.x * grad_1 + atom->p_ind.x * grad_2;
                  tmp_force.y =
                      neigh->dist_r.y * grad_1 + atom->p_ind.y * grad_2;
                  tmp_force.z =
                      neigh->dist_r.z * grad_1 + atom->p_ind.z * grad_2;
                  forces[n_i + 0] += tmp_force.x;
                  forces[n_i + 1] += tmp_force.y;
                  forces[n_i + 2] += tmp_force.z;
                  /* actio = reactio */
                  n_j = 3 * neigh->nr;
                  forces[n_j + 0] -= tmp_force.x;
                  forces[n_j + 1] -= tmp_force.y;
                  forces[n_j + 2] -= tmp_force.z;

#if defined(STRESS)
                  /* calculate stresses */
                  if (us) {
                    forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
                    forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
                    forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
                    forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
                    forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
                    forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
                  }
#endif  // STRESS
                }
              }

              /* dipole-dipole contributions */
              if (dp_alpha[type1] && dp_alpha[type2]) {
                pp_ij = SPROD(
                    atom->p_ind,
                    g_config.conf_atoms[neigh->nr - g_mpi.firstatom].p_ind);
                tmp_1 = 3 * rp_i * rp_j;
                tmp_2 = 3 * fnval_tail / neigh->r2;

                fnval = -(tmp_1 - pp_ij) * fnval_tail;
                grad_1 = (tmp_1 - pp_ij) * grad_tail;
                grad_2 = 2 * rp_i * rp_j;

                forces[g_calc.energy_p + h] += fnval;

                if (uf) {
                  tmp_force.x =
                      grad_1 * neigh->dist.x -
                      tmp_2 *
                          (grad_2 * neigh->dist.x -
                           rp_i * neigh->r *
                               g_config.conf_atoms[neigh->nr - g_mpi.firstatom]
                                   .p_ind.x -
                           rp_j * neigh->r * atom->p_ind.x);
                  tmp_force.y =
                      grad_1 * neigh->dist.y -
                      tmp_2 *
                          (grad_2 * neigh->dist.y -
                           rp_i * neigh->r *
                               g_config.conf_atoms[neigh->nr - g_mpi.firstatom]
                                   .p_ind.y -
                           rp_j * neigh->r * atom->p_ind.y);
                  tmp_force.z =
                      grad_1 * neigh->dist.z -
                      tmp_2 *
                          (grad_2 * neigh->dist.z -
                           rp_i * neigh->r *
                               g_config.conf_atoms[neigh->nr - g_mpi.firstatom]
                                   .p_ind.z -
                           rp_j * neigh->r * atom->p_ind.z);
                  forces[n_i + 0] -= tmp_force.x;
                  forces[n_i + 1] -= tmp_force.y;
                  forces[n_i + 2] -= tmp_force.z;
                  /* actio = reactio */
                  n_j = 3 * neigh->nr;
                  forces[n_j + 0] += tmp_force.x;
                  forces[n_j + 1] += tmp_force.y;
                  forces[n_j + 2] += tmp_force.z;

#if defined(STRESS)
                  /* calculate stresses */
                  if (us) {
                    forces[stresses + 0] += neigh->dist.x * tmp_force.x;
                    forces[stresses + 1] += neigh->dist.y * tmp_force.y;
                    forces[stresses + 2] += neigh->dist.z * tmp_force.z;
                    forces[stresses + 3] += neigh->dist.x * tmp_force.y;
                    forces[stresses + 4] += neigh->dist.y * tmp_force.z;
                    forces[stresses + 5] += neigh->dist.z * tmp_force.x;
                  }
#endif  // STRESS
                }
              }
            }
          } /* loop over neighbours */
        }   /* end F O U R T H loop over atoms */
#endif      // DIPOLE

        /* F I F T H  loop: self energy contributions and sum-up force
         * contributions */
        double qq;
#if defined(DSF)
       double fnval_cut, gtail_cut, ggrad_cut;
        elstat_value(g_config.dp_cut, dp_kappa, &fnval_cut, &gtail_cut, &ggrad_cut);
#endif // DSF
        for (i = 0; i < g_config.inconf[h]; i++) { /* atoms */
          atom =
              g_config.conf_atoms + i + g_config.cnfstart[h] - g_mpi.firstatom;
          type1 = atom->type;
          n_i = 3 * (g_config.cnfstart[h] + i);

          /* self energy contributions */
          if (charge[type1]) {
            qq = charge[type1] * charge[type1];
#if defined(DSF)
           fnval = qq * ( DP_EPS * dp_kappa / sqrt(M_PI) +
              (fnval_cut - gtail_cut * g_config.dp_cut * g_config.dp_cut )*0.5 );
#else
             fnval = DP_EPS * dp_kappa * qq / sqrt(M_PI);
#endif // DSF
            forces[g_calc.energy_p + h] -= fnval;
          }
#if defined(DIPOLE)
          double pp;
          if (dp_alpha[type1]) {
            pp = SPROD(atom->p_ind, atom->p_ind);
            fnval = pp / (2 * dp_alpha[type1]);
            forces[g_calc.energy_p + h] += fnval;
          }
/* alternative dipole self energy including kappa-dependence */
// if (dp_alpha[type1]) {
// pp = SPROD(atom->p_ind, atom->p_ind);
// fnval = kkk * pp / sqrt(M_PI);
// forces[energy_p + h] += fnval;
//}
#endif  // DIPOLE

          /* sum-up: whole force contributions flow into tmpsum */
          /*          if (uf) {*/
          /*#ifdef FWEIGHT*/
          /*             Weigh by absolute value of force */
          /*            forces[k] /= FORCE_EPS + atom->absforce;*/
          /*            forces[k + 1] /= FORCE_EPS + atom->absforce;*/
          /*            forces[k + 2] /= FORCE_EPS + atom->absforce;*/
          /*#endif |+ FWEIGHT +|*/
          /*#ifdef CONTRIB*/
          /*            if (atom->contrib)*/
          /*#endif |+ CONTRIB +|*/
          /*              tmpsum +=*/
          /*                conf_weight[h] * (dsquare(forces[k]) +
           * dsquare(forces[k + 1]) + dsquare(forces[k + 2]));*/
          /*            printf("tmpsum = %f (forces)\n",tmpsum);*/
          /*          }*/

        } /* end F I F T H loop over atoms */

        /* S I X T H  loop: EAM force */
        if (uf) { /* only required if we calc forces */
          for (i = 0; i < g_config.inconf[h]; i++) {
            atom = g_config.conf_atoms + i + g_config.cnfstart[h] -
                   g_mpi.firstatom;
            n_i = 3 * (g_config.cnfstart[h] + i);
            for (j = 0; j < atom->num_neigh; j++) {
              /* loop over neighbors */
              neigh = atom->neigh + j;
              /* In small cells, an atom might interact with itself */
              self = (neigh->nr == i + g_config.cnfstart[h]) ? 1 : 0;
              col_F = g_calc.paircol + g_param.ntypes +
                      atom->type; /* column of F */
              r = neigh->r;
              /* are we within reach? */
              if ((r < g_pot.calc_pot.end[neigh->col[1]]) ||
                  (r < g_pot.calc_pot.end[col_F - g_param.ntypes])) {
                rho_grad =
                    (r < g_pot.calc_pot.end[neigh->col[1]])
                        ? splint_grad_dir(&g_pot.calc_pot, xi, neigh->slot[1],
                                          neigh->shift[1], neigh->step[1])
                        : 0.0;
                if (atom->type == neigh->type) /* use actio = reactio */
                  rho_grad_j = rho_grad;
                else
                  rho_grad_j = (r < g_pot.calc_pot.end[col_F - g_param.ntypes])
                                   ? (*g_splint_grad)(&g_pot.calc_pot, xi,
                                                      col_F - g_param.ntypes, r)
                                   : 0.0;
                /* now we know everything - calculate forces */
                eam_force =
                    (rho_grad * atom->gradF +
                     rho_grad_j *
                         g_config.conf_atoms[(neigh->nr) - g_mpi.firstatom]
                             .gradF);
                /* avoid double counting if atom is interacting with a
                   copy of itself */
                if (self)
                  eam_force *= 0.5;
                tmp_force.x = neigh->dist_r.x * eam_force;
                tmp_force.y = neigh->dist_r.y * eam_force;
                tmp_force.z = neigh->dist_r.z * eam_force;
                forces[n_i + 0] += tmp_force.x;
                forces[n_i + 1] += tmp_force.y;
                forces[n_i + 2] += tmp_force.z;
                /* actio = reactio */
                n_j = 3 * neigh->nr;
                forces[n_j + 0] -= tmp_force.x;
                forces[n_j + 1] -= tmp_force.y;
                forces[n_j + 2] -= tmp_force.z;
#if defined(STRESS)
                /* and stresses */
                if (us) {
                  forces[stresses + 0] -= neigh->dist.x * tmp_force.x;
                  forces[stresses + 1] -= neigh->dist.y * tmp_force.y;
                  forces[stresses + 2] -= neigh->dist.z * tmp_force.z;
                  forces[stresses + 3] -= neigh->dist.x * tmp_force.y;
                  forces[stresses + 4] -= neigh->dist.y * tmp_force.z;
                  forces[stresses + 5] -= neigh->dist.z * tmp_force.x;
                }
#endif          // STRESS
              } /* within reach */
            }   /* loop over neighbours */
#if defined(FWEIGHT)
            /* Weigh by absolute value of force */
            forces[n_i + 0] /= FORCE_EPS + atom->absforce;
            forces[n_i + 1] /= FORCE_EPS + atom->absforce;
            forces[n_i + 2] /= FORCE_EPS + atom->absforce;
#endif  // FWEIGHT
        /* sum up forces  */
#if defined(CONTRIB)
            if (atom->contrib)
#endif  // CONTRIB
              tmpsum += g_config.conf_weight[h] *
                        (dsquare(forces[n_i + 0]) + dsquare(forces[n_i + 1]) +
                         dsquare(forces[n_i + 2]));
          }
        }

        /* end S I X T H loop over atoms */
        /* whole energy contributions flow into tmpsum */
        forces[g_calc.energy_p + h] /= (double)g_config.inconf[h];
        forces[g_calc.energy_p + h] -= g_config.force_0[g_calc.energy_p + h];
        tmpsum += g_config.conf_weight[h] * g_param.eweight *
                  dsquare(forces[g_calc.energy_p + h]);

#if defined(STRESS)
        /* whole stress contributions flow into tmpsum */
        if (uf && us) {
          for (i = 0; i < 6; i++) {
            forces[stresses + i] /= g_config.conf_vol[h - g_mpi.firstconf];
            forces[stresses + i] -= g_config.force_0[stresses + i];
            tmpsum += g_config.conf_weight[h] * g_param.sweight *
                      dsquare(forces[stresses + i]);
          }
        }
#endif  // STRESS
        /* limiting constraints per configuration */
        tmpsum += g_config.conf_weight[h] * dsquare(forces[g_calc.limit_p + h]);
      } /* end M A I N loop over configurations */
    }   /* parallel region */
#if defined(MPI)
    /* Reduce rho_sum */
    MPI_Reduce(&rho_sum_loc, &rho_sum, 1, MPI_DOUBLE, MPI_SUM, 0,
               MPI_COMM_WORLD);
#else   /* MPI */
    rho_sum = rho_sum_loc;
#endif  // MPI

/* dummy constraints (global) */
#if defined(APOT)
    /* add punishment for out of bounds (mostly for powell_lsq) */
    if (g_mpi.myid == 0) {
      tmpsum += apot_punish(xi_opt, forces);
    }
#endif  // APOT

#if !defined(NOPUNISH)
    if (g_mpi.myid == 0) {
      int g;
      for (g = 0; g < g_param.ntypes; g++) {
#if defined(NORESCALE)
        /* clear field */
        forces[g_calc.dummy_p + g_param.ntypes + g] = 0.0; /* Free end... */
        /* NEW: Constraint on U': U'(1.0)=0.0; */
        forces[g_calc.dummy_p + g] =
            DUMMY_WEIGHT *
            splint_grad(&calc_pot, xi, paircol + g_param.ntypes + g, 1.0);
#else   /* NOTHING */
        forces[g_calc.dummy_p + g_param.ntypes + g] = 0.0; /* Free end... */
        /* constraints on U`(n) */
        forces[g_calc.dummy_p + g] =
            DUMMY_WEIGHT *
                (*g_splint_grad)(
                    &g_pot.calc_pot, xi, g_calc.paircol + g_param.ntypes + g,
                    0.5 * (g_pot.calc_pot
                               .begin[g_calc.paircol + g_param.ntypes + g] +
                           g_pot.calc_pot
                               .end[g_calc.paircol + g_param.ntypes + g])) -
            g_config.force_0[g_calc.dummy_p + g];
#endif  // NORESCALE
        tmpsum += dsquare(forces[g_calc.dummy_p + g_param.ntypes + g]);
        tmpsum += dsquare(forces[g_calc.dummy_p + g]);
      } /* loop over types */
#if defined(NORESCALE)
      /* NEW: Constraint on n: <n>=1.0 ONE CONSTRAINT ONLY */
      /* Calculate averages */
      rho_sum /= (double)natoms;
      /* ATTN: if there are invariant potentials, things might be problematic */
      forces[dummy_p + g_param.ntypes] = DUMMY_WEIGHT * (rho_sum - 1.0);
      tmpsum += dsquare(forces[dummy_p + g_param.ntypes]);
#endif  // NORESCALE
    }
#endif  // NOPUNISH

#if defined(MPI)
    /* reduce global sum */
    sum = 0.0;
    MPI_Reduce(&tmpsum, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    /* gather forces, energies, stresses */
    if (g_mpi.myid == 0) { /* root node already has data in place */
      /* forces */
      MPI_Gatherv(MPI_IN_PLACE, g_mpi.myatoms, g_mpi.MPI_VECTOR, forces,
                  g_mpi.atom_len, g_mpi.atom_dist, g_mpi.MPI_VECTOR, 0,
                  MPI_COMM_WORLD);
      /* energies */
      MPI_Gatherv(MPI_IN_PLACE, g_mpi.myconf, MPI_DOUBLE,
                  forces + g_calc.energy_p, g_mpi.conf_len, g_mpi.conf_dist,
                  MPI_DOUBLE, 0, MPI_COMM_WORLD);
#if defined(STRESS)
      /* stresses */
      MPI_Gatherv(MPI_IN_PLACE, g_mpi.myconf, g_mpi.MPI_STENS,
                  forces + g_calc.stress_p, g_mpi.conf_len, g_mpi.conf_dist,
                  g_mpi.MPI_STENS, 0, MPI_COMM_WORLD);
#endif  // STRESS
#if !defined(NORESCALE)
      /* punishment constraints */
      MPI_Gatherv(MPI_IN_PLACE, g_mpi.myconf, MPI_DOUBLE,
                  forces + g_calc.limit_p, g_mpi.conf_len, g_mpi.conf_dist,
                  MPI_DOUBLE, 0, MPI_COMM_WORLD);
#endif  // !NORESCALE
    } else {
      /* forces */
      MPI_Gatherv(forces + g_mpi.firstatom * 3, g_mpi.myatoms, g_mpi.MPI_VECTOR,
                  forces, g_mpi.atom_len, g_mpi.atom_dist, g_mpi.MPI_VECTOR, 0,
                  MPI_COMM_WORLD);
      /* energies */
      MPI_Gatherv(forces + g_calc.energy_p + g_mpi.firstconf, g_mpi.myconf,
                  MPI_DOUBLE, forces + g_calc.energy_p, g_mpi.conf_len,
                  g_mpi.conf_dist, MPI_DOUBLE, 0, MPI_COMM_WORLD);
#if defined(STRESS)
      /* stresses */
      MPI_Gatherv(forces + g_calc.stress_p + 6 * g_mpi.firstconf, g_mpi.myconf,
                  g_mpi.MPI_STENS, forces + g_calc.stress_p, g_mpi.conf_len,
                  g_mpi.conf_dist, g_mpi.MPI_STENS, 0, MPI_COMM_WORLD);
#endif  // STRESS
#if !defined(NORESCALE)
      /* punishment constraints */
      MPI_Gatherv(forces + g_calc.limit_p + g_mpi.firstconf, g_mpi.myconf,
                  MPI_DOUBLE, forces + g_calc.limit_p, g_mpi.conf_len,
                  g_mpi.conf_dist, MPI_DOUBLE, 0, MPI_COMM_WORLD);
#endif  // !NORESCALE
    }
/* no need to pick up dummy constraints - they are already @ root */
#else
    sum = tmpsum; /* global sum = local sum  */
#endif  // MPI

    /* root process exits this function now */
    if (g_mpi.myid == 0) {
      g_calc.fcalls++; /* Increase function call counter */
      if (isnan(sum)) {
#if defined(DEBUG)
        printf("\n--> Force is nan! <--\n\n");
#endif  // DEBUG
        return 10e10;
      } else
        return sum;
    }
  }

  /* once a non-root process arrives here, all is done. */
  return -1.0;
}
Exemple #12
0
void do_voronoi_2d(void)

{
  int     i, j, l, n;
  real    det, detinv;
  vektor  icoord, jcoord, tmpvertex, vertex[NUM];
  int     ok, index[NUM];
  int     vertexcount, vertexnum, edgesnum;
  int     *edges;
  ivektor ivertex[NUM];
  real    idist2, jdist2;
  real    sin, cos, maxcos;
  int     minj, ord[NUM];

  /* Allocate memory for data of edges */
  edges = (int *) malloc( neighnum * sizeof(int) );

  if( edges == NULL )
    error("Cannot allocate memory for vertices");

  vertexcount = 0;
  area        = 0.0;

  /* Each possible vertex defined by the intersection of 2 lines is examined */  
  for (i=0; i<(neighnum-1); ++i)
    {
      icoord.x = candcoord[i].x;
      icoord.y = candcoord[i].y;
      idist2   = -canddist2[i];

      for (j=i+1; j<neighnum; ++j)
	{
	  jcoord.x = candcoord[j].x;
	  jcoord.y = candcoord[j].y;
	  jdist2   = -canddist2[j];

	  det = icoord.x * jcoord.y - icoord.y * jcoord.x;

	  /* check whether edges intersect */
	  if ( SQR(det) > TOL2)
	    {
	      detinv = 1.0 / det;

	      tmpvertex.x = ( icoord.y * jdist2 - jcoord.y * idist2 ) * detinv;
	      tmpvertex.y = ( jcoord.x * idist2 - icoord.x * jdist2 ) * detinv;

	      /* Check whether vertex belongs to voronoi cell */
	      l = 0;
	      ok = 1;

	      do {
		if( l!=i && l!=j )
		  ok = ( SPROD(candcoord[l] , tmpvertex ) <= canddist2[l] );

		++l;

	      } while ( (ok==1) && (l<neighnum) );

	      if( ok==1 )
		{ 
		  ivertex[vertexcount].x = i;
		  ivertex[vertexcount].y = j;
  
		  vertex[vertexcount].x  = 0.5 * tmpvertex.x;
		  vertex[vertexcount].y  = 0.5 * tmpvertex.y;

		  ++vertexcount;
		}
	    }
	}
    }

  vertexnum = vertexcount;

  /* Check whether some vertices coincide */
  for ( i=0; i<vertexnum; ++i )
    {
      index[i] = 1;
      for (j=i+1; j<vertexnum; ++j )
	if ( (SQR(vertex[j].x-vertex[i].x)<TOL2) && (SQR(vertex[j].y-vertex[i].y)<TOL2) )
	  index[i] = 0;
    }

  /* Remove coincident vertices */
  j = 0;
  for ( i=0; i<vertexnum; ++i )
    if ( index[i] != 0 )
      {
	ivertex[j].x = ivertex[i].x;
	ivertex[j].y = ivertex[i].y;

	vertex[j].x  = vertex[i].x;
	vertex[j].y  = vertex[i].y;
	
        ++j;
      }

  vertexnum = j;    

  /* Number of vertices of Voronoi cell must be greater than 2 */
  if ( vertexnum < 3 )  area = 0.0;
  else
    {
      /* Initialization */
      for (n=0; n<neighnum; ++n)
	edges[n] = 0;

      for (n=0; n<vertexnum; ++n)
	{
	  ++edges[ivertex[n].x];
	  ++edges[ivertex[n].y];
	}
     
      /* Number of edges of Voronoi cell */
      edgesnum = 0;
      for (n=0; n<neighnum; ++n)
	{
	  edgesnum += edges[n];
	}

      edgesnum /= 2;

      /* Check whether number of vertices equals number of edges */
      if ( edgesnum == vertexnum )
	{
	  
	  /* Statistics */
	  if( neighnum  > maxneigh ) maxneigh = neighnum;
	  sumneigh += neighnum;
	  if( vertexnum > maxvert  ) maxvert  = vertexnum;
	  sumvert  += vertexnum;
	  if( edgesnum  > maxedges ) maxedges = edgesnum;
	  sumedges += edgesnum;
	
	  ++atomcount;

	  /* Order vertices */
	  ord[0] = 0;
	  for ( i=0; i<vertexnum-1; ++i)
	    {
	      maxcos = -1.0;
	      for (j=0; j<vertexnum; ++j)
		{
		  sin = vertex[j].x * vertex[ord[i]].y - vertex[j].y * vertex[ord[i]].x;
		  if ( sin > TOL )
		    {
		      cos = SPROD( vertex[j], vertex[ord[i]] )/ sqrt(SPROD(vertex[j],vertex[j]))/ sqrt(SPROD(vertex[ord[i]],vertex[ord[i]]));
		      if ( cos > maxcos ) 
			{
			  maxcos = cos;
			  minj   = j;
			}
		    }
		}

	      ord[i+1] = minj;

	    }

	  /* Compute area of voronoi cell */
	  for (i=0; i<vertexnum-1; ++i)
	    area += 0.5 * (vertex[ord[i+1]].x * vertex[ord[i]].y - vertex[ord[i+1]].y * vertex[ord[i]].x);
	  
	  area += 0.5 * (vertex[ord[0]].x * vertex[ord[vertexnum-1]].y - vertex[ord[0]].y * vertex[ord[vertexnum-1]].x);

	} /* number of edges == number of vertices */

      else area = 0.0;

    } /* vertesnum < 3 */

  free(edges);
								  
}
Exemple #13
0
void do_voronoi_3d(void)

{
  int       i, j, k, l, n;
  real      ab, bc, ca, da, db, dc, det, detinv, tmp;
  vektor    icoord, jcoord, kcoord;
  real      idist2, jdist2, kdist2;
  vektor    tmpvek, tmpvertex, vertex[NUM];
  int       ok, vertexcount, vertexnum, facesnum, edgesnum;
  int       *vertexnumi;
  real      area_i, height;
  real      sin, cos, maxcos;
  int       mink, ord[NUM], index[NUM], surfind[NUM];
  vektor    *coord, center;
  vektorstr *vertexloc;


  /* Allocate memory for vertices */
  vertexnumi  = (int *) malloc( neighnum * sizeof(int));
  coord       = (vektor *) malloc( neighnum * sizeof(vektor));
  vertexloc   = (vektorstr *) malloc( neighnum * sizeof(vektorstr));

  if( vertexloc == NULL || coord == NULL || vertexnumi == NULL ) 
    error("Cannot allocate memory for vertices!\n");

  vertexcount = 0;
  volume      = 0.0;

  /* Each possible vertex defined by the intersection of 3 planes is examined */
  for (i=0; i<neighnum-2; ++i)
    {
      icoord.x = candcoord[i].x;
      icoord.y = candcoord[i].y;
      icoord.z = candcoord[i].z;
      idist2   = -canddist2[i];

      for (j=i+1; j<neighnum-1; ++j)
	{
	  jcoord.x = candcoord[j].x;
	  jcoord.y = candcoord[j].y;
	  jcoord.z = candcoord[j].z;
	  jdist2   = -canddist2[j];

	  ab = icoord.x * jcoord.y - jcoord.x * icoord.y;
	  bc = icoord.y * jcoord.z - jcoord.y * icoord.z;
	  ca = icoord.z * jcoord.x - jcoord.z * icoord.x;
	  da = idist2   * jcoord.x - jdist2   * icoord.x;
	  db = idist2   * jcoord.y - jdist2   * icoord.y;
	  dc = idist2   * jcoord.z - jdist2   * icoord.z;

	  for (k=j+1; k<neighnum; ++k)
	    {
	      kcoord.x = candcoord[k].x;
	      kcoord.y = candcoord[k].y;
	      kcoord.z = candcoord[k].z;
	      kdist2   = -canddist2[k];

	      det = kcoord.x * bc + kcoord.y * ca + kcoord.z * ab;

	      /* Check whether planes intersect */
	      if( SQR(det) > TOL2 )
		{
		  detinv = 1.0 / det;

		  tmpvertex.x = ( -kdist2 * bc + kcoord.y * dc - kcoord.z * db ) * detinv;
		  tmpvertex.y = ( -kcoord.x * dc - kdist2 * ca + kcoord.z * da ) * detinv;
		  tmpvertex.z = (  kcoord.x * db - kcoord.y * da - kdist2 * ab ) * detinv;

		  /* Check whether vertex belongs to the Voronoi cell */
		  l  = 0;
		  ok = 1;

		  do {
		    if( l!=i && l!=j && l!=k)
		      ok = ( SPROD( candcoord[l], tmpvertex ) <= canddist2[l] + TOL_VERT2 )    ;
	      
		    ++l;

		  } while( ok && (l<neighnum));
		    
		    if( ok )
		      {
			vertex[vertexcount].x  = 0.5 * tmpvertex.x;
			vertex[vertexcount].y  = 0.5 * tmpvertex.y;
			vertex[vertexcount].z  = 0.5 * tmpvertex.z;
	
			++vertexcount;
		      }

		} /* Planes intersect */

	    } /* k */
	} /* j */
    } /* i */

  vertexnum = vertexcount;

  /* Check whether some vertices coincide */
  for ( i=0; i<vertexnum; ++i )
    {
      index[i] = 1;
      for ( j=i+1; j<vertexnum; ++j )
	{
	  tmpvek.x = vertex[j].x - vertex[i].x;
	  tmpvek.y = vertex[j].y - vertex[i].y;
	  tmpvek.z = vertex[j].z - vertex[i].z;

	  if ( SPROD( tmpvek, tmpvek) < TOL2 )
	    index[i] = 0;
	}  
    }

  /* Remove coincident vertices */
  j = 0;
  for ( i=0; i<vertexnum; ++i )
    if ( index[i] != 0 )
      {
	vertex[j].x  = vertex[i].x;
	vertex[j].y  = vertex[i].y;
	vertex[j].z  = vertex[i].z;

	++j;
      }

  vertexnum = j;

  /* Number of vertices of Voronoi cell must be greater than 3 */
  if(vertexnum > 3 )  
    {
      /* Check whether faces exist */
      facesnum = 0;

      /* Each neighbour atom i corresponds to at most one surface * 
       * Sum over all surfaces */
      for (i=0; i<neighnum; ++i)
	{
	  /* Coordinates of center of surface i */
	  coord[i].x = 0.5 * candcoord[i].x;
	  coord[i].y = 0.5 * candcoord[i].y;
	  coord[i].z = 0.5 * candcoord[i].z;

          /* Look for vertices that belong to surface i */
          vertexnumi[i] = 0;
	  for (j=0; j<vertexnum; ++j)
	    {
	      surfind[j] = 0;

	      vertexloc[i][j].x = vertex[j].x - coord[i].x;
	      vertexloc[i][j].y = vertex[j].y - coord[i].y;
	      vertexloc[i][j].z = vertex[j].z - coord[i].z;

	      tmp = SPROD(coord[i],vertexloc[i][j]);

	      if( SQR(tmp) < TOL_DIST2 )
		{
		  /* vertex j belongs to surface i */
		  surfind[j] = 1; 
		  ++vertexnumi[i];
		}
	    }

	  /* Surface i exists */
	  if (vertexnumi[i] > 2)
	    {
	      ++facesnum;

	      /* Compute coordinates of vertices belonging to surface i */
	      k = 0;
	      for (j=0; j<vertexnum; ++j)
		if( surfind[j] == 1)
		  {
		    vertexloc[i][k].x = vertexloc[i][j].x;
		    vertexloc[i][k].y = vertexloc[i][j].y;
		    vertexloc[i][k].z = vertexloc[i][j].z;

		    ++k;
		  }
	    }
	  /* Transform into center of mass system */
	  center.x = 0.0;
	  center.y = 0.0; 
	  center.z = 0.0;
	  
	  if( vertexnumi[i] > 2)
	    {
	      for ( j=0; j<vertexnumi[i]; ++j)
		{
		  center.x += vertexloc[i][j].x;
		  center.y += vertexloc[i][j].y;
		  center.z += vertexloc[i][j].z;
		}
	      
	      tmp       = 1.0 / vertexnumi[i];
	      center.x *= tmp;
	      center.y *= tmp;
	      center.z *= tmp;
	      
	      for ( j=0; j<vertexnumi[i]; ++j)
		{
		  vertexloc[i][j].x -= center.x;
		  vertexloc[i][j].y -= center.y;
		  vertexloc[i][j].z -= center.z;
		}

	    }

	} /* i */

      /* Number of edges of Voronoi cell */
      edgesnum = 0;

      for ( n=0; n<neighnum; ++n)
	if( vertexnumi[n] > 2)
	  edgesnum += vertexnumi[n];
      
      edgesnum /= 2;

      /* Check whether Euler relation holds */
      if ( (vertexnum - edgesnum + facesnum) == 2 )
	{      

	  /* Statistics */
	  if( neighnum  > maxneigh  ) maxneigh = neighnum;
	  sumneigh += neighnum;
	  if( vertexnum > maxvert  ) maxvert  = vertexnum;
	  sumvert  += vertexnum;
	  if( edgesnum  > maxedges ) maxedges = edgesnum;
	  sumedges += edgesnum;
	  if( facesnum  > maxfaces ) maxfaces = facesnum;
	  sumfaces += facesnum;

	  ++ atomcount;

	  /* Compute volume of Voronoi cell */

	  /* For all potential faces */
	  for (i=0; i<neighnum; ++i)
	    /* Surface i exists */
	    if(vertexnumi[i] > 2)
	      {
		/* Sort vertices of face i */
		ord[0] = 0;
		for (j=0; j<vertexnumi[i]-1; ++j)
		  {
		    maxcos = -1.0;
		    for (k=0; k<vertexnumi[i]; ++k)
		      {
			tmpvek.x = vertexloc[i][k].y * vertexloc[i][ord[j]].z - vertexloc[i][k].z * vertexloc[i][ord[j]].y;
			tmpvek.y = vertexloc[i][k].z * vertexloc[i][ord[j]].x - vertexloc[i][k].x * vertexloc[i][ord[j]].z;
			tmpvek.z = vertexloc[i][k].x * vertexloc[i][ord[j]].y - vertexloc[i][k].y * vertexloc[i][ord[j]].x; 
 
			sin = SPROD( tmpvek, coord[i]);
		      
			if( sin > TOL )
			  {
			    cos = SPROD( vertexloc[i][k], vertexloc[i][ord[j]] )/ sqrt(SPROD(vertexloc[i][k],vertexloc[i][k]))/ sqrt(SPROD(vertexloc[i][ord[j]],vertexloc[i][ord[j]]));
			    if( cos > maxcos )
			      {
				maxcos = cos;
				mink   = k;
			      }
			  }
		      }

		    ord[j+1] = mink;
		  
		  }

		/* Compute area of surface i */
		area_i = 0.0;
		height = sqrt(SPROD( coord[i], coord[i] ));
		tmp    = 1.0 / height;

		for (j=0; j<vertexnumi[i]-1; ++j)
		    {
		      tmpvek.x = vertexloc[i][ord[j+1]].y * vertexloc[i][ord[j]].z - vertexloc[i][ord[j+1]].z * vertexloc[i][ord[j]].y;
		      tmpvek.y = vertexloc[i][ord[j+1]].z * vertexloc[i][ord[j]].x - vertexloc[i][ord[j+1]].x * vertexloc[i][ord[j]].z;
		      tmpvek.z = vertexloc[i][ord[j+1]].x * vertexloc[i][ord[j]].y - vertexloc[i][ord[j+1]].y * vertexloc[i][ord[j]].x; 
			      
		      area_i += 0.5 * SPROD( tmpvek, coord[i] ) * tmp;
	
		    }
		tmpvek.x = vertexloc[i][ord[0]].y * vertexloc[i][ord[vertexnumi[i]-1]].z - vertexloc[i][ord[0]].z * vertexloc[i][ord[vertexnumi[i]-1]].y;
		tmpvek.y = vertexloc[i][ord[0]].z * vertexloc[i][ord[vertexnumi[i]-1]].x - vertexloc[i][ord[0]].x * vertexloc[i][ord[vertexnumi[i]-1]].z;
		tmpvek.z = vertexloc[i][ord[0]].x * vertexloc[i][ord[vertexnumi[i]-1]].y - vertexloc[i][ord[0]].y * vertexloc[i][ord[vertexnumi[i]-1]].x; 
		  
		area_i +=  0.5 * SPROD( tmpvek, coord[i] ) * tmp;
	
		/* Volume of Voronoi cell */	  
		volume += area_i * height / 3.0;

	      } /* vertexnum[i] > 2 */

	} /* Euler relation holds */

    } /* Number of vertices > 3 */


  free(vertexloc);
  free(coord);
  free(vertexnumi);

}
Exemple #14
0
void voronoi(void)

{
  cell *p, *q;
  int i, j, k, l, m, n, r, s, t;
  int v, w, neighcount;
  vektor tmp;
  vektor pbc;
  real tmpdist2;
  int num = NUM;

  candcoord = (vektor *) malloc( num * sizeof(vektor));
  canddist2 = (real   *) malloc( num * sizeof(real));

  /* for each cell */
  for (i=0; i < cell_dim.x; ++i)
    for (j=0; j < cell_dim.y; ++j)
#ifndef TWOD
      for (k=0; k < cell_dim.z; ++k)
#endif
      {
#ifdef TWOD
        p = PTR_2D_V(cell_array,i,j  ,cell_dim);
#else
        p = PTR_3D_V(cell_array,i,j,k,cell_dim);
#endif

	/* for each atom in first cell */
	for (v=0; v<p->n; ++v)
	  {
	    neighcount = 0;

	    /* For each neighbour of this cell */
	    for (l=-1; l <= 1; ++l)
	      for (m=-1; m <= 1; ++m)
#ifndef TWOD
		for (n=-1; n <= 1; ++n)
#endif
		  {
		    /* Calculate Indicies of Neighbour */
		    r = i+l;  pbc.x = 0;
		    s = j+m;  pbc.y = 0;
#ifndef TWOD
		    t = k+n;  pbc.z = 0;
#endif

		    /* deal with periodic boundary conditions if necessary */
		    if (r<0) {
		      if (pbc_dirs.x==1) {
			r = cell_dim.x-1; 
			pbc.x -= box_x.x;      
			pbc.y -= box_x.y;
#ifndef TWOD
			pbc.z -= box_x.z;
#endif
		      } else continue;
		    }
		    if (s<0) {
		      if (pbc_dirs.y==1) {
			s = cell_dim.y-1;
			pbc.x -= box_y.x;      
			pbc.y -= box_y.y;
#ifndef TWOD
			pbc.z -= box_y.z;
#endif
		      } else continue;
		    }
#ifndef TWOD
		    if (t<0) {
		      if (pbc_dirs.z==1) {
			t = cell_dim.z-1;
			pbc.x -= box_z.x;      
			pbc.y -= box_z.y;
			pbc.z -= box_z.z;
		      } else continue;
		    }
#endif
		    if (r>cell_dim.x-1) {
		      if (pbc_dirs.x==1) {
			r = 0; 
			pbc.x += box_x.x;      
			pbc.y += box_x.y;
#ifndef TWOD
			pbc.z += box_x.z;
#endif
		      } else continue;
		    }
		    if (s>cell_dim.y-1) {
		      if (pbc_dirs.y==1) {
			s = 0; 
			pbc.x += box_y.x;      
			pbc.y += box_y.y;
#ifndef TWOD
			pbc.z += box_y.z;
#endif
		      } else continue;
		    }
#ifndef TWOD
		    if (t>cell_dim.z-1) {
		      if (pbc_dirs.z==1) {
			t = 0; 
			pbc.x += box_z.x;      
			pbc.y += box_z.y;
			pbc.z += box_z.z;
		      } else continue;
		    }
#endif
	    
		    /* Neighbour cell (note that p==q ist possible) */
#ifdef TWOD
		    q = PTR_2D_V(cell_array,r,s,cell_dim);
#else
		    q = PTR_3D_V(cell_array,r,s,t,cell_dim);
#endif
		    /* for each particle in second cell */
		    for (w=0; w<q->n; ++w)
		      {
			tmp.x    = q->ort[w].x - p->ort[v].x + pbc.x;
			tmp.y    = q->ort[w].y - p->ort[v].y + pbc.y;
#ifndef TWOD
			tmp.z    = q->ort[w].z - p->ort[v].z + pbc.z;
#endif
			tmpdist2 = SPROD( tmp, tmp );
		       
			/* Candidates for Voronoi cells */
#ifdef STRESS
			if( (tmpdist2 <= r2_cut) && (tmpdist2 > TOL2))
#else
			if( (tmpdist2 <= SQR(r_max)) && (tmpdist2 > TOL2))
#endif
			  {
			    if( neighcount > num-1 )
			      {
				num += 10;
				candcoord = (vektor *) realloc(candcoord, num * sizeof(vektor));
				canddist2 = (real   *) realloc(canddist2, num * sizeof(real));
			      }

			    candcoord[neighcount].x    = tmp.x;
			    candcoord[neighcount].y    = tmp.y;
#ifndef TWOD
			    candcoord[neighcount].z    = tmp.z;
#endif
			    canddist2[neighcount]      = tmpdist2;

			    ++ neighcount;

			  }

		      } /* w */

		  } /* lmn */

	    /* If there are less than four (three) points, a polyhedron (polygon) cannot
	       be constructed */
#ifndef TWOD
	    if( (neighnum = neighcount) < 4 )  volume = 0.0;
#else
	    if( (neighnum = neighcount) < 3 )  area   = 0.0;
#endif
	    else
	      {
		/* Sort candidates in ascending order of distance */
		sort();

		/* Perform Voronoi analysis */
#ifdef TWOD
		do_voronoi_2d();
#else
		do_voronoi_3d(); 
#endif
	      }
 
#ifndef TWOD
	    p->vol[v] = volume;
#else
	    p->vol[v] = area;
#endif

	  } /* v */

      } /* ijk */

}