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