]> hackdaworld.org Git - physik/posic.git/blob - moldyn.c
changed visualize script from angstrom to unit cell lengthes
[physik/posic.git] / moldyn.c
1 /*
2  * moldyn.c - molecular dynamics library main file
3  *
4  * author: Frank Zirkelbach <frank.zirkelbach@physik.uni-augsburg.de>
5  *
6  */
7
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <sys/time.h>
17 #include <time.h>
18 #include <math.h>
19
20 #include "moldyn.h"
21 #include "report/report.h"
22
23 /*
24  * global variables, pse and atom colors (only needed here)
25  */ 
26
27 static char *pse_name[]={
28         "*",
29         "H",
30         "He",
31         "Li",
32         "Be",
33         "B",
34         "C",
35         "N",
36         "O",
37         "F",
38         "Ne",
39         "Na",
40         "Mg",
41         "Al",
42         "Si",
43         "P",
44         "S",
45         "Cl",
46         "Ar",
47 };
48
49 static char *pse_col[]={
50         "*",
51         "White",
52         "He",
53         "Li",
54         "Be",
55         "B",
56         "Gray",
57         "N",
58         "Blue",
59         "F",
60         "Ne",
61         "Na",
62         "Mg",
63         "Al",
64         "Yellow",
65         "P",
66         "S",
67         "Cl",
68         "Ar",
69 };
70
71 /*
72  * the moldyn functions
73  */
74
75 int moldyn_init(t_moldyn *moldyn,int argc,char **argv) {
76
77         printf("[moldyn] init\n");
78
79         memset(moldyn,0,sizeof(t_moldyn));
80
81         moldyn->argc=argc;
82         moldyn->args=argv;
83
84         rand_init(&(moldyn->random),NULL,1);
85         moldyn->random.status|=RAND_STAT_VERBOSE;
86
87         return 0;
88 }
89
90 int moldyn_shutdown(t_moldyn *moldyn) {
91
92         printf("[moldyn] shutdown\n");
93
94         moldyn_log_shutdown(moldyn);
95         link_cell_shutdown(moldyn);
96         rand_close(&(moldyn->random));
97         free(moldyn->atom);
98
99         return 0;
100 }
101
102 int set_int_alg(t_moldyn *moldyn,u8 algo) {
103
104         printf("[moldyn] integration algorithm: ");
105
106         switch(algo) {
107                 case MOLDYN_INTEGRATE_VERLET:
108                         moldyn->integrate=velocity_verlet;
109                         printf("velocity verlet\n");
110                         break;
111                 default:
112                         printf("unknown integration algorithm: %02x\n",algo);
113                         printf("unknown\n");
114                         return -1;
115         }
116
117         return 0;
118 }
119
120 int set_cutoff(t_moldyn *moldyn,double cutoff) {
121
122         moldyn->cutoff=cutoff;
123
124         printf("[moldyn] cutoff [A]: %f\n",moldyn->cutoff);
125
126         return 0;
127 }
128
129 int set_bondlen(t_moldyn *moldyn,double b0,double b1,double bm) {
130
131         moldyn->bondlen[0]=b0*b0;
132         moldyn->bondlen[1]=b1*b1;
133         if(bm<0)
134                 moldyn->bondlen[2]=b0*b1;
135         else
136                 moldyn->bondlen[2]=bm*bm;
137
138         return 0;
139 }
140
141 int set_temperature(t_moldyn *moldyn,double t_ref) {
142
143         moldyn->t_ref=t_ref;
144
145         printf("[moldyn] temperature [K]: %f\n",moldyn->t_ref);
146
147         return 0;
148 }
149
150 int set_pressure(t_moldyn *moldyn,double p_ref) {
151
152         moldyn->p_ref=p_ref;
153
154         printf("[moldyn] pressure [bar]: %f\n",moldyn->p_ref/BAR);
155
156         return 0;
157 }
158
159 int set_pt_scale(t_moldyn *moldyn,u8 ptype,double ptc,u8 ttype,double ttc) {
160
161         moldyn->pt_scale=(ptype|ttype);
162         moldyn->t_tc=ttc;
163         moldyn->p_tc=ptc;
164
165         printf("[moldyn] p/t scaling:\n");
166
167         printf("  p: %s",ptype?"yes":"no ");
168         if(ptype)
169                 printf(" | type: %02x | factor: %f",ptype,ptc);
170         printf("\n");
171
172         printf("  t: %s",ttype?"yes":"no ");
173         if(ttype)
174                 printf(" | type: %02x | factor: %f",ttype,ttc);
175         printf("\n");
176
177         return 0;
178 }
179
180 int set_dim(t_moldyn *moldyn,double x,double y,double z,u8 visualize) {
181
182         moldyn->dim.x=x;
183         moldyn->dim.y=y;
184         moldyn->dim.z=z;
185
186         moldyn->volume=x*y*z;
187
188         if(visualize) {
189                 moldyn->vis.dim.x=x;
190                 moldyn->vis.dim.y=y;
191                 moldyn->vis.dim.z=z;
192         }
193
194         moldyn->dv=0.000001*moldyn->volume;
195
196         printf("[moldyn] dimensions in A and A^3 respectively:\n");
197         printf("  x: %f\n",moldyn->dim.x);
198         printf("  y: %f\n",moldyn->dim.y);
199         printf("  z: %f\n",moldyn->dim.z);
200         printf("  volume: %f\n",moldyn->volume);
201         printf("  visualize simulation box: %s\n",visualize?"yes":"no");
202         printf("  delta volume (pressure calc): %f\n",moldyn->dv);
203
204         return 0;
205 }
206
207 int set_nn_dist(t_moldyn *moldyn,double dist) {
208
209         moldyn->nnd=dist;
210
211         return 0;
212 }
213
214 int set_pbc(t_moldyn *moldyn,u8 x,u8 y,u8 z) {
215
216         printf("[moldyn] periodic boundary conditions:\n");
217
218         if(x)
219                 moldyn->status|=MOLDYN_STAT_PBX;
220
221         if(y)
222                 moldyn->status|=MOLDYN_STAT_PBY;
223
224         if(z)
225                 moldyn->status|=MOLDYN_STAT_PBZ;
226
227         printf("  x: %s\n",x?"yes":"no");
228         printf("  y: %s\n",y?"yes":"no");
229         printf("  z: %s\n",z?"yes":"no");
230
231         return 0;
232 }
233
234 int set_potential1b(t_moldyn *moldyn,pf_func1b func) {
235
236         moldyn->func1b=func;
237
238         return 0;
239 }
240
241 int set_potential2b(t_moldyn *moldyn,pf_func2b func) {
242
243         moldyn->func2b=func;
244
245         return 0;
246 }
247
248 int set_potential3b_j1(t_moldyn *moldyn,pf_func2b func) {
249
250         moldyn->func3b_j1=func;
251
252         return 0;
253 }
254
255 int set_potential3b_j2(t_moldyn *moldyn,pf_func2b func) {
256
257         moldyn->func3b_j2=func;
258
259         return 0;
260 }
261
262 int set_potential3b_j3(t_moldyn *moldyn,pf_func2b func) {
263
264         moldyn->func3b_j3=func;
265
266         return 0;
267 }
268
269 int set_potential3b_k1(t_moldyn *moldyn,pf_func3b func) {
270
271         moldyn->func3b_k1=func;
272
273         return 0;
274 }
275
276 int set_potential3b_k2(t_moldyn *moldyn,pf_func3b func) {
277
278         moldyn->func3b_k2=func;
279
280         return 0;
281 }
282
283 int set_potential_params(t_moldyn *moldyn,void *params) {
284
285         moldyn->pot_params=params;
286
287         return 0;
288 }
289
290 int set_avg_skip(t_moldyn *moldyn,int skip) {
291
292         printf("[moldyn] skip %d steps before starting average calc\n",skip);
293         moldyn->avg_skip=skip;
294
295         return 0;
296 }
297
298 int moldyn_set_log_dir(t_moldyn *moldyn,char *dir) {
299
300         strncpy(moldyn->vlsdir,dir,127);
301
302         return 0;
303 }
304
305 int moldyn_set_report(t_moldyn *moldyn,char *author,char *title) {
306
307         strncpy(moldyn->rauthor,author,63);
308         strncpy(moldyn->rtitle,title,63);
309
310         return 0;
311 }
312         
313 int moldyn_set_log(t_moldyn *moldyn,u8 type,int timer) {
314
315         char filename[128];
316         int ret;
317
318         printf("[moldyn] set log: ");
319
320         switch(type) {
321                 case LOG_TOTAL_ENERGY:
322                         moldyn->ewrite=timer;
323                         snprintf(filename,127,"%s/energy",moldyn->vlsdir);
324                         moldyn->efd=open(filename,
325                                          O_WRONLY|O_CREAT|O_EXCL,
326                                          S_IRUSR|S_IWUSR);
327                         if(moldyn->efd<0) {
328                                 perror("[moldyn] energy log fd open");
329                                 return moldyn->efd;
330                         }
331                         dprintf(moldyn->efd,"# total energy log file\n");
332                         printf("total energy (%d)\n",timer);
333                         break;
334                 case LOG_TOTAL_MOMENTUM:
335                         moldyn->mwrite=timer;
336                         snprintf(filename,127,"%s/momentum",moldyn->vlsdir);
337                         moldyn->mfd=open(filename,
338                                          O_WRONLY|O_CREAT|O_EXCL,
339                                          S_IRUSR|S_IWUSR);
340                         if(moldyn->mfd<0) {
341                                 perror("[moldyn] momentum log fd open");
342                                 return moldyn->mfd;
343                         }
344                         dprintf(moldyn->efd,"# total momentum log file\n");
345                         printf("total momentum (%d)\n",timer);
346                         break;
347                 case LOG_PRESSURE:
348                         moldyn->pwrite=timer;
349                         snprintf(filename,127,"%s/pressure",moldyn->vlsdir);
350                         moldyn->pfd=open(filename,
351                                          O_WRONLY|O_CREAT|O_EXCL,
352                                          S_IRUSR|S_IWUSR);
353                         if(moldyn->pfd<0) {
354                                 perror("[moldyn] pressure log file\n");
355                                 return moldyn->pfd;
356                         }
357                         dprintf(moldyn->pfd,"# pressure log file\n");
358                         printf("pressure (%d)\n",timer);
359                         break;
360                 case LOG_TEMPERATURE:
361                         moldyn->twrite=timer;
362                         snprintf(filename,127,"%s/temperature",moldyn->vlsdir);
363                         moldyn->tfd=open(filename,
364                                          O_WRONLY|O_CREAT|O_EXCL,
365                                          S_IRUSR|S_IWUSR);
366                         if(moldyn->tfd<0) {
367                                 perror("[moldyn] temperature log file\n");
368                                 return moldyn->tfd;
369                         }
370                         dprintf(moldyn->tfd,"# temperature log file\n");
371                         printf("temperature (%d)\n",timer);
372                         break;
373                 case SAVE_STEP:
374                         moldyn->swrite=timer;
375                         printf("save file (%d)\n",timer);
376                         break;
377                 case VISUAL_STEP:
378                         moldyn->vwrite=timer;
379                         ret=visual_init(moldyn,moldyn->vlsdir);
380                         if(ret<0) {
381                                 printf("[moldyn] visual init failure\n");
382                                 return ret;
383                         }
384                         printf("visual file (%d)\n",timer);
385                         break;
386                 case CREATE_REPORT:
387                         snprintf(filename,127,"%s/report.tex",moldyn->vlsdir);
388                         moldyn->rfd=open(filename,
389                                          O_WRONLY|O_CREAT|O_EXCL,
390                                          S_IRUSR|S_IWUSR);
391                         if(moldyn->rfd<0) {
392                                 perror("[moldyn] report fd open");      
393                                 return moldyn->rfd;
394                         }
395                         printf("report -> ");
396                         if(moldyn->efd) {
397                                 snprintf(filename,127,"%s/e_plot.scr",
398                                          moldyn->vlsdir);
399                                 moldyn->epfd=open(filename,
400                                                  O_WRONLY|O_CREAT|O_EXCL,
401                                                  S_IRUSR|S_IWUSR);
402                                 if(moldyn->epfd<0) {
403                                         perror("[moldyn] energy plot fd open");
404                                         return moldyn->epfd;
405                                 }
406                                 dprintf(moldyn->epfd,e_plot_script);
407                                 close(moldyn->epfd);
408                                 printf("energy ");
409                         }
410                         if(moldyn->pfd) {
411                                 snprintf(filename,127,"%s/pressure_plot.scr",
412                                          moldyn->vlsdir);
413                                 moldyn->ppfd=open(filename,
414                                                   O_WRONLY|O_CREAT|O_EXCL,
415                                                   S_IRUSR|S_IWUSR);
416                                 if(moldyn->ppfd<0) {
417                                         perror("[moldyn] p plot fd open");
418                                         return moldyn->ppfd;
419                                 }
420                                 dprintf(moldyn->ppfd,pressure_plot_script);
421                                 close(moldyn->ppfd);
422                                 printf("pressure ");
423                         }
424                         if(moldyn->tfd) {
425                                 snprintf(filename,127,"%s/temperature_plot.scr",
426                                          moldyn->vlsdir);
427                                 moldyn->tpfd=open(filename,
428                                                   O_WRONLY|O_CREAT|O_EXCL,
429                                                   S_IRUSR|S_IWUSR);
430                                 if(moldyn->tpfd<0) {
431                                         perror("[moldyn] t plot fd open");
432                                         return moldyn->tpfd;
433                                 }
434                                 dprintf(moldyn->tpfd,temperature_plot_script);
435                                 close(moldyn->tpfd);
436                                 printf("temperature ");
437                         }
438                         dprintf(moldyn->rfd,report_start,
439                                 moldyn->rauthor,moldyn->rtitle);
440                         printf("\n");
441                         break;
442                 default:
443                         printf("unknown log type: %02x\n",type);
444                         return -1;
445         }
446
447         return 0;
448 }
449
450 int moldyn_log_shutdown(t_moldyn *moldyn) {
451
452         char sc[256];
453
454         printf("[moldyn] log shutdown\n");
455         if(moldyn->efd) {
456                 close(moldyn->efd);
457                 if(moldyn->rfd) {
458                         dprintf(moldyn->rfd,report_energy);
459                         snprintf(sc,255,"cd %s && gnuplot e_plot.scr",
460                                  moldyn->vlsdir);
461                         system(sc);
462                 }
463         }
464         if(moldyn->mfd) close(moldyn->mfd);
465         if(moldyn->pfd) {
466                 close(moldyn->pfd);
467                 if(moldyn->rfd)
468                         dprintf(moldyn->rfd,report_pressure);
469                         snprintf(sc,255,"cd %s && gnuplot pressure_plot.scr",
470                                  moldyn->vlsdir);
471                         system(sc);
472         }
473         if(moldyn->tfd) {
474                 close(moldyn->tfd);
475                 if(moldyn->rfd)
476                         dprintf(moldyn->rfd,report_temperature);
477                         snprintf(sc,255,"cd %s && gnuplot temperature_plot.scr",
478                                  moldyn->vlsdir);
479                         system(sc);
480         }
481         if(moldyn->rfd) {
482                 dprintf(moldyn->rfd,report_end);
483                 close(moldyn->rfd);
484                 snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1",
485                          moldyn->vlsdir);
486                 system(sc);
487                 snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1",
488                          moldyn->vlsdir);
489                 system(sc);
490                 snprintf(sc,255,"cd %s && dvipdf report >/dev/null 2>&1",
491                          moldyn->vlsdir);
492                 system(sc);
493         }
494
495         return 0;
496 }
497
498 /*
499  * creating lattice functions
500  */
501
502 int create_lattice(t_moldyn *moldyn,u8 type,double lc,int element,double mass,
503                    u8 attr,u8 brand,int a,int b,int c,t_3dvec *origin) {
504
505         int new,count;
506         int ret;
507         t_3dvec orig;
508         void *ptr;
509         t_atom *atom;
510
511         new=a*b*c;
512         count=moldyn->count;
513
514         /* how many atoms do we expect */
515         if(type==CUBIC) new*=1;
516         if(type==FCC) new*=4;
517         if(type==DIAMOND) new*=8;
518
519         /* allocate space for atoms */
520         ptr=realloc(moldyn->atom,(count+new)*sizeof(t_atom));
521         if(!ptr) {
522                 perror("[moldyn] realloc (create lattice)");
523                 return -1;
524         }
525         moldyn->atom=ptr;
526         atom=&(moldyn->atom[count]);
527
528         /* no atoms on the boundaries (only reason: it looks better!) */
529         if(!origin) {
530                 orig.x=0.5*lc;
531                 orig.y=0.5*lc;
532                 orig.z=0.5*lc;
533         }
534         else {
535                 orig.x=origin->x;
536                 orig.y=origin->y;
537                 orig.z=origin->z;
538         }
539
540         switch(type) {
541                 case CUBIC:
542                         set_nn_dist(moldyn,lc);
543                         ret=cubic_init(a,b,c,lc,atom,&orig);
544                         break;
545                 case FCC:
546                         if(!origin)
547                                 v3_scale(&orig,&orig,0.5);
548                         set_nn_dist(moldyn,0.5*sqrt(2.0)*lc);
549                         ret=fcc_init(a,b,c,lc,atom,&orig);
550                         break;
551                 case DIAMOND:
552                         if(!origin)
553                                 v3_scale(&orig,&orig,0.25);
554                         set_nn_dist(moldyn,0.25*sqrt(3.0)*lc);
555                         ret=diamond_init(a,b,c,lc,atom,&orig);
556                         break;
557                 default:
558                         printf("unknown lattice type (%02x)\n",type);
559                         return -1;
560         }
561
562         /* debug */
563         if(ret!=new) {
564                 printf("[moldyn] creating lattice failed\n");
565                 printf("  amount of atoms\n");
566                 printf("  - expected: %d\n",new);
567                 printf("  - created: %d\n",ret);
568                 return -1;
569         }
570
571         moldyn->count+=new;
572         printf("[moldyn] created lattice with %d atoms\n",new);
573
574         for(ret=0;ret<new;ret++) {
575                 atom[ret].element=element;
576                 atom[ret].mass=mass;
577                 atom[ret].attr=attr;
578                 atom[ret].brand=brand;
579                 atom[ret].tag=count+ret;
580                 check_per_bound(moldyn,&(atom[ret].r));
581                 atom[ret].r_0=atom[ret].r;
582         }
583
584         /* update total system mass */
585         total_mass_calc(moldyn);
586
587         return ret;
588 }
589
590 int add_atom(t_moldyn *moldyn,int element,double mass,u8 brand,u8 attr,
591              t_3dvec *r,t_3dvec *v) {
592
593         t_atom *atom;
594         void *ptr;
595         int count;
596         
597         atom=moldyn->atom;
598         count=(moldyn->count)++;        // asshole style!
599
600         ptr=realloc(atom,(count+1)*sizeof(t_atom));
601         if(!ptr) {
602                 perror("[moldyn] realloc (add atom)");
603                 return -1;
604         }
605         moldyn->atom=ptr;
606
607         atom=moldyn->atom;
608
609         /* initialize new atom */
610         memset(&(atom[count]),0,sizeof(t_atom));
611         atom[count].r=*r;
612         atom[count].v=*v;
613         atom[count].element=element;
614         atom[count].mass=mass;
615         atom[count].brand=brand;
616         atom[count].tag=count;
617         atom[count].attr=attr;
618         check_per_bound(moldyn,&(atom[count].r));
619         atom[count].r_0=atom[count].r;
620
621         /* update total system mass */
622         total_mass_calc(moldyn);
623
624         return 0;
625 }
626
627 int del_atom(t_moldyn *moldyn,int tag) {
628
629         t_atom *new,*old;
630         int cnt;
631
632         old=moldyn->atom;
633
634         new=(t_atom *)malloc((moldyn->count-1)*sizeof(t_atom));
635         if(!new) {
636                 perror("[moldyn]malloc (del atom)");
637                 return -1;
638         }
639
640         for(cnt=0;cnt<tag;cnt++)
641                 new[cnt]=old[cnt];
642         
643         for(cnt=tag+1;cnt<moldyn->count;cnt++) {
644                 new[cnt-1]=old[cnt];
645                 new[cnt-1].tag=cnt-1;
646         }
647
648         moldyn->count-=1;
649         moldyn->atom=new;
650
651         free(old);
652
653         return 0;
654 }
655
656 /* cubic init */
657 int cubic_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
658
659         int count;
660         t_3dvec r;
661         int i,j,k;
662         t_3dvec o;
663
664         count=0;
665         if(origin)
666                 v3_copy(&o,origin);
667         else
668                 v3_zero(&o);
669
670         r.x=o.x;
671         for(i=0;i<a;i++) {
672                 r.y=o.y;
673                 for(j=0;j<b;j++) {
674                         r.z=o.z;
675                         for(k=0;k<c;k++) {
676                                 v3_copy(&(atom[count].r),&r);
677                                 count+=1;
678                                 r.z+=lc;
679                         }
680                         r.y+=lc;
681                 }
682                 r.x+=lc;
683         }
684
685         for(i=0;i<count;i++) {
686                 atom[i].r.x-=(a*lc)/2.0;
687                 atom[i].r.y-=(b*lc)/2.0;
688                 atom[i].r.z-=(c*lc)/2.0;
689         }
690
691         return count;
692 }
693
694 /* fcc lattice init */
695 int fcc_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
696
697         int count;
698         int i,j,k,l;
699         t_3dvec o,r,n;
700         t_3dvec basis[3];
701
702         count=0;
703         if(origin)
704                 v3_copy(&o,origin);
705         else
706                 v3_zero(&o);
707
708         /* construct the basis */
709         memset(basis,0,3*sizeof(t_3dvec));
710         basis[0].x=0.5*lc;
711         basis[0].y=0.5*lc;
712         basis[1].x=0.5*lc;
713         basis[1].z=0.5*lc;
714         basis[2].y=0.5*lc;
715         basis[2].z=0.5*lc;
716
717         /* fill up the room */
718         r.x=o.x;
719         for(i=0;i<a;i++) {
720                 r.y=o.y;
721                 for(j=0;j<b;j++) {
722                         r.z=o.z;
723                         for(k=0;k<c;k++) {
724                                 /* first atom */
725                                 v3_copy(&(atom[count].r),&r);
726                                 count+=1;
727                                 r.z+=lc;
728                                 /* the three face centered atoms */
729                                 for(l=0;l<3;l++) {
730                                         v3_add(&n,&r,&basis[l]);
731                                         v3_copy(&(atom[count].r),&n);
732                                         count+=1;
733                                 }
734                         }
735                         r.y+=lc;
736                 }
737                 r.x+=lc;
738         }
739                                 
740         /* coordinate transformation */
741         for(i=0;i<count;i++) {
742                 atom[i].r.x-=(a*lc)/2.0;
743                 atom[i].r.y-=(b*lc)/2.0;
744                 atom[i].r.z-=(c*lc)/2.0;
745         }
746
747         return count;
748 }
749
750 int diamond_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
751
752         int count;
753         t_3dvec o;
754
755         count=fcc_init(a,b,c,lc,atom,origin);
756
757         o.x=0.25*lc;
758         o.y=0.25*lc;
759         o.z=0.25*lc;
760
761         if(origin) v3_add(&o,&o,origin);
762
763         count+=fcc_init(a,b,c,lc,&atom[count],&o);
764
765         return count;
766 }
767
768 int destroy_atoms(t_moldyn *moldyn) {
769
770         if(moldyn->atom) free(moldyn->atom);
771
772         return 0;
773 }
774
775 int thermal_init(t_moldyn *moldyn,u8 equi_init) {
776
777         /*
778          * - gaussian distribution of velocities
779          * - zero total momentum
780          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
781          */
782
783         int i;
784         double v,sigma;
785         t_3dvec p_total,delta;
786         t_atom *atom;
787         t_random *random;
788
789         atom=moldyn->atom;
790         random=&(moldyn->random);
791
792         printf("[moldyn] thermal init (equi init: %s)\n",equi_init?"yes":"no");
793
794         /* gaussian distribution of velocities */
795         v3_zero(&p_total);
796         for(i=0;i<moldyn->count;i++) {
797                 sigma=sqrt(2.0*K_BOLTZMANN*moldyn->t_ref/atom[i].mass);
798                 /* x direction */
799                 v=sigma*rand_get_gauss(random);
800                 atom[i].v.x=v;
801                 p_total.x+=atom[i].mass*v;
802                 /* y direction */
803                 v=sigma*rand_get_gauss(random);
804                 atom[i].v.y=v;
805                 p_total.y+=atom[i].mass*v;
806                 /* z direction */
807                 v=sigma*rand_get_gauss(random);
808                 atom[i].v.z=v;
809                 p_total.z+=atom[i].mass*v;
810         }
811
812         /* zero total momentum */
813         v3_scale(&p_total,&p_total,1.0/moldyn->count);
814         for(i=0;i<moldyn->count;i++) {
815                 v3_scale(&delta,&p_total,1.0/atom[i].mass);
816                 v3_sub(&(atom[i].v),&(atom[i].v),&delta);
817         }
818
819         /* velocity scaling */
820         scale_velocity(moldyn,equi_init);
821
822         return 0;
823 }
824
825 double total_mass_calc(t_moldyn *moldyn) {
826
827         int i;
828
829         moldyn->mass=0.0;
830
831         for(i=0;i<moldyn->count;i++)
832                 moldyn->mass+=moldyn->atom[i].mass;
833
834         return moldyn->mass;
835 }
836
837 double temperature_calc(t_moldyn *moldyn) {
838
839         /* assume up to date kinetic energy, which is 3/2 N k_B T */
840
841         moldyn->t=(2.0*moldyn->ekin)/(3.0*K_BOLTZMANN*moldyn->count);
842
843         return moldyn->t;
844 }
845
846 double get_temperature(t_moldyn *moldyn) {
847
848         return moldyn->t;
849 }
850
851 int scale_velocity(t_moldyn *moldyn,u8 equi_init) {
852
853         int i;
854         double e,scale;
855         t_atom *atom;
856         int count;
857
858         atom=moldyn->atom;
859
860         /*
861          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
862          */
863
864         /* get kinetic energy / temperature & count involved atoms */
865         e=0.0;
866         count=0;
867         for(i=0;i<moldyn->count;i++) {
868                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB)) {
869                         e+=atom[i].mass*v3_absolute_square(&(atom[i].v));
870                         count+=1;
871                 }
872         }
873         e*=0.5;
874         if(count!=0) moldyn->t=e/(1.5*count*K_BOLTZMANN);
875         else return 0;  /* no atoms involved in scaling! */
876         
877         /* (temporary) hack for e,t = 0 */
878         if(e==0.0) {
879         moldyn->t=0.0;
880                 if(moldyn->t_ref!=0.0) {
881                         thermal_init(moldyn,equi_init);
882                         return 0;
883                 }
884                 else
885                         return 0; /* no scaling needed */
886         }
887
888
889         /* get scaling factor */
890         scale=moldyn->t_ref/moldyn->t;
891         if(equi_init&TRUE)
892                 scale*=2.0;
893         else
894                 if(moldyn->pt_scale&T_SCALE_BERENDSEN)
895                         scale=1.0+(scale-1.0)/moldyn->t_tc;
896         scale=sqrt(scale);
897
898         /* velocity scaling */
899         for(i=0;i<moldyn->count;i++) {
900                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB))
901                         v3_scale(&(atom[i].v),&(atom[i].v),scale);
902         }
903
904         return 0;
905 }
906
907 double ideal_gas_law_pressure(t_moldyn *moldyn) {
908
909         double p;
910
911         p=moldyn->count*moldyn->t*K_BOLTZMANN/moldyn->volume;
912
913         return p;
914 }
915
916 double virial_sum(t_moldyn *moldyn) {
917
918         int i;
919         double v;
920         t_virial *virial;
921
922         /* virial (sum over atom virials) */
923         v=0.0;
924         for(i=0;i<moldyn->count;i++) {
925                 virial=&(moldyn->atom[i].virial);
926                 v+=(virial->xx+virial->yy+virial->zz);
927         }
928         moldyn->virial=v;
929
930         /* global virial (absolute coordinates) */
931         virial=&(moldyn->gvir);
932         moldyn->gv=virial->xx+virial->yy+virial->zz;
933
934         return moldyn->virial;
935 }
936
937 double pressure_calc(t_moldyn *moldyn) {
938
939         /*
940          * PV = NkT + <W>
941          * with W = 1/3 sum_i f_i r_i (- skipped!)
942          * virial = sum_i f_i r_i
943          * 
944          * => P = (2 Ekin + virial) / (3V)
945          */
946
947         /* assume up to date virial & up to date kinetic energy */
948
949         /* pressure (atom virials) */
950         moldyn->p=2.0*moldyn->ekin+moldyn->virial;
951         moldyn->p/=(3.0*moldyn->volume);
952
953         /* pressure (absolute coordinates) */
954         moldyn->gp=2.0*moldyn->ekin+moldyn->gv;
955         moldyn->gp/=(3.0*moldyn->volume);
956
957         return moldyn->p;
958 }
959
960 int average_reset(t_moldyn *moldyn) {
961
962         printf("[moldyn] average reset\n");
963
964         /* update skip value */
965         moldyn->avg_skip=moldyn->total_steps;
966
967         /* kinetic energy */
968         moldyn->k_sum=0.0;
969         moldyn->k2_sum=0.0;
970         
971         /* potential energy */
972         moldyn->v_sum=0.0;
973         moldyn->v2_sum=0.0;
974
975         /* temperature */
976         moldyn->t_sum=0.0;
977
978         /* virial */
979         moldyn->virial_sum=0.0;
980         moldyn->gv_sum=0.0;
981
982         /* pressure */
983         moldyn->p_sum=0.0;
984         moldyn->gp_sum=0.0;
985
986         return 0;
987 }
988
989 int average_and_fluctuation_calc(t_moldyn *moldyn) {
990
991         int denom;
992
993         if(moldyn->total_steps<moldyn->avg_skip)
994                 return 0;
995
996         denom=moldyn->total_steps+1-moldyn->avg_skip;
997
998         /* assume up to date energies, temperature, pressure etc */
999
1000         /* kinetic energy */
1001         moldyn->k_sum+=moldyn->ekin;
1002         moldyn->k2_sum+=(moldyn->ekin*moldyn->ekin);
1003         moldyn->k_avg=moldyn->k_sum/denom;
1004         moldyn->k2_avg=moldyn->k2_sum/denom;
1005         moldyn->dk2_avg=moldyn->k2_avg-(moldyn->k_avg*moldyn->k_avg);
1006
1007         /* potential energy */
1008         moldyn->v_sum+=moldyn->energy;
1009         moldyn->v2_sum+=(moldyn->energy*moldyn->energy);
1010         moldyn->v_avg=moldyn->v_sum/denom;
1011         moldyn->v2_avg=moldyn->v2_sum/denom;
1012         moldyn->dv2_avg=moldyn->v2_avg-(moldyn->v_avg*moldyn->v_avg);
1013
1014         /* temperature */
1015         moldyn->t_sum+=moldyn->t;
1016         moldyn->t_avg=moldyn->t_sum/denom;
1017
1018         /* virial */
1019         moldyn->virial_sum+=moldyn->virial;
1020         moldyn->virial_avg=moldyn->virial_sum/denom;
1021         moldyn->gv_sum+=moldyn->gv;
1022         moldyn->gv_avg=moldyn->gv_sum/denom;
1023
1024         /* pressure */
1025         moldyn->p_sum+=moldyn->p;
1026         moldyn->p_avg=moldyn->p_sum/denom;
1027         moldyn->gp_sum+=moldyn->gp;
1028         moldyn->gp_avg=moldyn->gp_sum/denom;
1029
1030         return 0;
1031 }
1032
1033 int get_heat_capacity(t_moldyn *moldyn) {
1034
1035         double temp2,ighc;
1036
1037         /* averages needed for heat capacity calc */
1038         if(moldyn->total_steps<moldyn->avg_skip)
1039                 return 0;
1040
1041         /* (temperature average)^2 */
1042         temp2=moldyn->t_avg*moldyn->t_avg;
1043         printf("[moldyn] specific heat capacity for T=%f K [J/(kg K)]\n",
1044                moldyn->t_avg);
1045
1046         /* ideal gas contribution */
1047         ighc=3.0*moldyn->count*K_BOLTZMANN/2.0;
1048         printf("  ideal gas contribution: %f\n",
1049                ighc/moldyn->mass*KILOGRAM/JOULE);
1050
1051         /* specific heat for nvt ensemble */
1052         moldyn->c_v_nvt=moldyn->dv2_avg/(K_BOLTZMANN*temp2)+ighc;
1053         moldyn->c_v_nvt/=moldyn->mass;
1054
1055         /* specific heat for nve ensemble */
1056         moldyn->c_v_nve=ighc/(1.0-(moldyn->dv2_avg/(ighc*K_BOLTZMANN*temp2)));
1057         moldyn->c_v_nve/=moldyn->mass;
1058
1059         printf("  NVE: %f\n",moldyn->c_v_nve*KILOGRAM/JOULE);
1060         printf("  NVT: %f\n",moldyn->c_v_nvt*KILOGRAM/JOULE);
1061 printf("  --> <dV2> 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)));
1062
1063         return 0;
1064 }
1065
1066 double thermodynamic_pressure_calc(t_moldyn *moldyn) {
1067
1068         t_3dvec dim;
1069         //t_3dvec *tp;
1070         double u_up,u_down,dv;
1071         double scale,p;
1072         t_atom *store;
1073
1074         /*
1075          * dU = - p dV
1076          *
1077          * => p = - dU/dV
1078          *
1079          */
1080
1081         scale=0.00001;
1082         dv=8*scale*scale*scale*moldyn->volume;
1083
1084         store=malloc(moldyn->count*sizeof(t_atom));
1085         if(store==NULL) {
1086                 printf("[moldyn] allocating store mem failed\n");
1087                 return -1;
1088         }
1089
1090         /* save unscaled potential energy + atom/dim configuration */
1091         memcpy(store,moldyn->atom,moldyn->count*sizeof(t_atom));
1092         dim=moldyn->dim;
1093
1094         /* scale up dimension and atom positions */
1095         scale_dim(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
1096         scale_atoms(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
1097         link_cell_shutdown(moldyn);
1098         link_cell_init(moldyn,QUIET);
1099         potential_force_calc(moldyn);
1100         u_up=moldyn->energy;
1101
1102         /* restore atomic configuration + dim */
1103         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1104         moldyn->dim=dim;
1105
1106         /* scale down dimension and atom positions */
1107         scale_dim(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
1108         scale_atoms(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
1109         link_cell_shutdown(moldyn);
1110         link_cell_init(moldyn,QUIET);
1111         potential_force_calc(moldyn);
1112         u_down=moldyn->energy;
1113         
1114         /* calculate pressure */
1115         p=-(u_up-u_down)/dv;
1116 printf("-------> %.10f %.10f %f\n",u_up/EV/moldyn->count,u_down/EV/moldyn->count,p/BAR);
1117
1118         /* restore atomic configuration + dim */
1119         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1120         moldyn->dim=dim;
1121
1122         /* restore energy */
1123         potential_force_calc(moldyn);
1124
1125         link_cell_shutdown(moldyn);
1126         link_cell_init(moldyn,QUIET);
1127
1128         return p;
1129 }
1130
1131 double get_pressure(t_moldyn *moldyn) {
1132
1133         return moldyn->p;
1134
1135 }
1136
1137 int scale_dim(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1138
1139         t_3dvec *dim;
1140
1141         dim=&(moldyn->dim);
1142
1143         if(dir==SCALE_UP)
1144                 scale=1.0+scale;
1145
1146         if(dir==SCALE_DOWN)
1147                 scale=1.0-scale;
1148
1149         if(x) dim->x*=scale;
1150         if(y) dim->y*=scale;
1151         if(z) dim->z*=scale;
1152
1153         return 0;
1154 }
1155
1156 int scale_atoms(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1157
1158         int i;
1159         t_3dvec *r;
1160
1161         if(dir==SCALE_UP)
1162                 scale=1.0+scale;
1163
1164         if(dir==SCALE_DOWN)
1165                 scale=1.0-scale;
1166
1167         for(i=0;i<moldyn->count;i++) {
1168                 r=&(moldyn->atom[i].r);
1169                 if(x) r->x*=scale;
1170                 if(y) r->y*=scale;
1171                 if(z) r->z*=scale;
1172         }
1173
1174         return 0;
1175 }
1176
1177 int scale_volume(t_moldyn *moldyn) {
1178
1179         t_3dvec *dim,*vdim;
1180         double scale;
1181         t_linkcell *lc;
1182
1183         vdim=&(moldyn->vis.dim);
1184         dim=&(moldyn->dim);
1185         lc=&(moldyn->lc);
1186
1187         /* scaling factor */
1188         if(moldyn->pt_scale&P_SCALE_BERENDSEN) {
1189                 scale=1.0-(moldyn->p_ref-moldyn->p)/moldyn->p_tc;
1190                 scale=pow(scale,ONE_THIRD);
1191         }
1192         else {
1193                 scale=pow(moldyn->p/moldyn->p_ref,ONE_THIRD);
1194         }
1195 moldyn->debug=scale;
1196
1197         /* scale the atoms and dimensions */
1198         scale_atoms(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1199         scale_dim(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1200
1201         /* visualize dimensions */
1202         if(vdim->x!=0) {
1203                 vdim->x=dim->x;
1204                 vdim->y=dim->y;
1205                 vdim->z=dim->z;
1206         }
1207
1208         /* recalculate scaled volume */
1209         moldyn->volume=dim->x*dim->y*dim->z;
1210
1211         /* adjust/reinit linkcell */
1212         if(((int)(dim->x/moldyn->cutoff)!=lc->nx)||
1213            ((int)(dim->y/moldyn->cutoff)!=lc->ny)||
1214            ((int)(dim->z/moldyn->cutoff)!=lc->nx)) {
1215                 link_cell_shutdown(moldyn);
1216                 link_cell_init(moldyn,QUIET);
1217         } else {
1218                 lc->x*=scale;
1219                 lc->y*=scale;
1220                 lc->z*=scale;
1221         }
1222
1223         return 0;
1224
1225 }
1226
1227 double e_kin_calc(t_moldyn *moldyn) {
1228
1229         int i;
1230         t_atom *atom;
1231
1232         atom=moldyn->atom;
1233         moldyn->ekin=0.0;
1234
1235         for(i=0;i<moldyn->count;i++) {
1236                 atom[i].ekin=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v));
1237                 moldyn->ekin+=atom[i].ekin;
1238         }
1239
1240         return moldyn->ekin;
1241 }
1242
1243 double get_total_energy(t_moldyn *moldyn) {
1244
1245         return(moldyn->ekin+moldyn->energy);
1246 }
1247
1248 t_3dvec get_total_p(t_moldyn *moldyn) {
1249
1250         t_3dvec p,p_total;
1251         int i;
1252         t_atom *atom;
1253
1254         atom=moldyn->atom;
1255
1256         v3_zero(&p_total);
1257         for(i=0;i<moldyn->count;i++) {
1258                 v3_scale(&p,&(atom[i].v),atom[i].mass);
1259                 v3_add(&p_total,&p_total,&p);
1260         }
1261
1262         return p_total;
1263 }
1264
1265 double estimate_time_step(t_moldyn *moldyn,double nn_dist) {
1266
1267         double tau;
1268
1269         /* nn_dist is the nearest neighbour distance */
1270
1271         tau=(0.05*nn_dist*moldyn->atom[0].mass)/sqrt(3.0*K_BOLTZMANN*moldyn->t);
1272
1273         return tau;     
1274 }
1275
1276 /*
1277  * numerical tricks
1278  */
1279
1280 /* linked list / cell method */
1281
1282 int link_cell_init(t_moldyn *moldyn,u8 vol) {
1283
1284         t_linkcell *lc;
1285         int i;
1286
1287         lc=&(moldyn->lc);
1288
1289         /* partitioning the md cell */
1290         lc->nx=moldyn->dim.x/moldyn->cutoff;
1291         lc->x=moldyn->dim.x/lc->nx;
1292         lc->ny=moldyn->dim.y/moldyn->cutoff;
1293         lc->y=moldyn->dim.y/lc->ny;
1294         lc->nz=moldyn->dim.z/moldyn->cutoff;
1295         lc->z=moldyn->dim.z/lc->nz;
1296         lc->cells=lc->nx*lc->ny*lc->nz;
1297
1298 #ifdef STATIC_LISTS
1299         lc->subcell=malloc(lc->cells*sizeof(int*));
1300 #else
1301         lc->subcell=malloc(lc->cells*sizeof(t_list));
1302 #endif
1303
1304         if(lc->subcell==NULL) {
1305                 perror("[moldyn] cell init (malloc)");
1306                 return -1;
1307         }
1308
1309         if(lc->cells<27)
1310                 printf("[moldyn] FATAL: less then 27 subcells!\n");
1311
1312         if(vol) {
1313 #ifdef STATIC_LISTS
1314                 printf("[moldyn] initializing 'static' linked cells (%d)\n",
1315                        lc->cells);
1316 #else
1317                 printf("[moldyn] initializing 'dynamic' linked cells (%d)\n",
1318                        lc->cells);
1319 #endif
1320                 printf("  x: %d x %f A\n",lc->nx,lc->x);
1321                 printf("  y: %d x %f A\n",lc->ny,lc->y);
1322                 printf("  z: %d x %f A\n",lc->nz,lc->z);
1323         }
1324
1325 #ifdef STATIC_LISTS
1326         /* list init */
1327         for(i=0;i<lc->cells;i++) {
1328                 lc->subcell[i]=malloc((MAX_ATOMS_PER_LIST+1)*sizeof(int));
1329                 if(lc->subcell[i]==NULL) {
1330                         perror("[moldyn] list init (malloc)");
1331                         return -1;
1332                 }
1333                 /*
1334                 if(i==0)
1335                         printf(" ---> %d malloc %p (%p)\n",
1336                                i,lc->subcell[0],lc->subcell);
1337                 */
1338         }
1339 #else
1340         for(i=0;i<lc->cells;i++)
1341                 list_init_f(&(lc->subcell[i]));
1342 #endif
1343
1344         /* update the list */
1345         link_cell_update(moldyn);
1346
1347         return 0;
1348 }
1349
1350 int link_cell_update(t_moldyn *moldyn) {
1351
1352         int count,i,j,k;
1353         int nx,ny;
1354         t_atom *atom;
1355         t_linkcell *lc;
1356 #ifdef STATIC_LISTS
1357         int p;
1358 #endif
1359
1360         atom=moldyn->atom;
1361         lc=&(moldyn->lc);
1362
1363         nx=lc->nx;
1364         ny=lc->ny;
1365
1366         for(i=0;i<lc->cells;i++)
1367 #ifdef STATIC_LISTS
1368                 memset(lc->subcell[i],0,(MAX_ATOMS_PER_LIST+1)*sizeof(int));
1369 #else
1370                 list_destroy_f(&(lc->subcell[i]));
1371 #endif
1372
1373         for(count=0;count<moldyn->count;count++) {
1374                 i=((atom[count].r.x+(moldyn->dim.x/2))/lc->x);
1375                 j=((atom[count].r.y+(moldyn->dim.y/2))/lc->y);
1376                 k=((atom[count].r.z+(moldyn->dim.z/2))/lc->z);
1377         
1378 #ifdef STATIC_LISTS
1379                 p=0;
1380                 while(lc->subcell[i+j*nx+k*nx*ny][p]!=0)
1381                         p++;
1382
1383                 if(p>=MAX_ATOMS_PER_LIST) {
1384                         printf("[moldyn] FATAL: amount of atoms too high!\n");
1385                         return -1;
1386                 }
1387
1388                 lc->subcell[i+j*nx+k*nx*ny][p]=count;
1389 #else
1390                 list_add_immediate_f(&(lc->subcell[i+j*nx+k*nx*ny]),
1391                                      &(atom[count]));
1392                 /*
1393                 if(j==0&&k==0)
1394                         printf(" ---> %d %d malloc %p (%p)\n",
1395                                i,count,lc->subcell[i].current,lc->subcell);
1396                 */
1397 #endif
1398         }
1399
1400         return 0;
1401 }
1402
1403 int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,
1404 #ifdef STATIC_LISTS
1405                               int **cell
1406 #else
1407                               t_list *cell
1408 #endif
1409                              ) {
1410
1411         t_linkcell *lc;
1412         int a;
1413         int count1,count2;
1414         int ci,cj,ck;
1415         int nx,ny,nz;
1416         int x,y,z;
1417         u8 bx,by,bz;
1418
1419         lc=&(moldyn->lc);
1420         nx=lc->nx;
1421         ny=lc->ny;
1422         nz=lc->nz;
1423         count1=1;
1424         count2=27;
1425         a=nx*ny;
1426
1427         if(i>=nx||j>=ny||k>=nz)
1428                 printf("[moldyn] WARNING: lcni %d/%d %d/%d %d/%d\n",
1429                        i,nx,j,ny,k,nz);
1430
1431         cell[0]=lc->subcell[i+j*nx+k*a];
1432         for(ci=-1;ci<=1;ci++) {
1433                 bx=0;
1434                 x=i+ci;
1435                 if((x<0)||(x>=nx)) {
1436                         x=(x+nx)%nx;
1437                         bx=1;
1438                 }
1439                 for(cj=-1;cj<=1;cj++) {
1440                         by=0;
1441                         y=j+cj;
1442                         if((y<0)||(y>=ny)) {
1443                                 y=(y+ny)%ny;
1444                                 by=1;
1445                         }
1446                         for(ck=-1;ck<=1;ck++) {
1447                                 bz=0;
1448                                 z=k+ck;
1449                                 if((z<0)||(z>=nz)) {
1450                                         z=(z+nz)%nz;
1451                                         bz=1;
1452                                 }
1453                                 if(!(ci|cj|ck)) continue;
1454                                 if(bx|by|bz) {
1455                                         cell[--count2]=lc->subcell[x+y*nx+z*a];
1456                                 }
1457                                 else {
1458                                         cell[count1++]=lc->subcell[x+y*nx+z*a];
1459                                 }
1460                         }
1461                 }
1462         }
1463
1464         lc->dnlc=count1;
1465
1466         return count1;
1467 }
1468
1469 int link_cell_shutdown(t_moldyn *moldyn) {
1470
1471         int i;
1472         t_linkcell *lc;
1473
1474         lc=&(moldyn->lc);
1475
1476         for(i=0;i<lc->cells;i++) {
1477 #ifdef STATIC_LISTS
1478                 free(lc->subcell[i]);
1479 #else
1480                 //printf(" ---> %d free %p\n",i,lc->subcell[i].start);
1481                 list_destroy_f(&(lc->subcell[i]));
1482 #endif
1483         }
1484
1485         free(lc->subcell);
1486
1487         return 0;
1488 }
1489
1490 int moldyn_add_schedule(t_moldyn *moldyn,int runs,double tau) {
1491
1492         int count;
1493         void *ptr;
1494         t_moldyn_schedule *schedule;
1495
1496         schedule=&(moldyn->schedule);
1497         count=++(schedule->total_sched);
1498
1499         ptr=realloc(schedule->runs,count*sizeof(int));
1500         if(!ptr) {
1501                 perror("[moldyn] realloc (runs)");
1502                 return -1;
1503         }
1504         schedule->runs=ptr;
1505         schedule->runs[count-1]=runs;
1506
1507         ptr=realloc(schedule->tau,count*sizeof(double));
1508         if(!ptr) {
1509                 perror("[moldyn] realloc (tau)");
1510                 return -1;
1511         }
1512         schedule->tau=ptr;
1513         schedule->tau[count-1]=tau;
1514
1515         printf("[moldyn] schedule added:\n");
1516         printf("  number: %d | runs: %d | tau: %f\n",count-1,runs,tau);
1517                                        
1518
1519         return 0;
1520 }
1521
1522 int moldyn_set_schedule_hook(t_moldyn *moldyn,set_hook hook,void *hook_params) {
1523
1524         moldyn->schedule.hook=hook;
1525         moldyn->schedule.hook_params=hook_params;
1526         
1527         return 0;
1528 }
1529
1530 /*
1531  *
1532  * 'integration of newtons equation' - algorithms
1533  *
1534  */
1535
1536 /* start the integration */
1537
1538 int moldyn_integrate(t_moldyn *moldyn) {
1539
1540         int i;
1541         unsigned int e,m,s,v,p,t;
1542         t_3dvec momentum;
1543         t_moldyn_schedule *sched;
1544         t_atom *atom;
1545         int fd;
1546         char dir[128];
1547         double ds;
1548         double energy_scale;
1549         struct timeval t1,t2;
1550         //double tp;
1551
1552         sched=&(moldyn->schedule);
1553         atom=moldyn->atom;
1554
1555         /* initialize linked cell method */
1556         link_cell_init(moldyn,VERBOSE);
1557
1558         /* logging & visualization */
1559         e=moldyn->ewrite;
1560         m=moldyn->mwrite;
1561         s=moldyn->swrite;
1562         v=moldyn->vwrite;
1563         p=moldyn->pwrite;
1564         t=moldyn->twrite;
1565
1566         /* sqaure of some variables */
1567         moldyn->tau_square=moldyn->tau*moldyn->tau;
1568         moldyn->cutoff_square=moldyn->cutoff*moldyn->cutoff;
1569
1570         /* get current time */
1571         gettimeofday(&t1,NULL);
1572
1573         /* calculate initial forces */
1574         potential_force_calc(moldyn);
1575 #ifdef DEBUG
1576 //return 0;
1577 #endif
1578
1579         /* some stupid checks before we actually start calculating bullshit */
1580         if(moldyn->cutoff>0.5*moldyn->dim.x)
1581                 printf("[moldyn] WARNING: cutoff > 0.5 x dim.x\n");
1582         if(moldyn->cutoff>0.5*moldyn->dim.y)
1583                 printf("[moldyn] WARNING: cutoff > 0.5 x dim.y\n");
1584         if(moldyn->cutoff>0.5*moldyn->dim.z)
1585                 printf("[moldyn] WARNING: cutoff > 0.5 x dim.z\n");
1586         ds=0.5*atom[0].f.x*moldyn->tau_square/atom[0].mass;
1587         if(ds>0.05*moldyn->nnd)
1588                 printf("[moldyn] WARNING: forces too high / tau too small!\n");
1589
1590         /* zero absolute time */
1591         moldyn->time=0.0;
1592         moldyn->total_steps=0;
1593
1594         /* debugging, ignore */
1595         moldyn->debug=0;
1596
1597         /* tell the world */
1598         printf("[moldyn] integration start, go get a coffee ...\n");
1599
1600         /* executing the schedule */
1601         sched->count=0;
1602         while(sched->count<sched->total_sched) {
1603
1604                 /* setting amount of runs and finite time step size */
1605                 moldyn->tau=sched->tau[sched->count];
1606                 moldyn->tau_square=moldyn->tau*moldyn->tau;
1607                 moldyn->time_steps=sched->runs[sched->count];
1608
1609                 /* energy scaling factor (might change!) */
1610                 energy_scale=moldyn->count*EV;
1611
1612         /* integration according to schedule */
1613
1614         for(i=0;i<moldyn->time_steps;i++) {
1615
1616                 /* integration step */
1617                 moldyn->integrate(moldyn);
1618
1619                 /* calculate kinetic energy, temperature and pressure */
1620                 e_kin_calc(moldyn);
1621                 temperature_calc(moldyn);
1622                 virial_sum(moldyn);
1623                 pressure_calc(moldyn);
1624                 average_and_fluctuation_calc(moldyn);
1625
1626                 /* p/t scaling */
1627                 if(moldyn->pt_scale&(T_SCALE_BERENDSEN|T_SCALE_DIRECT))
1628                         scale_velocity(moldyn,FALSE);
1629                 if(moldyn->pt_scale&(P_SCALE_BERENDSEN|P_SCALE_DIRECT))
1630                         scale_volume(moldyn);
1631
1632                 /* check for log & visualization */
1633                 if(e) {
1634                         if(!(moldyn->total_steps%e))
1635                                 dprintf(moldyn->efd,
1636                                         "%f %f %f %f\n",
1637                                         moldyn->time,moldyn->ekin/energy_scale,
1638                                         moldyn->energy/energy_scale,
1639                                         get_total_energy(moldyn)/energy_scale);
1640                 }
1641                 if(m) {
1642                         if(!(moldyn->total_steps%m)) {
1643                                 momentum=get_total_p(moldyn);
1644                                 dprintf(moldyn->mfd,
1645                                         "%f %f %f %f %f\n",moldyn->time,
1646                                         momentum.x,momentum.y,momentum.z,
1647                                         v3_norm(&momentum));
1648                         }
1649                 }
1650                 if(p) {
1651                         if(!(moldyn->total_steps%p)) {
1652                                 dprintf(moldyn->pfd,
1653                                         "%f %f %f %f %f\n",moldyn->time,
1654                                          moldyn->p/BAR,moldyn->p_avg/BAR,
1655                                          moldyn->gp/BAR,moldyn->gp_avg/BAR);
1656                         }
1657                 }
1658                 if(t) {
1659                         if(!(moldyn->total_steps%t)) {
1660                                 dprintf(moldyn->tfd,
1661                                         "%f %f %f\n",
1662                                         moldyn->time,moldyn->t,moldyn->t_avg);
1663                         }
1664                 }
1665                 if(s) {
1666                         if(!(moldyn->total_steps%s)) {
1667                                 snprintf(dir,128,"%s/s-%07.f.save",
1668                                          moldyn->vlsdir,moldyn->time);
1669                                 fd=open(dir,O_WRONLY|O_TRUNC|O_CREAT,
1670                                         S_IRUSR|S_IWUSR);
1671                                 if(fd<0) perror("[moldyn] save fd open");
1672                                 else {
1673                                         write(fd,moldyn,sizeof(t_moldyn));
1674                                         write(fd,moldyn->atom,
1675                                               moldyn->count*sizeof(t_atom));
1676                                 }
1677                                 close(fd);
1678                         }       
1679                 }
1680                 if(v) {
1681                         if(!(moldyn->total_steps%v)) {
1682                                 visual_atoms(moldyn);
1683                         }
1684                 }
1685
1686                 /* display progress */
1687                 //if(!(moldyn->total_steps%10)) {
1688                         /* get current time */
1689                         gettimeofday(&t2,NULL);
1690
1691 printf("\rsched:%d, steps:%d/%d, T:%3.1f/%3.1f P:%4.1f/%4.1f V:%6.1f (%d)",
1692        sched->count,i,moldyn->total_steps,
1693        moldyn->t,moldyn->t_avg,
1694        moldyn->p_avg/BAR,moldyn->gp_avg/BAR,
1695        moldyn->volume,
1696        (int)(t2.tv_sec-t1.tv_sec));
1697
1698                         fflush(stdout);
1699
1700                         /* copy over time */
1701                         t1=t2;
1702                 //}
1703
1704                 /* increase absolute time */
1705                 moldyn->time+=moldyn->tau;
1706                 moldyn->total_steps+=1;
1707
1708         }
1709
1710                 /* check for hooks */
1711                 if(sched->hook) {
1712                         printf("\n ## schedule hook %d start ##\n",
1713                                sched->count);
1714                         sched->hook(moldyn,sched->hook_params);
1715                         printf(" ## schedule hook end ##\n");
1716                 }
1717
1718                 /* increase the schedule counter */
1719                 sched->count+=1;
1720
1721         }
1722
1723         return 0;
1724 }
1725
1726 /* velocity verlet */
1727
1728 int velocity_verlet(t_moldyn *moldyn) {
1729
1730         int i,count;
1731         double tau,tau_square,h;
1732         t_3dvec delta;
1733         t_atom *atom;
1734
1735         atom=moldyn->atom;
1736         count=moldyn->count;
1737         tau=moldyn->tau;
1738         tau_square=moldyn->tau_square;
1739
1740         for(i=0;i<count;i++) {
1741                 /* check whether fixed atom */
1742                 if(atom[i].attr&ATOM_ATTR_FP)
1743                         continue;
1744                 /* new positions */
1745                 h=0.5/atom[i].mass;
1746                 v3_scale(&delta,&(atom[i].v),tau);
1747                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
1748                 v3_scale(&delta,&(atom[i].f),h*tau_square);
1749                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
1750                 check_per_bound(moldyn,&(atom[i].r));
1751
1752                 /* velocities [actually v(t+tau/2)] */
1753                 v3_scale(&delta,&(atom[i].f),h*tau);
1754                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
1755         }
1756
1757         /* criticial check */
1758         moldyn_bc_check(moldyn);
1759
1760         /* neighbour list update */
1761         link_cell_update(moldyn);
1762
1763         /* forces depending on chosen potential */
1764         potential_force_calc(moldyn);
1765
1766         for(i=0;i<count;i++) {
1767                 /* check whether fixed atom */
1768                 if(atom[i].attr&ATOM_ATTR_FP)
1769                         continue;
1770                 /* again velocities [actually v(t+tau)] */
1771                 v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass);
1772                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
1773         }
1774
1775         return 0;
1776 }
1777
1778
1779 /*
1780  *
1781  * potentials & corresponding forces & virial routine
1782  * 
1783  */
1784
1785 /* generic potential and force calculation */
1786
1787 int potential_force_calc(t_moldyn *moldyn) {
1788
1789         int i,j,k,count;
1790         t_atom *itom,*jtom,*ktom;
1791         t_virial *virial;
1792         t_linkcell *lc;
1793 #ifdef STATIC_LISTS
1794         int *neighbour_i[27];
1795         int p,q;
1796         t_atom *atom;
1797 #else
1798         t_list neighbour_i[27];
1799         t_list neighbour_i2[27];
1800         t_list *this,*that;
1801 #endif
1802         u8 bc_ij,bc_ik;
1803         int dnlc;
1804
1805         count=moldyn->count;
1806         itom=moldyn->atom;
1807         lc=&(moldyn->lc);
1808 #ifdef STATIC_LISTS
1809         atom=moldyn->atom;
1810 #endif
1811
1812         /* reset energy */
1813         moldyn->energy=0.0;
1814
1815         /* reset global virial */
1816         memset(&(moldyn->gvir),0,sizeof(t_virial));
1817
1818         /* reset force, site energy and virial of every atom */
1819         for(i=0;i<count;i++) {
1820
1821                 /* reset force */
1822                 v3_zero(&(itom[i].f));
1823
1824                 /* reset virial */
1825                 virial=(&(itom[i].virial));
1826                 virial->xx=0.0;
1827                 virial->yy=0.0;
1828                 virial->zz=0.0;
1829                 virial->xy=0.0;
1830                 virial->xz=0.0;
1831                 virial->yz=0.0;
1832         
1833                 /* reset site energy */
1834                 itom[i].e=0.0;
1835
1836         }
1837
1838         /* get energy, force and virial of every atom */
1839
1840         /* first (and only) loop over atoms i */
1841         for(i=0;i<count;i++) {
1842
1843                 /* single particle potential/force */
1844                 if(itom[i].attr&ATOM_ATTR_1BP)
1845                         if(moldyn->func1b)
1846                                 moldyn->func1b(moldyn,&(itom[i]));
1847
1848                 if(!(itom[i].attr&(ATOM_ATTR_2BP|ATOM_ATTR_3BP)))
1849                         continue;
1850
1851                 /* 2 body pair potential/force */
1852         
1853                 link_cell_neighbour_index(moldyn,
1854                                           (itom[i].r.x+moldyn->dim.x/2)/lc->x,
1855                                           (itom[i].r.y+moldyn->dim.y/2)/lc->y,
1856                                           (itom[i].r.z+moldyn->dim.z/2)/lc->z,
1857                                           neighbour_i);
1858
1859                 dnlc=lc->dnlc;
1860
1861                 /* first loop over atoms j */
1862                 if(moldyn->func2b) {
1863                         for(j=0;j<27;j++) {
1864
1865                                 bc_ij=(j<dnlc)?0:1;
1866 #ifdef STATIC_LISTS
1867                                 p=0;
1868
1869                                 while(neighbour_i[j][p]!=0) {
1870
1871                                         jtom=&(atom[neighbour_i[j][p]]);
1872                                         p++;
1873
1874                                         if(jtom==&(itom[i]))
1875                                                 continue;
1876
1877                                         if((jtom->attr&ATOM_ATTR_2BP)&
1878                                            (itom[i].attr&ATOM_ATTR_2BP)) {
1879                                                 moldyn->func2b(moldyn,
1880                                                                &(itom[i]),
1881                                                                jtom,
1882                                                                bc_ij);
1883                                         }
1884                                 }
1885 #else
1886                                 this=&(neighbour_i[j]);
1887                                 list_reset_f(this);
1888
1889                                 if(this->start==NULL)
1890                                         continue;
1891
1892                                 do {
1893                                         jtom=this->current->data;
1894
1895                                         if(jtom==&(itom[i]))
1896                                                 continue;
1897
1898                                         if((jtom->attr&ATOM_ATTR_2BP)&
1899                                            (itom[i].attr&ATOM_ATTR_2BP)) {
1900                                                 moldyn->func2b(moldyn,
1901                                                                &(itom[i]),
1902                                                                jtom,
1903                                                                bc_ij);
1904                                         }
1905                                 } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
1906 #endif
1907
1908                         }
1909                 }
1910
1911                 /* 3 body potential/force */
1912
1913                 if(!(itom[i].attr&ATOM_ATTR_3BP))
1914                         continue;
1915
1916                 /* copy the neighbour lists */
1917 #ifdef STATIC_LISTS
1918                 /* no copy needed for static lists */
1919 #else
1920                 memcpy(neighbour_i2,neighbour_i,27*sizeof(t_list));
1921 #endif
1922
1923                 /* second loop over atoms j */
1924                 for(j=0;j<27;j++) {
1925
1926                         bc_ij=(j<dnlc)?0:1;
1927 #ifdef STATIC_LISTS
1928                         p=0;
1929
1930                         while(neighbour_i[j][p]!=0) {
1931
1932                                 jtom=&(atom[neighbour_i[j][p]]);
1933                                 p++;
1934 #else
1935                         this=&(neighbour_i[j]);
1936                         list_reset_f(this);
1937
1938                         if(this->start==NULL)
1939                                 continue;
1940
1941                         do {
1942
1943                                 jtom=this->current->data;
1944 #endif
1945
1946                                 if(jtom==&(itom[i]))
1947                                         continue;
1948
1949                                 if(!(jtom->attr&ATOM_ATTR_3BP))
1950                                         continue;
1951
1952                                 /* reset 3bp run */
1953                                 moldyn->run3bp=1;
1954
1955                                 if(moldyn->func3b_j1)
1956                                         moldyn->func3b_j1(moldyn,
1957                                                           &(itom[i]),
1958                                                           jtom,
1959                                                           bc_ij);
1960
1961                                 /* in first j loop, 3bp run can be skipped */
1962                                 if(!(moldyn->run3bp))
1963                                         continue;
1964                         
1965                                 /* first loop over atoms k */
1966                                 if(moldyn->func3b_k1) {
1967
1968                                 for(k=0;k<27;k++) {
1969
1970                                         bc_ik=(k<dnlc)?0:1;
1971 #ifdef STATIC_LISTS
1972                                         q=0;
1973
1974                                         while(neighbour_i[j][q]!=0) {
1975
1976                                                 ktom=&(atom[neighbour_i[k][q]]);
1977                                                 q++;
1978 #else
1979                                         that=&(neighbour_i2[k]);
1980                                         list_reset_f(that);
1981                                         
1982                                         if(that->start==NULL)
1983                                                 continue;
1984
1985                                         do {
1986                                                 ktom=that->current->data;
1987 #endif
1988
1989                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
1990                                                         continue;
1991
1992                                                 if(ktom==jtom)
1993                                                         continue;
1994
1995                                                 if(ktom==&(itom[i]))
1996                                                         continue;
1997
1998                                                 moldyn->func3b_k1(moldyn,
1999                                                                   &(itom[i]),
2000                                                                   jtom,
2001                                                                   ktom,
2002                                                                   bc_ik|bc_ij);
2003 #ifdef STATIC_LISTS
2004                                         }
2005 #else
2006                                         } while(list_next_f(that)!=\
2007                                                 L_NO_NEXT_ELEMENT);
2008 #endif
2009
2010                                 }
2011
2012                                 }
2013
2014                                 if(moldyn->func3b_j2)
2015                                         moldyn->func3b_j2(moldyn,
2016                                                           &(itom[i]),
2017                                                           jtom,
2018                                                           bc_ij);
2019
2020                                 /* second loop over atoms k */
2021                                 if(moldyn->func3b_k2) {
2022
2023                                 for(k=0;k<27;k++) {
2024
2025                                         bc_ik=(k<dnlc)?0:1;
2026 #ifdef STATIC_LISTS
2027                                         q=0;
2028
2029                                         while(neighbour_i[j][q]!=0) {
2030
2031                                                 ktom=&(atom[neighbour_i[k][q]]);
2032                                                 q++;
2033 #else
2034                                         that=&(neighbour_i2[k]);
2035                                         list_reset_f(that);
2036                                         
2037                                         if(that->start==NULL)
2038                                                 continue;
2039
2040                                         do {
2041                                                 ktom=that->current->data;
2042 #endif
2043
2044                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
2045                                                         continue;
2046
2047                                                 if(ktom==jtom)
2048                                                         continue;
2049
2050                                                 if(ktom==&(itom[i]))
2051                                                         continue;
2052
2053                                                 moldyn->func3b_k2(moldyn,
2054                                                                   &(itom[i]),
2055                                                                   jtom,
2056                                                                   ktom,
2057                                                                   bc_ik|bc_ij);
2058
2059 #ifdef STATIC_LISTS
2060                                         }
2061 #else
2062                                         } while(list_next_f(that)!=\
2063                                                 L_NO_NEXT_ELEMENT);
2064 #endif
2065
2066                                 }
2067                                 
2068                                 }
2069
2070                                 /* 2bp post function */
2071                                 if(moldyn->func3b_j3) {
2072                                         moldyn->func3b_j3(moldyn,
2073                                                           &(itom[i]),
2074                                                           jtom,bc_ij);
2075                                 }
2076 #ifdef STATIC_LISTS
2077                         }
2078 #else
2079                         } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2080 #endif
2081                 
2082                 }
2083                 
2084 #ifdef DEBUG
2085         //printf("\n\n");
2086 #endif
2087 #ifdef VDEBUG
2088         printf("\n\n");
2089 #endif
2090
2091         }
2092
2093 #ifdef DEBUG
2094         //printf("\nATOM 0: %f %f %f\n\n",itom->f.x,itom->f.y,itom->f.z);
2095         if(moldyn->time>DSTART&&moldyn->time<DEND) {
2096                 printf("force:\n");
2097                 printf("  x: %0.40f\n",moldyn->atom[DATOM].f.x);
2098                 printf("  y: %0.40f\n",moldyn->atom[DATOM].f.y);
2099                 printf("  z: %0.40f\n",moldyn->atom[DATOM].f.z);
2100         }
2101 #endif
2102
2103         /* some postprocessing */
2104         for(i=0;i<count;i++) {
2105                 /* calculate global virial */
2106                 moldyn->gvir.xx+=itom[i].r.x*itom[i].f.x;
2107                 moldyn->gvir.yy+=itom[i].r.y*itom[i].f.y;
2108                 moldyn->gvir.zz+=itom[i].r.z*itom[i].f.z;
2109                 moldyn->gvir.xy+=itom[i].r.y*itom[i].f.x;
2110                 moldyn->gvir.xz+=itom[i].r.z*itom[i].f.x;
2111                 moldyn->gvir.yz+=itom[i].r.z*itom[i].f.y;
2112
2113                 /* check forces regarding the given timestep */
2114                 if(v3_norm(&(itom[i].f))>\
2115                    0.1*moldyn->nnd*itom[i].mass/moldyn->tau_square)
2116                         printf("[moldyn] WARNING: pfc (high force: atom %d)\n",
2117                                i);
2118         }
2119
2120         return 0;
2121 }
2122
2123 /*
2124  * virial calculation
2125  */
2126
2127 //inline int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
2128 int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
2129
2130         a->virial.xx+=f->x*d->x;
2131         a->virial.yy+=f->y*d->y;
2132         a->virial.zz+=f->z*d->z;
2133         a->virial.xy+=f->x*d->y;
2134         a->virial.xz+=f->x*d->z;
2135         a->virial.yz+=f->y*d->z;
2136
2137         return 0;
2138 }
2139
2140 /*
2141  * periodic boundary checking
2142  */
2143
2144 //inline int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
2145 int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
2146         
2147         double x,y,z;
2148         t_3dvec *dim;
2149
2150         dim=&(moldyn->dim);
2151
2152         x=dim->x/2;
2153         y=dim->y/2;
2154         z=dim->z/2;
2155
2156         if(moldyn->status&MOLDYN_STAT_PBX) {
2157                 if(a->x>=x) a->x-=dim->x;
2158                 else if(-a->x>x) a->x+=dim->x;
2159         }
2160         if(moldyn->status&MOLDYN_STAT_PBY) {
2161                 if(a->y>=y) a->y-=dim->y;
2162                 else if(-a->y>y) a->y+=dim->y;
2163         }
2164         if(moldyn->status&MOLDYN_STAT_PBZ) {
2165                 if(a->z>=z) a->z-=dim->z;
2166                 else if(-a->z>z) a->z+=dim->z;
2167         }
2168
2169         return 0;
2170 }
2171         
2172 /*
2173  * debugging / critical check functions
2174  */
2175
2176 int moldyn_bc_check(t_moldyn *moldyn) {
2177
2178         t_atom *atom;
2179         t_3dvec *dim;
2180         int i;
2181         double x;
2182         u8 byte;
2183         int j,k;
2184
2185         atom=moldyn->atom;
2186         dim=&(moldyn->dim);
2187         x=dim->x/2;
2188
2189         for(i=0;i<moldyn->count;i++) {
2190                 if(atom[i].r.x>=dim->x/2||-atom[i].r.x>dim->x/2) {
2191                         printf("FATAL: atom %d: x: %.20f (%.20f)\n",
2192                                i,atom[i].r.x,dim->x/2);
2193                         printf("diagnostic:\n");
2194                         printf("-----------\natom.r.x:\n");
2195                         for(j=0;j<8;j++) {
2196                                 memcpy(&byte,(u8 *)(&(atom[i].r.x))+j,1);
2197                                 for(k=0;k<8;k++)
2198                                         printf("%d%c",
2199                                         ((byte)&(1<<k))?1:0,
2200                                         (k==7)?'\n':'|');
2201                         }
2202                         printf("---------------\nx=dim.x/2:\n");
2203                         for(j=0;j<8;j++) {
2204                                 memcpy(&byte,(u8 *)(&x)+j,1);
2205                                 for(k=0;k<8;k++)
2206                                         printf("%d%c",
2207                                         ((byte)&(1<<k))?1:0,
2208                                         (k==7)?'\n':'|');
2209                         }
2210                         if(atom[i].r.x==x) printf("the same!\n");
2211                         else printf("different!\n");
2212                 }
2213                 if(atom[i].r.y>=dim->y/2||-atom[i].r.y>dim->y/2)
2214                         printf("FATAL: atom %d: y: %.20f (%.20f)\n",
2215                                i,atom[i].r.y,dim->y/2);
2216                 if(atom[i].r.z>=dim->z/2||-atom[i].r.z>dim->z/2)
2217                         printf("FATAL: atom %d: z: %.20f (%.20f)\n",
2218                                i,atom[i].r.z,dim->z/2);
2219         }
2220
2221         return 0;
2222 }
2223
2224 /*
2225  * restore function
2226  */
2227
2228 int moldyn_read_save_file(t_moldyn *moldyn,char *file) {
2229
2230         int fd;
2231         int cnt,size;
2232         int fsize;
2233         int corr;
2234
2235         fd=open(file,O_RDONLY);
2236         if(fd<0) {
2237                 perror("[moldyn] load save file open");
2238                 return fd;
2239         }
2240
2241         fsize=lseek(fd,0,SEEK_END);
2242         lseek(fd,0,SEEK_SET);
2243
2244         size=sizeof(t_moldyn);
2245
2246         while(size) {
2247                 cnt=read(fd,moldyn,size);
2248                 if(cnt<0) {
2249                         perror("[moldyn] load save file read (moldyn)");
2250                         return cnt;
2251                 }
2252                 size-=cnt;
2253         }
2254
2255         size=moldyn->count*sizeof(t_atom);
2256
2257         /* correcting possible atom data offset */
2258         corr=0;
2259         if(fsize!=sizeof(t_moldyn)+size) {
2260                 corr=fsize-sizeof(t_moldyn)-size;
2261                 printf("[moldyn] WARNING: lsf (illegal file size)\n");
2262                 printf("  moifying offset:\n");
2263                 printf("  - current pos: %d\n",sizeof(t_moldyn));
2264                 printf("  - atom size: %d\n",size);
2265                 printf("  - file size: %d\n",fsize);
2266                 printf("  => correction: %d\n",corr);
2267                 lseek(fd,corr,SEEK_CUR);
2268         }
2269
2270         moldyn->atom=(t_atom *)malloc(size);
2271         if(moldyn->atom==NULL) {
2272                 perror("[moldyn] load save file malloc (atoms)");
2273                 return -1;
2274         }
2275
2276         while(size) {
2277                 cnt=read(fd,moldyn->atom,size);
2278                 if(cnt<0) {
2279                         perror("[moldyn] load save file read (atoms)");
2280                         return cnt;
2281                 }
2282                 size-=cnt;
2283         }
2284
2285         // hooks etc ...
2286
2287         return 0;
2288 }
2289
2290 int moldyn_load(t_moldyn *moldyn) {
2291
2292         // later ...
2293
2294         return 0;
2295 }
2296
2297 /*
2298  * post processing functions
2299  */
2300
2301 int get_line(int fd,char *line,int max) {
2302
2303         int count,ret;
2304
2305         count=0;
2306
2307         while(1) {
2308                 if(count==max) return count;
2309                 ret=read(fd,line+count,1);
2310                 if(ret<=0) return ret;
2311                 if(line[count]=='\n') {
2312                         line[count]='\0';
2313                         return count+1;
2314                 }
2315                 count+=1;
2316         }
2317 }
2318
2319 int pair_correlation_init(t_moldyn *moldyn,double dr) {
2320
2321         
2322         return 0;
2323 }
2324
2325 int calculate_diffusion_coefficient(t_moldyn *moldyn,double *dc) {
2326
2327         int i;
2328         t_atom *atom;
2329         t_3dvec dist;
2330         double d2;
2331         int a_cnt;
2332         int b_cnt;
2333
2334         atom=moldyn->atom;
2335         dc[0]=0;
2336         dc[1]=0;
2337         dc[2]=0;
2338         a_cnt=0;
2339         b_cnt=0;
2340
2341         for(i=0;i<moldyn->count;i++) {
2342
2343                 v3_sub(&dist,&(atom[i].r),&(atom[i].r_0));
2344                 check_per_bound(moldyn,&dist);
2345                 d2=v3_absolute_square(&dist);
2346
2347                 if(atom[i].brand) {
2348                         b_cnt+=1;
2349                         dc[1]+=d2;
2350                 }
2351                 else {
2352                         a_cnt+=1;
2353                         dc[0]+=d2;
2354                 }
2355
2356                 dc[2]+=d2;
2357         }
2358
2359         dc[0]*=(1.0/(6.0*moldyn->time*a_cnt));
2360         dc[1]*=(1.0/(6.0*moldyn->time*b_cnt));
2361         dc[2]*=(1.0/(6.0*moldyn->time*moldyn->count));
2362                 
2363         return 0;
2364 }
2365
2366 int calculate_pair_correlation(t_moldyn *moldyn,double dr,void *ptr) {
2367
2368         int slots;
2369         double *stat;
2370         int i,j;
2371         t_linkcell *lc;
2372 #ifdef STATIC_LISTS
2373         int *neighbour[27];
2374         int p;
2375 #else
2376         t_list neighbour[27];
2377 #endif
2378         t_atom *itom,*jtom;
2379         t_list *this;
2380         unsigned char bc;
2381         t_3dvec dist;
2382         double d;
2383         double norm;
2384         int o,s;
2385         unsigned char ibrand;
2386
2387         lc=&(moldyn->lc);
2388
2389         slots=2.0*moldyn->cutoff/dr;
2390         o=2*slots;
2391
2392         if(slots*dr<=moldyn->cutoff)
2393                 printf("[moldyn] WARNING: pcc (low #slots)\n");
2394
2395         printf("[moldyn] pair correlation calc info:\n");
2396         printf("  time: %f\n",moldyn->time);
2397         printf("  count: %d\n",moldyn->count);
2398         printf("  cutoff: %f\n",moldyn->cutoff);
2399         printf("  temperature: cur=%f avg=%f\n",moldyn->t,moldyn->t_avg);
2400
2401         if(ptr!=NULL) {
2402                 stat=(double *)ptr;
2403         }
2404         else {
2405                 stat=(double *)malloc(3*slots*sizeof(double));
2406                 if(stat==NULL) {
2407                         perror("[moldyn] pair correlation malloc");
2408                         return -1;
2409                 }
2410         }
2411
2412         memset(stat,0,3*slots*sizeof(double));
2413
2414         link_cell_init(moldyn,VERBOSE);
2415
2416         itom=moldyn->atom;
2417         
2418         for(i=0;i<moldyn->count;i++) {
2419                 /* neighbour indexing */
2420                 link_cell_neighbour_index(moldyn,
2421                                           (itom[i].r.x+moldyn->dim.x/2)/lc->x,
2422                                           (itom[i].r.y+moldyn->dim.y/2)/lc->x,
2423                                           (itom[i].r.z+moldyn->dim.z/2)/lc->x,
2424                                           neighbour);
2425
2426                 /* brand of atom i */
2427                 ibrand=itom[i].brand;
2428         
2429                 for(j=0;j<27;j++) {
2430
2431                         bc=(j<lc->dnlc)?0:1;
2432
2433 #ifdef STATIC_LISTS
2434                         p=0;
2435
2436                         while(neighbour[j][p]!=0) {
2437
2438                                 jtom=&(moldyn->atom[neighbour[j][p]]);
2439                                 p++;
2440 #else
2441                         this=&(neighbour[j]);
2442                         list_reset_f(this);
2443
2444                         if(this->start==NULL)
2445                                 continue;
2446
2447                         do {
2448
2449                                 jtom=this->current->data;
2450 #endif
2451                                 /* only count pairs once,
2452                                  * skip same atoms */
2453                                 if(itom[i].tag>=jtom->tag)
2454                                         continue;
2455
2456                                 /*
2457                                  * pair correlation calc
2458                                  */
2459
2460                                 /* distance */
2461                                 v3_sub(&dist,&(jtom->r),&(itom[i].r));
2462                                 if(bc) check_per_bound(moldyn,&dist);
2463                                 d=v3_absolute_square(&dist);
2464
2465                                 /* ignore if greater or equal cutoff */
2466                                 if(d>=4.0*moldyn->cutoff_square)
2467                                         continue;
2468
2469                                 /* fill the slots */
2470                                 d=sqrt(d);
2471                                 s=(int)(d/dr);
2472
2473                                 /* should never happen but it does 8) -
2474                                  * related to -ffloat-store problem! */
2475                                 if(s>=slots) {
2476                                         printf("[moldyn] WARNING: pcc (%d/%d)",
2477                                                s,slots);
2478                                         printf("\n");
2479                                         s=slots-1;
2480                                 }
2481
2482                                 if(ibrand!=jtom->brand) {
2483                                         /* mixed */
2484                                         stat[s]+=1;
2485                                 }
2486                                 else {
2487                                         /* type a - type a bonds */
2488                                         if(ibrand==0)
2489                                                 stat[s+slots]+=1;
2490                                         else
2491                                         /* type b - type b bonds */
2492                                                 stat[s+o]+=1;
2493                                 }
2494 #ifdef STATIC_LISTS
2495                         }
2496 #else
2497                         } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2498 #endif
2499                 }
2500         }
2501
2502         /* normalization */
2503         for(i=1;i<slots;i++) {
2504                  // normalization: 4 pi r^2 dr
2505                  // here: not double counting pairs -> 2 pi r r dr
2506                  // ... and actually it's a constant times r^2
2507                 norm=i*i*dr*dr;
2508                 stat[i]/=norm;
2509                 stat[slots+i]/=norm;
2510                 stat[o+i]/=norm;
2511         }
2512         /* */
2513
2514         if(ptr==NULL) {
2515                 /* todo: store/print pair correlation function */
2516                 free(stat);
2517         }
2518
2519         free(moldyn->atom);
2520
2521         link_cell_shutdown(moldyn);
2522
2523         return 0;
2524 }
2525
2526 int analyze_bonds(t_moldyn *moldyn) {
2527
2528         
2529         
2530
2531         return 0;
2532 }
2533
2534 /*
2535  * visualization code
2536  */
2537
2538 int visual_init(t_moldyn *moldyn,char *filebase) {
2539
2540         strncpy(moldyn->vis.fb,filebase,128);
2541
2542         return 0;
2543 }
2544
2545 int visual_atoms(t_moldyn *moldyn) {
2546
2547         int i,j,fd;
2548         char file[128+64];
2549         t_3dvec dim;
2550         double help;
2551         t_visual *v;
2552         t_atom *atom;
2553         t_atom *btom;
2554         t_linkcell *lc;
2555 #ifdef STATIC_LISTS
2556         int *neighbour[27];
2557         int p;
2558 #else
2559         t_list neighbour[27];
2560 #endif
2561         u8 bc;
2562         t_3dvec dist;
2563         double d2;
2564         u8 brand;
2565
2566         v=&(moldyn->vis);
2567         dim.x=v->dim.x;
2568         dim.y=v->dim.y;
2569         dim.z=v->dim.z;
2570         atom=moldyn->atom;
2571         lc=&(moldyn->lc);
2572
2573         help=(dim.x+dim.y);
2574
2575         sprintf(file,"%s/atomic_conf_%07.f.xyz",v->fb,moldyn->time);
2576         fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
2577         if(fd<0) {
2578                 perror("open visual save file fd");
2579                 return -1;
2580         }
2581
2582         /* write the actual data file */
2583
2584         // povray header
2585         dprintf(fd,"# [P] %d %07.f <%f,%f,%f>\n",
2586                 moldyn->count,moldyn->time,help/40.0,help/40.0,-0.8*help);
2587
2588         // atomic configuration
2589         for(i=0;i<moldyn->count;i++) {
2590                 // atom type, positions, color and kinetic energy
2591                 dprintf(fd,"%s %f %f %f %s %f\n",pse_name[atom[i].element],
2592                                                  atom[i].r.x,
2593                                                  atom[i].r.y,
2594                                                  atom[i].r.z,
2595                                                  pse_col[atom[i].element],
2596                                                  atom[i].ekin);
2597
2598                 /*
2599                  * bond detection should usually be done by potential
2600                  * functions. brrrrr! EVIL!
2601                  * 
2602                  * todo: potentials need to export a 'find_bonds' function!
2603                  */
2604
2605                 // bonds between atoms
2606                 if(!(atom[i].attr&ATOM_ATTR_VB))
2607                         continue;
2608                 link_cell_neighbour_index(moldyn,
2609                                           (atom[i].r.x+moldyn->dim.x/2)/lc->x,
2610                                           (atom[i].r.y+moldyn->dim.y/2)/lc->y,
2611                                           (atom[i].r.z+moldyn->dim.z/2)/lc->z,
2612                                           neighbour);
2613                 for(j=0;j<27;j++) {
2614                         bc=j<lc->dnlc?0:1;
2615 #ifdef STATIC_LISTS
2616                         p=0;
2617                         while(neighbour[j][p]!=0) {
2618                                 btom=&(atom[neighbour[j][p]]);
2619                                 p++;
2620 #else
2621                         list_reset_f(&neighbour[j]);
2622                         if(neighbour[j].start==NULL)
2623                                 continue;
2624                         do {
2625                                 btom=neighbour[j].current->data;
2626 #endif
2627                                 if(btom==&atom[i])      // skip identical atoms
2628                                         continue;
2629                                 //if(btom<&atom[i])     // skip half of them
2630                                 //      continue;
2631                                 v3_sub(&dist,&(atom[i].r),&(btom->r));
2632                                 if(bc) check_per_bound(moldyn,&dist);
2633                                 d2=v3_absolute_square(&dist);
2634                                 brand=atom[i].brand;
2635                                 if(brand==btom->brand) {
2636                                         if(d2>moldyn->bondlen[brand])
2637                                                 continue;
2638                                 }
2639                                 else {
2640                                         if(d2>moldyn->bondlen[2])
2641                                                 continue;
2642                                 }
2643                                 dprintf(fd,"# [B] %f %f %f %f %f %f\n",
2644                                         atom[i].r.x,atom[i].r.y,atom[i].r.z,
2645                                         btom->r.x,btom->r.y,btom->r.z);
2646 #ifdef STATIC_LISTS
2647                         }
2648 #else
2649                         } while(list_next_f(&neighbour[j])!=L_NO_NEXT_ELEMENT);
2650 #endif
2651                 }
2652         }
2653
2654         // boundaries
2655         if(dim.x) {
2656                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2657                         -dim.x/2,-dim.y/2,-dim.z/2,
2658                         dim.x/2,-dim.y/2,-dim.z/2);
2659                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2660                         -dim.x/2,-dim.y/2,-dim.z/2,
2661                         -dim.x/2,dim.y/2,-dim.z/2);
2662                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2663                         dim.x/2,dim.y/2,-dim.z/2,
2664                         dim.x/2,-dim.y/2,-dim.z/2);
2665                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2666                         -dim.x/2,dim.y/2,-dim.z/2,
2667                         dim.x/2,dim.y/2,-dim.z/2);
2668
2669                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2670                         -dim.x/2,-dim.y/2,dim.z/2,
2671                         dim.x/2,-dim.y/2,dim.z/2);
2672                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2673                         -dim.x/2,-dim.y/2,dim.z/2,
2674                         -dim.x/2,dim.y/2,dim.z/2);
2675                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2676                         dim.x/2,dim.y/2,dim.z/2,
2677                         dim.x/2,-dim.y/2,dim.z/2);
2678                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2679                         -dim.x/2,dim.y/2,dim.z/2,
2680                         dim.x/2,dim.y/2,dim.z/2);
2681
2682                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2683                         -dim.x/2,-dim.y/2,dim.z/2,
2684                         -dim.x/2,-dim.y/2,-dim.z/2);
2685                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2686                         -dim.x/2,dim.y/2,dim.z/2,
2687                         -dim.x/2,dim.y/2,-dim.z/2);
2688                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2689                         dim.x/2,-dim.y/2,dim.z/2,
2690                         dim.x/2,-dim.y/2,-dim.z/2);
2691                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2692                         dim.x/2,dim.y/2,dim.z/2,
2693                         dim.x/2,dim.y/2,-dim.z/2);
2694         }
2695
2696         close(fd);
2697
2698         return 0;
2699 }
2700