X-Git-Url: https://hackdaworld.org/gitweb/?a=blobdiff_plain;f=moldyn.c;h=433be6824c9663f9bfa745ca0b82d08b566abd2b;hb=refs%2Fheads%2Forigin;hp=e02557c38f78d57e3336fff421697de55c571de1;hpb=dc70c570abec4596355df26ff19756658e33e762;p=physik%2Fposic.git diff --git a/moldyn.c b/moldyn.c index e02557c..433be68 100644 --- a/moldyn.c +++ b/moldyn.c @@ -16,396 +16,1108 @@ #include #include "moldyn.h" +#include "report/report.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"); +int moldyn_init(t_moldyn *moldyn,int argc,char **argv) { + + printf("[moldyn] init\n"); + + memset(moldyn,0,sizeof(t_moldyn)); + + rand_init(&(moldyn->random),NULL,1); + moldyn->random.status|=RAND_STAT_VERBOSE; return 0; } -int moldyn_parse_argv(t_moldyn *moldyn,int argc,char **argv) { +int moldyn_shutdown(t_moldyn *moldyn) { - int i; - t_ho_params hop; - t_lj_params ljp; - double s,e; + printf("[moldyn] shutdown\n"); - memset(moldyn,0,sizeof(t_moldyn)); + moldyn_log_shutdown(moldyn); + link_cell_shutdown(moldyn); + rand_close(&(moldyn->random)); + free(moldyn->atom); + + return 0; +} + +int set_int_alg(t_moldyn *moldyn,u8 algo) { - /* 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 'D': - moldyn->dwrite=atoi(argv[++i]); - strncpy(moldyn->dfb,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])) { + printf("[moldyn] integration algorithm: "); + + switch(algo) { case MOLDYN_INTEGRATE_VERLET: moldyn->integrate=velocity_verlet; + printf("velocity verlet\n"); break; default: - printf("unknown integration algo %s\n",argv[i]); - moldyn_usage(argv); + printf("unknown integration algorithm: %02x\n",algo); + printf("unknown\n"); 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; + return 0; +} + +int set_cutoff(t_moldyn *moldyn,double cutoff) { + + moldyn->cutoff=cutoff; + + printf("[moldyn] cutoff [A]: %f\n",moldyn->cutoff); + + return 0; +} + +int set_temperature(t_moldyn *moldyn,double t_ref) { + + moldyn->t_ref=t_ref; + + printf("[moldyn] temperature [K]: %f\n",moldyn->t_ref); + + return 0; +} + +int set_pressure(t_moldyn *moldyn,double p_ref) { + + moldyn->p_ref=p_ref; + + printf("[moldyn] pressure [bar]: %f\n",moldyn->p_ref/BAR); + + return 0; +} + +int set_pt_scale(t_moldyn *moldyn,u8 ptype,double ptc,u8 ttype,double ttc) { + + moldyn->pt_scale=(ptype|ttype); + moldyn->t_tc=ttc; + moldyn->p_tc=ptc; + + printf("[moldyn] p/t scaling:\n"); + + printf(" p: %s",ptype?"yes":"no "); + if(ptype) + printf(" | type: %02x | factor: %f",ptype,ptc); + printf("\n"); + + printf(" t: %s",ttype?"yes":"no "); + if(ttype) + printf(" | type: %02x | factor: %f",ttype,ttc); + printf("\n"); + + return 0; +} + +int set_dim(t_moldyn *moldyn,double x,double y,double z,u8 visualize) { + + moldyn->dim.x=x; + moldyn->dim.y=y; + moldyn->dim.z=z; + + moldyn->volume=x*y*z; + + if(visualize) { + moldyn->vis.dim.x=x; + moldyn->vis.dim.y=y; + moldyn->vis.dim.z=z; + } + + moldyn->dv=0.000001*moldyn->volume; + + printf("[moldyn] dimensions in A and A^3 respectively:\n"); + printf(" x: %f\n",moldyn->dim.x); + printf(" y: %f\n",moldyn->dim.y); + printf(" z: %f\n",moldyn->dim.z); + printf(" volume: %f\n",moldyn->volume); + printf(" visualize simulation box: %s\n",visualize?"yes":"no"); + printf(" delta volume (pressure calc): %f\n",moldyn->dv); + + return 0; +} + +int set_nn_dist(t_moldyn *moldyn,double dist) { + + moldyn->nnd=dist; + + return 0; +} + +int set_pbc(t_moldyn *moldyn,u8 x,u8 y,u8 z) { + + printf("[moldyn] periodic boundary conditions:\n"); + + if(x) + moldyn->status|=MOLDYN_STAT_PBX; + + if(y) + moldyn->status|=MOLDYN_STAT_PBY; + + if(z) + moldyn->status|=MOLDYN_STAT_PBZ; + + printf(" x: %s\n",x?"yes":"no"); + printf(" y: %s\n",y?"yes":"no"); + printf(" z: %s\n",z?"yes":"no"); + + return 0; +} + +int set_potential1b(t_moldyn *moldyn,pf_func1b func) { + + moldyn->func1b=func; + + return 0; +} + +int set_potential2b(t_moldyn *moldyn,pf_func2b func) { + + moldyn->func2b=func; + + return 0; +} + +int set_potential3b_j1(t_moldyn *moldyn,pf_func2b func) { + + moldyn->func3b_j1=func; + + return 0; +} + +int set_potential3b_j2(t_moldyn *moldyn,pf_func2b func) { + + moldyn->func3b_j2=func; + + return 0; +} + +int set_potential3b_j3(t_moldyn *moldyn,pf_func2b func) { + + moldyn->func3b_j3=func; + + return 0; +} + +int set_potential3b_k1(t_moldyn *moldyn,pf_func3b func) { + + moldyn->func3b_k1=func; + + return 0; +} + +int set_potential3b_k2(t_moldyn *moldyn,pf_func3b func) { + + moldyn->func3b_k2=func; + + return 0; +} + +int set_potential_params(t_moldyn *moldyn,void *params) { + + moldyn->pot_params=params; + + return 0; +} + +int set_avg_skip(t_moldyn *moldyn,int skip) { + + printf("[moldyn] skip %d steps before starting average calc\n",skip); + moldyn->avg_skip=skip; + + return 0; +} + +int moldyn_set_log_dir(t_moldyn *moldyn,char *dir) { + + strncpy(moldyn->vlsdir,dir,127); + + return 0; +} + +int moldyn_set_report(t_moldyn *moldyn,char *author,char *title) { + + strncpy(moldyn->rauthor,author,63); + strncpy(moldyn->rtitle,title,63); + + return 0; +} + +int moldyn_set_log(t_moldyn *moldyn,u8 type,int timer) { + + char filename[128]; + int ret; + + printf("[moldyn] set log: "); + + switch(type) { + case LOG_TOTAL_ENERGY: + moldyn->ewrite=timer; + snprintf(filename,127,"%s/energy",moldyn->vlsdir); + moldyn->efd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->efd<0) { + perror("[moldyn] energy log fd open"); + return moldyn->efd; + } + dprintf(moldyn->efd,"# total energy log file\n"); + printf("total energy (%d)\n",timer); 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; + case LOG_TOTAL_MOMENTUM: + moldyn->mwrite=timer; + snprintf(filename,127,"%s/momentum",moldyn->vlsdir); + moldyn->mfd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->mfd<0) { + perror("[moldyn] momentum log fd open"); + return moldyn->mfd; + } + dprintf(moldyn->efd,"# total momentum log file\n"); + printf("total momentum (%d)\n",timer); + break; + case LOG_PRESSURE: + moldyn->pwrite=timer; + snprintf(filename,127,"%s/pressure",moldyn->vlsdir); + moldyn->pfd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->pfd<0) { + perror("[moldyn] pressure log file\n"); + return moldyn->pfd; + } + dprintf(moldyn->pfd,"# pressure log file\n"); + printf("pressure (%d)\n",timer); + break; + case LOG_TEMPERATURE: + moldyn->twrite=timer; + snprintf(filename,127,"%s/temperature",moldyn->vlsdir); + moldyn->tfd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->tfd<0) { + perror("[moldyn] temperature log file\n"); + return moldyn->tfd; + } + dprintf(moldyn->tfd,"# temperature log file\n"); + printf("temperature (%d)\n",timer); + break; + case SAVE_STEP: + moldyn->swrite=timer; + printf("save file (%d)\n",timer); + break; + case VISUAL_STEP: + moldyn->vwrite=timer; + ret=visual_init(&(moldyn->vis),moldyn->vlsdir); + if(ret<0) { + printf("[moldyn] visual init failure\n"); + return ret; + } + printf("visual file (%d)\n",timer); + break; + case CREATE_REPORT: + snprintf(filename,127,"%s/report.tex",moldyn->vlsdir); + moldyn->rfd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->rfd<0) { + perror("[moldyn] report fd open"); + return moldyn->rfd; + } + printf("report -> "); + if(moldyn->efd) { + snprintf(filename,127,"%s/e_plot.scr", + moldyn->vlsdir); + moldyn->epfd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->epfd<0) { + perror("[moldyn] energy plot fd open"); + return moldyn->epfd; + } + dprintf(moldyn->epfd,e_plot_script); + close(moldyn->epfd); + printf("energy "); + } + if(moldyn->pfd) { + snprintf(filename,127,"%s/pressure_plot.scr", + moldyn->vlsdir); + moldyn->ppfd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->ppfd<0) { + perror("[moldyn] p plot fd open"); + return moldyn->ppfd; + } + dprintf(moldyn->ppfd,pressure_plot_script); + close(moldyn->ppfd); + printf("pressure "); + } + if(moldyn->tfd) { + snprintf(filename,127,"%s/temperature_plot.scr", + moldyn->vlsdir); + moldyn->tpfd=open(filename, + O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IWUSR); + if(moldyn->tpfd<0) { + perror("[moldyn] t plot fd open"); + return moldyn->tpfd; + } + dprintf(moldyn->tpfd,temperature_plot_script); + close(moldyn->tpfd); + printf("temperature "); + } + dprintf(moldyn->rfd,report_start, + moldyn->rauthor,moldyn->rtitle); + printf("\n"); break; default: - printf("unknown potential %s\n",argv[i]); - moldyn_usage(argv); + printf("unknown log type: %02x\n",type); 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_shutdown(t_moldyn *moldyn) { + + char sc[256]; + + printf("[moldyn] log shutdown\n"); + if(moldyn->efd) { + close(moldyn->efd); + if(moldyn->rfd) { + dprintf(moldyn->rfd,report_energy); + snprintf(sc,255,"cd %s && gnuplot e_plot.scr", + moldyn->vlsdir); + system(sc); } } + if(moldyn->mfd) close(moldyn->mfd); + if(moldyn->pfd) { + close(moldyn->pfd); + if(moldyn->rfd) + dprintf(moldyn->rfd,report_pressure); + snprintf(sc,255,"cd %s && gnuplot pressure_plot.scr", + moldyn->vlsdir); + system(sc); + } + if(moldyn->tfd) { + close(moldyn->tfd); + if(moldyn->rfd) + dprintf(moldyn->rfd,report_temperature); + snprintf(sc,255,"cd %s && gnuplot temperature_plot.scr", + moldyn->vlsdir); + system(sc); + } + if(moldyn->rfd) { + dprintf(moldyn->rfd,report_end); + close(moldyn->rfd); + snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1", + moldyn->vlsdir); + system(sc); + snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1", + moldyn->vlsdir); + system(sc); + snprintf(sc,255,"cd %s && dvipdf report >/dev/null 2>&1", + moldyn->vlsdir); + system(sc); + } + if(&(moldyn->vis)) visual_tini(&(moldyn->vis)); return 0; } -int moldyn_log_init(t_moldyn *moldyn) { +/* + * creating lattice functions + */ + +int create_lattice(t_moldyn *moldyn,u8 type,double lc,int element,double mass, + u8 attr,u8 brand,int a,int b,int c,t_3dvec *origin) { - moldyn->lvstat=0; - t_visual *vis; + int new,count; + int ret; + t_3dvec orig; + void *ptr; + t_atom *atom; - vis=&(moldyn->vis); + new=a*b*c; + count=moldyn->count; - 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; + /* how many atoms do we expect */ + if(type==CUBIC) new*=1; + if(type==FCC) new*=4; + if(type==DIAMOND) new*=8; + + /* allocate space for atoms */ + ptr=realloc(moldyn->atom,(count+new)*sizeof(t_atom)); + if(!ptr) { + perror("[moldyn] realloc (create lattice)"); + return -1; + } + moldyn->atom=ptr; + atom=&(moldyn->atom[count]); + + /* no atoms on the boundaries (only reason: it looks better!) */ + if(!origin) { + orig.x=0.5*lc; + orig.y=0.5*lc; + orig.z=0.5*lc; + } + else { + orig.x=origin->x; + orig.y=origin->y; + orig.z=origin->z; } - 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; + switch(type) { + case CUBIC: + set_nn_dist(moldyn,lc); + ret=cubic_init(a,b,c,lc,atom,&orig); + break; + case FCC: + if(!origin) + v3_scale(&orig,&orig,0.5); + set_nn_dist(moldyn,0.5*sqrt(2.0)*lc); + ret=fcc_init(a,b,c,lc,atom,&orig); + break; + case DIAMOND: + if(!origin) + v3_scale(&orig,&orig,0.25); + set_nn_dist(moldyn,0.25*sqrt(3.0)*lc); + ret=diamond_init(a,b,c,lc,atom,&orig); + break; + default: + printf("unknown lattice type (%02x)\n",type); + return -1; + } + + /* debug */ + if(ret!=new) { + printf("[moldyn] creating lattice failed\n"); + printf(" amount of atoms\n"); + printf(" - expected: %d\n",new); + printf(" - created: %d\n",ret); + return -1; + } + + moldyn->count+=new; + printf("[moldyn] created lattice with %d atoms\n",new); + + for(ret=0;retmfd,"# moldyn total momentum logfile\n"); - moldyn->lvstat|=MOLDYN_LVSTAT_TOTAL_M; + r.x+=lc; } - if(moldyn->swrite) - moldyn->lvstat|=MOLDYN_LVSTAT_SAVE; + for(i=0;idwrite) { - moldyn->dfd=open(moldyn->dfb,O_WRONLY|O_CREAT|O_TRUNC); - if(moldyn->dfd<0) { - perror("[moldyn] dfd open"); - return moldyn->dfd; + int count; + int i,j,k,l; + t_3dvec o,r,n; + t_3dvec basis[3]; + + count=0; + if(origin) + v3_copy(&o,origin); + else + v3_zero(&o); + + /* construct the basis */ + memset(basis,0,3*sizeof(t_3dvec)); + basis[0].x=0.5*lc; + basis[0].y=0.5*lc; + basis[1].x=0.5*lc; + basis[1].z=0.5*lc; + basis[2].y=0.5*lc; + basis[2].z=0.5*lc; + + /* fill up the room */ + r.x=o.x; + for(i=0;idfd,moldyn,sizeof(t_moldyn)); - moldyn->lvstat|=MOLDYN_LVSTAT_DUMP; + r.x+=lc; + } + + /* coordinate transformation */ + for(i=0;ivwrite)&&(vis)) { - moldyn->visual=vis; - visual_init(vis,moldyn->vfb); - moldyn->lvstat|=MOLDYN_LVSTAT_VISUAL; + return count; +} + +int diamond_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) { + + int count; + t_3dvec o; + + count=fcc_init(a,b,c,lc,atom,origin); + + o.x=0.25*lc; + o.y=0.25*lc; + o.z=0.25*lc; + + if(origin) v3_add(&o,&o,origin); + + count+=fcc_init(a,b,c,lc,&atom[count],&o); + + return count; +} + +int add_atom(t_moldyn *moldyn,int element,double mass,u8 brand,u8 attr, + t_3dvec *r,t_3dvec *v) { + + t_atom *atom; + void *ptr; + int count; + + atom=moldyn->atom; + count=(moldyn->count)++; + + ptr=realloc(atom,(count+1)*sizeof(t_atom)); + if(!ptr) { + perror("[moldyn] realloc (add atom)"); + return -1; } + moldyn->atom=ptr; - moldyn->lvstat|=MOLDYN_LVSTAT_INITIALIZED; + atom=moldyn->atom; + atom[count].r=*r; + atom[count].v=*v; + atom[count].element=element; + atom[count].mass=mass; + atom[count].brand=brand; + atom[count].tag=count; + atom[count].attr=attr; + + /* update total system mass */ + total_mass_calc(moldyn); return 0; } -int moldyn_log_shutdown(t_moldyn *moldyn) { +int destroy_atoms(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); + if(moldyn->atom) free(moldyn->atom); return 0; } -int moldyn_init(t_moldyn *moldyn,int argc,char **argv) { +int thermal_init(t_moldyn *moldyn,u8 equi_init) { - int ret; + /* + * - gaussian distribution of velocities + * - zero total momentum + * - velocity scaling (E = 3/2 N k T), E: kinetic energy + */ - ret=moldyn_parse_argv(moldyn,argc,argv); - if(ret<0) return ret; + int i; + double v,sigma; + t_3dvec p_total,delta; + t_atom *atom; + t_random *random; - ret=moldyn_log_init(moldyn); - if(ret<0) return ret; + atom=moldyn->atom; + random=&(moldyn->random); - rand_init(&(moldyn->random),NULL,1); - moldyn->random.status|=RAND_STAT_VERBOSE; + printf("[moldyn] thermal init (equi init: %s)\n",equi_init?"yes":"no"); + + /* gaussian distribution of velocities */ + v3_zero(&p_total); + for(i=0;icount;i++) { + sigma=sqrt(2.0*K_BOLTZMANN*moldyn->t_ref/atom[i].mass); + /* x direction */ + v=sigma*rand_get_gauss(random); + atom[i].v.x=v; + p_total.x+=atom[i].mass*v; + /* y direction */ + v=sigma*rand_get_gauss(random); + atom[i].v.y=v; + p_total.y+=atom[i].mass*v; + /* z direction */ + v=sigma*rand_get_gauss(random); + atom[i].v.z=v; + p_total.z+=atom[i].mass*v; + } - moldyn->status=0; + /* zero total momentum */ + v3_scale(&p_total,&p_total,1.0/moldyn->count); + 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(moldyn,equi_init); return 0; } -int moldyn_shutdown(t_moldyn *moldyn) { +double total_mass_calc(t_moldyn *moldyn) { - moldyn_log_shutdown(moldyn); - rand_close(&(moldyn->random)); - free(moldyn->atom); + int i; - return 0; + moldyn->mass=0.0; + + for(i=0;icount;i++) + moldyn->mass+=moldyn->atom[i].mass; + + return moldyn->mass; +} + +double temperature_calc(t_moldyn *moldyn) { + + /* assume up to date kinetic energy, which is 3/2 N k_B T */ + + moldyn->t=(2.0*moldyn->ekin)/(3.0*K_BOLTZMANN*moldyn->count); + + return moldyn->t; } -int create_lattice(unsigned char type,int element,double mass,double lc, - int a,int b,int c,t_atom **atom) { +double get_temperature(t_moldyn *moldyn) { + return moldyn->t; +} + +int scale_velocity(t_moldyn *moldyn,u8 equi_init) { + + int i; + double e,scale; + t_atom *atom; int count; - int ret; - t_3dvec origin; - count=a*b*c; + atom=moldyn->atom; - if(type==FCC) count*=4; - if(type==DIAMOND) count*=8; + /* + * - velocity scaling (E = 3/2 N k T), E: kinetic energy + */ - *atom=malloc(count*sizeof(t_atom)); - if(*atom==NULL) { - perror("malloc (atoms)"); - return -1; + /* get kinetic energy / temperature & count involved atoms */ + e=0.0; + count=0; + for(i=0;icount;i++) { + if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB)) { + e+=atom[i].mass*v3_absolute_square(&(atom[i].v)); + count+=1; + } + } + e*=0.5; + if(count!=0) moldyn->t=e/(1.5*count*K_BOLTZMANN); + else return 0; /* no atoms involved in scaling! */ + + /* (temporary) hack for e,t = 0 */ + if(e==0.0) { + moldyn->t=0.0; + if(moldyn->t_ref!=0.0) { + thermal_init(moldyn,equi_init); + return 0; + } + else + return 0; /* no scaling needed */ } - v3_zero(&origin); - switch(type) { - case FCC: - ret=fcc_init(a,b,c,lc,*atom,&origin); - break; - case DIAMOND: - ret=diamond_init(a,b,c,lc,*atom,&origin); - break; - default: - printf("unknown lattice type (%02x)\n",type); - return -1; + /* get scaling factor */ + scale=moldyn->t_ref/moldyn->t; + if(equi_init&TRUE) + scale*=2.0; + else + if(moldyn->pt_scale&T_SCALE_BERENDSEN) + scale=1.0+(scale-1.0)/moldyn->t_tc; + scale=sqrt(scale); + + /* velocity scaling */ + for(i=0;icount;i++) { + if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB)) + v3_scale(&(atom[i].v),&(atom[i].v),scale); } - /* debug */ - if(ret!=count) { - printf("ok, there is something wrong ...\n"); - printf("calculated -> %d atoms\n",count); - printf("created -> %d atoms\n",ret); + return 0; +} + +double ideal_gas_law_pressure(t_moldyn *moldyn) { + + double p; + + p=moldyn->count*moldyn->t*K_BOLTZMANN/moldyn->volume; + + return p; +} + +double virial_sum(t_moldyn *moldyn) { + + int i; + double v; + t_virial *virial; + + /* virial (sum over atom virials) */ + v=0.0; + for(i=0;icount;i++) { + virial=&(moldyn->atom[i].virial); + v+=(virial->xx+virial->yy+virial->zz); + } + moldyn->virial=v; + + /* global virial (absolute coordinates) */ + virial=&(moldyn->gvir); + moldyn->gv=virial->xx+virial->yy+virial->zz; + + return moldyn->virial; +} + +double pressure_calc(t_moldyn *moldyn) { + + /* + * PV = NkT + + * with W = 1/3 sum_i f_i r_i (- skipped!) + * virial = sum_i f_i r_i + * + * => P = (2 Ekin + virial) / (3V) + */ + + /* assume up to date virial & up to date kinetic energy */ + + /* pressure (atom virials) */ + moldyn->p=2.0*moldyn->ekin+moldyn->virial; + moldyn->p/=(3.0*moldyn->volume); + + /* pressure (absolute coordinates) */ + moldyn->gp=2.0*moldyn->ekin+moldyn->gv; + moldyn->gp/=(3.0*moldyn->volume); + + return moldyn->p; +} + +int average_and_fluctuation_calc(t_moldyn *moldyn) { + + if(moldyn->total_stepsavg_skip) + return 0; + + int denom=moldyn->total_steps+1-moldyn->avg_skip; + + /* assume up to date energies, temperature, pressure etc */ + + /* kinetic energy */ + moldyn->k_sum+=moldyn->ekin; + moldyn->k2_sum+=(moldyn->ekin*moldyn->ekin); + moldyn->k_avg=moldyn->k_sum/denom; + moldyn->k2_avg=moldyn->k2_sum/denom; + moldyn->dk2_avg=moldyn->k2_avg-(moldyn->k_avg*moldyn->k_avg); + + /* potential energy */ + moldyn->v_sum+=moldyn->energy; + moldyn->v2_sum+=(moldyn->energy*moldyn->energy); + moldyn->v_avg=moldyn->v_sum/denom; + moldyn->v2_avg=moldyn->v2_sum/denom; + moldyn->dv2_avg=moldyn->v2_avg-(moldyn->v_avg*moldyn->v_avg); + + /* temperature */ + moldyn->t_sum+=moldyn->t; + moldyn->t_avg=moldyn->t_sum/denom; + + /* virial */ + moldyn->virial_sum+=moldyn->virial; + moldyn->virial_avg=moldyn->virial_sum/denom; + moldyn->gv_sum+=moldyn->gv; + moldyn->gv_avg=moldyn->gv_sum/denom; + + /* pressure */ + moldyn->p_sum+=moldyn->p; + moldyn->p_avg=moldyn->p_sum/denom; + moldyn->gp_sum+=moldyn->gp; + moldyn->gp_avg=moldyn->gp_sum/denom; + + return 0; +} + +int get_heat_capacity(t_moldyn *moldyn) { + + double temp2,ighc; + + /* averages needed for heat capacity calc */ + if(moldyn->total_stepsavg_skip) + return 0; + + /* (temperature average)^2 */ + temp2=moldyn->t_avg*moldyn->t_avg; + printf("[moldyn] specific heat capacity for T=%f K [J/(kg K)]\n", + moldyn->t_avg); + + /* ideal gas contribution */ + ighc=3.0*moldyn->count*K_BOLTZMANN/2.0; + printf(" ideal gas contribution: %f\n", + ighc/moldyn->mass*KILOGRAM/JOULE); + + /* specific heat for nvt ensemble */ + moldyn->c_v_nvt=moldyn->dv2_avg/(K_BOLTZMANN*temp2)+ighc; + moldyn->c_v_nvt/=moldyn->mass; + + /* specific heat for nve ensemble */ + moldyn->c_v_nve=ighc/(1.0-(moldyn->dv2_avg/(ighc*K_BOLTZMANN*temp2))); + moldyn->c_v_nve/=moldyn->mass; + + printf(" NVE: %f\n",moldyn->c_v_nve*KILOGRAM/JOULE); + printf(" NVT: %f\n",moldyn->c_v_nvt*KILOGRAM/JOULE); +printf(" --> sim: %f experimental: %f\n",moldyn->dv2_avg,1.5*moldyn->count*K_B2*moldyn->t_avg*moldyn->t_avg*(1.0-1.5*moldyn->count*K_BOLTZMANN/(700*moldyn->mass*JOULE/KILOGRAM))); + + return 0; +} + +double thermodynamic_pressure_calc(t_moldyn *moldyn) { + + t_3dvec dim,*tp; + double u_up,u_down,dv; + double scale,p; + t_atom *store; + + /* + * dU = - p dV + * + * => p = - dU/dV + * + */ + + scale=0.00001; + dv=8*scale*scale*scale*moldyn->volume; + + store=malloc(moldyn->count*sizeof(t_atom)); + if(store==NULL) { + printf("[moldyn] allocating store mem failed\n"); return -1; } - while(count) { - (*atom)[count-1].element=element; - (*atom)[count-1].mass=mass; - count-=1; - } + /* save unscaled potential energy + atom/dim configuration */ + memcpy(store,moldyn->atom,moldyn->count*sizeof(t_atom)); + dim=moldyn->dim; + + /* scale up dimension and atom positions */ + scale_dim(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE); + scale_atoms(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE); + link_cell_shutdown(moldyn); + link_cell_init(moldyn,QUIET); + potential_force_calc(moldyn); + u_up=moldyn->energy; + + /* restore atomic configuration + dim */ + memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom)); + moldyn->dim=dim; + + /* scale down dimension and atom positions */ + scale_dim(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE); + scale_atoms(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE); + link_cell_shutdown(moldyn); + link_cell_init(moldyn,QUIET); + potential_force_calc(moldyn); + u_down=moldyn->energy; + + /* calculate pressure */ + p=-(u_up-u_down)/dv; +printf("-------> %.10f %.10f %f\n",u_up/EV/moldyn->count,u_down/EV/moldyn->count,p/BAR); + + /* restore atomic configuration + dim */ + memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom)); + moldyn->dim=dim; - return ret; + /* restore energy */ + potential_force_calc(moldyn); + + link_cell_shutdown(moldyn); + link_cell_init(moldyn,QUIET); + + return p; } -int destroy_lattice(t_atom *atom) { +double get_pressure(t_moldyn *moldyn) { - if(atom) free(atom); + return moldyn->p; - return 0; } -int thermal_init(t_moldyn *moldyn) { - - /* - * - gaussian distribution of velocities - * - zero total momentum - * - velocity scaling (E = 3/2 N k T), E: kinetic energy - */ +int scale_dim(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) { - int i; - double v,sigma; - t_3dvec p_total,delta; - t_atom *atom; - t_random *random; + t_3dvec *dim; - atom=moldyn->atom; - random=&(moldyn->random); + dim=&(moldyn->dim); - /* 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; - p_total.x+=atom[i].mass*v; - /* y direction */ - v=sigma*rand_get_gauss(random); - atom[i].v.y=v; - p_total.y+=atom[i].mass*v; - /* z direction */ - v=sigma*rand_get_gauss(random); - atom[i].v.z=v; - p_total.z+=atom[i].mass*v; - } + if(dir==SCALE_UP) + scale=1.0+scale; - /* zero total momentum */ - v3_scale(&p_total,&p_total,1.0/moldyn->count); - for(i=0;icount;i++) { - v3_scale(&delta,&p_total,1.0/atom[i].mass); - v3_sub(&(atom[i].v),&(atom[i].v),&delta); - } + if(dir==SCALE_DOWN) + scale=1.0-scale; - /* velocity scaling */ - scale_velocity(moldyn); + if(x) dim->x*=scale; + if(y) dim->y*=scale; + if(z) dim->z*=scale; return 0; } -int scale_velocity(t_moldyn *moldyn) { +int scale_atoms(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) { int i; - double e,c; - t_atom *atom; + t_3dvec *r; - atom=moldyn->atom; + if(dir==SCALE_UP) + scale=1.0+scale; - /* - * - 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*moldyn->count*K_BOLTZMANN*moldyn->t)); - for(i=0;icount;i++) - v3_scale(&(atom[i].v),&(atom[i].v),(1.0/c)); + if(dir==SCALE_DOWN) + scale=1.0-scale; + + for(i=0;icount;i++) { + r=&(moldyn->atom[i].r); + if(x) r->x*=scale; + if(y) r->y*=scale; + if(z) r->z*=scale; + } return 0; } -double get_e_kin(t_atom *atom,int count) { +int scale_volume(t_moldyn *moldyn) { - int i; - double e; + t_3dvec *dim,*vdim; + double scale; + t_linkcell *lc; - e=0.0; + vdim=&(moldyn->vis.dim); + dim=&(moldyn->dim); + lc=&(moldyn->lc); - for(i=0;ipt_scale&P_SCALE_BERENDSEN) { + scale=1.0-(moldyn->p_ref-moldyn->p)/moldyn->p_tc; + scale=pow(scale,ONE_THIRD); + } + else { + scale=pow(moldyn->p/moldyn->p_ref,ONE_THIRD); } +moldyn->debug=scale; - return e; -} + /* scale the atoms and dimensions */ + scale_atoms(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE); + scale_dim(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE); + + /* visualize dimensions */ + if(vdim->x!=0) { + vdim->x=dim->x; + vdim->y=dim->y; + vdim->z=dim->z; + } + + /* recalculate scaled volume */ + moldyn->volume=dim->x*dim->y*dim->z; + + /* adjust/reinit linkcell */ + if(((int)(dim->x/moldyn->cutoff)!=lc->nx)|| + ((int)(dim->y/moldyn->cutoff)!=lc->ny)|| + ((int)(dim->z/moldyn->cutoff)!=lc->nx)) { + link_cell_shutdown(moldyn); + link_cell_init(moldyn,QUIET); + } else { + lc->x*=scale; + lc->y*=scale; + lc->z*=scale; + } -double get_e_pot(t_moldyn *moldyn) { + return 0; - return moldyn->energy; } -double get_total_energy(t_moldyn *moldyn) { +double e_kin_calc(t_moldyn *moldyn) { + + int i; + t_atom *atom; + + atom=moldyn->atom; + moldyn->ekin=0.0; + + for(i=0;icount;i++) + moldyn->ekin+=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v)); - double e; + return moldyn->ekin; +} - e=get_e_kin(moldyn->atom,moldyn->count); - e+=get_e_pot(moldyn); +double get_total_energy(t_moldyn *moldyn) { - return e; + return(moldyn->ekin+moldyn->energy); } -t_3dvec get_total_p(t_atom *atom, int count) { +t_3dvec get_total_p(t_moldyn *moldyn) { t_3dvec p,p_total; int i; + t_atom *atom; + + atom=moldyn->atom; v3_zero(&p_total); - for(i=0;icount;i++) { v3_scale(&p,&(atom[i].v),atom[i].mass); v3_add(&p_total,&p_total,&p); } @@ -413,15 +1125,13 @@ t_3dvec get_total_p(t_atom *atom, int count) { return p_total; } -double estimate_time_step(t_moldyn *moldyn,double nn_dist,double t) { +double estimate_time_step(t_moldyn *moldyn,double nn_dist) { 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); + /* nn_dist is the nearest neighbour distance */ + + tau=(0.05*nn_dist*moldyn->atom[0].mass)/sqrt(3.0*K_BOLTZMANN*moldyn->t); return tau; } @@ -432,16 +1142,13 @@ double estimate_time_step(t_moldyn *moldyn,double nn_dist,double t) { /* linked list / cell method */ -int link_cell_init(t_moldyn *moldyn) { +int link_cell_init(t_moldyn *moldyn,u8 vol) { 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; @@ -453,11 +1160,18 @@ int link_cell_init(t_moldyn *moldyn) { lc->cells=lc->nx*lc->ny*lc->nz; lc->subcell=malloc(lc->cells*sizeof(t_list)); - printf("initializing linked cells (%d)\n",lc->cells); + if(lc->cells<27) + printf("[moldyn] FATAL: less then 27 subcells!\n"); + + if(vol) { + printf("[moldyn] initializing linked cells (%d)\n",lc->cells); + printf(" x: %d x %f A\n",lc->nx,lc->x); + printf(" y: %d x %f A\n",lc->ny,lc->y); + printf(" z: %d x %f A\n",lc->nz,lc->z); + } for(i=0;icells;i++) - //list_init(&(lc->subcell[i]),1); - list_init(&(lc->subcell[i]),lc->listfd); + list_init_f(&(lc->subcell[i])); link_cell_update(moldyn); @@ -467,26 +1181,30 @@ int link_cell_init(t_moldyn *moldyn) { int link_cell_update(t_moldyn *moldyn) { int count,i,j,k; - int nx,ny,nz; + int nx,ny; t_atom *atom; t_linkcell *lc; + double x,y,z; atom=moldyn->atom; lc=&(moldyn->lc); nx=lc->nx; ny=lc->ny; - nz=lc->nz; + + x=moldyn->dim.x/2; + y=moldyn->dim.y/2; + z=moldyn->dim.z/2; for(i=0;icells;i++) - list_destroy(&(moldyn->lc.subcell[i])); + list_destroy_f(&(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])); + 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_f(&(lc->subcell[i+j*nx+k*nx*ny]), + &(atom[count])); } return 0; @@ -500,7 +1218,7 @@ int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,t_list *cell) { int ci,cj,ck; int nx,ny,nz; int x,y,z; - unsigned char bx,by,bz; + u8 bx,by,bz; lc=&(moldyn->lc); nx=lc->nx; @@ -510,7 +1228,6 @@ int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,t_list *cell) { count2=27; a=nx*ny; - cell[0]=lc->subcell[i+j*nx+k*a]; for(ci=-1;ci<=1;ci++) { bx=0; @@ -544,7 +1261,9 @@ int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,t_list *cell) { } } - return count2; + lc->dnlc=count1; + + return count1; } int link_cell_shutdown(t_moldyn *moldyn) { @@ -555,10 +1274,50 @@ int link_cell_shutdown(t_moldyn *moldyn) { lc=&(moldyn->lc); for(i=0;inx*lc->ny*lc->nz;i++) - list_shutdown(&(moldyn->lc.subcell[i])); + list_destroy_f(&(moldyn->lc.subcell[i])); + + free(lc->subcell); + + return 0; +} + +int moldyn_add_schedule(t_moldyn *moldyn,int runs,double tau) { + + int count; + void *ptr; + t_moldyn_schedule *schedule; + + schedule=&(moldyn->schedule); + count=++(schedule->total_sched); - if(lc->listfd) close(lc->listfd); + ptr=realloc(schedule->runs,count*sizeof(int)); + if(!ptr) { + perror("[moldyn] realloc (runs)"); + return -1; + } + schedule->runs=ptr; + schedule->runs[count-1]=runs; + + ptr=realloc(schedule->tau,count*sizeof(double)); + if(!ptr) { + perror("[moldyn] realloc (tau)"); + return -1; + } + schedule->tau=ptr; + schedule->tau[count-1]=tau; + + printf("[moldyn] schedule added:\n"); + printf(" number: %d | runs: %d | tau: %f\n",count-1,runs,tau); + + + return 0; +} + +int moldyn_set_schedule_hook(t_moldyn *moldyn,set_hook hook,void *hook_params) { + moldyn->schedule.hook=hook; + moldyn->schedule.hook_params=hook_params; + return 0; } @@ -573,81 +1332,174 @@ int link_cell_shutdown(t_moldyn *moldyn) { int moldyn_integrate(t_moldyn *moldyn) { int i; - unsigned int e,m,s,d,v; - t_3dvec p; - + unsigned int e,m,s,v,p,t; + t_3dvec momentum; + t_moldyn_schedule *sched; + t_atom *atom; int fd; - char fb[128]; + char dir[128]; + double ds; + double energy_scale; + //double tp; + + sched=&(moldyn->schedule); + atom=moldyn->atom; /* initialize linked cell method */ - link_cell_init(moldyn); + link_cell_init(moldyn,VERBOSE); /* 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; - } + p=moldyn->pwrite; + t=moldyn->twrite; /* sqaure of some variables */ moldyn->tau_square=moldyn->tau*moldyn->tau; moldyn->cutoff_square=moldyn->cutoff*moldyn->cutoff; + /* energy scaling factor */ + energy_scale=moldyn->count*EV; + /* calculate initial forces */ - moldyn->potential_force_function(moldyn); + potential_force_calc(moldyn); +#ifdef DEBUG +return 0; +#endif + + /* some stupid checks before we actually start calculating bullshit */ + if(moldyn->cutoff>0.5*moldyn->dim.x) + printf("[moldyn] warning: cutoff > 0.5 x dim.x\n"); + if(moldyn->cutoff>0.5*moldyn->dim.y) + printf("[moldyn] warning: cutoff > 0.5 x dim.y\n"); + if(moldyn->cutoff>0.5*moldyn->dim.z) + printf("[moldyn] warning: cutoff > 0.5 x dim.z\n"); + ds=0.5*atom[0].f.x*moldyn->tau_square/atom[0].mass; + if(ds>0.05*moldyn->nnd) + printf("[moldyn] warning: forces too high / tau too small!\n"); + + /* zero absolute time */ + moldyn->time=0.0; + moldyn->total_steps=0; + + /* debugging, ignore */ + moldyn->debug=0; + + /* tell the world */ + printf("[moldyn] integration start, go get a coffee ...\n"); + + /* executing the schedule */ + sched->count=0; + while(sched->counttotal_sched) { + + /* setting amount of runs and finite time step size */ + moldyn->tau=sched->tau[sched->count]; + moldyn->tau_square=moldyn->tau*moldyn->tau; + moldyn->time_steps=sched->runs[sched->count]; + + /* integration according to schedule */ for(i=0;itime_steps;i++) { /* integration step */ moldyn->integrate(moldyn); + /* calculate kinetic energy, temperature and pressure */ + e_kin_calc(moldyn); + temperature_calc(moldyn); + virial_sum(moldyn); + pressure_calc(moldyn); + average_and_fluctuation_calc(moldyn); + + /* p/t scaling */ + if(moldyn->pt_scale&(T_SCALE_BERENDSEN|T_SCALE_DIRECT)) + scale_velocity(moldyn,FALSE); + if(moldyn->pt_scale&(P_SCALE_BERENDSEN|P_SCALE_DIRECT)) + scale_volume(moldyn); + /* check for log & visualization */ if(e) { if(!(i%e)) dprintf(moldyn->efd, - "%.15f %.45f\n",i*moldyn->tau, - get_total_energy(moldyn)); + "%f %f %f %f\n", + moldyn->time,moldyn->ekin/energy_scale, + moldyn->energy/energy_scale, + get_total_energy(moldyn)/energy_scale); } if(m) { if(!(i%m)) { - p=get_total_p(moldyn->atom,moldyn->count); + momentum=get_total_p(moldyn); dprintf(moldyn->mfd, - "%.15f %.45f\n",i*moldyn->tau, - v3_norm(&p)); + "%f %f %f %f %f\n",moldyn->time, + momentum.x,momentum.y,momentum.z, + v3_norm(&momentum)); + } + } + if(p) { + if(!(i%p)) { + dprintf(moldyn->pfd, + "%f %f %f %f %f\n",moldyn->time, + moldyn->p/BAR,moldyn->p_avg/BAR, + moldyn->gp/BAR,moldyn->gp_avg/BAR); + } + } + if(t) { + if(!(i%t)) { + dprintf(moldyn->tfd, + "%f %f %f\n", + moldyn->time,moldyn->t,moldyn->t_avg); } } 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); + snprintf(dir,128,"%s/s-%07.f.save", + moldyn->vlsdir,moldyn->time); + fd=open(dir,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(d) { - if(!(i%d)) - write(moldyn->dfd,moldyn->atom, - moldyn->count*sizeof(t_atom)); - - } if(v) { if(!(i%v)) { - visual_atoms(moldyn->visual,i*moldyn->tau, + visual_atoms(&(moldyn->vis),moldyn->time, moldyn->atom,moldyn->count); - printf("\rsteps: %d",i); - fflush(stdout); } } + + /* display progress */ + if(!(i%10)) { + printf("\rsched:%d, steps:%d, T:%3.1f/%3.1f P:%4.1f/%4.1f V:%6.1f", + sched->count,i, + moldyn->t,moldyn->t_avg, + moldyn->p_avg/BAR,moldyn->p/BAR, + moldyn->volume); + fflush(stdout); + } + + /* increase absolute time */ + moldyn->time+=moldyn->tau; + moldyn->total_steps+=1; + + } + + /* check for hooks */ + if(sched->hook) { + printf("\n ## schedule hook %d/%d start ##\n", + sched->count+1,sched->total_sched-1); + sched->hook(moldyn,sched->hook_params); + printf(" ## schedule hook end ##\n"); + } + + /* increase the schedule counter */ + sched->count+=1; + } return 0; @@ -658,7 +1510,7 @@ int moldyn_integrate(t_moldyn *moldyn) { int velocity_verlet(t_moldyn *moldyn) { int i,count; - double tau,tau_square; + double tau,tau_square,h; t_3dvec delta; t_atom *atom; @@ -669,14 +1521,15 @@ int velocity_verlet(t_moldyn *moldyn) { for(i=0;idim)); + check_per_bound(moldyn,&(atom[i].r)); - /* velocities */ - v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass); + /* velocities [actually v(t+tau/2)] */ + v3_scale(&delta,&(atom[i].f),h*tau); v3_add(&(atom[i].v),&(atom[i].v),&delta); } @@ -684,10 +1537,10 @@ int velocity_verlet(t_moldyn *moldyn) { link_cell_update(moldyn); /* forces depending on chosen potential */ - moldyn->potential_force_function(moldyn); + potential_force_calc(moldyn); for(i=0;ipot_params; - atom=moldyn->atom; - lc=&(moldyn->lc); - sc=params->spring_constant; - equi_dist=params->equilibrium_distance; count=moldyn->count; + itom=moldyn->atom; + lc=&(moldyn->lc); + + /* reset energy */ + moldyn->energy=0.0; - /* reset energy counter */ - u=0.0; + /* reset global virial */ + memset(&(moldyn->gvir),0,sizeof(t_virial)); + /* reset force, site energy and virial of every atom */ 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); + v3_zero(&(itom[i].f)); + + /* reset virial */ + virial=(&(itom[i].virial)); + virial->xx=0.0; + virial->yy=0.0; + virial->zz=0.0; + virial->xy=0.0; + virial->xz=0.0; + virial->yz=0.0; + + /* reset site energy */ + itom[i].e=0.0; - /* - * 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); + /* get energy, force and virial of every atom */ + + /* first (and only) loop over atoms i */ + for(i=0;ifunc1b) + moldyn->func1b(moldyn,&(itom[i])); + + if(!(itom[i].attr&(ATOM_ATTR_2BP|ATOM_ATTR_3BP))) + continue; + + /* 2 body pair potential/force */ + + link_cell_neighbour_index(moldyn, + (itom[i].r.x+moldyn->dim.x/2)/lc->x, + (itom[i].r.y+moldyn->dim.y/2)/lc->y, + (itom[i].r.z+moldyn->dim.z/2)/lc->z, + neighbour_i); + + dnlc=lc->dnlc; + + /* first loop over atoms j */ + if(moldyn->func2b) { + for(j=0;j<27;j++) { + + this=&(neighbour_i[j]); + list_reset_f(this); + + if(this->start==NULL) + continue; + + bc_ij=(jcurrent->data; + + if(jtom==&(itom[i])) + continue; + + if((jtom->attr&ATOM_ATTR_2BP)& + (itom[i].attr&ATOM_ATTR_2BP)) { + moldyn->func2b(moldyn, + &(itom[i]), + jtom, + bc_ij); + } + } while(list_next_f(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) { + /* 3 body potential/force */ + + if(!(itom[i].attr&ATOM_ATTR_3BP)) + continue; + + /* copy the neighbour lists */ + memcpy(neighbour_i2,neighbour_i,27*sizeof(t_list)); + + /* second loop over atoms j */ + for(j=0;j<27;j++) { + + this=&(neighbour_i[j]); + list_reset_f(this); + + if(this->start==NULL) + continue; + + bc_ij=(jcurrent->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); + jtom=this->current->data; + + if(jtom==&(itom[i])) + continue; + + if(!(jtom->attr&ATOM_ATTR_3BP)) + continue; + + /* reset 3bp run */ + moldyn->run3bp=1; + + if(moldyn->func3b_j1) + moldyn->func3b_j1(moldyn, + &(itom[i]), + jtom, + bc_ij); + + /* in first j loop, 3bp run can be skipped */ + if(!(moldyn->run3bp)) + continue; + + /* first loop over atoms k */ + if(moldyn->func3b_k1) { + + for(k=0;k<27;k++) { + + that=&(neighbour_i2[k]); + list_reset_f(that); + + if(that->start==NULL) + continue; + + bc_ik=(kcurrent->data; + + if(!(ktom->attr&ATOM_ATTR_3BP)) + continue; + + if(ktom==jtom) + continue; + + if(ktom==&(itom[i])) + continue; + + moldyn->func3b_k1(moldyn, + &(itom[i]), + jtom, + ktom, + bc_ik|bc_ij); + + } while(list_next_f(that)!=\ + L_NO_NEXT_ELEMENT); + } - } while(list_next(this)!=L_NO_NEXT_ELEMENT); - } + } + + if(moldyn->func3b_j2) + moldyn->func3b_j2(moldyn, + &(itom[i]), + jtom, + bc_ij); + + /* second loop over atoms k */ + if(moldyn->func3b_k2) { + + for(k=0;k<27;k++) { + + that=&(neighbour_i2[k]); + list_reset_f(that); + + if(that->start==NULL) + continue; + + bc_ik=(kcurrent->data; + + if(!(ktom->attr&ATOM_ATTR_3BP)) + continue; + + if(ktom==jtom) + continue; + + if(ktom==&(itom[i])) + continue; + + moldyn->func3b_k2(moldyn, + &(itom[i]), + jtom, + ktom, + bc_ik|bc_ij); + + } while(list_next_f(that)!=\ + L_NO_NEXT_ELEMENT); + + } + + } + + /* 2bp post function */ + if(moldyn->func3b_j3) { + moldyn->func3b_j3(moldyn, + &(itom[i]), + jtom,bc_ij); + } + + } while(list_next_f(this)!=L_NO_NEXT_ELEMENT); + } + +#ifdef DEBUG + //printf("\n\n"); +#endif +#ifdef VDEBUG + printf("\n\n"); +#endif + } - moldyn->energy=0.5*u; +#ifdef DEBUG + printf("\nATOM 0: %f %f %f\n\n",itom->f.x,itom->f.y,itom->f.z); +#endif + + /* calculate global virial */ + for(i=0;igvir.xx+=moldyn->atom[i].r.x*moldyn->atom[i].f.x; + moldyn->gvir.yy+=moldyn->atom[i].r.y*moldyn->atom[i].f.y; + moldyn->gvir.zz+=moldyn->atom[i].r.z*moldyn->atom[i].f.z; + moldyn->gvir.xy+=moldyn->atom[i].r.y*moldyn->atom[i].f.x; + moldyn->gvir.xz+=moldyn->atom[i].r.z*moldyn->atom[i].f.x; + moldyn->gvir.yz+=moldyn->atom[i].r.z*moldyn->atom[i].f.y; + } return 0; } -/* lennard jones potential & force for one sort of atoms */ - -int lennard_jones(t_moldyn *moldyn) { +/* + * virial calculation + */ - 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; +//inline int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) { +int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) { - params=moldyn->pot_params; - atom=moldyn->atom; - lc=&(moldyn->lc); - count=moldyn->count; - eps=params->epsilon4; - sig6=params->sigma6; - sig12=params->sigma12; + a->virial.xx+=f->x*d->x; + a->virial.yy+=f->y*d->y; + a->virial.zz+=f->z*d->z; + a->virial.xy+=f->x*d->y; + a->virial.xz+=f->x*d->z; + a->virial.yz+=f->y*d->z; - /* reset energy counter */ - u=0.0; + return 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 */ - h1=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); +/* + * periodic boundary checking + */ - /* neighbours not doing boundary condition overflow */ - for(j=1;jstart!=NULL) { +//inline int check_per_bound(t_moldyn *moldyn,t_3dvec *a) { +int check_per_bound(t_moldyn *moldyn,t_3dvec *a) { + + double x,y,z; + t_3dvec *dim; - 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 */ - h1=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); - - } - } + dim=&(moldyn->dim); - /* neighbours due to boundary conditions */ - for(j=c;j<27;j++) { - this=&(neighbour[j]); - list_reset(this); /* check boundary conditions */ - if(this->start!=NULL) { + x=dim->x/2; + y=dim->y/2; + z=dim->z/2; - 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 */ - h1=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); + if(moldyn->status&MOLDYN_STAT_PBX) { + if(a->x>=x) a->x-=dim->x; + else if(-a->x>x) a->x+=dim->x; + } + if(moldyn->status&MOLDYN_STAT_PBY) { + if(a->y>=y) a->y-=dim->y; + else if(-a->y>y) a->y+=dim->y; + } + if(moldyn->status&MOLDYN_STAT_PBZ) { + if(a->z>=z) a->z-=dim->z; + else if(-a->z>z) a->z+=dim->z; + } + + return 0; +} + +/* + * debugging / critical check functions + */ + +int moldyn_bc_check(t_moldyn *moldyn) { + + t_atom *atom; + t_3dvec *dim; + int i; + double x; + u8 byte; + int j,k; + + atom=moldyn->atom; + dim=&(moldyn->dim); + x=dim->x/2; + for(i=0;icount;i++) { + if(atom[i].r.x>=dim->x/2||-atom[i].r.x>dim->x/2) { + printf("FATAL: atom %d: x: %.20f (%.20f)\n", + i,atom[i].r.x,dim->x/2); + printf("diagnostic:\n"); + printf("-----------\natom.r.x:\n"); + for(j=0;j<8;j++) { + memcpy(&byte,(u8 *)(&(atom[i].r.x))+j,1); + for(k=0;k<8;k++) + printf("%d%c", + ((byte)&(1<=dim->y/2||-atom[i].r.y>dim->y/2) + printf("FATAL: atom %d: y: %.20f (%.20f)\n", + i,atom[i].r.y,dim->y/2); + if(atom[i].r.z>=dim->z/2||-atom[i].r.z>dim->z/2) + printf("FATAL: atom %d: z: %.20f (%.20f)\n", + i,atom[i].r.z,dim->z/2); } - moldyn->energy=0.5*u; - return 0; } +/* + * post processing functions + */ + +int get_line(int fd,char *line,int max) { + + int count,ret; + + count=0; + + while(1) { + if(count==max) return count; + ret=read(fd,line+count,1); + if(ret<=0) return ret; + if(line[count]=='\n') { + line[count]='\0'; + return count+1; + } + count+=1; + } +} +