+ lc->dnlc=count1;
+
+ return count1;
+}
+
+int link_cell_shutdown(t_moldyn *moldyn) {
+
+ int i;
+ t_linkcell *lc;
+
+ lc=&(moldyn->lc);
+
+ 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
+ }
+
+ 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;
+
+ 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;
+
+ /* 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);
+ /*
+ thermodynamic_pressure_calc(moldyn);
+ printf("\n\nDEBUG: numeric pressure calc: %f\n\n",
+ moldyn->tp/BAR);
+ */
+
+ /* 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\n",
+ moldyn->time,moldyn->ekin/energy_scale,
+ moldyn->energy/energy_scale,
+ get_total_energy(moldyn)/energy_scale);
+ }
+ if(m) {
+ if(!(moldyn->total_steps%m)) {
+ momentum=get_total_p(moldyn);
+ dprintf(moldyn->mfd,
+ "%f %f %f %f %f\n",moldyn->time,
+ momentum.x,momentum.y,momentum.z,
+ v3_norm(&momentum));
+ }
+ }
+ if(p) {
+ if(!(moldyn->total_steps%p)) {
+ dprintf(moldyn->pfd,
+ "%f %f %f %f %f %f %f\n",moldyn->time,
+ moldyn->p/BAR,moldyn->p_avg/BAR,
+ moldyn->gp/BAR,moldyn->gp_avg/BAR,
+ moldyn->tp/BAR,moldyn->tp_avg/BAR);
+ }
+ }
+ if(t) {
+ if(!(moldyn->total_steps%t)) {
+ dprintf(moldyn->tfd,
+ "%f %f %f\n",
+ moldyn->time,moldyn->t,moldyn->t_avg);
+ }
+ }
+ if(v) {
+ if(!(moldyn->total_steps%v)) {
+ dprintf(moldyn->vfd,
+ "%f %f\n",moldyn->time,moldyn->volume);
+ }
+ }
+ if(s) {
+ if(!(moldyn->total_steps%s)) {
+ snprintf(dir,128,"%s/s-%07.f.save",
+ moldyn->vlsdir,moldyn->time);
+ fd=open(dir,O_WRONLY|O_TRUNC|O_CREAT,
+ S_IRUSR|S_IWUSR);
+ 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(a) {
+ if(!(moldyn->total_steps%a)) {
+ visual_atoms(moldyn);
+ }
+ }
+
+ /* display progress */
+ //if(!(moldyn->total_steps%10)) {
+ /* get current time */
+ gettimeofday(&t2,NULL);
+
+printf("\rsched:%d, steps:%d/%d, T:%4.1f/%4.1f P:%4.1f/%4.1f V:%6.1f (%d)",
+ sched->count,i,moldyn->total_steps,
+ moldyn->t,moldyn->t_avg,
+ moldyn->p/BAR,moldyn->p_avg/BAR,
+ //moldyn->p/BAR,(moldyn->p-2.0*moldyn->ekin/(3.0*moldyn->volume))/BAR,
+ moldyn->volume,
+ (int)(t2.tv_sec-t1.tv_sec));
+
+ fflush(stdout);
+
+ /* copy over time */
+ t1=t2;
+ //}
+
+ /* increase absolute time */
+ moldyn->time+=moldyn->tau;
+ moldyn->total_steps+=1;
+
+ }
+
+ /* check for hooks */
+ if(sched->hook) {
+ printf("\n ## schedule hook %d start ##\n",
+ sched->count);
+ sched->hook(moldyn,sched->hook_params);
+ printf(" ## schedule hook end ##\n");
+ }
+
+ /* increase the schedule counter */
+ sched->count+=1;
+
+ }
+
+ return 0;
+}
+
+/* velocity verlet */
+
+int velocity_verlet(t_moldyn *moldyn) {
+
+ int i,count;
+ double tau,tau_square,h;
+ t_3dvec delta;
+ t_atom *atom;
+
+ atom=moldyn->atom;
+ count=moldyn->count;
+ tau=moldyn->tau;
+ tau_square=moldyn->tau_square;
+
+ for(i=0;i<count;i++) {
+ /* check whether fixed atom */
+ if(atom[i].attr&ATOM_ATTR_FP)
+ continue;
+ /* new positions */
+ h=0.5/atom[i].mass;
+ v3_scale(&delta,&(atom[i].v),tau);
+ v3_add(&(atom[i].r),&(atom[i].r),&delta);
+ v3_scale(&delta,&(atom[i].f),h*tau_square);
+ v3_add(&(atom[i].r),&(atom[i].r),&delta);
+ check_per_bound(moldyn,&(atom[i].r));
+
+ /* velocities [actually v(t+tau/2)] */
+ v3_scale(&delta,&(atom[i].f),h*tau);
+ v3_add(&(atom[i].v),&(atom[i].v),&delta);
+ }
+
+ /* criticial check */
+ moldyn_bc_check(moldyn);
+
+ /* neighbour list update */
+ link_cell_update(moldyn);
+
+ /* forces depending on chosen potential */
+ potential_force_calc(moldyn);
+
+ for(i=0;i<count;i++) {
+ /* check whether fixed atom */
+ if(atom[i].attr&ATOM_ATTR_FP)
+ continue;
+ /* again velocities [actually v(t+tau)] */
+ v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass);
+ v3_add(&(atom[i].v),&(atom[i].v),&delta);
+ }
+
+ return 0;
+}
+
+
+/*
+ *
+ * potentials & corresponding forces & virial routine
+ *
+ */
+
+/* generic potential and force calculation */
+
+int potential_force_calc(t_moldyn *moldyn) {
+
+ int i,j,k,count;
+ t_atom *itom,*jtom,*ktom;
+ t_virial *virial;
+ t_linkcell *lc;
+#ifdef STATIC_LISTS
+ int *neighbour_i[27];
+ int p,q;
+ t_atom *atom;
+#else
+ t_list neighbour_i[27];
+ t_list neighbour_i2[27];
+ t_list *this,*that;
+#endif
+ u8 bc_ij,bc_ik;
+ int dnlc;
+
+ count=moldyn->count;
+ itom=moldyn->atom;
+ lc=&(moldyn->lc);
+#ifdef STATIC_LISTS
+ atom=moldyn->atom;
+#endif
+
+ /* reset energy */
+ moldyn->energy=0.0;
+
+ /* reset global virial */
+ memset(&(moldyn->gvir),0,sizeof(t_virial));
+
+ /* reset force, site energy and virial of every atom */
+ for(i=0;i<count;i++) {
+
+ /* reset force */
+ 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;
+
+ }
+
+ /* get energy, force and virial of every atom */
+
+ /* first (and only) loop over atoms i */
+ for(i=0;i<count;i++) {
+
+ /* single particle potential/force */
+ if(itom[i].attr&ATOM_ATTR_1BP)
+ if(moldyn->func1b)
+ 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++) {
+
+ bc_ij=(j<dnlc)?0:1;
+#ifdef STATIC_LISTS
+ p=0;
+
+ while(neighbour_i[j][p]!=0) {
+
+ jtom=&(atom[neighbour_i[j][p]]);
+ p++;
+
+ 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);
+ }
+ }
+#else
+ this=&(neighbour_i[j]);
+ list_reset_f(this);
+
+ if(this->start==NULL)
+ continue;
+
+ do {
+ jtom=this->current->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);
+#endif
+
+ }
+ }
+
+ /* 3 body potential/force */
+
+ if(!(itom[i].attr&ATOM_ATTR_3BP))
+ continue;
+
+ /* copy the neighbour lists */
+#ifdef STATIC_LISTS
+ /* no copy needed for static lists */
+#else
+ memcpy(neighbour_i2,neighbour_i,27*sizeof(t_list));
+#endif
+
+ /* second loop over atoms j */
+ for(j=0;j<27;j++) {
+
+ bc_ij=(j<dnlc)?0:1;
+#ifdef STATIC_LISTS
+ p=0;
+
+ while(neighbour_i[j][p]!=0) {
+
+ jtom=&(atom[neighbour_i[j][p]]);
+ p++;
+#else
+ this=&(neighbour_i[j]);
+ list_reset_f(this);
+
+ if(this->start==NULL)
+ continue;
+
+ do {
+
+ jtom=this->current->data;
+#endif
+
+ 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++) {
+
+ bc_ik=(k<dnlc)?0:1;
+#ifdef STATIC_LISTS
+ q=0;
+
+ while(neighbour_i[j][q]!=0) {
+
+ ktom=&(atom[neighbour_i[k][q]]);
+ q++;
+#else
+ that=&(neighbour_i2[k]);
+ list_reset_f(that);
+
+ if(that->start==NULL)
+ continue;
+
+ do {
+ ktom=that->current->data;
+#endif
+
+ 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);
+#ifdef STATIC_LISTS
+ }
+#else
+ } while(list_next_f(that)!=\
+ L_NO_NEXT_ELEMENT);
+#endif
+
+ }
+
+ }
+
+ 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++) {
+
+ bc_ik=(k<dnlc)?0:1;
+#ifdef STATIC_LISTS
+ q=0;
+
+ while(neighbour_i[j][q]!=0) {
+
+ ktom=&(atom[neighbour_i[k][q]]);
+ q++;
+#else
+ that=&(neighbour_i2[k]);
+ list_reset_f(that);
+
+ if(that->start==NULL)
+ continue;
+
+ do {
+ ktom=that->current->data;
+#endif
+
+ 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);
+
+#ifdef STATIC_LISTS
+ }
+#else
+ } while(list_next_f(that)!=\
+ L_NO_NEXT_ELEMENT);
+#endif
+
+ }
+
+ }
+
+ /* 2bp post function */
+ if(moldyn->func3b_j3) {
+ moldyn->func3b_j3(moldyn,
+ &(itom[i]),
+ jtom,bc_ij);
+ }
+#ifdef STATIC_LISTS
+ }
+#else
+ } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
+#endif
+
+ }
+
+#ifdef DEBUG
+ //printf("\n\n");
+#endif
+#ifdef VDEBUG
+ printf("\n\n");
+#endif
+
+ }
+
+#ifdef DEBUG
+ //printf("\nATOM 0: %f %f %f\n\n",itom->f.x,itom->f.y,itom->f.z);
+ if(moldyn->time>DSTART&&moldyn->time<DEND) {
+ printf("force:\n");
+ printf(" x: %0.40f\n",moldyn->atom[DATOM].f.x);
+ printf(" y: %0.40f\n",moldyn->atom[DATOM].f.y);
+ printf(" z: %0.40f\n",moldyn->atom[DATOM].f.z);
+ }
+#endif
+
+ /* some postprocessing */
+ for(i=0;i<count;i++) {
+ /* calculate global virial */
+ moldyn->gvir.xx+=itom[i].r.x*itom[i].f.x;
+ moldyn->gvir.yy+=itom[i].r.y*itom[i].f.y;
+ moldyn->gvir.zz+=itom[i].r.z*itom[i].f.z;
+ moldyn->gvir.xy+=itom[i].r.y*itom[i].f.x;
+ moldyn->gvir.xz+=itom[i].r.z*itom[i].f.x;
+ moldyn->gvir.yz+=itom[i].r.z*itom[i].f.y;
+
+ /* check forces regarding the given timestep */
+ if(v3_norm(&(itom[i].f))>\
+ 0.1*moldyn->nnd*itom[i].mass/moldyn->tau_square)
+ printf("[moldyn] WARNING: pfc (high force: atom %d)\n",
+ i);
+ }
+
+ return 0;
+}
+
+/*
+ * virial calculation
+ */
+
+//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) {
+
+ 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;
+
+ return 0;
+}
+
+/*
+ * periodic boundary checking
+ */
+
+//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;
+
+ dim=&(moldyn->dim);
+
+ x=dim->x/2;
+ y=dim->y/2;
+ z=dim->z/2;
+
+ 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;i<moldyn->count;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<<k))?1:0,
+ (k==7)?'\n':'|');
+ }
+ printf("---------------\nx=dim.x/2:\n");
+ for(j=0;j<8;j++) {
+ memcpy(&byte,(u8 *)(&x)+j,1);
+ for(k=0;k<8;k++)
+ printf("%d%c",
+ ((byte)&(1<<k))?1:0,
+ (k==7)?'\n':'|');
+ }
+ if(atom[i].r.x==x) printf("the same!\n");
+ else printf("different!\n");
+ }
+ if(atom[i].r.y>=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);
+ }
+
+ return 0;
+}
+
+/*
+ * restore function
+ */
+
+int moldyn_read_save_file(t_moldyn *moldyn,char *file) {
+
+ int fd;
+ int cnt,size;
+ int fsize;
+ int corr;
+
+ fd=open(file,O_RDONLY);
+ if(fd<0) {
+ perror("[moldyn] load save file open");
+ return fd;
+ }
+
+ fsize=lseek(fd,0,SEEK_END);
+ lseek(fd,0,SEEK_SET);
+
+ size=sizeof(t_moldyn);
+
+ while(size) {
+ cnt=read(fd,moldyn,size);
+ if(cnt<0) {
+ perror("[moldyn] load save file read (moldyn)");
+ return cnt;
+ }
+ size-=cnt;
+ }
+
+ size=moldyn->count*sizeof(t_atom);
+
+ /* correcting possible atom data offset */
+ corr=0;
+ if(fsize!=sizeof(t_moldyn)+size) {
+ corr=fsize-sizeof(t_moldyn)-size;
+ printf("[moldyn] WARNING: lsf (illegal file size)\n");
+ printf(" moifying offset:\n");
+ printf(" - current pos: %d\n",sizeof(t_moldyn));
+ printf(" - atom size: %d\n",size);
+ printf(" - file size: %d\n",fsize);
+ printf(" => correction: %d\n",corr);
+ lseek(fd,corr,SEEK_CUR);
+ }
+
+ moldyn->atom=(t_atom *)malloc(size);
+ if(moldyn->atom==NULL) {
+ perror("[moldyn] load save file malloc (atoms)");
+ return -1;
+ }
+
+ while(size) {
+ cnt=read(fd,moldyn->atom,size);
+ if(cnt<0) {
+ perror("[moldyn] load save file read (atoms)");
+ return cnt;
+ }
+ size-=cnt;
+ }
+
+ // hooks etc ...
+
+ return 0;
+}
+
+int moldyn_free_save_file(t_moldyn *moldyn) {
+
+ free(moldyn->atom);
+
+ return 0;
+}
+
+int moldyn_load(t_moldyn *moldyn) {
+
+ // later ...
+
+ return 0;
+}
+
+/*
+ * function to find/callback all combinations of 2 body bonds
+ */
+
+int process_2b_bonds(t_moldyn *moldyn,void *data,
+ int (*process)(t_moldyn *moldyn,t_atom *itom,t_atom *jtom,
+ void *data,u8 bc)) {
+
+ t_linkcell *lc;
+#ifdef STATIC_LISTS
+ int *neighbour[27];
+ int p;
+#else
+ t_list neighbour[27];
+#endif
+ u8 bc;
+ t_atom *itom,*jtom;
+ int i,j;
+ t_list *this;
+
+ lc=&(moldyn->lc);
+ itom=moldyn->atom;
+
+ for(i=0;i<moldyn->count;i++) {
+ /* neighbour indexing */
+ link_cell_neighbour_index(moldyn,
+ (itom[i].r.x+moldyn->dim.x/2)/lc->x,
+ (itom[i].r.y+moldyn->dim.y/2)/lc->x,
+ (itom[i].r.z+moldyn->dim.z/2)/lc->x,
+ neighbour);
+
+ for(j=0;j<27;j++) {
+
+ bc=(j<lc->dnlc)?0:1;
+
+#ifdef STATIC_LISTS
+ p=0;
+
+ while(neighbour[j][p]!=0) {
+
+ jtom=&(moldyn->atom[neighbour[j][p]]);
+ p++;
+#else
+ this=&(neighbour[j]);
+ list_reset_f(this);
+
+ if(this->start==NULL)
+ continue;
+
+ do {
+
+ jtom=this->current->data;
+#endif
+
+ /* process bond */
+ process(moldyn,&(itom[i]),jtom,data,bc);
+
+#ifdef STATIC_LISTS
+ }
+#else
+ } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
+#endif
+ }
+ }
+
+ 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') {
+ memset(line+count,0,max-count-1);
+ //line[count]='\0';
+ return count+1;
+ }
+ count+=1;
+ }
+}
+
+int pair_correlation_init(t_moldyn *moldyn,double dr) {
+
+
+ return 0;
+}
+
+int calculate_diffusion_coefficient(t_moldyn *moldyn,double *dc) {
+
+ int i;
+ t_atom *atom;
+ t_3dvec dist;
+ double d2;
+ int a_cnt;
+ int b_cnt;
+
+ atom=moldyn->atom;
+ dc[0]=0;
+ dc[1]=0;
+ dc[2]=0;
+ a_cnt=0;
+ b_cnt=0;
+
+ for(i=0;i<moldyn->count;i++) {
+
+ v3_sub(&dist,&(atom[i].r),&(atom[i].r_0));
+ check_per_bound(moldyn,&dist);
+ d2=v3_absolute_square(&dist);
+
+ if(atom[i].brand) {
+ b_cnt+=1;
+ dc[1]+=d2;
+ }
+ else {
+ a_cnt+=1;
+ dc[0]+=d2;
+ }
+
+ dc[2]+=d2;
+ }
+
+ dc[0]*=(1.0/(6.0*moldyn->time*a_cnt));
+ dc[1]*=(1.0/(6.0*moldyn->time*b_cnt));
+ dc[2]*=(1.0/(6.0*moldyn->time*moldyn->count));
+
+ return 0;
+}
+
+int bonding_analyze(t_moldyn *moldyn,double *cnt) {
+
+ return 0;
+}
+
+int calculate_pair_correlation_process(t_moldyn *moldyn,t_atom *itom,
+ t_atom *jtom,void *data,u8 bc) {
+
+ t_3dvec dist;
+ double d;
+ int s;
+ t_pcc *pcc;
+
+ /* only count pairs once,
+ * skip same atoms */
+ if(itom->tag>=jtom->tag)
+ return 0;
+
+ /*
+ * pair correlation calc
+ */
+
+ /* get pcc data */
+ pcc=data;
+
+ /* distance */
+ v3_sub(&dist,&(jtom->r),&(itom->r));
+ if(bc) check_per_bound(moldyn,&dist);
+ d=v3_absolute_square(&dist);
+
+ /* ignore if greater cutoff */
+ if(d>moldyn->cutoff_square)
+ return 0;
+
+ /* fill the slots */
+ d=sqrt(d);
+ s=(int)(d/pcc->dr);
+
+ /* should never happen but it does 8) -
+ * related to -ffloat-store problem! */
+ if(s>=pcc->o1) {
+ printf("[moldyn] WARNING: pcc (%d/%d)",
+ s,pcc->o1);
+ printf("\n");
+ s=pcc->o1-1;
+ }
+
+ if(itom->brand!=jtom->brand) {
+ /* mixed */
+ pcc->stat[s]+=1;
+ }
+ else {
+ /* type a - type a bonds */
+ if(itom->brand==0)
+ pcc->stat[s+pcc->o1]+=1;
+ else
+ /* type b - type b bonds */
+ pcc->stat[s+pcc->o2]+=1;
+ }
+
+ return 0;
+}
+
+int calculate_pair_correlation(t_moldyn *moldyn,double dr,void *ptr) {
+
+ t_pcc pcc;
+ double norm;
+ int i;
+
+ pcc.dr=dr;
+ pcc.o1=moldyn->cutoff/dr;
+ pcc.o2=2*pcc.o1;
+
+ if(pcc.o1*dr<=moldyn->cutoff)
+ printf("[moldyn] WARNING: pcc (low #slots)\n");
+
+ printf("[moldyn] pair correlation calc info:\n");
+ printf(" time: %f\n",moldyn->time);
+ printf(" count: %d\n",moldyn->count);
+ printf(" cutoff: %f\n",moldyn->cutoff);
+ printf(" temperature: cur=%f avg=%f\n",moldyn->t,moldyn->t_avg);
+
+ if(ptr!=NULL) {
+ pcc.stat=(double *)ptr;
+ }
+ else {
+ pcc.stat=(double *)malloc(3*pcc.o1*sizeof(double));
+ if(pcc.stat==NULL) {
+ perror("[moldyn] pair correlation malloc");
+ return -1;
+ }
+ }
+
+ memset(pcc.stat,0,3*pcc.o1*sizeof(double));
+
+ /* process */
+ process_2b_bonds(moldyn,&pcc,calculate_pair_correlation_process);
+
+ /* normalization */
+ for(i=1;i<pcc.o1;i++) {
+ // normalization: 4 pi r^2 dr
+ // here: not double counting pairs -> 2 pi r r dr
+ // ... and actually it's a constant times r^2
+ norm=i*i*dr*dr;
+ pcc.stat[i]/=norm;
+ pcc.stat[pcc.o1+i]/=norm;
+ pcc.stat[pcc.o2+i]/=norm;
+ }
+ /* */
+
+ if(ptr==NULL) {
+ /* todo: store/print pair correlation function */
+ free(pcc.stat);
+ }
+
+ return 0;
+}
+
+int bond_analyze_process(t_moldyn *moldyn,t_atom *itom,t_atom *jtom,
+ void *data,u8 bc) {
+
+ t_ba *ba;
+ t_3dvec dist;
+ double d;
+
+ if(itom->tag>=jtom->tag)
+ return 0;
+
+ /* distance */
+ v3_sub(&dist,&(jtom->r),&(itom->r));
+ if(bc) check_per_bound(moldyn,&dist);
+ d=v3_absolute_square(&dist);
+
+ /* ignore if greater or equal cutoff */
+ if(d>moldyn->cutoff_square)
+ return 0;
+
+ /* check for potential bond */
+ if(moldyn->check_2b_bond(moldyn,itom,jtom,bc)==FALSE)
+ return 0;
+
+ /* now count this bonding ... */
+ ba=data;
+
+ /* increase total bond counter
+ * ... double counting!
+ */
+ ba->tcnt+=2;
+
+ if(itom->brand==0)
+ ba->acnt[jtom->tag]+=1;
+ else
+ ba->bcnt[jtom->tag]+=1;
+
+ if(jtom->brand==0)
+ ba->acnt[itom->tag]+=1;
+ else
+ ba->bcnt[itom->tag]+=1;
+
+ return 0;
+}
+
+int bond_analyze(t_moldyn *moldyn,double *quality) {
+
+ // by now: # bonds of type 'a-4b' and 'b-4a' / # bonds total
+
+ int qcnt;
+ int ccnt,cset;
+ t_ba ba;
+ int i;
+ t_atom *atom;
+
+ ba.acnt=malloc(moldyn->count*sizeof(int));
+ if(ba.acnt==NULL) {
+ perror("[moldyn] bond analyze malloc (a)");
+ return -1;
+ }
+ memset(ba.acnt,0,moldyn->count*sizeof(int));
+
+ ba.bcnt=malloc(moldyn->count*sizeof(int));
+ if(ba.bcnt==NULL) {
+ perror("[moldyn] bond analyze malloc (b)");
+ return -1;
+ }
+ memset(ba.bcnt,0,moldyn->count*sizeof(int));
+
+ ba.tcnt=0;
+ qcnt=0;
+ ccnt=0;
+ cset=0;
+
+ atom=moldyn->atom;
+
+ process_2b_bonds(moldyn,&ba,bond_analyze_process);
+
+ for(i=0;i<moldyn->count;i++) {
+ if(atom[i].brand==0) {
+ if((ba.acnt[i]==0)&(ba.bcnt[i]==4))
+ qcnt+=4;
+ }
+ else {
+ if((ba.acnt[i]==4)&(ba.bcnt[i]==0)) {
+ qcnt+=4;
+ ccnt+=1;
+ }
+ cset+=1;
+ }
+ }
+
+ printf("[moldyn] bond analyze: c_cnt=%d | set=%d\n",ccnt,cset);
+ printf("[moldyn] bond analyze: q_cnt=%d | tot=%d\n",qcnt,ba.tcnt);
+
+ if(quality) {
+ quality[0]=1.0*ccnt/cset;
+ quality[1]=1.0*qcnt/ba.tcnt;
+ }
+ else {
+ printf("[moldyn] bond analyze: c_bnd_q=%f\n",1.0*qcnt/ba.tcnt);
+ printf("[moldyn] bond analyze: tot_q=%f\n",1.0*qcnt/ba.tcnt);
+ }
+
+ return 0;
+}
+
+/*
+ * visualization code
+ */
+
+int visual_init(t_moldyn *moldyn,char *filebase) {
+
+ strncpy(moldyn->vis.fb,filebase,128);
+
+ return 0;
+}
+
+int visual_bonds_process(t_moldyn *moldyn,t_atom *itom,t_atom *jtom,
+ void *data,u8 bc) {
+
+ t_vb *vb;
+
+ vb=data;
+
+ if(itom->tag>=jtom->tag)
+ return 0;
+
+ if(moldyn->check_2b_bond(moldyn,itom,jtom,bc)==FALSE)
+ return 0;
+
+ if((itom->attr&ATOM_ATTR_VB)|(jtom->attr&ATOM_ATTR_VB))
+ dprintf(vb->fd,"# [B] %f %f %f %f %f %f\n",
+ itom->r.x,itom->r.y,itom->r.z,
+ jtom->r.x,jtom->r.y,jtom->r.z);
+
+ return 0;
+}
+
+int visual_atoms(t_moldyn *moldyn) {
+
+ int i;
+ char file[128+64];
+ t_3dvec dim;
+ double help;
+ t_visual *v;
+ t_atom *atom;
+ t_vb vb;
+
+ v=&(moldyn->vis);
+ dim.x=v->dim.x;
+ dim.y=v->dim.y;
+ dim.z=v->dim.z;
+ atom=moldyn->atom;
+
+ help=(dim.x+dim.y);
+
+ sprintf(file,"%s/atomic_conf_%07.f.xyz",v->fb,moldyn->time);
+ vb.fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
+ if(vb.fd<0) {
+ perror("open visual save file fd");
+ return -1;
+ }
+
+ /* write the actual data file */
+
+ // povray header
+ dprintf(vb.fd,"# [P] %d %07.f <%f,%f,%f>\n",
+ moldyn->count,moldyn->time,help/40.0,help/40.0,-0.8*help);
+
+ // atomic configuration
+ for(i=0;i<moldyn->count;i++)
+ // atom type, positions, color and kinetic energy
+ dprintf(vb.fd,"%s %f %f %f %s %f\n",pse_name[atom[i].element],
+ atom[i].r.x,
+ atom[i].r.y,
+ atom[i].r.z,
+ pse_col[atom[i].element],
+ atom[i].ekin);
+
+ // bonds between atoms
+ process_2b_bonds(moldyn,&vb,visual_bonds_process);
+
+ // boundaries
+ if(dim.x) {
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,-dim.y/2,-dim.z/2,
+ dim.x/2,-dim.y/2,-dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,-dim.y/2,-dim.z/2,
+ -dim.x/2,dim.y/2,-dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ dim.x/2,dim.y/2,-dim.z/2,
+ dim.x/2,-dim.y/2,-dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,dim.y/2,-dim.z/2,
+ dim.x/2,dim.y/2,-dim.z/2);
+
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,-dim.y/2,dim.z/2,
+ dim.x/2,-dim.y/2,dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,-dim.y/2,dim.z/2,
+ -dim.x/2,dim.y/2,dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ dim.x/2,dim.y/2,dim.z/2,
+ dim.x/2,-dim.y/2,dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,dim.y/2,dim.z/2,
+ dim.x/2,dim.y/2,dim.z/2);
+
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,-dim.y/2,dim.z/2,
+ -dim.x/2,-dim.y/2,-dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ -dim.x/2,dim.y/2,dim.z/2,
+ -dim.x/2,dim.y/2,-dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ dim.x/2,-dim.y/2,dim.z/2,
+ dim.x/2,-dim.y/2,-dim.z/2);
+ dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
+ dim.x/2,dim.y/2,dim.z/2,
+ dim.x/2,dim.y/2,-dim.z/2);
+ }
+
+ close(vb.fd);
+