float-store bugfix (unstatisfying!) + slightly new design of sic.c
[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)++;
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         atom[count].r=*r;
609         atom[count].v=*v;
610         atom[count].element=element;
611         atom[count].mass=mass;
612         atom[count].brand=brand;
613         atom[count].tag=count;
614         atom[count].attr=attr;
615         check_per_bound(moldyn,&(atom[count].r));
616         atom[count].r_0=atom[count].r;
617
618         /* update total system mass */
619         total_mass_calc(moldyn);
620
621         return 0;
622 }
623
624 int del_atom(t_moldyn *moldyn,int tag) {
625
626         t_atom *new,*old;
627         int cnt;
628
629         old=moldyn->atom;
630
631         new=(t_atom *)malloc((moldyn->count-1)*sizeof(t_atom));
632         if(!new) {
633                 perror("[moldyn]malloc (del atom)");
634                 return -1;
635         }
636
637         for(cnt=0;cnt<tag;cnt++)
638                 new[cnt]=old[cnt];
639         
640         for(cnt=tag+1;cnt<moldyn->count;cnt++) {
641                 new[cnt-1]=old[cnt];
642                 new[cnt-1].tag=cnt-1;
643         }
644
645         moldyn->count-=1;
646         moldyn->atom=new;
647
648         free(old);
649
650         return 0;
651 }
652
653 /* cubic init */
654 int cubic_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
655
656         int count;
657         t_3dvec r;
658         int i,j,k;
659         t_3dvec o;
660
661         count=0;
662         if(origin)
663                 v3_copy(&o,origin);
664         else
665                 v3_zero(&o);
666
667         r.x=o.x;
668         for(i=0;i<a;i++) {
669                 r.y=o.y;
670                 for(j=0;j<b;j++) {
671                         r.z=o.z;
672                         for(k=0;k<c;k++) {
673                                 v3_copy(&(atom[count].r),&r);
674                                 count+=1;
675                                 r.z+=lc;
676                         }
677                         r.y+=lc;
678                 }
679                 r.x+=lc;
680         }
681
682         for(i=0;i<count;i++) {
683                 atom[i].r.x-=(a*lc)/2.0;
684                 atom[i].r.y-=(b*lc)/2.0;
685                 atom[i].r.z-=(c*lc)/2.0;
686         }
687
688         return count;
689 }
690
691 /* fcc lattice init */
692 int fcc_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
693
694         int count;
695         int i,j,k,l;
696         t_3dvec o,r,n;
697         t_3dvec basis[3];
698
699         count=0;
700         if(origin)
701                 v3_copy(&o,origin);
702         else
703                 v3_zero(&o);
704
705         /* construct the basis */
706         memset(basis,0,3*sizeof(t_3dvec));
707         basis[0].x=0.5*lc;
708         basis[0].y=0.5*lc;
709         basis[1].x=0.5*lc;
710         basis[1].z=0.5*lc;
711         basis[2].y=0.5*lc;
712         basis[2].z=0.5*lc;
713
714         /* fill up the room */
715         r.x=o.x;
716         for(i=0;i<a;i++) {
717                 r.y=o.y;
718                 for(j=0;j<b;j++) {
719                         r.z=o.z;
720                         for(k=0;k<c;k++) {
721                                 /* first atom */
722                                 v3_copy(&(atom[count].r),&r);
723                                 count+=1;
724                                 r.z+=lc;
725                                 /* the three face centered atoms */
726                                 for(l=0;l<3;l++) {
727                                         v3_add(&n,&r,&basis[l]);
728                                         v3_copy(&(atom[count].r),&n);
729                                         count+=1;
730                                 }
731                         }
732                         r.y+=lc;
733                 }
734                 r.x+=lc;
735         }
736                                 
737         /* coordinate transformation */
738         for(i=0;i<count;i++) {
739                 atom[i].r.x-=(a*lc)/2.0;
740                 atom[i].r.y-=(b*lc)/2.0;
741                 atom[i].r.z-=(c*lc)/2.0;
742         }
743
744         return count;
745 }
746
747 int diamond_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
748
749         int count;
750         t_3dvec o;
751
752         count=fcc_init(a,b,c,lc,atom,origin);
753
754         o.x=0.25*lc;
755         o.y=0.25*lc;
756         o.z=0.25*lc;
757
758         if(origin) v3_add(&o,&o,origin);
759
760         count+=fcc_init(a,b,c,lc,&atom[count],&o);
761
762         return count;
763 }
764
765 int destroy_atoms(t_moldyn *moldyn) {
766
767         if(moldyn->atom) free(moldyn->atom);
768
769         return 0;
770 }
771
772 int thermal_init(t_moldyn *moldyn,u8 equi_init) {
773
774         /*
775          * - gaussian distribution of velocities
776          * - zero total momentum
777          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
778          */
779
780         int i;
781         double v,sigma;
782         t_3dvec p_total,delta;
783         t_atom *atom;
784         t_random *random;
785
786         atom=moldyn->atom;
787         random=&(moldyn->random);
788
789         printf("[moldyn] thermal init (equi init: %s)\n",equi_init?"yes":"no");
790
791         /* gaussian distribution of velocities */
792         v3_zero(&p_total);
793         for(i=0;i<moldyn->count;i++) {
794                 sigma=sqrt(2.0*K_BOLTZMANN*moldyn->t_ref/atom[i].mass);
795                 /* x direction */
796                 v=sigma*rand_get_gauss(random);
797                 atom[i].v.x=v;
798                 p_total.x+=atom[i].mass*v;
799                 /* y direction */
800                 v=sigma*rand_get_gauss(random);
801                 atom[i].v.y=v;
802                 p_total.y+=atom[i].mass*v;
803                 /* z direction */
804                 v=sigma*rand_get_gauss(random);
805                 atom[i].v.z=v;
806                 p_total.z+=atom[i].mass*v;
807         }
808
809         /* zero total momentum */
810         v3_scale(&p_total,&p_total,1.0/moldyn->count);
811         for(i=0;i<moldyn->count;i++) {
812                 v3_scale(&delta,&p_total,1.0/atom[i].mass);
813                 v3_sub(&(atom[i].v),&(atom[i].v),&delta);
814         }
815
816         /* velocity scaling */
817         scale_velocity(moldyn,equi_init);
818
819         return 0;
820 }
821
822 double total_mass_calc(t_moldyn *moldyn) {
823
824         int i;
825
826         moldyn->mass=0.0;
827
828         for(i=0;i<moldyn->count;i++)
829                 moldyn->mass+=moldyn->atom[i].mass;
830
831         return moldyn->mass;
832 }
833
834 double temperature_calc(t_moldyn *moldyn) {
835
836         /* assume up to date kinetic energy, which is 3/2 N k_B T */
837
838         moldyn->t=(2.0*moldyn->ekin)/(3.0*K_BOLTZMANN*moldyn->count);
839
840         return moldyn->t;
841 }
842
843 double get_temperature(t_moldyn *moldyn) {
844
845         return moldyn->t;
846 }
847
848 int scale_velocity(t_moldyn *moldyn,u8 equi_init) {
849
850         int i;
851         double e,scale;
852         t_atom *atom;
853         int count;
854
855         atom=moldyn->atom;
856
857         /*
858          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
859          */
860
861         /* get kinetic energy / temperature & count involved atoms */
862         e=0.0;
863         count=0;
864         for(i=0;i<moldyn->count;i++) {
865                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB)) {
866                         e+=atom[i].mass*v3_absolute_square(&(atom[i].v));
867                         count+=1;
868                 }
869         }
870         e*=0.5;
871         if(count!=0) moldyn->t=e/(1.5*count*K_BOLTZMANN);
872         else return 0;  /* no atoms involved in scaling! */
873         
874         /* (temporary) hack for e,t = 0 */
875         if(e==0.0) {
876         moldyn->t=0.0;
877                 if(moldyn->t_ref!=0.0) {
878                         thermal_init(moldyn,equi_init);
879                         return 0;
880                 }
881                 else
882                         return 0; /* no scaling needed */
883         }
884
885
886         /* get scaling factor */
887         scale=moldyn->t_ref/moldyn->t;
888         if(equi_init&TRUE)
889                 scale*=2.0;
890         else
891                 if(moldyn->pt_scale&T_SCALE_BERENDSEN)
892                         scale=1.0+(scale-1.0)/moldyn->t_tc;
893         scale=sqrt(scale);
894
895         /* velocity scaling */
896         for(i=0;i<moldyn->count;i++) {
897                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB))
898                         v3_scale(&(atom[i].v),&(atom[i].v),scale);
899         }
900
901         return 0;
902 }
903
904 double ideal_gas_law_pressure(t_moldyn *moldyn) {
905
906         double p;
907
908         p=moldyn->count*moldyn->t*K_BOLTZMANN/moldyn->volume;
909
910         return p;
911 }
912
913 double virial_sum(t_moldyn *moldyn) {
914
915         int i;
916         double v;
917         t_virial *virial;
918
919         /* virial (sum over atom virials) */
920         v=0.0;
921         for(i=0;i<moldyn->count;i++) {
922                 virial=&(moldyn->atom[i].virial);
923                 v+=(virial->xx+virial->yy+virial->zz);
924         }
925         moldyn->virial=v;
926
927         /* global virial (absolute coordinates) */
928         virial=&(moldyn->gvir);
929         moldyn->gv=virial->xx+virial->yy+virial->zz;
930
931         return moldyn->virial;
932 }
933
934 double pressure_calc(t_moldyn *moldyn) {
935
936         /*
937          * PV = NkT + <W>
938          * with W = 1/3 sum_i f_i r_i (- skipped!)
939          * virial = sum_i f_i r_i
940          * 
941          * => P = (2 Ekin + virial) / (3V)
942          */
943
944         /* assume up to date virial & up to date kinetic energy */
945
946         /* pressure (atom virials) */
947         moldyn->p=2.0*moldyn->ekin+moldyn->virial;
948         moldyn->p/=(3.0*moldyn->volume);
949
950         /* pressure (absolute coordinates) */
951         moldyn->gp=2.0*moldyn->ekin+moldyn->gv;
952         moldyn->gp/=(3.0*moldyn->volume);
953
954         return moldyn->p;
955 }
956
957 int average_and_fluctuation_calc(t_moldyn *moldyn) {
958
959         int denom;
960
961         if(moldyn->total_steps<moldyn->avg_skip)
962                 return 0;
963
964         denom=moldyn->total_steps+1-moldyn->avg_skip;
965
966         /* assume up to date energies, temperature, pressure etc */
967
968         /* kinetic energy */
969         moldyn->k_sum+=moldyn->ekin;
970         moldyn->k2_sum+=(moldyn->ekin*moldyn->ekin);
971         moldyn->k_avg=moldyn->k_sum/denom;
972         moldyn->k2_avg=moldyn->k2_sum/denom;
973         moldyn->dk2_avg=moldyn->k2_avg-(moldyn->k_avg*moldyn->k_avg);
974
975         /* potential energy */
976         moldyn->v_sum+=moldyn->energy;
977         moldyn->v2_sum+=(moldyn->energy*moldyn->energy);
978         moldyn->v_avg=moldyn->v_sum/denom;
979         moldyn->v2_avg=moldyn->v2_sum/denom;
980         moldyn->dv2_avg=moldyn->v2_avg-(moldyn->v_avg*moldyn->v_avg);
981
982         /* temperature */
983         moldyn->t_sum+=moldyn->t;
984         moldyn->t_avg=moldyn->t_sum/denom;
985
986         /* virial */
987         moldyn->virial_sum+=moldyn->virial;
988         moldyn->virial_avg=moldyn->virial_sum/denom;
989         moldyn->gv_sum+=moldyn->gv;
990         moldyn->gv_avg=moldyn->gv_sum/denom;
991
992         /* pressure */
993         moldyn->p_sum+=moldyn->p;
994         moldyn->p_avg=moldyn->p_sum/denom;
995         moldyn->gp_sum+=moldyn->gp;
996         moldyn->gp_avg=moldyn->gp_sum/denom;
997
998         return 0;
999 }
1000
1001 int get_heat_capacity(t_moldyn *moldyn) {
1002
1003         double temp2,ighc;
1004
1005         /* averages needed for heat capacity calc */
1006         if(moldyn->total_steps<moldyn->avg_skip)
1007                 return 0;
1008
1009         /* (temperature average)^2 */
1010         temp2=moldyn->t_avg*moldyn->t_avg;
1011         printf("[moldyn] specific heat capacity for T=%f K [J/(kg K)]\n",
1012                moldyn->t_avg);
1013
1014         /* ideal gas contribution */
1015         ighc=3.0*moldyn->count*K_BOLTZMANN/2.0;
1016         printf("  ideal gas contribution: %f\n",
1017                ighc/moldyn->mass*KILOGRAM/JOULE);
1018
1019         /* specific heat for nvt ensemble */
1020         moldyn->c_v_nvt=moldyn->dv2_avg/(K_BOLTZMANN*temp2)+ighc;
1021         moldyn->c_v_nvt/=moldyn->mass;
1022
1023         /* specific heat for nve ensemble */
1024         moldyn->c_v_nve=ighc/(1.0-(moldyn->dv2_avg/(ighc*K_BOLTZMANN*temp2)));
1025         moldyn->c_v_nve/=moldyn->mass;
1026
1027         printf("  NVE: %f\n",moldyn->c_v_nve*KILOGRAM/JOULE);
1028         printf("  NVT: %f\n",moldyn->c_v_nvt*KILOGRAM/JOULE);
1029 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)));
1030
1031         return 0;
1032 }
1033
1034 double thermodynamic_pressure_calc(t_moldyn *moldyn) {
1035
1036         t_3dvec dim;
1037         //t_3dvec *tp;
1038         double u_up,u_down,dv;
1039         double scale,p;
1040         t_atom *store;
1041
1042         /*
1043          * dU = - p dV
1044          *
1045          * => p = - dU/dV
1046          *
1047          */
1048
1049         scale=0.00001;
1050         dv=8*scale*scale*scale*moldyn->volume;
1051
1052         store=malloc(moldyn->count*sizeof(t_atom));
1053         if(store==NULL) {
1054                 printf("[moldyn] allocating store mem failed\n");
1055                 return -1;
1056         }
1057
1058         /* save unscaled potential energy + atom/dim configuration */
1059         memcpy(store,moldyn->atom,moldyn->count*sizeof(t_atom));
1060         dim=moldyn->dim;
1061
1062         /* scale up dimension and atom positions */
1063         scale_dim(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
1064         scale_atoms(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
1065         link_cell_shutdown(moldyn);
1066         link_cell_init(moldyn,QUIET);
1067         potential_force_calc(moldyn);
1068         u_up=moldyn->energy;
1069
1070         /* restore atomic configuration + dim */
1071         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1072         moldyn->dim=dim;
1073
1074         /* scale down dimension and atom positions */
1075         scale_dim(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
1076         scale_atoms(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
1077         link_cell_shutdown(moldyn);
1078         link_cell_init(moldyn,QUIET);
1079         potential_force_calc(moldyn);
1080         u_down=moldyn->energy;
1081         
1082         /* calculate pressure */
1083         p=-(u_up-u_down)/dv;
1084 printf("-------> %.10f %.10f %f\n",u_up/EV/moldyn->count,u_down/EV/moldyn->count,p/BAR);
1085
1086         /* restore atomic configuration + dim */
1087         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1088         moldyn->dim=dim;
1089
1090         /* restore energy */
1091         potential_force_calc(moldyn);
1092
1093         link_cell_shutdown(moldyn);
1094         link_cell_init(moldyn,QUIET);
1095
1096         return p;
1097 }
1098
1099 double get_pressure(t_moldyn *moldyn) {
1100
1101         return moldyn->p;
1102
1103 }
1104
1105 int scale_dim(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1106
1107         t_3dvec *dim;
1108
1109         dim=&(moldyn->dim);
1110
1111         if(dir==SCALE_UP)
1112                 scale=1.0+scale;
1113
1114         if(dir==SCALE_DOWN)
1115                 scale=1.0-scale;
1116
1117         if(x) dim->x*=scale;
1118         if(y) dim->y*=scale;
1119         if(z) dim->z*=scale;
1120
1121         return 0;
1122 }
1123
1124 int scale_atoms(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1125
1126         int i;
1127         t_3dvec *r;
1128
1129         if(dir==SCALE_UP)
1130                 scale=1.0+scale;
1131
1132         if(dir==SCALE_DOWN)
1133                 scale=1.0-scale;
1134
1135         for(i=0;i<moldyn->count;i++) {
1136                 r=&(moldyn->atom[i].r);
1137                 if(x) r->x*=scale;
1138                 if(y) r->y*=scale;
1139                 if(z) r->z*=scale;
1140         }
1141
1142         return 0;
1143 }
1144
1145 int scale_volume(t_moldyn *moldyn) {
1146
1147         t_3dvec *dim,*vdim;
1148         double scale;
1149         t_linkcell *lc;
1150
1151         vdim=&(moldyn->vis.dim);
1152         dim=&(moldyn->dim);
1153         lc=&(moldyn->lc);
1154
1155         /* scaling factor */
1156         if(moldyn->pt_scale&P_SCALE_BERENDSEN) {
1157                 scale=1.0-(moldyn->p_ref-moldyn->p)/moldyn->p_tc;
1158                 scale=pow(scale,ONE_THIRD);
1159         }
1160         else {
1161                 scale=pow(moldyn->p/moldyn->p_ref,ONE_THIRD);
1162         }
1163 moldyn->debug=scale;
1164
1165         /* scale the atoms and dimensions */
1166         scale_atoms(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1167         scale_dim(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1168
1169         /* visualize dimensions */
1170         if(vdim->x!=0) {
1171                 vdim->x=dim->x;
1172                 vdim->y=dim->y;
1173                 vdim->z=dim->z;
1174         }
1175
1176         /* recalculate scaled volume */
1177         moldyn->volume=dim->x*dim->y*dim->z;
1178
1179         /* adjust/reinit linkcell */
1180         if(((int)(dim->x/moldyn->cutoff)!=lc->nx)||
1181            ((int)(dim->y/moldyn->cutoff)!=lc->ny)||
1182            ((int)(dim->z/moldyn->cutoff)!=lc->nx)) {
1183                 link_cell_shutdown(moldyn);
1184                 link_cell_init(moldyn,QUIET);
1185         } else {
1186                 lc->x*=scale;
1187                 lc->y*=scale;
1188                 lc->z*=scale;
1189         }
1190
1191         return 0;
1192
1193 }
1194
1195 double e_kin_calc(t_moldyn *moldyn) {
1196
1197         int i;
1198         t_atom *atom;
1199
1200         atom=moldyn->atom;
1201         moldyn->ekin=0.0;
1202
1203         for(i=0;i<moldyn->count;i++) {
1204                 atom[i].ekin=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v));
1205                 moldyn->ekin+=atom[i].ekin;
1206         }
1207
1208         return moldyn->ekin;
1209 }
1210
1211 double get_total_energy(t_moldyn *moldyn) {
1212
1213         return(moldyn->ekin+moldyn->energy);
1214 }
1215
1216 t_3dvec get_total_p(t_moldyn *moldyn) {
1217
1218         t_3dvec p,p_total;
1219         int i;
1220         t_atom *atom;
1221
1222         atom=moldyn->atom;
1223
1224         v3_zero(&p_total);
1225         for(i=0;i<moldyn->count;i++) {
1226                 v3_scale(&p,&(atom[i].v),atom[i].mass);
1227                 v3_add(&p_total,&p_total,&p);
1228         }
1229
1230         return p_total;
1231 }
1232
1233 double estimate_time_step(t_moldyn *moldyn,double nn_dist) {
1234
1235         double tau;
1236
1237         /* nn_dist is the nearest neighbour distance */
1238
1239         tau=(0.05*nn_dist*moldyn->atom[0].mass)/sqrt(3.0*K_BOLTZMANN*moldyn->t);
1240
1241         return tau;     
1242 }
1243
1244 /*
1245  * numerical tricks
1246  */
1247
1248 /* linked list / cell method */
1249
1250 int link_cell_init(t_moldyn *moldyn,u8 vol) {
1251
1252         t_linkcell *lc;
1253         int i;
1254
1255         lc=&(moldyn->lc);
1256
1257         /* partitioning the md cell */
1258         lc->nx=moldyn->dim.x/moldyn->cutoff;
1259         lc->x=moldyn->dim.x/lc->nx;
1260         lc->ny=moldyn->dim.y/moldyn->cutoff;
1261         lc->y=moldyn->dim.y/lc->ny;
1262         lc->nz=moldyn->dim.z/moldyn->cutoff;
1263         lc->z=moldyn->dim.z/lc->nz;
1264         lc->cells=lc->nx*lc->ny*lc->nz;
1265
1266 #ifdef STATIC_LISTS
1267         lc->subcell=malloc(lc->cells*sizeof(int*));
1268 #else
1269         lc->subcell=malloc(lc->cells*sizeof(t_list));
1270 #endif
1271
1272         if(lc->subcell==NULL) {
1273                 perror("[moldyn] cell init (malloc)");
1274                 return -1;
1275         }
1276
1277         if(lc->cells<27)
1278                 printf("[moldyn] FATAL: less then 27 subcells!\n");
1279
1280         if(vol) {
1281 #ifdef STATIC_LISTS
1282                 printf("[moldyn] initializing 'static' linked cells (%d)\n",
1283                        lc->cells);
1284 #else
1285                 printf("[moldyn] initializing 'dynamic' linked cells (%d)\n",
1286                        lc->cells);
1287 #endif
1288                 printf("  x: %d x %f A\n",lc->nx,lc->x);
1289                 printf("  y: %d x %f A\n",lc->ny,lc->y);
1290                 printf("  z: %d x %f A\n",lc->nz,lc->z);
1291         }
1292
1293 #ifdef STATIC_LISTS
1294         /* list init */
1295         for(i=0;i<lc->cells;i++) {
1296                 lc->subcell[i]=malloc((MAX_ATOMS_PER_LIST+1)*sizeof(int));
1297                 if(lc->subcell[i]==NULL) {
1298                         perror("[moldyn] list init (malloc)");
1299                         return -1;
1300                 }
1301                 /*
1302                 if(i==0)
1303                         printf(" ---> %d malloc %p (%p)\n",
1304                                i,lc->subcell[0],lc->subcell);
1305                 */
1306         }
1307 #else
1308         for(i=0;i<lc->cells;i++)
1309                 list_init_f(&(lc->subcell[i]));
1310 #endif
1311
1312         /* update the list */
1313         link_cell_update(moldyn);
1314
1315         return 0;
1316 }
1317
1318 int link_cell_update(t_moldyn *moldyn) {
1319
1320         int count,i,j,k;
1321         int nx,ny;
1322         t_atom *atom;
1323         t_linkcell *lc;
1324 #ifdef STATIC_LISTS
1325         int p;
1326 #endif
1327
1328         atom=moldyn->atom;
1329         lc=&(moldyn->lc);
1330
1331         nx=lc->nx;
1332         ny=lc->ny;
1333
1334         for(i=0;i<lc->cells;i++)
1335 #ifdef STATIC_LISTS
1336                 memset(lc->subcell[i],0,(MAX_ATOMS_PER_LIST+1)*sizeof(int));
1337 #else
1338                 list_destroy_f(&(lc->subcell[i]));
1339 #endif
1340
1341         for(count=0;count<moldyn->count;count++) {
1342                 i=((atom[count].r.x+(moldyn->dim.x/2))/lc->x);
1343                 j=((atom[count].r.y+(moldyn->dim.y/2))/lc->y);
1344                 k=((atom[count].r.z+(moldyn->dim.z/2))/lc->z);
1345
1346 #ifdef STATIC_LISTS
1347                 p=0;
1348                 while(lc->subcell[i+j*nx+k*nx*ny][p]!=0)
1349                         p++;
1350
1351                 if(p>=MAX_ATOMS_PER_LIST) {
1352                         printf("[moldyn] FATAL: amount of atoms too high!\n");
1353                         return -1;
1354                 }
1355
1356                 lc->subcell[i+j*nx+k*nx*ny][p]=count;
1357 #else
1358                 list_add_immediate_f(&(lc->subcell[i+j*nx+k*nx*ny]),
1359                                      &(atom[count]));
1360                 /*
1361                 if(j==0&&k==0)
1362                         printf(" ---> %d %d malloc %p (%p)\n",
1363                                i,count,lc->subcell[i].current,lc->subcell);
1364                 */
1365 #endif
1366         }
1367
1368         return 0;
1369 }
1370
1371 int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,
1372 #ifdef STATIC_LISTS
1373                               int **cell
1374 #else
1375                               t_list *cell
1376 #endif
1377                              ) {
1378
1379         t_linkcell *lc;
1380         int a;
1381         int count1,count2;
1382         int ci,cj,ck;
1383         int nx,ny,nz;
1384         int x,y,z;
1385         u8 bx,by,bz;
1386
1387         lc=&(moldyn->lc);
1388         nx=lc->nx;
1389         ny=lc->ny;
1390         nz=lc->nz;
1391         count1=1;
1392         count2=27;
1393         a=nx*ny;
1394
1395         cell[0]=lc->subcell[i+j*nx+k*a];
1396         for(ci=-1;ci<=1;ci++) {
1397                 bx=0;
1398                 x=i+ci;
1399                 if((x<0)||(x>=nx)) {
1400                         x=(x+nx)%nx;
1401                         bx=1;
1402                 }
1403                 for(cj=-1;cj<=1;cj++) {
1404                         by=0;
1405                         y=j+cj;
1406                         if((y<0)||(y>=ny)) {
1407                                 y=(y+ny)%ny;
1408                                 by=1;
1409                         }
1410                         for(ck=-1;ck<=1;ck++) {
1411                                 bz=0;
1412                                 z=k+ck;
1413                                 if((z<0)||(z>=nz)) {
1414                                         z=(z+nz)%nz;
1415                                         bz=1;
1416                                 }
1417                                 if(!(ci|cj|ck)) continue;
1418                                 if(bx|by|bz) {
1419                                         cell[--count2]=lc->subcell[x+y*nx+z*a];
1420                                 }
1421                                 else {
1422                                         cell[count1++]=lc->subcell[x+y*nx+z*a];
1423                                 }
1424                         }
1425                 }
1426         }
1427
1428         lc->dnlc=count1;
1429
1430         return count1;
1431 }
1432
1433 int link_cell_shutdown(t_moldyn *moldyn) {
1434
1435         int i;
1436         t_linkcell *lc;
1437
1438         lc=&(moldyn->lc);
1439
1440         for(i=0;i<lc->cells;i++) {
1441 #ifdef STATIC_LISTS
1442                 free(lc->subcell[i]);
1443 #else
1444                 //printf(" ---> %d free %p\n",i,lc->subcell[i].start);
1445                 list_destroy_f(&(lc->subcell[i]));
1446 #endif
1447         }
1448
1449         free(lc->subcell);
1450
1451         return 0;
1452 }
1453
1454 int moldyn_add_schedule(t_moldyn *moldyn,int runs,double tau) {
1455
1456         int count;
1457         void *ptr;
1458         t_moldyn_schedule *schedule;
1459
1460         schedule=&(moldyn->schedule);
1461         count=++(schedule->total_sched);
1462
1463         ptr=realloc(schedule->runs,count*sizeof(int));
1464         if(!ptr) {
1465                 perror("[moldyn] realloc (runs)");
1466                 return -1;
1467         }
1468         schedule->runs=ptr;
1469         schedule->runs[count-1]=runs;
1470
1471         ptr=realloc(schedule->tau,count*sizeof(double));
1472         if(!ptr) {
1473                 perror("[moldyn] realloc (tau)");
1474                 return -1;
1475         }
1476         schedule->tau=ptr;
1477         schedule->tau[count-1]=tau;
1478
1479         printf("[moldyn] schedule added:\n");
1480         printf("  number: %d | runs: %d | tau: %f\n",count-1,runs,tau);
1481                                        
1482
1483         return 0;
1484 }
1485
1486 int moldyn_set_schedule_hook(t_moldyn *moldyn,set_hook hook,void *hook_params) {
1487
1488         moldyn->schedule.hook=hook;
1489         moldyn->schedule.hook_params=hook_params;
1490         
1491         return 0;
1492 }
1493
1494 /*
1495  *
1496  * 'integration of newtons equation' - algorithms
1497  *
1498  */
1499
1500 /* start the integration */
1501
1502 int moldyn_integrate(t_moldyn *moldyn) {
1503
1504         int i;
1505         unsigned int e,m,s,v,p,t;
1506         t_3dvec momentum;
1507         t_moldyn_schedule *sched;
1508         t_atom *atom;
1509         int fd;
1510         char dir[128];
1511         double ds;
1512         double energy_scale;
1513         struct timeval t1,t2;
1514         //double tp;
1515
1516         sched=&(moldyn->schedule);
1517         atom=moldyn->atom;
1518
1519         /* initialize linked cell method */
1520         link_cell_init(moldyn,VERBOSE);
1521
1522         /* logging & visualization */
1523         e=moldyn->ewrite;
1524         m=moldyn->mwrite;
1525         s=moldyn->swrite;
1526         v=moldyn->vwrite;
1527         p=moldyn->pwrite;
1528         t=moldyn->twrite;
1529
1530         /* sqaure of some variables */
1531         moldyn->tau_square=moldyn->tau*moldyn->tau;
1532         moldyn->cutoff_square=moldyn->cutoff*moldyn->cutoff;
1533
1534         /* get current time */
1535         gettimeofday(&t1,NULL);
1536
1537         /* calculate initial forces */
1538         potential_force_calc(moldyn);
1539 #ifdef DEBUG
1540 //return 0;
1541 #endif
1542
1543         /* some stupid checks before we actually start calculating bullshit */
1544         if(moldyn->cutoff>0.5*moldyn->dim.x)
1545                 printf("[moldyn] warning: cutoff > 0.5 x dim.x\n");
1546         if(moldyn->cutoff>0.5*moldyn->dim.y)
1547                 printf("[moldyn] warning: cutoff > 0.5 x dim.y\n");
1548         if(moldyn->cutoff>0.5*moldyn->dim.z)
1549                 printf("[moldyn] warning: cutoff > 0.5 x dim.z\n");
1550         ds=0.5*atom[0].f.x*moldyn->tau_square/atom[0].mass;
1551         if(ds>0.05*moldyn->nnd)
1552                 printf("[moldyn] warning: forces too high / tau too small!\n");
1553
1554         /* zero absolute time */
1555         moldyn->time=0.0;
1556         moldyn->total_steps=0;
1557
1558         /* debugging, ignore */
1559         moldyn->debug=0;
1560
1561         /* tell the world */
1562         printf("[moldyn] integration start, go get a coffee ...\n");
1563
1564         /* executing the schedule */
1565         sched->count=0;
1566         while(sched->count<sched->total_sched) {
1567
1568                 /* setting amount of runs and finite time step size */
1569                 moldyn->tau=sched->tau[sched->count];
1570                 moldyn->tau_square=moldyn->tau*moldyn->tau;
1571                 moldyn->time_steps=sched->runs[sched->count];
1572
1573                 /* energy scaling factor (might change!) */
1574                 energy_scale=moldyn->count*EV;
1575
1576         /* integration according to schedule */
1577
1578         for(i=0;i<moldyn->time_steps;i++) {
1579
1580                 /* integration step */
1581                 moldyn->integrate(moldyn);
1582
1583                 /* calculate kinetic energy, temperature and pressure */
1584                 e_kin_calc(moldyn);
1585                 temperature_calc(moldyn);
1586                 virial_sum(moldyn);
1587                 pressure_calc(moldyn);
1588                 average_and_fluctuation_calc(moldyn);
1589
1590                 /* p/t scaling */
1591                 if(moldyn->pt_scale&(T_SCALE_BERENDSEN|T_SCALE_DIRECT))
1592                         scale_velocity(moldyn,FALSE);
1593                 if(moldyn->pt_scale&(P_SCALE_BERENDSEN|P_SCALE_DIRECT))
1594                         scale_volume(moldyn);
1595
1596                 /* check for log & visualization */
1597                 if(e) {
1598                         if(!(moldyn->total_steps%e))
1599                                 dprintf(moldyn->efd,
1600                                         "%f %f %f %f\n",
1601                                         moldyn->time,moldyn->ekin/energy_scale,
1602                                         moldyn->energy/energy_scale,
1603                                         get_total_energy(moldyn)/energy_scale);
1604                 }
1605                 if(m) {
1606                         if(!(moldyn->total_steps%m)) {
1607                                 momentum=get_total_p(moldyn);
1608                                 dprintf(moldyn->mfd,
1609                                         "%f %f %f %f %f\n",moldyn->time,
1610                                         momentum.x,momentum.y,momentum.z,
1611                                         v3_norm(&momentum));
1612                         }
1613                 }
1614                 if(p) {
1615                         if(!(moldyn->total_steps%p)) {
1616                                 dprintf(moldyn->pfd,
1617                                         "%f %f %f %f %f\n",moldyn->time,
1618                                          moldyn->p/BAR,moldyn->p_avg/BAR,
1619                                          moldyn->gp/BAR,moldyn->gp_avg/BAR);
1620                         }
1621                 }
1622                 if(t) {
1623                         if(!(moldyn->total_steps%t)) {
1624                                 dprintf(moldyn->tfd,
1625                                         "%f %f %f\n",
1626                                         moldyn->time,moldyn->t,moldyn->t_avg);
1627                         }
1628                 }
1629                 if(s) {
1630                         if(!(moldyn->total_steps%s)) {
1631                                 snprintf(dir,128,"%s/s-%07.f.save",
1632                                          moldyn->vlsdir,moldyn->time);
1633                                 fd=open(dir,O_WRONLY|O_TRUNC|O_CREAT,
1634                                         S_IRUSR|S_IWUSR);
1635                                 if(fd<0) perror("[moldyn] save fd open");
1636                                 else {
1637                                         write(fd,moldyn,sizeof(t_moldyn));
1638                                         write(fd,moldyn->atom,
1639                                               moldyn->count*sizeof(t_atom));
1640                                 }
1641                                 close(fd);
1642                         }       
1643                 }
1644                 if(v) {
1645                         if(!(moldyn->total_steps%v)) {
1646                                 visual_atoms(moldyn);
1647                         }
1648                 }
1649
1650                 /* display progress */
1651                 //if(!(moldyn->total_steps%10)) {
1652                         /* get current time */
1653                         gettimeofday(&t2,NULL);
1654
1655 printf("\rsched:%d, steps:%d/%d, T:%3.1f/%3.1f P:%4.1f/%4.1f V:%6.1f (%d)",
1656        sched->count,i,moldyn->total_steps,
1657        moldyn->t,moldyn->t_avg,
1658        moldyn->p_avg/BAR,moldyn->gp_avg/BAR,
1659        moldyn->volume,
1660        (int)(t2.tv_sec-t1.tv_sec));
1661
1662                         fflush(stdout);
1663
1664                         /* copy over time */
1665                         t1=t2;
1666                 //}
1667
1668                 /* increase absolute time */
1669                 moldyn->time+=moldyn->tau;
1670                 moldyn->total_steps+=1;
1671
1672         }
1673
1674                 /* check for hooks */
1675                 if(sched->hook) {
1676                         printf("\n ## schedule hook %d start ##\n",
1677                                sched->count);
1678                         sched->hook(moldyn,sched->hook_params);
1679                         printf(" ## schedule hook end ##\n");
1680                 }
1681
1682                 /* increase the schedule counter */
1683                 sched->count+=1;
1684
1685         }
1686
1687         return 0;
1688 }
1689
1690 /* velocity verlet */
1691
1692 int velocity_verlet(t_moldyn *moldyn) {
1693
1694         int i,count;
1695         double tau,tau_square,h;
1696         t_3dvec delta;
1697         t_atom *atom;
1698
1699         atom=moldyn->atom;
1700         count=moldyn->count;
1701         tau=moldyn->tau;
1702         tau_square=moldyn->tau_square;
1703
1704         for(i=0;i<count;i++) {
1705                 /* new positions */
1706                 h=0.5/atom[i].mass;
1707                 v3_scale(&delta,&(atom[i].v),tau);
1708                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
1709                 v3_scale(&delta,&(atom[i].f),h*tau_square);
1710                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
1711                 check_per_bound(moldyn,&(atom[i].r));
1712
1713                 /* velocities [actually v(t+tau/2)] */
1714                 v3_scale(&delta,&(atom[i].f),h*tau);
1715                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
1716         }
1717
1718         /* neighbour list update */
1719         link_cell_update(moldyn);
1720
1721         /* forces depending on chosen potential */
1722         potential_force_calc(moldyn);
1723
1724         for(i=0;i<count;i++) {
1725                 /* again velocities [actually v(t+tau)] */
1726                 v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass);
1727                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
1728         }
1729
1730         return 0;
1731 }
1732
1733
1734 /*
1735  *
1736  * potentials & corresponding forces & virial routine
1737  * 
1738  */
1739
1740 /* generic potential and force calculation */
1741
1742 int potential_force_calc(t_moldyn *moldyn) {
1743
1744         int i,j,k,count;
1745         t_atom *itom,*jtom,*ktom;
1746         t_virial *virial;
1747         t_linkcell *lc;
1748 #ifdef STATIC_LISTS
1749         int *neighbour_i[27];
1750         int p,q;
1751         t_atom *atom;
1752 #else
1753         t_list neighbour_i[27];
1754         t_list neighbour_i2[27];
1755         t_list *this,*that;
1756 #endif
1757         u8 bc_ij,bc_ik;
1758         int dnlc;
1759
1760         count=moldyn->count;
1761         itom=moldyn->atom;
1762         lc=&(moldyn->lc);
1763 #ifdef STATIC_LISTS
1764         atom=moldyn->atom;
1765 #endif
1766
1767         /* reset energy */
1768         moldyn->energy=0.0;
1769
1770         /* reset global virial */
1771         memset(&(moldyn->gvir),0,sizeof(t_virial));
1772
1773         /* reset force, site energy and virial of every atom */
1774         for(i=0;i<count;i++) {
1775
1776                 /* reset force */
1777                 v3_zero(&(itom[i].f));
1778
1779                 /* reset virial */
1780                 virial=(&(itom[i].virial));
1781                 virial->xx=0.0;
1782                 virial->yy=0.0;
1783                 virial->zz=0.0;
1784                 virial->xy=0.0;
1785                 virial->xz=0.0;
1786                 virial->yz=0.0;
1787         
1788                 /* reset site energy */
1789                 itom[i].e=0.0;
1790
1791         }
1792
1793         /* get energy, force and virial of every atom */
1794
1795         /* first (and only) loop over atoms i */
1796         for(i=0;i<count;i++) {
1797
1798                 /* single particle potential/force */
1799                 if(itom[i].attr&ATOM_ATTR_1BP)
1800                         if(moldyn->func1b)
1801                                 moldyn->func1b(moldyn,&(itom[i]));
1802
1803                 if(!(itom[i].attr&(ATOM_ATTR_2BP|ATOM_ATTR_3BP)))
1804                         continue;
1805
1806                 /* 2 body pair potential/force */
1807         
1808                 link_cell_neighbour_index(moldyn,
1809                                           (itom[i].r.x+moldyn->dim.x/2)/lc->x,
1810                                           (itom[i].r.y+moldyn->dim.y/2)/lc->y,
1811                                           (itom[i].r.z+moldyn->dim.z/2)/lc->z,
1812                                           neighbour_i);
1813
1814                 dnlc=lc->dnlc;
1815
1816                 /* first loop over atoms j */
1817                 if(moldyn->func2b) {
1818                         for(j=0;j<27;j++) {
1819
1820                                 bc_ij=(j<dnlc)?0:1;
1821 #ifdef STATIC_LISTS
1822                                 p=0;
1823
1824                                 while(neighbour_i[j][p]!=0) {
1825
1826                                         jtom=&(atom[neighbour_i[j][p]]);
1827                                         p++;
1828
1829                                         if(jtom==&(itom[i]))
1830                                                 continue;
1831
1832                                         if((jtom->attr&ATOM_ATTR_2BP)&
1833                                            (itom[i].attr&ATOM_ATTR_2BP)) {
1834                                                 moldyn->func2b(moldyn,
1835                                                                &(itom[i]),
1836                                                                jtom,
1837                                                                bc_ij);
1838                                         }
1839                                 }
1840 #else
1841                                 this=&(neighbour_i[j]);
1842                                 list_reset_f(this);
1843
1844                                 if(this->start==NULL)
1845                                         continue;
1846
1847                                 do {
1848                                         jtom=this->current->data;
1849
1850                                         if(jtom==&(itom[i]))
1851                                                 continue;
1852
1853                                         if((jtom->attr&ATOM_ATTR_2BP)&
1854                                            (itom[i].attr&ATOM_ATTR_2BP)) {
1855                                                 moldyn->func2b(moldyn,
1856                                                                &(itom[i]),
1857                                                                jtom,
1858                                                                bc_ij);
1859                                         }
1860                                 } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
1861 #endif
1862
1863                         }
1864                 }
1865
1866                 /* 3 body potential/force */
1867
1868                 if(!(itom[i].attr&ATOM_ATTR_3BP))
1869                         continue;
1870
1871                 /* copy the neighbour lists */
1872 #ifdef STATIC_LISTS
1873                 /* no copy needed for static lists */
1874 #else
1875                 memcpy(neighbour_i2,neighbour_i,27*sizeof(t_list));
1876 #endif
1877
1878                 /* second loop over atoms j */
1879                 for(j=0;j<27;j++) {
1880
1881                         bc_ij=(j<dnlc)?0:1;
1882 #ifdef STATIC_LISTS
1883                         p=0;
1884
1885                         while(neighbour_i[j][p]!=0) {
1886
1887                                 jtom=&(atom[neighbour_i[j][p]]);
1888                                 p++;
1889 #else
1890                         this=&(neighbour_i[j]);
1891                         list_reset_f(this);
1892
1893                         if(this->start==NULL)
1894                                 continue;
1895
1896                         do {
1897
1898                                 jtom=this->current->data;
1899 #endif
1900
1901                                 if(jtom==&(itom[i]))
1902                                         continue;
1903
1904                                 if(!(jtom->attr&ATOM_ATTR_3BP))
1905                                         continue;
1906
1907                                 /* reset 3bp run */
1908                                 moldyn->run3bp=1;
1909
1910                                 if(moldyn->func3b_j1)
1911                                         moldyn->func3b_j1(moldyn,
1912                                                           &(itom[i]),
1913                                                           jtom,
1914                                                           bc_ij);
1915
1916                                 /* in first j loop, 3bp run can be skipped */
1917                                 if(!(moldyn->run3bp))
1918                                         continue;
1919                         
1920                                 /* first loop over atoms k */
1921                                 if(moldyn->func3b_k1) {
1922
1923                                 for(k=0;k<27;k++) {
1924
1925                                         bc_ik=(k<dnlc)?0:1;
1926 #ifdef STATIC_LISTS
1927                                         q=0;
1928
1929                                         while(neighbour_i[j][q]!=0) {
1930
1931                                                 ktom=&(atom[neighbour_i[k][q]]);
1932                                                 q++;
1933 #else
1934                                         that=&(neighbour_i2[k]);
1935                                         list_reset_f(that);
1936                                         
1937                                         if(that->start==NULL)
1938                                                 continue;
1939
1940                                         do {
1941                                                 ktom=that->current->data;
1942 #endif
1943
1944                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
1945                                                         continue;
1946
1947                                                 if(ktom==jtom)
1948                                                         continue;
1949
1950                                                 if(ktom==&(itom[i]))
1951                                                         continue;
1952
1953                                                 moldyn->func3b_k1(moldyn,
1954                                                                   &(itom[i]),
1955                                                                   jtom,
1956                                                                   ktom,
1957                                                                   bc_ik|bc_ij);
1958 #ifdef STATIC_LISTS
1959                                         }
1960 #else
1961                                         } while(list_next_f(that)!=\
1962                                                 L_NO_NEXT_ELEMENT);
1963 #endif
1964
1965                                 }
1966
1967                                 }
1968
1969                                 if(moldyn->func3b_j2)
1970                                         moldyn->func3b_j2(moldyn,
1971                                                           &(itom[i]),
1972                                                           jtom,
1973                                                           bc_ij);
1974
1975                                 /* second loop over atoms k */
1976                                 if(moldyn->func3b_k2) {
1977
1978                                 for(k=0;k<27;k++) {
1979
1980                                         bc_ik=(k<dnlc)?0:1;
1981 #ifdef STATIC_LISTS
1982                                         q=0;
1983
1984                                         while(neighbour_i[j][q]!=0) {
1985
1986                                                 ktom=&(atom[neighbour_i[k][q]]);
1987                                                 q++;
1988 #else
1989                                         that=&(neighbour_i2[k]);
1990                                         list_reset_f(that);
1991                                         
1992                                         if(that->start==NULL)
1993                                                 continue;
1994
1995                                         do {
1996                                                 ktom=that->current->data;
1997 #endif
1998
1999                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
2000                                                         continue;
2001
2002                                                 if(ktom==jtom)
2003                                                         continue;
2004
2005                                                 if(ktom==&(itom[i]))
2006                                                         continue;
2007
2008                                                 moldyn->func3b_k2(moldyn,
2009                                                                   &(itom[i]),
2010                                                                   jtom,
2011                                                                   ktom,
2012                                                                   bc_ik|bc_ij);
2013
2014 #ifdef STATIC_LISTS
2015                                         }
2016 #else
2017                                         } while(list_next_f(that)!=\
2018                                                 L_NO_NEXT_ELEMENT);
2019 #endif
2020
2021                                 }
2022                                 
2023                                 }
2024
2025                                 /* 2bp post function */
2026                                 if(moldyn->func3b_j3) {
2027                                         moldyn->func3b_j3(moldyn,
2028                                                           &(itom[i]),
2029                                                           jtom,bc_ij);
2030                                 }
2031 #ifdef STATIC_LISTS
2032                         }
2033 #else
2034                         } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2035 #endif
2036                 
2037                 }
2038                 
2039 #ifdef DEBUG
2040         //printf("\n\n");
2041 #endif
2042 #ifdef VDEBUG
2043         printf("\n\n");
2044 #endif
2045
2046         }
2047
2048 #ifdef DEBUG
2049         //printf("\nATOM 0: %f %f %f\n\n",itom->f.x,itom->f.y,itom->f.z);
2050         if(moldyn->time>DSTART&&moldyn->time<DEND) {
2051                 printf("force:\n");
2052                 printf("  x: %0.40f\n",moldyn->atom[5832].f.x);
2053                 printf("  y: %0.40f\n",moldyn->atom[5832].f.y);
2054                 printf("  z: %0.40f\n",moldyn->atom[5832].f.z);
2055         }
2056 #endif
2057
2058         /* calculate global virial */
2059         for(i=0;i<count;i++) {
2060                 moldyn->gvir.xx+=moldyn->atom[i].r.x*moldyn->atom[i].f.x;
2061                 moldyn->gvir.yy+=moldyn->atom[i].r.y*moldyn->atom[i].f.y;
2062                 moldyn->gvir.zz+=moldyn->atom[i].r.z*moldyn->atom[i].f.z;
2063                 moldyn->gvir.xy+=moldyn->atom[i].r.y*moldyn->atom[i].f.x;
2064                 moldyn->gvir.xz+=moldyn->atom[i].r.z*moldyn->atom[i].f.x;
2065                 moldyn->gvir.yz+=moldyn->atom[i].r.z*moldyn->atom[i].f.y;
2066         }
2067
2068         return 0;
2069 }
2070
2071 /*
2072  * virial calculation
2073  */
2074
2075 //inline int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
2076 int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
2077
2078         a->virial.xx+=f->x*d->x;
2079         a->virial.yy+=f->y*d->y;
2080         a->virial.zz+=f->z*d->z;
2081         a->virial.xy+=f->x*d->y;
2082         a->virial.xz+=f->x*d->z;
2083         a->virial.yz+=f->y*d->z;
2084
2085         return 0;
2086 }
2087
2088 /*
2089  * periodic boundary checking
2090  */
2091
2092 //inline int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
2093 int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
2094         
2095         double x,y,z;
2096         t_3dvec *dim;
2097
2098         dim=&(moldyn->dim);
2099
2100         x=dim->x/2;
2101         y=dim->y/2;
2102         z=dim->z/2;
2103
2104         if(moldyn->status&MOLDYN_STAT_PBX) {
2105                 if(a->x>=x) a->x-=dim->x;
2106                 else if(-a->x>x) a->x+=dim->x;
2107         }
2108         if(moldyn->status&MOLDYN_STAT_PBY) {
2109                 if(a->y>=y) a->y-=dim->y;
2110                 else if(-a->y>y) a->y+=dim->y;
2111         }
2112         if(moldyn->status&MOLDYN_STAT_PBZ) {
2113                 if(a->z>=z) a->z-=dim->z;
2114                 else if(-a->z>z) a->z+=dim->z;
2115         }
2116
2117         return 0;
2118 }
2119         
2120 /*
2121  * debugging / critical check functions
2122  */
2123
2124 int moldyn_bc_check(t_moldyn *moldyn) {
2125
2126         t_atom *atom;
2127         t_3dvec *dim;
2128         int i;
2129         double x;
2130         u8 byte;
2131         int j,k;
2132
2133         atom=moldyn->atom;
2134         dim=&(moldyn->dim);
2135         x=dim->x/2;
2136
2137         for(i=0;i<moldyn->count;i++) {
2138                 if(atom[i].r.x>=dim->x/2||-atom[i].r.x>dim->x/2) {
2139                         printf("FATAL: atom %d: x: %.20f (%.20f)\n",
2140                                i,atom[i].r.x,dim->x/2);
2141                         printf("diagnostic:\n");
2142                         printf("-----------\natom.r.x:\n");
2143                         for(j=0;j<8;j++) {
2144                                 memcpy(&byte,(u8 *)(&(atom[i].r.x))+j,1);
2145                                 for(k=0;k<8;k++)
2146                                         printf("%d%c",
2147                                         ((byte)&(1<<k))?1:0,
2148                                         (k==7)?'\n':'|');
2149                         }
2150                         printf("---------------\nx=dim.x/2:\n");
2151                         for(j=0;j<8;j++) {
2152                                 memcpy(&byte,(u8 *)(&x)+j,1);
2153                                 for(k=0;k<8;k++)
2154                                         printf("%d%c",
2155                                         ((byte)&(1<<k))?1:0,
2156                                         (k==7)?'\n':'|');
2157                         }
2158                         if(atom[i].r.x==x) printf("the same!\n");
2159                         else printf("different!\n");
2160                 }
2161                 if(atom[i].r.y>=dim->y/2||-atom[i].r.y>dim->y/2)
2162                         printf("FATAL: atom %d: y: %.20f (%.20f)\n",
2163                                i,atom[i].r.y,dim->y/2);
2164                 if(atom[i].r.z>=dim->z/2||-atom[i].r.z>dim->z/2)
2165                         printf("FATAL: atom %d: z: %.20f (%.20f)\n",
2166                                i,atom[i].r.z,dim->z/2);
2167         }
2168
2169         return 0;
2170 }
2171
2172 /*
2173  * restore function
2174  */
2175
2176 int moldyn_read_save_file(t_moldyn *moldyn,char *file) {
2177
2178         int fd;
2179         int cnt,size;
2180
2181         fd=open(file,O_RDONLY);
2182         if(fd<0) {
2183                 perror("[moldyn] load save file open");
2184                 return fd;
2185         }
2186
2187         size=sizeof(t_moldyn);
2188
2189         while(size) {
2190                 cnt=read(fd,moldyn,size);
2191                 if(cnt<0) {
2192                         perror("[moldyn] load save file read (moldyn)");
2193                         return cnt;
2194                 }
2195                 size-=cnt;
2196         }
2197
2198         size=moldyn->count*sizeof(t_atom);
2199
2200         moldyn->atom=(t_atom *)malloc(size);
2201         if(moldyn->atom==NULL) {
2202                 perror("[moldyn] load save file malloc (atoms)");
2203                 return -1;
2204         }
2205
2206         while(size) {
2207                 cnt=read(fd,moldyn->atom,size);
2208                 if(cnt<0) {
2209                         perror("[moldyn] load save file read (atoms)");
2210                         return cnt;
2211                 }
2212                 size-=cnt;
2213         }
2214
2215         // hooks etc ...
2216
2217         return 0;
2218 }
2219
2220 int moldyn_load(t_moldyn *moldyn) {
2221
2222         // later ...
2223
2224         return 0;
2225 }
2226
2227 /*
2228  * post processing functions
2229  */
2230
2231 int get_line(int fd,char *line,int max) {
2232
2233         int count,ret;
2234
2235         count=0;
2236
2237         while(1) {
2238                 if(count==max) return count;
2239                 ret=read(fd,line+count,1);
2240                 if(ret<=0) return ret;
2241                 if(line[count]=='\n') {
2242                         line[count]='\0';
2243                         return count+1;
2244                 }
2245                 count+=1;
2246         }
2247 }
2248
2249 int pair_correlation_init(t_moldyn *moldyn,double dr) {
2250
2251         
2252         return 0;
2253 }
2254
2255 int calculate_pair_correlation(t_moldyn *moldyn,double dr,void *ptr) {
2256
2257         int slots;
2258         double *stat;
2259         int i,j;
2260         t_linkcell *lc;
2261 #ifdef STATIC_LISTS
2262         int *neighbour[27];
2263         int p;
2264 #else
2265         t_list neighbour[27];
2266 #endif
2267         t_atom *itom,*jtom;
2268         t_list *this;
2269         unsigned char bc;
2270         t_3dvec dist;
2271         double d;
2272         //double norm;
2273         int o,s;
2274         unsigned char ibrand;
2275
2276         lc=&(moldyn->lc);
2277
2278         slots=moldyn->cutoff/dr;
2279         o=2*slots;
2280
2281         printf("[moldyn] pair correlation calc info:\n");
2282         printf("  time: %f\n",moldyn->time);
2283         printf("  count: %d\n",moldyn->count);
2284         printf("  cutoff: %f\n",moldyn->cutoff);
2285         printf("  temperature: cur=%f avg=%f\n",moldyn->t,moldyn->t_avg);
2286
2287         if(ptr!=NULL) {
2288                 stat=(double *)ptr;
2289         }
2290         else {
2291                 stat=(double *)malloc(3*slots*sizeof(double));
2292                 if(stat==NULL) {
2293                         perror("[moldyn] pair correlation malloc");
2294                         return -1;
2295                 }
2296         }
2297
2298         memset(stat,0,3*slots*sizeof(double));
2299
2300         link_cell_init(moldyn,VERBOSE);
2301
2302         itom=moldyn->atom;
2303         
2304         for(i=0;i<moldyn->count;i++) {
2305                 /* neighbour indexing */
2306                 link_cell_neighbour_index(moldyn,
2307                                           (itom[i].r.x+moldyn->dim.x/2)/lc->x,
2308                                           (itom[i].r.y+moldyn->dim.y/2)/lc->x,
2309                                           (itom[i].r.z+moldyn->dim.z/2)/lc->x,
2310                                           neighbour);
2311
2312                 /* brand of atom i */
2313                 ibrand=itom[i].brand;
2314         
2315                 for(j=0;j<27;j++) {
2316
2317                         bc=(j<lc->dnlc)?0:1;
2318
2319 #ifdef STATIC_LISTS
2320                         p=0;
2321
2322                         while(neighbour[j][p]!=0) {
2323
2324                                 jtom=&(moldyn->atom[neighbour[j][p]]);
2325                                 p++;
2326 #else
2327                         this=&(neighbour[j]);
2328                         list_reset_f(this);
2329
2330                         if(this->start==NULL)
2331                                 continue;
2332
2333                         do {
2334
2335                                 jtom=this->current->data;
2336 #endif
2337                                 /* only count pairs once,
2338                                  * skip same atoms */
2339                                 if(itom[i].tag>=jtom->tag)
2340                                         continue;
2341
2342                                 /*
2343                                  * pair correlation calc
2344                                  */
2345
2346                                 /* distance */
2347                                 v3_sub(&dist,&(jtom->r),&(itom[i].r));
2348                                 if(bc) check_per_bound(moldyn,&dist);
2349                                 d=v3_absolute_square(&dist);
2350
2351                                 /* ignore if greater or equal cutoff */
2352                                 if(d>=moldyn->cutoff_square)
2353                                         continue;
2354
2355                                 /* fill the slots */
2356                                 d=sqrt(d);
2357                                 s=(int)(d/dr);
2358
2359                                 /* should never happen but it does 8) -
2360                                  * related to -ffloat-store problem! */
2361                                 if(s>=slots) s=slots-1;
2362
2363                                 if(ibrand!=jtom->brand) {
2364                                         /* mixed */
2365                                         stat[s]+=1;
2366                                 }
2367                                 else {
2368                                         /* type a - type a bonds */
2369                                         if(ibrand==0)
2370                                                 stat[s+slots]+=1;
2371                                         else
2372                                         /* type b - type b bonds */
2373                                                 stat[s+o]+=1;
2374                                 }
2375 #ifdef STATIC_LISTS
2376                         }
2377 #else
2378                         } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2379 #endif
2380                 }
2381         }
2382
2383         /* normalization 
2384         for(i=1;i<slots;i++) {
2385                  // normalization: 4 pi r r dr
2386                  // here: not double counting pairs -> 2 pi r r dr
2387                 norm=2*M_PI*moldyn->count*(i*dr*i*dr)*dr;
2388                 stat[i]/=norm;
2389                 stat[slots+i]/=norm;
2390                 stat[o+i]/=norm;
2391         }
2392         */
2393
2394         if(ptr==NULL) {
2395                 /* todo: store/print pair correlation function */
2396                 free(stat);
2397         }
2398
2399         free(moldyn->atom);
2400
2401         link_cell_shutdown(moldyn);
2402
2403         return 0;
2404 }
2405
2406 int analyze_bonds(t_moldyn *moldyn) {
2407
2408         
2409         
2410
2411         return 0;
2412 }
2413
2414 /*
2415  * visualization code
2416  */
2417
2418 int visual_init(t_moldyn *moldyn,char *filebase) {
2419
2420         strncpy(moldyn->vis.fb,filebase,128);
2421
2422         return 0;
2423 }
2424
2425 int visual_atoms(t_moldyn *moldyn) {
2426
2427         int i,j,fd;
2428         char file[128+64];
2429         t_3dvec dim;
2430         double help;
2431         t_visual *v;
2432         t_atom *atom;
2433         t_atom *btom;
2434         t_linkcell *lc;
2435 #ifdef STATIC_LISTS
2436         int *neighbour[27];
2437         int p;
2438 #else
2439         t_list neighbour[27];
2440 #endif
2441         u8 bc;
2442         t_3dvec dist;
2443         double d2;
2444         u8 brand;
2445
2446         v=&(moldyn->vis);
2447         dim.x=v->dim.x;
2448         dim.y=v->dim.y;
2449         dim.z=v->dim.z;
2450         atom=moldyn->atom;
2451         lc=&(moldyn->lc);
2452
2453         help=(dim.x+dim.y);
2454
2455         sprintf(file,"%s/atomic_conf_%07.f.xyz",v->fb,moldyn->time);
2456         fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
2457         if(fd<0) {
2458                 perror("open visual save file fd");
2459                 return -1;
2460         }
2461
2462         /* write the actual data file */
2463
2464         // povray header
2465         dprintf(fd,"# [P] %d %07.f <%f,%f,%f>\n",
2466                 moldyn->count,moldyn->time,help/40.0,help/40.0,-0.8*help);
2467
2468         // atomic configuration
2469         for(i=0;i<moldyn->count;i++) {
2470                 // atom type, positions, color and kinetic energy
2471                 dprintf(fd,"%s %f %f %f %s %f\n",pse_name[atom[i].element],
2472                                                  atom[i].r.x,
2473                                                  atom[i].r.y,
2474                                                  atom[i].r.z,
2475                                                  pse_col[atom[i].element],
2476                                                  atom[i].ekin);
2477
2478                 /*
2479                  * bond detection should usually be done by potential
2480                  * functions. brrrrr! EVIL!
2481                  * 
2482                  * todo: potentials need to export a 'find_bonds' function!
2483                  */
2484
2485                 // bonds between atoms
2486                 if(!(atom[i].attr&ATOM_ATTR_VB))
2487                         continue;
2488                 link_cell_neighbour_index(moldyn,
2489                                           (atom[i].r.x+moldyn->dim.x/2)/lc->x,
2490                                           (atom[i].r.y+moldyn->dim.y/2)/lc->y,
2491                                           (atom[i].r.z+moldyn->dim.z/2)/lc->z,
2492                                           neighbour);
2493                 for(j=0;j<27;j++) {
2494                         bc=j<lc->dnlc?0:1;
2495 #ifdef STATIC_LISTS
2496                         p=0;
2497                         while(neighbour[j][p]!=0) {
2498                                 btom=&(atom[neighbour[j][p]]);
2499                                 p++;
2500 #else
2501                         list_reset_f(&neighbour[j]);
2502                         if(neighbour[j].start==NULL)
2503                                 continue;
2504                         do {
2505                                 btom=neighbour[j].current->data;
2506 #endif
2507                                 if(btom==&atom[i])      // skip identical atoms
2508                                         continue;
2509                                 //if(btom<&atom[i])     // skip half of them
2510                                 //      continue;
2511                                 v3_sub(&dist,&(atom[i].r),&(btom->r));
2512                                 if(bc) check_per_bound(moldyn,&dist);
2513                                 d2=v3_absolute_square(&dist);
2514                                 brand=atom[i].brand;
2515                                 if(brand==btom->brand) {
2516                                         if(d2>moldyn->bondlen[brand])
2517                                                 continue;
2518                                 }
2519                                 else {
2520                                         if(d2>moldyn->bondlen[2])
2521                                                 continue;
2522                                 }
2523                                 dprintf(fd,"# [B] %f %f %f %f %f %f\n",
2524                                         atom[i].r.x,atom[i].r.y,atom[i].r.z,
2525                                         btom->r.x,btom->r.y,btom->r.z);
2526 #ifdef STATIC_LISTS
2527                         }
2528 #else
2529                         } while(list_next_f(&neighbour[j])!=L_NO_NEXT_ELEMENT);
2530 #endif
2531                 }
2532         }
2533
2534         // boundaries
2535         if(dim.x) {
2536                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2537                         -dim.x/2,-dim.y/2,-dim.z/2,
2538                         dim.x/2,-dim.y/2,-dim.z/2);
2539                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2540                         -dim.x/2,-dim.y/2,-dim.z/2,
2541                         -dim.x/2,dim.y/2,-dim.z/2);
2542                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2543                         dim.x/2,dim.y/2,-dim.z/2,
2544                         dim.x/2,-dim.y/2,-dim.z/2);
2545                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2546                         -dim.x/2,dim.y/2,-dim.z/2,
2547                         dim.x/2,dim.y/2,-dim.z/2);
2548
2549                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2550                         -dim.x/2,-dim.y/2,dim.z/2,
2551                         dim.x/2,-dim.y/2,dim.z/2);
2552                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2553                         -dim.x/2,-dim.y/2,dim.z/2,
2554                         -dim.x/2,dim.y/2,dim.z/2);
2555                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2556                         dim.x/2,dim.y/2,dim.z/2,
2557                         dim.x/2,-dim.y/2,dim.z/2);
2558                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2559                         -dim.x/2,dim.y/2,dim.z/2,
2560                         dim.x/2,dim.y/2,dim.z/2);
2561
2562                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2563                         -dim.x/2,-dim.y/2,dim.z/2,
2564                         -dim.x/2,-dim.y/2,-dim.z/2);
2565                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2566                         -dim.x/2,dim.y/2,dim.z/2,
2567                         -dim.x/2,dim.y/2,-dim.z/2);
2568                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2569                         dim.x/2,-dim.y/2,dim.z/2,
2570                         dim.x/2,-dim.y/2,-dim.z/2);
2571                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2572                         dim.x/2,dim.y/2,dim.z/2,
2573                         dim.x/2,dim.y/2,-dim.z/2);
2574         }
2575
2576         close(fd);
2577
2578         return 0;
2579 }
2580