+ /* save for use in 3bp */
+ exchange->f_c=f_c;
+ exchange->df_c=df_c;
+
+ /* enable the run of 3bp function and 2bp post processing */
+ exchange->run3bp=1;
+ exchange->run2bp_post=1;
+
+ /* reset 3bp sums */
+ exchange->zeta_ij=0.0;
+ exchange->zeta_ji=0.0;
+ v3_zero(&(exchange->dzeta_ij));
+ v3_zero(&(exchange->dzeta_ji));
+
+ return 0;
+}
+
+/* tersoff 2 body post part */
+
+int tersoff_mult_post_2bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,u8 bc) {
+
+ /*
+ * here we have to allow for the 3bp sums
+ *
+ * that is:
+ * - zeta_ij, dzeta_ij
+ * - zeta_ji, dzeta_ji
+ *
+ * to compute the 3bp contribution to:
+ * - Vij, dVij
+ * - dVji
+ *
+ */
+
+ t_tersoff_mult_params *params;
+ t_tersoff_exchange *exchange;
+
+ t_3dvec force,temp;
+ t_3dvec *dist_ij;
+ double b,db,tmp;
+ double f_c,df_c,f_a,df_a;
+ double chi,ni,betaini,nj,betajnj;
+ double zeta;
+
+ params=moldyn->pot2b_params;
+ exchange=&(params->exchange);
+
+ /* we do not run if f_c_ij was detected to be 0! */
+ if(!(exchange->run2bp_post))
+ return 0;
+
+ f_c=exchange->f_c;
+ df_c=exchange->df_c;
+ f_a=exchange->f_a;
+ df_a=exchange->df_a;
+ betaini=exchange->betaini;
+ betajnj=exchange->betajnj;
+ ni=*(exchange->n_i);
+ nj=*(exchange->n_j);
+ chi=exchange->chi;
+ dist_ij=&(exchange->dist_ij);
+
+ /* Vij and dVij */
+ zeta=exchange->zeta_ij;
+ if(zeta==0.0) {
+ moldyn->debug++; /* just for debugging ... */
+ db=0.0;
+ b=chi;
+ v3_scale(&force,dist_ij,df_a*b*f_c);
+ }
+ else {
+ tmp=betaini*pow(zeta,ni-1.0); /* beta^n * zeta^n-1 */
+ b=(1+zeta*tmp); /* 1 + beta^n zeta^n */
+ db=chi*pow(b,-1.0/(2*ni)-1); /* x(...)^(-1/2n - 1) */
+ b=db*b; /* b_ij */
+ db*=-0.5*tmp; /* db_ij */
+ v3_scale(&force,&(exchange->dzeta_ij),f_a*db);
+ v3_scale(&temp,dist_ij,df_a*b);
+ v3_add(&force,&force,&temp);
+ v3_scale(&force,&force,f_c);
+ }
+ v3_scale(&temp,dist_ij,df_c*b*f_a);
+ v3_add(&force,&force,&temp);
+ v3_scale(&force,&force,-0.5);
+
+ /* add force */
+ v3_add(&(ai->f),&(ai->f),&force);
+
+ /* add energy of 3bp sum */
+ moldyn->energy+=(0.5*f_c*b*f_a);
+
+ /* dVji */
+ zeta=exchange->zeta_ji;
+ if(zeta==0.0) {
+ moldyn->debug++;
+ b=chi;
+ v3_scale(&force,dist_ij,df_a*b*f_c);
+ }
+ else {
+ tmp=betajnj*pow(zeta,nj-1.0); /* beta^n * zeta^n-1 */
+ b=(1+zeta*tmp); /* 1 + beta^n zeta^n */
+ db=chi*pow(b,-1.0/(2*nj)-1); /* x(...)^(-1/2n - 1) */
+ b=db*b; /* b_ij */
+ db*=-0.5*tmp; /* db_ij */
+ v3_scale(&force,&(exchange->dzeta_ji),f_a*db);
+ v3_scale(&temp,dist_ij,df_a*b);
+ v3_add(&force,&force,&temp);
+ v3_scale(&force,&force,f_c);
+ }
+ v3_scale(&temp,dist_ij,df_c*b*f_a);
+ v3_add(&force,&force,&temp);
+ v3_scale(&force,&force,-0.5);
+
+ /* add force */
+ v3_sub(&(ai->f),&(ai->f),&force);
+
+ return 0;
+}
+
+/* tersoff 3 body part */
+
+int tersoff_mult_3bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,t_atom *ak,u8 bc) {
+
+ t_tersoff_mult_params *params;
+ t_tersoff_exchange *exchange;
+ t_3dvec dist_ij,dist_ik,dist_jk;
+ t_3dvec temp1,temp2;
+ t_3dvec *dzeta;
+ double R,S,s_r;
+ double B,mu;
+ double d_ij,d_ik,d_jk;
+ double rr,dd;
+ double f_c,df_c;
+ double f_c_ik,df_c_ik,arg;
+ double f_c_jk;
+ double n,c,d,h;
+ double c2,d2,c2d2;
+ double cos_theta,d_costheta1,d_costheta2;
+ double h_cos,d2_h_cos2;
+ double frac,g,zeta,chi;
+ double tmp;
+ int num;
+
+ params=moldyn->pot3b_params;
+ exchange=&(params->exchange);
+
+ if(!(exchange->run3bp))
+ return 0;
+
+ /*
+ * calc of 3bp contribution of V_ij and dV_ij/ji/jk &
+ * 2bp contribution of dV_jk
+ *
+ * for Vij and dV_ij we still need:
+ * - b_ij, db_ij (zeta_ij)
+ * - f_c_ik, df_c_ik, constants_i, cos_theta_ijk, d_costheta_ijk
+ *
+ * for dV_ji we still need:
+ * - b_ji, db_ji (zeta_ji)
+ * - f_c_jk, d_c_jk, constants_j, cos_theta_jik, d_costheta_jik
+ *
+ * for dV_jk we need:
+ * - f_c_jk
+ * - f_a_jk
+ * - db_jk (zeta_jk)
+ * - f_c_ji, df_c_ji, constants_j, cos_theta_jki, d_costheta_jki
+ *
+ */
+
+ /*
+ * get exchange data
+ */
+
+ /* dist_ij, d_ij - this is < S_ij ! */
+ dist_ij=exchange->dist_ij;
+ d_ij=exchange->d_ij;
+
+ /* f_c_ij, df_c_ij (same for ji) */
+ f_c=exchange->f_c;
+ df_c=exchange->df_c;
+
+ /*
+ * calculate unknown values now ...
+ */
+
+ /* V_ij and dV_ij stuff (in b_ij there is f_c_ik) */
+
+ /* dist_ik, d_ik */
+ v3_sub(&dist_ik,&(ak->r),&(ai->r));
+ if(bc) check_per_bound(moldyn,&dist_ik);
+ d_ik=v3_norm(&dist_ik);
+
+ /* ik constants */
+ num=ai->bnum;
+ if(num==ak->bnum) {
+ R=params->R[num];
+ S=params->S[num];
+ }
+ else {
+ R=params->Rmixed;
+ S=params->Smixed;
+ }
+
+ /* zeta_ij/dzeta_ij contribution only for d_ik < S */
+ if(d_ik<S) {
+
+ /* get constants_i from exchange data */
+ n=*(exchange->n_i);
+ c=*(exchange->c_i);
+ d=*(exchange->d_i);
+ h=*(exchange->h_i);
+ c2=exchange->ci2;
+ d2=exchange->di2;
+ c2d2=exchange->ci2di2;
+
+ /* cosine of theta_ijk by scalaproduct */
+ rr=v3_scalar_product(&dist_ij,&dist_ik);
+ dd=d_ij*d_ik;
+ cos_theta=rr/dd;
+
+ /* d_costheta */
+ tmp=1.0/dd;
+ d_costheta1=cos_theta/(d_ij*d_ij)-tmp;
+ d_costheta2=cos_theta/(d_ik*d_ik)-tmp;
+
+ /* some usefull values */
+ h_cos=(h-cos_theta);
+ d2_h_cos2=d2+(h_cos*h_cos);
+ frac=c2/(d2_h_cos2);
+
+ /* g(cos_theta) */
+ g=1.0+c2d2-frac;
+
+ /* d_costheta_ij and dg(cos_theta) - needed in any case! */
+ v3_scale(&temp1,&dist_ij,d_costheta1);
+ v3_scale(&temp2,&dist_ik,d_costheta2);
+ v3_add(&temp1,&temp1,&temp2);
+ v3_scale(&temp1,&temp1,-2.0*frac*h_cos/d2_h_cos2); /* dg */
+
+ /* f_c_ik & df_c_ik + {d,}zeta contribution */
+ dzeta=&(exchange->dzeta_ij);
+ if(d_ik<R) {
+ /* {d,}f_c_ik */
+ // => f_c_ik=1.0;
+ // => df_c_ik=0.0; of course we do not set this!
+
+ /* zeta_ij */
+ exchange->zeta_ij+=g;
+
+ /* dzeta_ij */
+ v3_add(dzeta,dzeta,&temp1);
+ }
+ else {
+ /* {d,}f_c_ik */
+ s_r=S-R;
+ arg=M_PI*(d_ik-R)/s_r;
+ f_c_ik=0.5+0.5*cos(arg);
+ df_c_ik=-0.5*sin(arg)*(M_PI/(s_r*d_ik));
+
+ /* zeta_ij */
+ exchange->zeta_ij+=f_c_ik*g;
+
+ /* dzeta_ij */
+ v3_scale(&temp1,&temp1,f_c_ik);
+ v3_scale(&temp2,&dist_ik,g*df_c_ik);
+ v3_add(&temp1,&temp1,&temp2);
+ v3_add(dzeta,dzeta,&temp1);