+
+ /* display progress */
+ if(!(i%10)) {
+ /* get current time */
+ gettimeofday(&t2,NULL);
+
+printf("sched:%d, steps:%d/%d, T:%4.1f/%4.1f P:%4.1f/%4.1f V:%6.1f (%d)\n",
+ 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 */
+#ifndef ALBE_FAST
+ potential_force_calc(moldyn);
+#else
+ albe_potential_force_calc(moldyn);
+#endif
+
+ 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;
+#elif LOWMEM_LISTS
+ int neighbour_i[27];
+ int p,q;
+#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 */
+#ifdef PARALLEL
+ i=omp_get_thread_num();
+ #pragma omp parallel for private(virial)
+#endif
+ 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]!=-1) {
+
+ jtom=&(atom[neighbour_i[j][p]]);
+ p++;
+#elif LOWMEM_LISTS
+ p=neighbour_i[j];
+
+ while(p!=-1) {
+
+ jtom=&(itom[p]);
+ p=lc->subcell->list[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_2BP)&
+ (itom[i].attr&ATOM_ATTR_2BP)) {
+ moldyn->func2b(moldyn,
+ &(itom[i]),
+ jtom,
+ bc_ij);
+ }
+#ifdef STATIC_LISTS
+ }
+#elif LOWMEM_LISTS
+ }
+#else
+ } 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 */
+#elif LOWMEM_LISTS
+ /* no copy needed for lowmem 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]!=-1) {
+
+ jtom=&(atom[neighbour_i[j][p]]);
+ p++;
+#elif LOWMEM_LISTS
+ p=neighbour_i[j];
+
+ while(p!=-1) {
+
+ jtom=&(itom[p]);
+ p=lc->subcell->list[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[k][q]!=-1) {
+
+ ktom=&(atom[neighbour_i[k][q]]);
+ q++;
+#elif LOWMEM_LISTS
+ q=neighbour_i[k];
+
+ while(q!=-1) {
+
+ ktom=&(itom[q]);
+ q=lc->subcell->list[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
+ }
+#elif LOWMEM_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[k][q]!=-1) {
+
+ ktom=&(atom[neighbour_i[k][q]]);
+ q++;
+#elif LOWMEM_LISTS
+ q=neighbour_i[k];
+
+ while(q!=-1) {
+
+ ktom=&(itom[q]);
+ q=lc->subcell->list[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
+ }
+#elif LOWMEM_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
+ }
+#elif LOWMEM_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 */
+#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;
+}
+
+/*
+ * 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;