+
+#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 */
+#ifdef PARALLEL
+ #pragma omp parallel for
+#endif
+ 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;
+}
+
+int check_per_bound_and_care_for_pbc(t_moldyn *moldyn,t_atom *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->r.x>=x) {
+ a->pbc[0]+=1;
+ a->r.x-=dim->x;
+ }
+ else if(-a->r.x>x) {
+ a->pbc[0]-=1;
+ a->r.x+=dim->x;
+ }
+ }
+ if(moldyn->status&MOLDYN_STAT_PBY) {
+ if(a->r.y>=y) {
+ a->pbc[1]+=1;
+ a->r.y-=dim->y;
+ }
+ else if(-a->r.y>y) {
+ a->pbc[1]-=1;
+ a->r.y+=dim->y;
+ }
+ }
+ if(moldyn->status&MOLDYN_STAT_PBZ) {
+ if(a->r.z>=z) {
+ a->pbc[2]+=1;
+ a->r.z-=dim->z;
+ }
+ else if(-a->r.z>z) {
+ a->pbc[2]-=1;
+ a->r.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(" modifying 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;
+ }
+
+#ifdef PTHREADS
+ amutex=malloc(moldyn->count*sizeof(pthread_mutex_t));
+ if(amutex==NULL) {
+ perror("[moldyn] load save file (mutexes)");
+ return -1;
+ }
+ for(cnt=0;cnt<moldyn->count;cnt++)
+ pthread_mutex_init(&(amutex[cnt]),NULL);
+#endif
+
+ // 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;
+#elif LOWMEM_LISTS
+ int neighbour[27];
+ int p;
+#else
+ t_list neighbour[27];
+ t_list *this;
+#endif
+ u8 bc;
+ t_atom *itom,*jtom;
+ int i,j;
+
+ 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]!=-1) {
+
+ jtom=&(moldyn->atom[neighbour[j][p]]);
+ p++;
+#elif LOWMEM_LISTS
+ p=neighbour[j];
+
+ while(p!=-1) {
+
+ jtom=&(itom[p]);
+ p=lc->subcell->list[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
+ }
+#elif LOWMEM_LISTS
+ }
+#else
+ } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
+#endif
+ }
+ }
+
+ return 0;
+
+}
+
+/*
+ * function to find neighboured atoms
+ */
+
+int process_neighbours(t_moldyn *moldyn,void *data,t_atom *atom,
+ int (*process)(t_moldyn *moldyn,t_atom *atom,t_atom *natom,
+ void *data,u8 bc)) {
+
+ t_linkcell *lc;
+#ifdef STATIC_LISTS
+ int *neighbour[27];
+ int p;
+#elif LOWMEM_LISTS
+ int neighbour[27];
+ int p;
+#else
+ t_list neighbour[27];
+ t_list *this;
+#endif
+ u8 bc;
+ t_atom *natom;
+ int j;
+
+ lc=&(moldyn->lc);
+
+ /* neighbour indexing */
+ link_cell_neighbour_index(moldyn,
+ (atom->r.x+moldyn->dim.x/2)/lc->x,
+ (atom->r.y+moldyn->dim.y/2)/lc->x,
+ (atom->r.z+moldyn->dim.z/2)/lc->x,
+ neighbour);
+
+ for(j=0;j<27;j++) {
+
+ bc=(j<lc->dnlc)?0:1;