4 * author: Frank Zirkelbach <frank.zirkelbach@physik.uni-augsburg.de>
12 #include <sys/types.h>
24 #include "../moldyn.h"
25 #include "../math/math.h"
32 #define albe_v_calc(a,f,d) a->virial.xx+=f->x*d->x; \
33 a->virial.yy+=f->y*d->y; \
34 a->virial.zz+=f->z*d->z; \
35 a->virial.xy+=f->x*d->y; \
36 a->virial.xz+=f->x*d->z; \
37 a->virial.yz+=f->y*d->z
39 int albe_potential_force_calc(t_moldyn *moldyn) {
42 t_atom *itom,*jtom,*ktom;
50 t_list neighbour_i[27];
51 t_list neighbour_i2[27];
61 t_albe_mult_params *params;
62 t_albe_exchange *exchange;
76 double cos_theta,h_cos,d2_h_cos2,frac,g,dg,s_r,arg;
77 double f_c_ik,df_c_ik;
80 double f_a,df_a,b,db,f_c,df_c;
89 double dijdik_inv,fcdg,dfcg;
90 t_3dvec dcosdrj,dcosdrk;
102 params=moldyn->pot_params;
103 exchange=&(params->exchange);
109 /* reset global virial */
110 memset(&(moldyn->gvir),0,sizeof(t_virial));
112 /* reset force, site energy and virial of every atom */
114 #pragma omp parallel for private(virial)
116 for(i=0;i<count;i++) {
119 v3_zero(&(itom[i].f));
122 virial=(&(itom[i].virial));
130 /* reset site energy */
135 /* get energy, force and virial of every atom */
137 /* first (and only) loop over atoms i */
138 for(i=0;i<count;i++) {
140 if(!(itom[i].attr&ATOM_ATTR_3BP))
143 link_cell_neighbour_index(moldyn,
144 (itom[i].r.x+moldyn->dim.x/2)/lc->x,
145 (itom[i].r.y+moldyn->dim.y/2)/lc->y,
146 (itom[i].r.z+moldyn->dim.z/2)/lc->z,
151 /* copy the neighbour lists */
153 memcpy(neighbour_i2,neighbour_i,27*sizeof(t_list));
159 /* loop over atoms j */
166 while(neighbour_i[j][p]!=0) {
168 jtom=&(atom[neighbour_i[j][p]]);
171 this=&(neighbour_i[j]);
174 if(this->start==NULL)
179 jtom=this->current->data;
185 if(!(jtom->attr&ATOM_ATTR_3BP))
192 /* j1 func here ... */
193 /* albe 3 body potential function (first ij loop) */
199 * set ij depending values
202 if(brand_i==jtom->brand) {
203 S2=params->S2[brand_i];
210 v3_sub(&dist_ij,&(jtom->r),&(ai->r));
211 if(bc_ij) check_per_bound(moldyn,&dist_ij);
212 d_ij2=v3_absolute_square(&dist_ij);
214 /* if d_ij2 > S2 => no force & potential energy contribution */
221 /* reset k counter for first k loop */
224 /* first loop over atoms k */
231 while(neighbour_i[j][q]!=0) {
233 ktom=&(atom[neighbour_i[k][q]]);
236 that=&(neighbour_i2[k]);
239 if(that->start==NULL)
243 ktom=that->current->data;
246 if(!(ktom->attr&ATOM_ATTR_3BP))
256 /* k1 func here ... */
257 /* albe 3 body potential function (first k loop) */
259 if(kcount>ALBE_MAXN) {
260 printf("FATAL: neighbours = %d\n",kcount);
261 printf(" -> %d %d %d\n",ai->tag,jtom->tag,ktom->tag);
265 if(brand_i==ktom->brand) {
266 Rk=params->R[brand_i];
267 Sk=params->S[brand_i];
268 Sk2=params->S2[brand_i];
269 /* albe needs i,k depending c,d,h and gamma values */
270 exchange->gamma_i=&(params->gamma[brand_i]);
271 exchange->c_i=&(params->c[brand_i]);
272 exchange->d_i=&(params->d[brand_i]);
273 exchange->h_i=&(params->h[brand_i]);
279 /* albe needs i,k depending c,d,h and gamma values */
280 exchange->gamma_i=&(params->gamma_m);
281 exchange->c_i=&(params->c_mixed);
282 exchange->d_i=&(params->d_mixed);
283 exchange->h_i=&(params->h_mixed);
285 exchange->ci2=*(exchange->c_i)**(exchange->c_i);
286 exchange->di2=*(exchange->d_i)**(exchange->d_i);
287 exchange->ci2di2=exchange->ci2/exchange->di2;
290 v3_sub(&dist_ik,&(ktom->r),&(ai->r));
291 if(bc_ik) check_per_bound(moldyn,&dist_ik);
292 d_ik2=v3_absolute_square(&dist_ik);
294 /* store data for second k loop */
295 exchange->dist_ik[kcount]=dist_ik;
296 exchange->d_ik2[kcount]=d_ik2;
298 /* return if not within cutoff */
308 cos_theta=v3_scalar_product(&dist_ij,&dist_ik)/(d_ij*d_ik);
311 h_cos=*(exchange->h_i)+cos_theta; // + in albe formalism
312 d2_h_cos2=exchange->di2+(h_cos*h_cos);
313 frac=exchange->ci2/d2_h_cos2;
314 g=*(exchange->gamma_i)*(1.0+exchange->ci2di2-frac);
315 dg=2.0*frac**(exchange->gamma_i)*h_cos/d2_h_cos2; // + in albe f..
317 /* zeta sum += f_c_ik * g_ijk */
325 arg=M_PI*(d_ik-Rk)/s_r;
326 f_c_ik=0.5+0.5*cos(arg);
327 df_c_ik=0.5*sin(arg)*(M_PI/(s_r*d_ik));
331 /* store even more data for second k loop */
332 exchange->g[kcount]=g;
333 exchange->dg[kcount]=dg;
334 exchange->d_ik[kcount]=d_ik;
335 exchange->cos_theta[kcount]=cos_theta;
336 exchange->f_c_ik[kcount]=f_c_ik;
337 exchange->df_c_ik[kcount]=df_c_ik;
339 /* increase k counter */
345 } while(list_next_f(that)!=\
352 /* j2 func here ... */
355 if(brand_i==jtom->brand) {
356 S=params->S[brand_i];
357 R=params->R[brand_i];
358 B=params->B[brand_i];
359 A=params->A[brand_i];
360 r0=params->r0[brand_i];
361 mu=params->mu[brand_i];
362 lambda=params->lambda[brand_i];
371 lambda=params->lambda_m;
381 arg=M_PI*(d_ij-R)/s_r;
382 f_c=0.5+0.5*cos(arg);
383 df_c=0.5*sin(arg)*(M_PI/(s_r*d_ij));
387 f_a=-B*exp(-mu*(d_ij-r0));
391 f_r=A*exp(-lambda*(d_ij-r0));
392 df_r=lambda*f_r/d_ij;
400 b=1.0/sqrt(1.0+zeta_ij);
401 db=-0.5*b/(1.0+zeta_ij);
404 /* force contribution for atom i */
405 scale=-0.5*(f_c*(df_r-b*df_a)+df_c*(f_r-b*f_a)); // - in albe formalism
406 v3_scale(&force,&(dist_ij),scale);
407 v3_add(&(ai->f),&(ai->f),&force);
409 /* force contribution for atom j */
410 v3_scale(&force,&force,-1.0); // dri rij = - drj rij
411 v3_add(&(jtom->f),&(jtom->f),&force);
414 virial_calc(ai,&force,&(dist_ij));
417 if(moldyn->time>DSTART&&moldyn->time<DEND) {
418 if((ai==&(moldyn->atom[DATOM]))|(jtom==&(moldyn->atom[DATOM]))) {
419 printf("force 3bp (j2): [%d %d sum]\n",ai->tag,jtom->tag);
420 printf(" adding %f %f %f\n",force.x,force.y,force.z);
421 if(ai==&(moldyn->atom[0]))
422 printf(" total i: %f %f %f\n",ai->f.x,ai->f.y,ai->f.z);
423 if(jtom==&(moldyn->atom[0]))
424 printf(" total j: %f %f %f\n",jtom->f.x,jtom->f.y,jtom->f.z);
425 printf(" energy: %f = %f %f %f %f\n",0.5*f_c*(b*f_a+f_r),
427 printf(" %f %f %f\n",zeta_ij,.0,.0);
432 /* dzeta prefactor = - f_c f_a db, (* -0.5 due to force calc) */
433 pre_dzeta=0.5*f_a*f_c*db;
435 /* energy contribution */
436 energy=0.5*f_c*(f_r-b*f_a); // - in albe formalism
437 moldyn->energy+=energy;
440 /* reset k counter for second k loop */
444 /* second loop over atoms k */
451 while(neighbour_i[j][q]!=0) {
453 ktom=&(atom[neighbour_i[k][q]]);
456 that=&(neighbour_i2[k]);
459 if(that->start==NULL)
463 ktom=that->current->data;
466 if(!(ktom->attr&ATOM_ATTR_3BP))
476 /* k2 func here ... */
477 /* albe 3 body potential function (second k loop) */
480 printf("FATAL: neighbours!\n");
483 d_ik2=exchange->d_ik2[kcount];
485 if(brand_i==ktom->brand)
486 Sk2=params->S2[brand_i];
490 /* return if d_ik > S */
497 dist_ik=exchange->dist_ik[kcount];
498 d_ik=exchange->d_ik[kcount];
500 /* f_c_ik, df_c_ik */
501 f_c_ik=exchange->f_c_ik[kcount];
502 df_c_ik=exchange->df_c_ik[kcount];
504 /* g, dg, cos_theta */
505 g=exchange->g[kcount];
506 dg=exchange->dg[kcount];
507 cos_theta=exchange->cos_theta[kcount];
509 /* cos_theta derivatives wrt j,k */
510 dijdik_inv=1.0/(d_ij*d_ik);
511 v3_scale(&dcosdrj,&dist_ik,dijdik_inv); // j
512 v3_scale(&tmp,&dist_ij,-cos_theta/d_ij2);
513 v3_add(&dcosdrj,&dcosdrj,&tmp);
514 v3_scale(&dcosdrk,&dist_ij,dijdik_inv); // k
515 v3_scale(&tmp,&dist_ik,-cos_theta/d_ik2);
516 v3_add(&dcosdrk,&dcosdrk,&tmp);
518 /* f_c_ik * dg, df_c_ik * g */
522 /* derivative wrt j */
523 v3_scale(&force,&dcosdrj,fcdg*pre_dzeta);
525 /* force contribution */
526 v3_add(&(jtom->f),&(jtom->f),&force);
529 if(moldyn->time>DSTART&&moldyn->time<DEND) {
530 if(jtom==&(moldyn->atom[DATOM])) {
531 printf("force 3bp (k2): [%d %d %d]\n",ai->tag,jtom->tag,ktom->tag);
532 printf(" adding %f %f %f\n",force.x,force.y,force.z);
533 printf(" total j: %f %f %f\n",jtom->f.x,jtom->f.y,jtom->f.z);
534 printf(" angle: %f\n",acos(cos_theta)*360.0/(2*M_PI));
535 printf(" d ij ik = %f %f\n",d_ij,d_ik);
541 virial_calc(ai,&force,&dist_ij);
543 /* force contribution to atom i */
544 v3_scale(&force,&force,-1.0);
545 v3_add(&(ai->f),&(ai->f),&force);
547 /* derivative wrt k */
548 v3_scale(&force,&dist_ik,-1.0*dfcg); // dri rik = - drk rik
549 v3_scale(&tmp,&dcosdrk,fcdg);
550 v3_add(&force,&force,&tmp);
551 v3_scale(&force,&force,pre_dzeta);
553 /* force contribution */
554 v3_add(&(ktom->f),&(ktom->f),&force);
557 if(moldyn->time>DSTART&&moldyn->time<DEND) {
558 if(ktom==&(moldyn->atom[DATOM])) {
559 printf("force 3bp (k2): [%d %d %d]\n",ai->tag,jtom->tag,ktom->tag);
560 printf(" adding %f %f %f\n",force.x,force.y,force.z);
561 printf(" total k: %f %f %f\n",ktom->f.x,ktom->f.y,ktom->f.z);
562 printf(" angle: %f\n",acos(cos_theta)*360.0/(2*M_PI));
563 printf(" d ij ik = %f %f\n",d_ij,d_ik);
569 virial_calc(ai,&force,&dist_ik);
571 /* force contribution to atom i */
572 v3_scale(&force,&force,-1.0);
573 v3_add(&(ai->f),&(ai->f),&force);
575 /* increase k counter */
583 } while(list_next_f(that)!=\
592 } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
607 //printf("\nATOM 0: %f %f %f\n\n",itom->f.x,itom->f.y,itom->f.z);
608 if(moldyn->time>DSTART&&moldyn->time<DEND) {
610 printf(" x: %0.40f\n",moldyn->atom[DATOM].f.x);
611 printf(" y: %0.40f\n",moldyn->atom[DATOM].f.y);
612 printf(" z: %0.40f\n",moldyn->atom[DATOM].f.z);
616 /* some postprocessing */
618 #pragma omp parallel for
620 for(i=0;i<count;i++) {
621 /* calculate global virial */
622 moldyn->gvir.xx+=itom[i].r.x*itom[i].f.x;
623 moldyn->gvir.yy+=itom[i].r.y*itom[i].f.y;
624 moldyn->gvir.zz+=itom[i].r.z*itom[i].f.z;
625 moldyn->gvir.xy+=itom[i].r.y*itom[i].f.x;
626 moldyn->gvir.xz+=itom[i].r.z*itom[i].f.x;
627 moldyn->gvir.yz+=itom[i].r.z*itom[i].f.y;
629 /* check forces regarding the given timestep */
630 if(v3_norm(&(itom[i].f))>\
631 0.1*moldyn->nnd*itom[i].mass/moldyn->tau_square)
632 printf("[moldyn] WARNING: pfc (high force: atom %d)\n",