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