X-Git-Url: https://hackdaworld.org/gitweb/?a=blobdiff_plain;f=moldyn.c;h=57f76c433ae7d431fc860dc51ddc21b6982a6d29;hb=06912ca45b46de412570a4bd5b5484aa9e8d6e6b;hp=ecba8baffc40a07c641eee9bfed8838c7c8116cc;hpb=eceebe3ee412aa8cea3e6a7f0038883707f78460;p=physik%2Fposic.git diff --git a/moldyn.c b/moldyn.c index ecba8ba..57f76c4 100644 --- a/moldyn.c +++ b/moldyn.c @@ -5,16 +5,232 @@ * */ -#include "moldyn.h" - +#define _GNU_SOURCE #include #include +#include +#include +#include +#include +#include #include +#include "moldyn.h" + #include "math/math.h" #include "init/init.h" #include "random/random.h" +#include "visual/visual.h" +#include "list/list.h" + +int moldyn_usage(char **argv) { + + printf("\n%s usage:\n\n",argv[0]); + printf("--- general options ---\n"); + printf("-E (log total energy)\n"); + printf("-M (log total momentum)\n"); + printf("-D (dump total information)\n"); + printf("-S (single save file)\n"); + printf("-V (rasmol file)\n"); + printf("--- physics options ---\n"); + printf("-T [K] (%f)\n",MOLDYN_TEMP); + printf("-t [s] (%.15f)\n",MOLDYN_TAU); + printf("-C [m] (%.15f)\n",MOLDYN_CUTOFF); + printf("-R (%d)\n",MOLDYN_RUNS); + printf(" -- integration algo --\n"); + printf(" -I (%d)\n",MOLDYN_INTEGRATE_DEFAULT); + printf(" 0: velocity verlet\n"); + printf(" -- potential --\n"); + printf(" -P \n"); + printf(" 0: harmonic oscillator\n"); + printf(" param1: spring constant\n"); + printf(" param2: equilibrium distance\n"); + printf(" 1: lennard jones\n"); + printf(" param1: epsilon\n"); + printf(" param2: sigma\n"); + printf("\n"); + + return 0; +} + +int moldyn_parse_argv(t_moldyn *moldyn,int argc,char **argv) { + + int i; + t_ho_params hop; + t_lj_params ljp; + t_tersoff_params tp; + double s,e; + + memset(moldyn,0,sizeof(t_moldyn)); + + /* default values */ + moldyn->t=MOLDYN_TEMP; + moldyn->tau=MOLDYN_TAU; + moldyn->time_steps=MOLDYN_RUNS; + moldyn->integrate=velocity_verlet; + moldyn->potential_force_function=lennard_jones; + + /* parse argv */ + for(i=1;iewrite=atoi(argv[++i]); + strncpy(moldyn->efb,argv[++i],64); + break; + case 'M': + moldyn->mwrite=atoi(argv[++i]); + strncpy(moldyn->mfb,argv[++i],64); + break; + case 'S': + moldyn->swrite=atoi(argv[++i]); + strncpy(moldyn->sfb,argv[++i],64); + break; + case 'V': + moldyn->vwrite=atoi(argv[++i]); + strncpy(moldyn->vfb,argv[++i],64); + break; + case 'T': + moldyn->t=atof(argv[++i]); + break; + case 't': + moldyn->tau=atof(argv[++i]); + break; + case 'C': + moldyn->cutoff=atof(argv[++i]); + break; + case 'R': + moldyn->time_steps=atoi(argv[++i]); + break; + case 'I': + /* integration algorithm */ + switch(atoi(argv[++i])) { + case MOLDYN_INTEGRATE_VERLET: + moldyn->integrate=velocity_verlet; + break; + default: + printf("unknown integration algo %s\n",argv[i]); + moldyn_usage(argv); + return -1; + } + + case 'P': + /* potential + params */ + switch(atoi(argv[++i])) { + case MOLDYN_POTENTIAL_HO: + hop.spring_constant=atof(argv[++i]); + hop.equilibrium_distance=atof(argv[++i]); + moldyn->pot_params=malloc(sizeof(t_ho_params)); + memcpy(moldyn->pot_params,&hop,sizeof(t_ho_params)); + moldyn->potential_force_function=harmonic_oscillator; + break; + case MOLDYN_POTENTIAL_LJ: + e=atof(argv[++i]); + s=atof(argv[++i]); + ljp.epsilon4=4*e; + ljp.sigma6=s*s*s*s*s*s; + ljp.sigma12=ljp.sigma6*ljp.sigma6; + moldyn->pot_params=malloc(sizeof(t_lj_params)); + memcpy(moldyn->pot_params,&ljp,sizeof(t_lj_params)); + moldyn->potential_force_function=lennard_jones; + break; + default: + printf("unknown potential %s\n",argv[i]); + moldyn_usage(argv); + return -1; + } + + default: + printf("unknown option %s\n",argv[i]); + moldyn_usage(argv); + return -1; + } + } else { + moldyn_usage(argv); + return -1; + } + } + + return 0; +} + +int moldyn_log_init(t_moldyn *moldyn) { + + moldyn->lvstat=0; + t_visual *vis; + + vis=&(moldyn->vis); + + if(moldyn->ewrite) { + moldyn->efd=open(moldyn->efb,O_WRONLY|O_CREAT|O_TRUNC); + if(moldyn->efd<0) { + perror("[moldyn] efd open"); + return moldyn->efd; + } + dprintf(moldyn->efd,"# moldyn total energy logfile\n"); + moldyn->lvstat|=MOLDYN_LVSTAT_TOTAL_E; + } + + if(moldyn->mwrite) { + moldyn->mfd=open(moldyn->mfb,O_WRONLY|O_CREAT|O_TRUNC); + if(moldyn->mfd<0) { + perror("[moldyn] mfd open"); + return moldyn->mfd; + } + dprintf(moldyn->mfd,"# moldyn total momentum logfile\n"); + moldyn->lvstat|=MOLDYN_LVSTAT_TOTAL_M; + } + + if(moldyn->swrite) + moldyn->lvstat|=MOLDYN_LVSTAT_SAVE; + + if((moldyn->vwrite)&&(vis)) { + moldyn->visual=vis; + visual_init(vis,moldyn->vfb); + moldyn->lvstat|=MOLDYN_LVSTAT_VISUAL; + } + moldyn->lvstat|=MOLDYN_LVSTAT_INITIALIZED; + + return 0; +} + +int moldyn_log_shutdown(t_moldyn *moldyn) { + + if(moldyn->efd) close(moldyn->efd); + if(moldyn->mfd) close(moldyn->efd); + if(moldyn->dfd) close(moldyn->efd); + if(moldyn->visual) visual_tini(moldyn->visual); + + return 0; +} + +int moldyn_init(t_moldyn *moldyn,int argc,char **argv) { + + int ret; + + ret=moldyn_parse_argv(moldyn,argc,argv); + if(ret<0) return ret; + + ret=moldyn_log_init(moldyn); + if(ret<0) return ret; + + rand_init(&(moldyn->random),NULL,1); + moldyn->random.status|=RAND_STAT_VERBOSE; + + moldyn->status=0; + + return 0; +} + +int moldyn_shutdown(t_moldyn *moldyn) { + + moldyn_log_shutdown(moldyn); + rand_close(&(moldyn->random)); + free(moldyn->atom); + + return 0; +} int create_lattice(unsigned char type,int element,double mass,double lc, int a,int b,int c,t_atom **atom) { @@ -72,7 +288,7 @@ int destroy_lattice(t_atom *atom) { return 0; } -int thermal_init(t_atom *atom,t_random *random,int count,double t) { +int thermal_init(t_moldyn *moldyn) { /* * - gaussian distribution of velocities @@ -83,11 +299,16 @@ int thermal_init(t_atom *atom,t_random *random,int count,double t) { int i; double v,sigma; t_3dvec p_total,delta; + t_atom *atom; + t_random *random; + + atom=moldyn->atom; + random=&(moldyn->random); /* gaussian distribution of velocities */ v3_zero(&p_total); - for(i=0;icount;i++) { + sigma=sqrt(2.0*K_BOLTZMANN*moldyn->t/atom[i].mass); /* x direction */ v=sigma*rand_get_gauss(random); atom[i].v.x=v; @@ -103,31 +324,34 @@ int thermal_init(t_atom *atom,t_random *random,int count,double t) { } /* zero total momentum */ - v3_scale(&p_total,&p_total,1.0/count); - for(i=0;icount); + for(i=0;icount;i++) { v3_scale(&delta,&p_total,1.0/atom[i].mass); v3_sub(&(atom[i].v),&(atom[i].v),&delta); } /* velocity scaling */ - scale_velocity(atom,count,t); + scale_velocity(moldyn); return 0; } -int scale_velocity(t_atom *atom,int count,double t) { +int scale_velocity(t_moldyn *moldyn) { int i; double e,c; + t_atom *atom; + + atom=moldyn->atom; /* * - velocity scaling (E = 3/2 N k T), E: kinetic energy */ e=0.0; - for(i=0;icount;i++) e+=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v)); - c=sqrt((2.0*e)/(3.0*count*K_BOLTZMANN*t)); - for(i=0;icount*K_BOLTZMANN*moldyn->t)); + for(i=0;icount;i++) v3_scale(&(atom[i].v),&(atom[i].v),(1.0/c)); return 0; @@ -147,6 +371,21 @@ double get_e_kin(t_atom *atom,int count) { return e; } +double get_e_pot(t_moldyn *moldyn) { + + return moldyn->energy; +} + +double get_total_energy(t_moldyn *moldyn) { + + double e; + + e=get_e_kin(moldyn->atom,moldyn->count); + e+=get_e_pot(moldyn); + + return e; +} + t_3dvec get_total_p(t_atom *atom, int count) { t_3dvec p,p_total; @@ -161,37 +400,991 @@ t_3dvec get_total_p(t_atom *atom, int count) { return p_total; } -double potential_lennard_jones_2(t_moldyn *moldyn,void *ptr) { +double estimate_time_step(t_moldyn *moldyn,double nn_dist,double t) { - t_lj_params *params; + double tau; + + tau=0.05*nn_dist/(sqrt(3.0*K_BOLTZMANN*t/moldyn->atom[0].mass)); + tau*=1.0E-9; + if(tautau) + printf("[moldyn] warning: time step (%f > %.15f)\n", + moldyn->tau,tau); + + return tau; +} + +/* + * numerical tricks + */ + +/* linked list / cell method */ + +int link_cell_init(t_moldyn *moldyn) { + + t_linkcell *lc; + int i; + + lc=&(moldyn->lc); + + /* list log fd */ + lc->listfd=open("/dev/null",O_WRONLY); + + /* partitioning the md cell */ + lc->nx=moldyn->dim.x/moldyn->cutoff; + lc->x=moldyn->dim.x/lc->nx; + lc->ny=moldyn->dim.y/moldyn->cutoff; + lc->y=moldyn->dim.y/lc->ny; + lc->nz=moldyn->dim.z/moldyn->cutoff; + lc->z=moldyn->dim.z/lc->nz; + + lc->cells=lc->nx*lc->ny*lc->nz; + lc->subcell=malloc(lc->cells*sizeof(t_list)); + + printf("initializing linked cells (%d)\n",lc->cells); + + for(i=0;icells;i++) + //list_init(&(lc->subcell[i]),1); + list_init(&(lc->subcell[i])); + + link_cell_update(moldyn); + + return 0; +} + +int link_cell_update(t_moldyn *moldyn) { + + int count,i,j,k; + int nx,ny,nz; t_atom *atom; - int i,j; - int count; - t_3dvec distance; - double d,help; + t_linkcell *lc; + + atom=moldyn->atom; + lc=&(moldyn->lc); + + nx=lc->nx; + ny=lc->ny; + nz=lc->nz; + + for(i=0;icells;i++) + list_destroy(&(moldyn->lc.subcell[i])); + + for(count=0;countcount;count++) { + i=(atom[count].r.x+(moldyn->dim.x/2))/lc->x; + j=(atom[count].r.y+(moldyn->dim.y/2))/lc->y; + k=(atom[count].r.z+(moldyn->dim.z/2))/lc->z; + list_add_immediate_ptr(&(moldyn->lc.subcell[i+j*nx+k*nx*ny]), + &(atom[count])); + } + + return 0; +} + +int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,t_list *cell) { + + t_linkcell *lc; + int a; + int count1,count2; + int ci,cj,ck; + int nx,ny,nz; + int x,y,z; + unsigned char bx,by,bz; + + lc=&(moldyn->lc); + nx=lc->nx; + ny=lc->ny; + nz=lc->nz; + count1=1; + count2=27; + a=nx*ny; + + + cell[0]=lc->subcell[i+j*nx+k*a]; + for(ci=-1;ci<=1;ci++) { + bx=0; + x=i+ci; + if((x<0)||(x>=nx)) { + x=(x+nx)%nx; + bx=1; + } + for(cj=-1;cj<=1;cj++) { + by=0; + y=j+cj; + if((y<0)||(y>=ny)) { + y=(y+ny)%ny; + by=1; + } + for(ck=-1;ck<=1;ck++) { + bz=0; + z=k+ck; + if((z<0)||(z>=nz)) { + z=(z+nz)%nz; + bz=1; + } + if(!(ci|cj|ck)) continue; + if(bx|by|bz) { + cell[--count2]=lc->subcell[x+y*nx+z*a]; + } + else { + cell[count1++]=lc->subcell[x+y*nx+z*a]; + } + } + } + } + + lc->dnlc=count2; + lc->countn=27; + + return count2; +} + +int link_cell_shutdown(t_moldyn *moldyn) { + + int i; + t_linkcell *lc; + + lc=&(moldyn->lc); + + for(i=0;inx*lc->ny*lc->nz;i++) + list_shutdown(&(moldyn->lc.subcell[i])); + + if(lc->listfd) close(lc->listfd); + + return 0; +} + +/* + * + * 'integration of newtons equation' - algorithms + * + */ + +/* start the integration */ + +int moldyn_integrate(t_moldyn *moldyn) { + + int i; + unsigned int e,m,s,d,v; + t_3dvec p; + + int fd; + char fb[128]; + + /* initialize linked cell method */ + link_cell_init(moldyn); + + /* logging & visualization */ + e=moldyn->ewrite; + m=moldyn->mwrite; + s=moldyn->swrite; + d=moldyn->dwrite; + v=moldyn->vwrite; + + if(!(moldyn->lvstat&MOLDYN_LVSTAT_INITIALIZED)) { + printf("[moldyn] warning, lv system not initialized\n"); + return -1; + } + + /* sqaure of some variables */ + moldyn->tau_square=moldyn->tau*moldyn->tau; + moldyn->cutoff_square=moldyn->cutoff*moldyn->cutoff; + + /* calculate initial forces */ + moldyn->potential_force_function(moldyn); + + for(i=0;itime_steps;i++) { + + /* integration step */ + moldyn->integrate(moldyn); + + /* check for log & visualization */ + if(e) { + if(!(i%e)) + dprintf(moldyn->efd, + "%.15f %.45f\n",i*moldyn->tau, + get_total_energy(moldyn)); + } + if(m) { + if(!(i%m)) { + p=get_total_p(moldyn->atom,moldyn->count); + dprintf(moldyn->mfd, + "%.15f %.45f\n",i*moldyn->tau, + v3_norm(&p)); + } + } + if(s) { + if(!(i%s)) { + snprintf(fb,128,"%s-%f-%.15f.save",moldyn->sfb, + moldyn->t,i*moldyn->tau); + fd=open(fb,O_WRONLY|O_TRUNC|O_CREAT); + if(fd<0) perror("[moldyn] save fd open"); + else { + write(fd,moldyn,sizeof(t_moldyn)); + write(fd,moldyn->atom, + moldyn->count*sizeof(t_atom)); + } + close(fd); + } + } + if(v) { + if(!(i%v)) { + visual_atoms(moldyn->visual,i*moldyn->tau, + moldyn->atom,moldyn->count); + printf("\rsteps: %d",i); + fflush(stdout); + } + } + } + + return 0; +} + +/* velocity verlet */ + +int velocity_verlet(t_moldyn *moldyn) { + + int i,count; + double tau,tau_square; + t_3dvec delta; + t_atom *atom; + + atom=moldyn->atom; + count=moldyn->count; + tau=moldyn->tau; + tau_square=moldyn->tau_square; + + for(i=0;idim)); + + /* velocities */ + v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass); + v3_add(&(atom[i].v),&(atom[i].v),&delta); + } + + /* neighbour list update */ +printf("list update ...\n"); + link_cell_update(moldyn); +printf("done\n"); + + /* forces depending on chosen potential */ +printf("calc potential/force ...\n"); + potential_force_calc(moldyn); + //moldyn->potential_force_function(moldyn); +printf("done\n"); + + for(i=0;idim.x/2)/lc->x,\ + (atom[i].r.y+moldyn->dim.y/2)/lc->y,\ + (atom[i].r.z+moldyn->dim.z/2)/lc->z,\ + nb_list); + + +int potential_force_calc(t_moldyn *moldyn) { + + int i,count; + t_atom *atom; + t_linkcell *lc; + t_list neighbour[27]; + t_list *this; double u; + + count=moldyn->count; + atom=moldyn->atom; + lc=&(moldyn->lc); + + /* reset energy */ + u=0.0; + + for(i=0;istatus&MOLDYN_STAT_1BP) + moldyn->pf_func1b(moldyn,&(atom[i])); + + /* 2 body pair potential/force */ + if(moldyn->status&MOLDYN_STAT_2BP) { + + CREATE_CELL_LIST(neighbour); + + /* + * processing cell of atom i + * => no need to check for empty list + * (1 element at minimum) + */ + + this=&(neighbour[0]); + list_reset(this); + do { + btom=this->current->data; + if(btom!=&(atom[i])) + moldyn->pf_func2b(moldyn, + &(atom[i]),btom); + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + /* + * direct neighbour cells + * => no boundary condition check necessary + */ + for(j=0;jdnlc;j++) { + this=&(neighbour[j]); + list_reset(this); + if(this->start!=NULL) { + do { + btom=this->current->data; + moldyn->pf_func2b(moldyn, + &(atom[i]), + btom); + } while(list_next(this)!=\ + L_NO_NEXT_ELEMENT); + } + + /* + * neighbour cells due to periodic bc + * => check boundary conditions + */ + for(j=lc->dnlc;jcountn;j++) { + this=&(neighbour[j]); + list_reset(this); + if(this->start!=NULL) { + do { + btom=this->current->data; + moldyn->pf_func2b(moldyn, + &(atom[i]), + btom); + + } + + } + + return 0; +} + + +/* harmonic oscillator potential and force */ + +int harmonic_oscillator(t_moldyn *moldyn) { + + t_ho_params *params; + t_atom *atom,*btom; + t_linkcell *lc; + t_list *this,neighbour[27]; + int i,j,c; + int count; + t_3dvec force,distance; + double d,u; + double sc,equi_dist; + int ni,nj,nk; + + params=moldyn->pot_params; + atom=moldyn->atom; + lc=&(moldyn->lc); + sc=params->spring_constant; + equi_dist=params->equilibrium_distance; + count=moldyn->count; + + /* reset energy counter */ + u=0.0; + + for(i=0;idim.x/2))/lc->x; + nj=(atom[i].r.y+(moldyn->dim.y/2))/lc->y; + nk=(atom[i].r.z+(moldyn->dim.z/2))/lc->z; + c=link_cell_neighbour_index(moldyn,ni,nj,nk,neighbour); + + /* + * processing cell of atom i + * => no need to check for empty list (1 element at minimum) + */ + this=&(neighbour[0]); + list_reset(this); + do { + btom=this->current->data; + if(btom==&(atom[i])) + continue; + v3_sub(&distance,&(atom[i].r),&(btom->r)); + d=v3_norm(&distance); + if(d<=moldyn->cutoff) { + u+=(0.5*sc*(d-equi_dist)*(d-equi_dist)); + v3_scale(&force,&distance, + -sc*(1.0-(equi_dist/d))); + v3_add(&(atom[i].f),&(atom[i].f),&force); + } + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + /* + * direct neighbour cells + * => no boundary condition check necessary + */ + for(j=1;jstart!=NULL) { + + do { + btom=this->current->data; + v3_sub(&distance,&(atom[i].r),&(btom->r)); + d=v3_norm(&distance); + if(d<=moldyn->cutoff) { + u+=(0.5*sc*(d-equi_dist)*(d-equi_dist)); + v3_scale(&force,&distance, + -sc*(1.0-(equi_dist/d))); + v3_add(&(atom[i].f),&(atom[i].f), + &force); + } + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + } + } + + /* + * indirect neighbour cells + * => check boundary conditions + */ + for(j=c;j<27;j++) { + this=&(neighbour[j]); + list_reset(this); /* check boundary conditions */ + if(this->start!=NULL) { + + do { + btom=this->current->data; + v3_sub(&distance,&(atom[i].r),&(btom->r)); + v3_per_bound(&distance,&(moldyn->dim)); + d=v3_norm(&distance); + if(d<=moldyn->cutoff) { + u+=(0.5*sc*(d-equi_dist)*(d-equi_dist)); + v3_scale(&force,&distance, + -sc*(1.0-(equi_dist/d))); + v3_add(&(atom[i].f),&(atom[i].f), + &force); + } + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + } + } + } + + moldyn->energy=0.5*u; + + return 0; +} + +/* lennard jones potential & force for one sort of atoms */ + +int lennard_jones(t_moldyn *moldyn) { + + t_lj_params *params; + t_atom *atom,*btom; + t_linkcell *lc; + t_list *this,neighbour[27]; + int i,j,c; + int count; + t_3dvec force,distance; + double d,h1,h2,u; double eps,sig6,sig12; + int ni,nj,nk; - params=ptr; + params=moldyn->pot_params; atom=moldyn->atom; + lc=&(moldyn->lc); count=moldyn->count; - eps=params->epsilon; + eps=params->epsilon4; sig6=params->sigma6; sig12=params->sigma12; + /* reset energy counter */ u=0.0; + for(i=0;idim.x/2))/lc->x; + nj=(atom[i].r.y+(moldyn->dim.y/2))/lc->y; + nk=(atom[i].r.z+(moldyn->dim.z/2))/lc->z; + c=link_cell_neighbour_index(moldyn,ni,nj,nk,neighbour); + + /* processing cell of atom i */ + this=&(neighbour[0]); + list_reset(this); /* list has 1 element at minimum */ + do { + btom=this->current->data; + if(btom==&(atom[i])) + continue; + v3_sub(&distance,&(atom[i].r),&(btom->r)); + d=v3_absolute_square(&distance); /* 1/r^2 */ + if(d<=moldyn->cutoff_square) { + d=1.0/d; /* 1/r^2 */ + h2=d*d; /* 1/r^4 */ + h2*=d; /* 1/r^6 */ + h1=h2*h2; /* 1/r^12 */ + u+=eps*(sig12*h1-sig6*h2); + h2*=d; /* 1/r^8 */ + h1*=d; /* 1/r^14 */ + h2*=6*sig6; + h1*=12*sig12; + d=+h1-h2; + d*=eps; + v3_scale(&force,&distance,d); + v3_add(&(atom[i].f),&(atom[i].f),&force); + } + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + /* neighbours not doing boundary condition overflow */ + for(j=1;jstart!=NULL) { + + do { + btom=this->current->data; + v3_sub(&distance,&(atom[i].r),&(btom->r)); + d=v3_absolute_square(&distance); /* r^2 */ + if(d<=moldyn->cutoff_square) { + d=1.0/d; /* 1/r^2 */ + h2=d*d; /* 1/r^4 */ + h2*=d; /* 1/r^6 */ + h1=h2*h2; /* 1/r^12 */ + u+=eps*(sig12*h1-sig6*h2); + h2*=d; /* 1/r^8 */ + h1*=d; /* 1/r^14 */ + h2*=6*sig6; + h1*=12*sig12; + d=+h1-h2; + d*=eps; + v3_scale(&force,&distance,d); + v3_add(&(atom[i].f),&(atom[i].f), + &force); + } + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + } + } + + /* neighbours due to boundary conditions */ + for(j=c;j<27;j++) { + this=&(neighbour[j]); + list_reset(this); /* check boundary conditions */ + if(this->start!=NULL) { + + do { + btom=this->current->data; + v3_sub(&distance,&(atom[i].r),&(btom->r)); + v3_per_bound(&distance,&(moldyn->dim)); + d=v3_absolute_square(&distance); /* r^2 */ + if(d<=moldyn->cutoff_square) { + d=1.0/d; /* 1/r^2 */ + h2=d*d; /* 1/r^4 */ + h2*=d; /* 1/r^6 */ + h1=h2*h2; /* 1/r^12 */ + u+=eps*(sig12*h1-sig6*h2); + h2*=d; /* 1/r^8 */ + h1*=d; /* 1/r^14 */ + h2*=6*sig6; + h1*=12*sig12; + d=+h1-h2; + d*=eps; + v3_scale(&force,&distance,d); + v3_add(&(atom[i].f),&(atom[i].f), + &force); + } + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + } } } + + moldyn->energy=0.5*u; - return u; + return 0; } +/* tersoff potential & force for 2 sorts of atoms */ + +int tersoff(t_moldyn *moldyn) { + + t_tersoff_params *params; + t_atom *atom,*btom,*ktom; + t_linkcell *lc; + t_list *this,*thisk,neighbour[27],neighbourk[27]; + int i,j,k,c,ck; + int count; + double u; + int ni,nj,nk; + int ki,kj,kk; + + + params=moldyn->pot_params; + atom=moldyn->atom; + lc=&(moldyn->lc); + count=moldyn->count; + + /* reset energy counter */ + u=0.0; + + for(i=0;idim.x/2))/lc->x; + nj=(atom[i].r.y+(moldyn->dim.y/2))/lc->y; + nk=(atom[i].r.z+(moldyn->dim.z/2))/lc->z; + c=link_cell_neighbour_index(moldyn,ni,nj,nk,neighbour); + + /* + * processing cell of atom i + * => no need to check for empty list (1 element at minimum) + */ + this=&(neighbour[0]); + list_reset(this); + do { + btom=this->current->data; + if(btom==&(atom[i])) + continue; + + /* 2 body stuff */ + + /* we need: f_c, df_c, f_r, df_r */ + + v3_sub(&dist_ij,btom,&(atom[i])); + d_ij=v3_norm(&dist_ij); + if(d_ij<=S) { + + /* determine the tersoff parameters */ + if(atom[i].element!=btom->element) { + S=sqrt(TERSOFF_S[e1]*TERSOFF_S[e2]); + R=R_m; + A=; + lambda=; + B=; + mu=; + chi=; + beta=; + betaN=; + + if(d_ij<=R) { + df_r=-lambda*A*exp(-lambda*d_ij)/d_ij; + v3_scale(&force,&dist_ij,df_r); + v3_add(&(atom[i].f),&(atom[i].f), + &force); + } + else { + s_r=S-R; + arg1=PI*(d_ij-R)/s_r; + f_c=0.5+0.5*cos(arg1); + df_c=-0.5*sin(arg1)*(PI/(s_r*d_ij)); + f_r=A*exp(-lambda*d_ij); + df_r=-lambda*f_r/d_ij; + scale=df_c*f_r+df_r*f_c; + v3_scale(&force,&dist_ij,scale); + v3_add(&(atom[i].f),&(atom[i].f), + &force); + } + } + else + continue; + + + /* end 2 body stuff */ + + /* determine cell neighbours of btom */ + ki=(btom->r.x+(moldyn->dim.x/2))/lc->x; + kj=(btom->r.y+(moldyn->dim.y/2))/lc->y; + kk=(btom->r.z+(moldyn->dim.z/2))/lc->z; + ck=link_cell_neighbour_index(moldyn,ki,kj,kk, + neighbourk); + + /* go for zeta - 3 body stuff! */ + zeta=0.0; + d_ij2=d_ij*d_ij; + + /* cell of btom */ + thisk=&(neighbourk[0]); + list_reset(thisk); + do { + ktom=thisk->current->data; + if(ktom==btom) + continue; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (1) */ + + v3_sub(&dist_ik,ktom,&(atom[i])); + d_ik=v3_norm(&dist_ik); + if(d_ik<=Sik) { + + Rik=; + Sik=; + Aik=; + lambda_ik=; + Bik=; + mu_ik=; + omega_ik=; + c_i=; + d_i=; + h_i=; + + + if(d_ik<=Rik) { + f_cik=1.0; + df_cik=0.0; + } + else { + sik_rik=Sik-Rik; + arg1ik=PI*(d_ik-Rik)/sik_rik; + f_cik=0.5+0.5*cos(arg1ik); + df_cik=-0.5*sin(arg1ik)* \ + (PI/(sik_rik*d_ik)); + f_rik=Aik*exp(-lambda_ik*d_ik); + f_aik=-Bik*exp(-mu_ik*d_ik); + } + + v3_sub(&distance_jk,ktom,btom); + cos_theta=(d_ij2+d_ik*d_ik-d_jk*d_jk)/\ + (2*d_ij*d_ik); + sin_theta=sqrt(1.0/\ + (cos_theta*cos_theta)); + theta=arccos(cos_theta); + + + } + else + continue; + + /* end 3 body stuff (1) */ + + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + /* direct neighbours of btom cell */ + for(k=1;kstart!=NULL) { + + do { + ktom=thisk->current->data; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (2) */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + } + } + + /* indirect neighbours of btom cell */ + for(k=ck;k<27;k++) { + thisk=&(neighbourk[k]); + list_reset(thisk); + if(thisk->start!=NULL) { + + do { + ktom=thisk->current->data; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + } + } + + + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + /* + * direct neighbour cells of atom i + */ + for(j=1;jstart!=NULL) { + + do { + btom=this->current->data; + + /* 2 body stuff */ + + + /* determine cell neighbours of btom */ + ki=(btom->r.x+(moldyn->dim.x/2))/lc->x; + kj=(btom->r.y+(moldyn->dim.y/2))/lc->y; + kk=(btom->r.z+(moldyn->dim.z/2))/lc->z; + ck=link_cell_neighbour_index(moldyn,ki,kj,kk, + neighbourk); + + /* cell of btom */ + thisk=&(neighbourk[0]); + list_reset(thisk); + do { + ktom=thisk->current->data; + if(ktom==btom) + continue; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (1) */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + /* direct neighbours of btom cell */ + for(k=1;kstart!=NULL) { + + do { + ktom=thisk->current->data; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (2) */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + } + } + + /* indirect neighbours of btom cell */ + for(k=ck;k<27;k++) { + thisk=&(neighbourk[k]); + list_reset(thisk); + if(thisk->start!=NULL) { + + do { + ktom=thisk->current->data; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (3) */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + } + } + + + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + } + } + + /* + * indirect neighbour cells of atom i + */ + for(j=c;j<27;j++) { + this=&(neighbour[j]); + list_reset(this); + if(this->start!=NULL) { + + do { + btom=this->current->data; + + /* 2 body stuff */ + + + /* determine cell neighbours of btom */ + ki=(btom->r.x+(moldyn->dim.x/2))/lc->x; + kj=(btom->r.y+(moldyn->dim.y/2))/lc->y; + kk=(btom->r.z+(moldyn->dim.z/2))/lc->z; + ck=link_cell_neighbour_index(moldyn,ki,kj,kk, + neighbourk); + + /* cell of btom */ + thisk=&(neighbourk[0]); + list_reset(thisk); + do { + ktom=thisk->current->data; + if(ktom==btom) + continue; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (1) */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + /* direct neighbours of btom cell */ + for(k=1;kstart!=NULL) { + + do { + ktom=thisk->current->data; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (2) */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + } + } + + /* indirect neighbours of btom cell */ + for(k=ck;k<27;k++) { + thisk=&(neighbourk[k]); + list_reset(thisk); + if(thisk->start!=NULL) { + + do { + ktom=thisk->current->data; + if(ktom==&(atom[i])) + continue; + + /* 3 body stuff (3) */ + + } while(list_next(thisk)!=L_NO_NEXT_ELEMENT); + + } + } + + + } while(list_next(this)!=L_NO_NEXT_ELEMENT); + + } + } + + } + + moldyn->energy=0.5*u; + + return 0; +}