X-Git-Url: https://hackdaworld.org/gitweb/?a=blobdiff_plain;f=potentials%2Ftersoff.c;h=531d292131121ad5acb7b1ce2a4a0c551199b34a;hb=0b96eb313c9bfec6272b1f8de0d99c4ce26d1686;hp=16f771c7be4b614f10c6fd70b9476fb0bfd5e23f;hpb=ea612b88a0588b8f46fafaebf3b37fb46c83c0cf;p=physik%2Fposic.git diff --git a/potentials/tersoff.c b/potentials/tersoff.c index 16f771c..531d292 100644 --- a/potentials/tersoff.c +++ b/potentials/tersoff.c @@ -85,10 +85,9 @@ int tersoff_mult_1bp(t_moldyn *moldyn,t_atom *ai) { int tersoff_mult_2bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,u8 bc) { t_tersoff_mult_params *params; - t_tersoff_exchange *exchange; t_3dvec dist_ij,force; double d_ij,d_ij2; - double A,B,R,S,S2,lambda,mu; + double A,R,S,S2,lambda; double f_r,df_r; double f_c,df_c; int brand; @@ -96,31 +95,10 @@ int tersoff_mult_2bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,u8 bc) { double arg; /* use newtons third law */ - //if(aipot_params; brand=aj->brand; - exchange=&(params->exchange); - - /* clear 3bp and 2bp post run */ - exchange->run3bp=0; - exchange->run2bp_post=0; - - /* reset S > r > R mark */ - exchange->d_ij_between_rs=0; - - /* - * calc of 2bp contribution of V_ij and dV_ij/ji - * - * for Vij and dV_ij we need: - * - f_c_ij, df_c_ij - * - f_r_ij, df_r_ij - * - * for dV_ji we need: - * - f_c_ji = f_c_ij, df_c_ji = df_c_ij - * - f_r_ji = f_r_ij; df_r_ji = df_r_ij - * - */ /* determine cutoff square */ if(brand==ai->brand) @@ -128,71 +106,41 @@ int tersoff_mult_2bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,u8 bc) { else S2=params->S2mixed; - /* dist_ij, d_ij */ + /* dist_ij, d_ij2 */ v3_sub(&dist_ij,&(aj->r),&(ai->r)); if(bc) check_per_bound(moldyn,&dist_ij); d_ij2=v3_absolute_square(&dist_ij); /* if d_ij2 > S2 => no force & potential energy contribution */ - if(d_ij2>S2) + if(d_ij2>S2) { return 0; + } /* now we will need the distance */ - //d_ij=v3_norm(&dist_ij); d_ij=sqrt(d_ij2); - /* save for use in 3bp */ - exchange->d_ij=d_ij; - exchange->d_ij2=d_ij2; - exchange->dist_ij=dist_ij; - /* more constants */ - exchange->beta_j=&(params->beta[brand]); - exchange->n_j=&(params->n[brand]); - exchange->c_j=&(params->c[brand]); - exchange->d_j=&(params->d[brand]); - exchange->h_j=&(params->h[brand]); if(brand==ai->brand) { S=params->S[brand]; R=params->R[brand]; A=params->A[brand]; - B=params->B[brand]; lambda=params->lambda[brand]; - mu=params->mu[brand]; - exchange->chi=1.0; - exchange->betajnj=exchange->betaini; - exchange->cj2=exchange->ci2; - exchange->dj2=exchange->di2; - exchange->cj2dj2=exchange->ci2di2; } else { S=params->Smixed; R=params->Rmixed; A=params->Amixed; - B=params->Bmixed; lambda=params->lambda_m; - mu=params->mu_m; - params->exchange.chi=params->chi; - exchange->betajnj=pow(*(exchange->beta_j),*(exchange->n_j)); - exchange->cj2=params->c[brand]*params->c[brand]; - exchange->dj2=params->d[brand]*params->d[brand]; - exchange->cj2dj2=exchange->cj2/exchange->dj2; } - /* f_r_ij = f_r_ji, df_r_ij = df_r_ji */ + /* f_r_ij, df_r_ij */ f_r=A*exp(-lambda*d_ij); df_r=lambda*f_r/d_ij; - /* f_a, df_a calc (again, same for ij and ji) | save for later use! */ - exchange->f_a=-B*exp(-mu*d_ij); - exchange->df_a=mu*exchange->f_a/d_ij; - - /* f_c, df_c calc (again, same for ij and ji) */ + /* f_c, df_c */ if(d_ij r > R */ - exchange->d_ij_between_rs=1; } - /* add forces of 2bp (ij, ji) contribution - * dVij = dVji and we sum up both: no 1/2) */ + /* add forces */ v3_add(&(ai->f),&(ai->f),&force); + v3_sub(&(aj->f),&(aj->f),&force); + +#ifdef DEBUG + if((ai==&(moldyn->atom[0]))|(aj==&(moldyn->atom[0]))) { + printf("force 2bp: [%d %d]\n",ai->tag,aj->tag); + printf("adding %f %f %f\n",force.x,force.y,force.z); + if(ai==&(moldyn->atom[0])) + printf("total i: %f %f %f\n",ai->f.x,ai->f.y,ai->f.z); + if(aj==&(moldyn->atom[0])) + printf("total j: %f %f %f\n",aj->f.x,aj->f.y,aj->f.z); + } +#endif /* virial */ - virial_calc(ai,&force,&dist_ij); + //virial_calc(ai,&force,&dist_ij); + //virial_calc(aj,&force,&dist_ij); //ai->virial.xx-=force.x*dist_ij.x; //ai->virial.yy-=force.y*dist_ij.y; //ai->virial.zz-=force.z*dist_ij.z; @@ -219,270 +176,86 @@ int tersoff_mult_2bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,u8 bc) { //ai->virial.xz-=force.x*dist_ij.z; //ai->virial.yz-=force.y*dist_ij.z; -#ifdef DEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVij, dVji (2bp) contrib:\n"); - printf("%f | %f\n",force.x,ai->f.x); - printf("%f | %f\n",force.y,ai->f.y); - printf("%f | %f\n",force.z,ai->f.z); -} -#endif -#ifdef VDEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVij, dVji (2bp) contrib:\n"); - printf("%f | %f\n",force.x*dist_ij.x,ai->virial.xx); - printf("%f | %f\n",force.y*dist_ij.y,ai->virial.yy); - printf("%f | %f\n",force.z*dist_ij.z,ai->virial.zz); -} -#endif - - /* energy 2bp contribution (ij, ji) is 0.5 f_r f_c ... */ - moldyn->energy+=(0.5*f_r*f_c); - - /* 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)); + /* energy 2bp contribution */ + moldyn->energy+=f_r*f_c; 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 - * - */ +/* tersoff 3 body potential function (first ij loop) */ +int tersoff_mult_3bp_j1(t_moldyn *moldyn,t_atom *ai,t_atom *aj,u8 bc) { 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; + unsigned char brand; + double S2; + t_3dvec dist_ij; + double d_ij2,d_ij; params=moldyn->pot_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 ... */ - 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); + /* reset zeta sum */ + exchange->zeta_ij=0.0; - /* virial */ - virial_calc(ai,&force,dist_ij); - //ai->virial.xx-=force.x*dist_ij->x; - //ai->virial.yy-=force.y*dist_ij->y; - //ai->virial.zz-=force.z*dist_ij->z; - //ai->virial.xy-=force.x*dist_ij->y; - //ai->virial.xz-=force.x*dist_ij->z; - //ai->virial.yz-=force.y*dist_ij->z; + /* + * set ij depending values + */ -#ifdef DEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVij (3bp) contrib:\n"); - printf("%f | %f\n",force.x,ai->f.x); - printf("%f | %f\n",force.y,ai->f.y); - printf("%f | %f\n",force.z,ai->f.z); -} -#endif -#ifdef VDEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVij (3bp) contrib:\n"); - printf("%f | %f\n",force.x*dist_ij->x,ai->virial.xx); - printf("%f | %f\n",force.y*dist_ij->y,ai->virial.yy); - printf("%f | %f\n",force.z*dist_ij->z,ai->virial.zz); -} -#endif + brand=ai->brand; + + if(brand==aj->brand) + S2=params->S2[brand]; + else + S2=params->S2mixed; - /* add energy of 3bp sum */ - moldyn->energy+=(0.5*f_c*b*f_a); + /* dist_ij, d_ij2 */ + v3_sub(&dist_ij,&(aj->r),&(ai->r)); + if(bc) check_per_bound(moldyn,&dist_ij); + d_ij2=v3_absolute_square(&dist_ij); - /* 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); + /* if d_ij2 > S2 => no force & potential energy contribution */ + if(d_ij2>S2) { + moldyn->run3bp=0; + return 0; } - 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); - - /* virial - plus sign, as dist_ij = - dist_ji - (really??) */ -// TEST ... with a minus instead - virial_calc(ai,&force,dist_ij); - //ai->virial.xx-=force.x*dist_ij->x; - //ai->virial.yy-=force.y*dist_ij->y; - //ai->virial.zz-=force.z*dist_ij->z; - //ai->virial.xy-=force.x*dist_ij->y; - //ai->virial.xz-=force.x*dist_ij->z; - //ai->virial.yz-=force.y*dist_ij->z; + /* d_ij */ + d_ij=sqrt(d_ij2); -#ifdef DEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVji (3bp) contrib:\n"); - printf("%f | %f\n",force.x,ai->f.x); - printf("%f | %f\n",force.y,ai->f.y); - printf("%f | %f\n",force.z,ai->f.z); -} -#endif -#ifdef VDEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVji (3bp) contrib:\n"); - printf("%f | %f\n",force.x*dist_ij->x,ai->virial.xx); - printf("%f | %f\n",force.y*dist_ij->y,ai->virial.yy); - printf("%f | %f\n",force.z*dist_ij->z,ai->virial.zz); -} -#endif + /* store values */ + exchange->dist_ij=dist_ij; + exchange->d_ij2=d_ij2; + exchange->d_ij=d_ij; + /* reset k counter for first k loop */ + exchange->kcount=0; + return 0; } -/* tersoff 3 body part */ - -int tersoff_mult_3bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,t_atom *ak,u8 bc) { +/* tersoff 3 body potential function (first k loop) */ +int tersoff_mult_3bp_k1(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,S2,s_r; - double B,mu; - double d_ij,d_ik,d_jk,d_ij2,d_ik2,d_jk2; - 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 brand; + unsigned char brand; + double R,S,S2; + t_3dvec dist_ij,dist_ik; + double d_ik2,d_ik,d_ij; + double cos_theta,h_cos,d2_h_cos2,frac,g,dg,s_r,arg; + double f_c_ik,df_c_ik; + int kcount; params=moldyn->pot_params; exchange=&(params->exchange); + kcount=exchange->kcount; - 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; - d_ij2=exchange->d_ij2; - - /* 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_ik2=v3_absolute_square(&dist_ik); + if(kcount>TERSOFF_MAXN) { + printf("FATAL: neighbours = %d\n",kcount); + printf(" -> %d %d %d\n",ai->tag,aj->tag,ak->tag); + } /* ik constants */ brand=ai->brand; @@ -497,215 +270,298 @@ int tersoff_mult_3bp(t_moldyn *moldyn,t_atom *ai,t_atom *aj,t_atom *ak,u8 bc) { S2=params->S2mixed; } - /* zeta_ij/dzeta_ij contribution only for d_ik < S */ - if(d_ik2n_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_ij2-tmp; - d_costheta2=cos_theta/d_ik2-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 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); - } + /* dist_ik, d_ik2 */ + v3_sub(&dist_ik,&(ak->r),&(ai->r)); + if(bc) check_per_bound(moldyn,&dist_ik); + d_ik2=v3_absolute_square(&dist_ik); + + /* store data for second k loop */ + exchange->dist_ik[kcount]=dist_ik; + exchange->d_ik2[kcount]=d_ik2; + + /* return if not within cutoff */ + if(d_ik2>S2) { + exchange->kcount++; + return 0; + } + + /* d_ik */ + d_ik=sqrt(d_ik2); + + /* dist_ij, d_ij */ + dist_ij=exchange->dist_ij; + d_ij=exchange->d_ij; + + /* cos theta */ + cos_theta=v3_scalar_product(&dist_ij,&dist_ik)/(d_ij*d_ik); + + /* g_ijk */ + h_cos=*(exchange->h_i)-cos_theta; + d2_h_cos2=exchange->di2+(h_cos*h_cos); + frac=exchange->ci2/d2_h_cos2; + g=1.0+exchange->ci2di2-frac; + dg=-2.0*frac*h_cos/d2_h_cos2; + + /* zeta sum += f_c_ik * g_ijk */ + if(d_ik<=R) { + exchange->zeta_ij+=g; + f_c_ik=1.0; + df_c_ik=0.0; + } + else { + 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)); + exchange->zeta_ij+=f_c_ik*g; } - /* dV_ji stuff (in b_ji there is f_c_jk) + dV_jk stuff! */ + /* store even more data for second k loop */ + exchange->g[kcount]=g; + exchange->dg[kcount]=dg; + exchange->d_ik[kcount]=d_ik; + exchange->cos_theta[kcount]=cos_theta; + exchange->f_c_ik[kcount]=f_c_ik; + exchange->df_c_ik[kcount]=df_c_ik; - /* dist_jk, d_jk */ - v3_sub(&dist_jk,&(ak->r),&(aj->r)); - if(bc) check_per_bound(moldyn,&dist_jk); - d_jk2=v3_absolute_square(&dist_jk); + /* increase k counter */ + exchange->kcount++; + + return 0; +} + +int tersoff_mult_3bp_j2(t_moldyn *moldyn,t_atom *ai,t_atom *aj,u8 bc) { + + t_tersoff_mult_params *params; + t_tersoff_exchange *exchange; + t_3dvec force; + double f_a,df_a,b,db,f_c,df_c; + double mu,B,chi; + double d_ij; + unsigned char brand; + double ni,tmp; + double S,R,s_r,arg; + + params=moldyn->pot_params; + exchange=&(params->exchange); - /* jk constants */ brand=aj->brand; - if(brand==ak->brand) { - R=params->R[brand]; + if(brand==ai->brand) { S=params->S[brand]; - S2=params->S2[brand]; + R=params->R[brand]; B=params->B[brand]; mu=params->mu[brand]; chi=1.0; } else { - R=params->Rmixed; S=params->Smixed; - S2=params->S2mixed; + R=params->Rmixed; B=params->Bmixed; mu=params->mu_m; chi=params->chi; } - /* zeta_ji/dzeta_ji contribution only for d_jk < S_jk */ - if(d_jk2n_j); - c=*(exchange->c_j); - d=*(exchange->d_j); - h=*(exchange->h_j); - c2=exchange->cj2; - d2=exchange->dj2; - c2d2=exchange->cj2dj2; - - /* cosine of theta_jik by scalaproduct */ - rr=-v3_scalar_product(&dist_ij,&dist_jk); /* -1, as ij -> ji */ - dd=d_ij*d_jk; - cos_theta=rr/dd; - - /* d_costheta */ - d_costheta1=1.0/dd; - d_costheta2=cos_theta/d_ij2; - - /* 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_jik and dg(cos_theta) - needed in any case! */ - v3_scale(&temp1,&dist_jk,d_costheta1); - v3_scale(&temp2,&dist_ij,-d_costheta2); /* ji -> ij => -1 */ - //v3_add(&temp1,&temp1,&temp2); - v3_sub(&temp1,&temp1,&temp2); /* there is a minus! */ - v3_scale(&temp1,&temp1,-2.0*frac*h_cos/d2_h_cos2); /* dg */ - - /* store dg in temp2 and use it for dVjk later */ - v3_copy(&temp2,&temp1); - - /* f_c_jk + {d,}zeta contribution (df_c_jk = 0) */ - dzeta=&(exchange->dzeta_ji); - if(d_jkzeta_ji+=g; - - /* dzeta_ji */ - v3_add(dzeta,dzeta,&temp1); - } - else { - /* f_c_jk */ - s_r=S-R; - arg=M_PI*(d_jk-R)/s_r; - f_c_jk=0.5+0.5*cos(arg); - - /* zeta_ji */ - exchange->zeta_ji+=f_c_jk*g; - - /* dzeta_ji */ - v3_scale(&temp1,&temp1,f_c_jk); - v3_add(dzeta,dzeta,&temp1); - } - - /* dV_jk stuff | add force contribution on atom i immediately */ - if(exchange->d_ij_between_rs) { - zeta=f_c*g; - v3_scale(&temp1,&temp2,f_c); - v3_scale(&temp2,&dist_ij,df_c*g); - v3_add(&temp2,&temp2,&temp1); /* -> dzeta_jk in temp2 */ - } - else { - zeta=g; - // dzeta_jk is simply dg, which is stored in temp2 - } - /* betajnj * zeta_jk ^ nj-1 */ - tmp=exchange->betajnj*pow(zeta,(n-1.0)); - tmp=-chi/2.0*pow((1+tmp*zeta),(-1.0/(2.0*n)-1))*tmp; - v3_scale(&temp2,&temp2,tmp*B*exp(-mu*d_jk)*f_c_jk*0.5); - v3_add(&(ai->f),&(ai->f),&temp2); /* -1 skipped in f_a calc ^ */ - /* scaled with 0.5 ^ */ - - /* virial */ - ai->virial.xx-=temp2.x*dist_jk.x; - ai->virial.yy-=temp2.y*dist_jk.y; - ai->virial.zz-=temp2.z*dist_jk.z; - ai->virial.xy-=temp2.x*dist_jk.y; - ai->virial.xz-=temp2.x*dist_jk.z; - ai->virial.yz-=temp2.y*dist_jk.z; + d_ij=exchange->d_ij; + + /* f_c, df_c */ + if(d_ijzeta_ij==0.0) { + b=chi; + db=0.0; + } + else { + ni=*(exchange->n_i); + tmp=exchange->betaini*pow(exchange->zeta_ij,ni-1.0); + b=(1.0+exchange->zeta_ij*tmp); + db=chi*pow(b,-1.0/(2*ni)-1.0); + b=db*b; + db*=-0.5*tmp; + } + + /* force contribution */ + v3_scale(&force,&(exchange->dist_ij),df_a*f_c+f_a*df_c); + v3_scale(&force,&force,-0.5*b); + v3_add(&(ai->f),&(ai->f),&force); + v3_sub(&(aj->f),&(aj->f),&force); #ifdef DEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVjk (3bp) contrib:\n"); - printf("%f | %f\n",temp2.x,ai->f.x); - printf("%f | %f\n",temp2.y,ai->f.y); - printf("%f | %f\n",temp2.z,ai->f.z); -} + if((ai==&(moldyn->atom[0]))|(aj==&(moldyn->atom[0]))) { + printf("force 3bp (j2): [%d %d sum]\n",ai->tag,aj->tag); + printf("adding %f %f %f\n",force.x,force.y,force.z); + if(ai==&(moldyn->atom[0])) + printf("total i: %f %f %f\n",ai->f.x,ai->f.y,ai->f.z); + if(aj==&(moldyn->atom[0])) + printf("total j: %f %f %f\n",aj->f.x,aj->f.y,aj->f.z); + } #endif -#ifdef VDEBUG -if(ai==&(moldyn->atom[0])) { - printf("dVjk (3bp) contrib:\n"); - printf("%f | %f\n",temp2.x*dist_jk.x,ai->virial.xx); - printf("%f | %f\n",temp2.y*dist_jk.y,ai->virial.yy); - printf("%f | %f\n",temp2.z*dist_jk.z,ai->virial.zz); + + /* virial */ + //virial_calc(ai,&force,&(exchange->dist_ij)); + //virial_calc(aj,&force,&(exchange->dist_ij)); + + /* dzeta prefactor = - 0.5 f_c f_a db */ + exchange->pre_dzeta=-0.5*f_a*f_c*db; + + /* energy contribution */ + moldyn->energy+=0.5*f_c*b*f_a; + + /* reset k counter for second k loop */ + exchange->kcount=0; + + return 0; } + +/* tersoff 3 body potential function (second k loop) */ +int tersoff_mult_3bp_k2(t_moldyn *moldyn, + t_atom *ai,t_atom *aj,t_atom *ak,u8 bc) { + + t_tersoff_mult_params *params; + t_tersoff_exchange *exchange; + int kcount; + t_3dvec dist_ik,dist_ij; + double d_ik2,d_ik,d_ij2,d_ij; + unsigned char brand; + double S2; + double g,dg,cos_theta; + double pre_dzeta; + double f_c_ik,df_c_ik; + double dijdik_inv,fcdg,dfcg; + t_3dvec dcosdri,dcosdrj,dcosdrk; + t_3dvec force,tmp; + + params=moldyn->pot_params; + exchange=&(params->exchange); + kcount=exchange->kcount; + + if(kcount>TERSOFF_MAXN) + printf("FATAL: neighbours!\n"); + + /* d_ik2 */ + d_ik2=exchange->d_ik2[kcount]; + + brand=ak->brand; + if(brand==ai->brand) + S2=params->S2[brand]; + else + S2=params->S2mixed; + + /* return if d_ik > S */ + if(d_ik2>S2) { + exchange->kcount++; + return 0; + } + + /* prefactor dzeta */ + pre_dzeta=exchange->pre_dzeta; + + /* dist_ik, d_ik */ + dist_ik=exchange->dist_ik[kcount]; + d_ik=exchange->d_ik[kcount]; + + /* f_c_ik, df_c_ik */ + f_c_ik=exchange->f_c_ik[kcount]; + df_c_ik=exchange->df_c_ik[kcount]; + + /* dist_ij, d_ij2, d_ij */ + dist_ij=exchange->dist_ij; + d_ij2=exchange->d_ij2; + d_ij=exchange->d_ij; + + /* g, dg, cos_theta */ + g=exchange->g[kcount]; + dg=exchange->dg[kcount]; + cos_theta=exchange->cos_theta[kcount]; + + /* cos_theta derivatives wrt i,j,k */ + dijdik_inv=1.0/(d_ij*d_ik); + v3_scale(&dcosdrj,&dist_ik,dijdik_inv); + v3_scale(&tmp,&dist_ij,-cos_theta/d_ij2); + v3_add(&dcosdrj,&dcosdrj,&tmp); + v3_scale(&dcosdrk,&dist_ij,dijdik_inv); + v3_scale(&tmp,&dist_ik,-cos_theta/d_ik2); + v3_add(&dcosdrk,&dcosdrk,&tmp); + v3_add(&dcosdri,&dcosdrj,&dcosdrk); + v3_scale(&dcosdri,&dcosdri,-1.0); + + /* f_c_ik * dg, df_c_ik * g */ + fcdg=f_c_ik*dg; + dfcg=df_c_ik*g; + + /* derivative wrt i */ + v3_scale(&force,&dist_ik,dfcg); + v3_scale(&tmp,&dcosdri,fcdg); + v3_add(&force,&force,&tmp); + v3_scale(&force,&force,pre_dzeta); + + /* force contribution */ + v3_add(&(ai->f),&(ai->f),&force); + +#ifdef DEBUG + if(ai==&(moldyn->atom[0])) { + printf("force 3bp (k2): [%d %d %d]\n",ai->tag,aj->tag,ak->tag); + printf("adding %f %f %f\n",force.x,force.y,force.z); + printf("total i: %f %f %f\n",ai->f.x,ai->f.y,ai->f.z); + } +#endif + + /* virial */ + //virial_calc(ai,&force,&dist_ij); + + /* derivatice wrt j */ + v3_scale(&force,&dcosdrj,fcdg*pre_dzeta); + + /* force contribution */ + v3_add(&(aj->f),&(aj->f),&force); + +#ifdef DEBUG + if(aj==&(moldyn->atom[0])) { + printf("force 3bp (k2): [%d %d %d]\n",ai->tag,aj->tag,ak->tag); + printf("adding %f %f %f\n",force.x,force.y,force.z); + printf("total j: %f %f %f\n",aj->f.x,aj->f.y,aj->f.z); + } #endif + /* virial */ + //virial_calc(aj,&force,&dist_ij); + + /* derivative wrt k */ + v3_scale(&force,&dist_ik,dfcg); + v3_scale(&tmp,&dcosdrk,fcdg); + v3_add(&force,&force,&tmp); + v3_scale(&force,&force,pre_dzeta); + + /* force contribution */ + v3_add(&(ak->f),&(ak->f),&force); + +#ifdef DEBUG + if(ak==&(moldyn->atom[0])) { + printf("force 3bp (k2): [%d %d %d]\n",ai->tag,aj->tag,ak->tag); + printf("adding %f %f %f\n",force.x,force.y,force.z); + printf("total k: %f %f %f\n",ak->f.x,ak->f.y,ak->f.z); } +#endif + + /* virial */ + virial_calc(ak,&force,&dist_ik); + + /* increase k counter */ + exchange->kcount++; return 0; -} +}