+ t_3dvec dim;
+ //t_3dvec *tp;
+ double h,dv;
+ double y0,y1;
+ double su,sd;
+ t_atom *store;
+
+ /*
+ * dU = - p dV
+ *
+ * => p = - dU/dV
+ *
+ */
+
+ /* store atomic configuration + dimension */
+ store=malloc(moldyn->count*sizeof(t_atom));
+ if(store==NULL) {
+ printf("[moldyn] allocating store mem failed\n");
+ return -1;
+ }
+ memcpy(store,moldyn->atom,moldyn->count*sizeof(t_atom));
+ dim=moldyn->dim;
+
+ /* x1, y1 */
+ sd=0.00001;
+ h=(1.0-sd)*(1.0-sd)*(1.0-sd);
+ su=pow(2.0-h,ONE_THIRD)-1.0;
+ dv=(1.0-h)*moldyn->volume;
+
+ /* scale up dimension and atom positions */
+ scale_dim(moldyn,SCALE_UP,su,TRUE,TRUE,TRUE);
+ scale_atoms(moldyn,SCALE_UP,su,TRUE,TRUE,TRUE);
+ link_cell_shutdown(moldyn);
+ link_cell_init(moldyn,QUIET);
+ potential_force_calc(moldyn);
+ y1=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,sd,TRUE,TRUE,TRUE);
+ scale_atoms(moldyn,SCALE_DOWN,sd,TRUE,TRUE,TRUE);
+ link_cell_shutdown(moldyn);
+ link_cell_init(moldyn,QUIET);
+ potential_force_calc(moldyn);
+ y0=moldyn->energy;
+
+ /* calculate pressure */
+ moldyn->tp=-(y1-y0)/(2.0*dv);
+
+ /* restore atomic configuration */
+ memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
+ moldyn->dim=dim;
+ link_cell_shutdown(moldyn);
+ link_cell_init(moldyn,QUIET);
+ //potential_force_calc(moldyn);
+
+ /* free store buffer */
+ if(store)
+ free(store);
+
+ return moldyn->tp;
+}
+
+double get_pressure(t_moldyn *moldyn) {
+
+ return moldyn->p;
+
+}
+
+int scale_dim(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
+
+ t_3dvec *dim;
+
+ dim=&(moldyn->dim);
+
+ if(dir==SCALE_UP)
+ scale=1.0+scale;
+
+ if(dir==SCALE_DOWN)
+ scale=1.0-scale;
+
+ if(x) dim->x*=scale;
+ if(y) dim->y*=scale;
+ if(z) dim->z*=scale;
+
+ return 0;
+}
+
+int scale_atoms(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
+
+ int i;
+ t_3dvec *r;
+
+ if(dir==SCALE_UP)
+ scale=1.0+scale;
+
+ if(dir==SCALE_DOWN)
+ scale=1.0-scale;
+
+ for(i=0;i<moldyn->count;i++) {
+ r=&(moldyn->atom[i].r);
+ if(x) r->x*=scale;
+ if(y) r->y*=scale;
+ if(z) r->z*=scale;
+ }
+
+ return 0;
+}
+
+int scale_atoms_ind(t_moldyn *moldyn,double x,double y,double z) {
+
+ int i;
+ t_3dvec *r;
+
+ for(i=0;i<moldyn->count;i++) {
+ r=&(moldyn->atom[i].r);
+ r->x*=x;
+ r->y*=y;
+ r->z*=z;
+ }
+
+ return 0;
+}
+
+int scale_dim_ind(t_moldyn *moldyn,double x,double y,double z) {
+
+ t_3dvec *dim;
+
+ dim=&(moldyn->dim);
+
+ dim->x*=x;
+ dim->y*=y;
+ dim->z*=z;
+
+ return 0;
+}
+
+int scale_volume(t_moldyn *moldyn) {
+
+ t_3dvec *dim,*vdim;
+ double scale;
+ t_linkcell *lc;
+ //double sx,sy,sz;
+
+ vdim=&(moldyn->vis.dim);
+ dim=&(moldyn->dim);
+ lc=&(moldyn->lc);
+
+ /* scaling factor */
+ if(moldyn->pt_scale&P_SCALE_BERENDSEN) {
+ scale=1.0-(moldyn->p_ref-moldyn->p)*moldyn->p_tc*moldyn->tau;
+ scale=pow(scale,ONE_THIRD);
+ }
+ else {
+ scale=pow(moldyn->p/moldyn->p_ref,ONE_THIRD);
+ }
+
+
+ /*
+ sx=1.0-(moldyn->p_ref-moldyn->px)*moldyn->p_tc*moldyn->tau;
+ sy=1.0-(moldyn->p_ref-moldyn->py)*moldyn->p_tc*moldyn->tau;
+ sz=1.0-(moldyn->p_ref-moldyn->pz)*moldyn->p_tc*moldyn->tau;
+ sx=pow(sx,ONE_THIRD);
+ sy=pow(sy,ONE_THIRD);
+ sz=pow(sz,ONE_THIRD);
+ */
+
+ /* scale the atoms and dimensions */
+ scale_atoms(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
+ scale_dim(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
+ //scale_atoms_ind(moldyn,sx,sy,sz);
+ //scale_dim_ind(moldyn,sx,sy,sz);
+
+ /* 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;
+ //lc->x*=sx;
+ //lc->y*=sx;
+ //lc->z*=sy;
+ }
+
+ return 0;
+
+}
+
+double e_kin_calc(t_moldyn *moldyn) {
+
+ int i;
+ t_atom *atom;
+
+ atom=moldyn->atom;
+ moldyn->ekin=0.0;
+ //moldyn->ekinx=0.0;
+ //moldyn->ekiny=0.0;
+ //moldyn->ekinz=0.0;
+
+ for(i=0;i<moldyn->count;i++) {
+ atom[i].ekin=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v));
+ moldyn->ekin+=atom[i].ekin;
+ //moldyn->ekinx+=0.5*atom[i].mass*atom[i].v.x*atom[i].v.x;
+ //moldyn->ekiny+=0.5*atom[i].mass*atom[i].v.y*atom[i].v.y;
+ //moldyn->ekinz+=0.5*atom[i].mass*atom[i].v.z*atom[i].v.z;
+ }
+
+ return moldyn->ekin;
+}
+
+double get_total_energy(t_moldyn *moldyn) {
+
+ return(moldyn->ekin+moldyn->energy);
+}
+
+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;i<moldyn->count;i++) {
+ v3_scale(&p,&(atom[i].v),atom[i].mass);
+ v3_add(&p_total,&p_total,&p);
+ }
+
+ return p_total;
+}
+
+double estimate_time_step(t_moldyn *moldyn,double nn_dist) {
+
+ double 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;
+}
+
+/*
+ * numerical tricks
+ */
+
+/* linked list / cell method */
+
+int link_cell_init(t_moldyn *moldyn,u8 vol) {
+
+ t_linkcell *lc;
+#ifndef LOWMEM_LISTS
+ int i;
+#endif
+
+ lc=&(moldyn->lc);
+
+ /* 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;
+
+#ifdef STATIC_LISTS
+ lc->subcell=malloc(lc->cells*sizeof(int*));
+#elif LOWMEM_LISTS
+ lc->subcell=malloc(sizeof(t_lowmem_list));
+#else
+ lc->subcell=malloc(lc->cells*sizeof(t_list));
+#endif
+
+ if(lc->subcell==NULL) {
+ perror("[moldyn] cell init (malloc)");
+ return -1;
+ }
+
+ if(lc->cells<27)
+ printf("[moldyn] FATAL: less then 27 subcells! (%d)\n",
+ lc->cells);
+
+ if(vol) {
+#ifdef STATIC_LISTS
+ printf("[moldyn] initializing 'static' linked cells (%d)\n",
+ lc->cells);
+#elif LOWMEM_LISTS
+ printf("[moldyn] initializing 'lowmem' linked cells (%d)\n",
+ lc->cells);
+#else
+ printf("[moldyn] initializing 'dynamic' linked cells (%d)\n",
+ lc->cells);
+#endif
+ 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);
+ }
+
+#ifdef STATIC_LISTS
+ /* list init */
+ for(i=0;i<lc->cells;i++) {
+ lc->subcell[i]=malloc((MAX_ATOMS_PER_LIST+1)*sizeof(int));
+ if(lc->subcell[i]==NULL) {
+ perror("[moldyn] list init (malloc)");
+ return -1;
+ }
+ /*
+ if(i==0)
+ printf(" ---> %d malloc %p (%p)\n",
+ i,lc->subcell[0],lc->subcell);
+ */
+ }
+#elif LOWMEM_LISTS
+ lc->subcell->head=malloc(lc->cells*sizeof(int));
+ if(lc->subcell->head==NULL) {
+ perror("[moldyn] head init (malloc)");
+ return -1;
+ }
+ lc->subcell->list=malloc(moldyn->count*sizeof(int));
+ if(lc->subcell->list==NULL) {
+ perror("[moldyn] list init (malloc)");
+ return -1;
+ }
+#else
+ for(i=0;i<lc->cells;i++)
+ list_init_f(&(lc->subcell[i]));
+#endif
+
+ /* update the list */
+ link_cell_update(moldyn);
+
+ return 0;
+}
+
+int link_cell_update(t_moldyn *moldyn) {
+
+ int count,i,j,k;
+ int nx,nxy;
+ t_atom *atom;
+ t_linkcell *lc;
+#ifdef STATIC_LISTS
+ int p;
+#elif LOWMEM_LISTS
+ int p;
+#endif
+
+ atom=moldyn->atom;
+ lc=&(moldyn->lc);
+
+ nx=lc->nx;
+ nxy=nx*lc->ny;
+
+ for(i=0;i<lc->cells;i++)
+#ifdef STATIC_LISTS
+ memset(lc->subcell[i],-1,(MAX_ATOMS_PER_LIST+1)*sizeof(int));
+#elif LOWMEM_LISTS
+ lc->subcell->head[i]=-1;
+#else
+ list_destroy_f(&(lc->subcell[i]));
+#endif
+
+ for(count=0;count<moldyn->count;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);
+
+#ifdef STATIC_LISTS
+ p=0;
+ while(lc->subcell[i+j*nx+k*nxy][p]!=-1)
+ p++;
+
+ if(p>=MAX_ATOMS_PER_LIST) {
+ printf("[moldyn] FATAL: amount of atoms too high!\n");
+ return -1;
+ }
+
+ lc->subcell[i+j*nx+k*nxy][p]=count;
+#elif LOWMEM_LISTS
+ p=i+j*nx+k*nxy;
+ lc->subcell->list[count]=lc->subcell->head[p];
+ lc->subcell->head[p]=count;
+#else
+ list_add_immediate_f(&(lc->subcell[i+j*nx+k*nxy]),
+ &(atom[count]));
+ /*
+ if(j==0&&k==0)
+ printf(" ---> %d %d malloc %p (%p)\n",
+ i,count,lc->subcell[i].current,lc->subcell);
+ */
+#endif
+ }
+
+ return 0;
+}
+
+int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,
+#ifdef STATIC_LISTS
+ int **cell
+#elif LOWMEM_LISTS
+ int *cell
+#else
+ t_list *cell
+#endif
+ ) {
+
+ t_linkcell *lc;
+ int a;
+ int count1,count2;
+ int ci,cj,ck;
+ int nx,ny,nz;
+ int x,y,z;
+ u8 bx,by,bz;
+
+ lc=&(moldyn->lc);
+ nx=lc->nx;
+ ny=lc->ny;
+ nz=lc->nz;
+ count1=1;
+ count2=27;
+ a=nx*ny;
+
+ if(i>=nx||j>=ny||k>=nz)
+ printf("[moldyn] WARNING: lcni %d/%d %d/%d %d/%d\n",
+ i,nx,j,ny,k,nz);
+
+#ifndef LOWMEM_LISTS
+ cell[0]=lc->subcell[i+j*nx+k*a];
+#else
+ cell[0]=lc->subcell->head[i+j*nx+k*a];
+#endif
+ 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) {
+#ifndef LOWMEM_LISTS
+ cell[--count2]=lc->subcell[x+y*nx+z*a];
+#else
+ cell[--count2]=lc->subcell->head[x+y*nx+z*a];
+#endif
+
+ }
+ else {
+#ifndef LOWMEM_LISTS
+ cell[count1++]=lc->subcell[x+y*nx+z*a];
+#else
+ cell[count1++]=lc->subcell->head[x+y*nx+z*a];
+#endif
+ }
+ }
+ }
+ }
+
+ lc->dnlc=count1;
+
+ return count1;
+}
+
+int link_cell_shutdown(t_moldyn *moldyn) {
+
+#ifndef LOWMEM_LISTS
+ int i;
+#endif
+ t_linkcell *lc;
+
+ lc=&(moldyn->lc);
+
+#if LOWMEM_LISTS
+ free(lc->subcell->head);
+ free(lc->subcell->list);
+
+#else
+
+ for(i=0;i<lc->cells;i++) {
+#ifdef STATIC_LISTS
+ free(lc->subcell[i]);
+#else
+ //printf(" ---> %d free %p\n",i,lc->subcell[i].start);
+ list_destroy_f(&(lc->subcell[i]));
+#endif
+ }
+#endif
+
+ 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);
+
+ 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;
+}
+
+/*
+ *
+ * 'integration of newtons equation' - algorithms
+ *
+ */
+
+/* start the integration */
+
+int moldyn_integrate(t_moldyn *moldyn) {
+
+ int i;
+ unsigned int e,m,s,v,p,t,a;
+ t_3dvec momentum;
+ t_moldyn_schedule *sched;
+ t_atom *atom;
+ int fd;
+ char dir[128];
+ double ds;
+ double energy_scale;
+ struct timeval t1,t2;
+ //double tp;
+
+#ifdef VISUAL_THREAD
+ u8 first,change;
+ pthread_t io_thread;
+ int ret;
+ t_moldyn md_copy;
+ t_atom *atom_copy;
+
+ first=1;
+ change=0;
+#endif
+
+ sched=&(moldyn->schedule);
+ atom=moldyn->atom;
+
+ /* initialize linked cell method */
+ link_cell_init(moldyn,VERBOSE);
+
+ /* logging & visualization */
+ e=moldyn->ewrite;
+ m=moldyn->mwrite;
+ s=moldyn->swrite;
+ v=moldyn->vwrite;
+ a=moldyn->awrite;
+ p=moldyn->pwrite;
+ t=moldyn->twrite;
+
+ /* sqaure of some variables */
+ moldyn->tau_square=moldyn->tau*moldyn->tau;
+
+ /* get current time */
+ gettimeofday(&t1,NULL);
+
+ /* calculate initial forces */
+ 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");
+ if(moldyn->count) {
+ 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 */
+ // should have right values!
+ //moldyn->time=0.0;
+ //moldyn->total_steps=0;
+
+ /* debugging, ignore */
+ moldyn->debug=0;
+
+ /* zero & init moldyn copy */
+#ifdef VISUAL_THREAD
+ memset(&md_copy,0,sizeof(t_moldyn));
+ atom_copy=malloc(moldyn->count*sizeof(t_atom));
+ if(atom_copy==NULL) {
+ perror("[moldyn] malloc atom copy (init)");
+ return -1;
+ }
+#endif
+
+#ifdef PTHREADS
+ printf("##################\n");
+ printf("# USING PTHREADS #\n");
+ printf("##################\n");
+#endif
+ /* tell the world */
+ printf("[moldyn] integration start, go get a coffee ...\n");
+
+ /* executing the schedule */
+ sched->count=0;
+ while(sched->count<sched->total_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];
+
+ /* energy scaling factor (might change!) */
+ energy_scale=moldyn->count*EV;
+
+ /* integration according to schedule */
+
+ for(i=0;i<moldyn->time_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);
+#ifdef PDEBUG
+ thermodynamic_pressure_calc(moldyn);
+ printf("\n\nDEBUG: numeric pressure calc: %f\n\n",
+ moldyn->tp/BAR);
+#endif
+
+ /* calculate fluctuations + averages */
+ 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(!(moldyn->total_steps%e))
+ dprintf(moldyn->efd,
+ "%f %f %f %f %f %f\n",
+ moldyn->time,moldyn->ekin/energy_scale,
+ moldyn->energy/energy_scale,
+ get_total_energy(moldyn)/energy_scale,
+ moldyn->ekin/EV,moldyn->energy/EV);
+ }