incorporated visual functions to moldyn api
[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_temperature(t_moldyn *moldyn,double t_ref) {
130
131         moldyn->t_ref=t_ref;
132
133         printf("[moldyn] temperature [K]: %f\n",moldyn->t_ref);
134
135         return 0;
136 }
137
138 int set_pressure(t_moldyn *moldyn,double p_ref) {
139
140         moldyn->p_ref=p_ref;
141
142         printf("[moldyn] pressure [bar]: %f\n",moldyn->p_ref/BAR);
143
144         return 0;
145 }
146
147 int set_pt_scale(t_moldyn *moldyn,u8 ptype,double ptc,u8 ttype,double ttc) {
148
149         moldyn->pt_scale=(ptype|ttype);
150         moldyn->t_tc=ttc;
151         moldyn->p_tc=ptc;
152
153         printf("[moldyn] p/t scaling:\n");
154
155         printf("  p: %s",ptype?"yes":"no ");
156         if(ptype)
157                 printf(" | type: %02x | factor: %f",ptype,ptc);
158         printf("\n");
159
160         printf("  t: %s",ttype?"yes":"no ");
161         if(ttype)
162                 printf(" | type: %02x | factor: %f",ttype,ttc);
163         printf("\n");
164
165         return 0;
166 }
167
168 int set_dim(t_moldyn *moldyn,double x,double y,double z,u8 visualize) {
169
170         moldyn->dim.x=x;
171         moldyn->dim.y=y;
172         moldyn->dim.z=z;
173
174         moldyn->volume=x*y*z;
175
176         if(visualize) {
177                 moldyn->vis.dim.x=x;
178                 moldyn->vis.dim.y=y;
179                 moldyn->vis.dim.z=z;
180         }
181
182         moldyn->dv=0.000001*moldyn->volume;
183
184         printf("[moldyn] dimensions in A and A^3 respectively:\n");
185         printf("  x: %f\n",moldyn->dim.x);
186         printf("  y: %f\n",moldyn->dim.y);
187         printf("  z: %f\n",moldyn->dim.z);
188         printf("  volume: %f\n",moldyn->volume);
189         printf("  visualize simulation box: %s\n",visualize?"yes":"no");
190         printf("  delta volume (pressure calc): %f\n",moldyn->dv);
191
192         return 0;
193 }
194
195 int set_nn_dist(t_moldyn *moldyn,double dist) {
196
197         moldyn->nnd=dist;
198
199         return 0;
200 }
201
202 int set_pbc(t_moldyn *moldyn,u8 x,u8 y,u8 z) {
203
204         printf("[moldyn] periodic boundary conditions:\n");
205
206         if(x)
207                 moldyn->status|=MOLDYN_STAT_PBX;
208
209         if(y)
210                 moldyn->status|=MOLDYN_STAT_PBY;
211
212         if(z)
213                 moldyn->status|=MOLDYN_STAT_PBZ;
214
215         printf("  x: %s\n",x?"yes":"no");
216         printf("  y: %s\n",y?"yes":"no");
217         printf("  z: %s\n",z?"yes":"no");
218
219         return 0;
220 }
221
222 int set_potential1b(t_moldyn *moldyn,pf_func1b func) {
223
224         moldyn->func1b=func;
225
226         return 0;
227 }
228
229 int set_potential2b(t_moldyn *moldyn,pf_func2b func) {
230
231         moldyn->func2b=func;
232
233         return 0;
234 }
235
236 int set_potential3b_j1(t_moldyn *moldyn,pf_func2b func) {
237
238         moldyn->func3b_j1=func;
239
240         return 0;
241 }
242
243 int set_potential3b_j2(t_moldyn *moldyn,pf_func2b func) {
244
245         moldyn->func3b_j2=func;
246
247         return 0;
248 }
249
250 int set_potential3b_j3(t_moldyn *moldyn,pf_func2b func) {
251
252         moldyn->func3b_j3=func;
253
254         return 0;
255 }
256
257 int set_potential3b_k1(t_moldyn *moldyn,pf_func3b func) {
258
259         moldyn->func3b_k1=func;
260
261         return 0;
262 }
263
264 int set_potential3b_k2(t_moldyn *moldyn,pf_func3b func) {
265
266         moldyn->func3b_k2=func;
267
268         return 0;
269 }
270
271 int set_potential_params(t_moldyn *moldyn,void *params) {
272
273         moldyn->pot_params=params;
274
275         return 0;
276 }
277
278 int set_avg_skip(t_moldyn *moldyn,int skip) {
279
280         printf("[moldyn] skip %d steps before starting average calc\n",skip);
281         moldyn->avg_skip=skip;
282
283         return 0;
284 }
285
286 int moldyn_set_log_dir(t_moldyn *moldyn,char *dir) {
287
288         strncpy(moldyn->vlsdir,dir,127);
289
290         return 0;
291 }
292
293 int moldyn_set_report(t_moldyn *moldyn,char *author,char *title) {
294
295         strncpy(moldyn->rauthor,author,63);
296         strncpy(moldyn->rtitle,title,63);
297
298         return 0;
299 }
300         
301 int moldyn_set_log(t_moldyn *moldyn,u8 type,int timer) {
302
303         char filename[128];
304         int ret;
305
306         printf("[moldyn] set log: ");
307
308         switch(type) {
309                 case LOG_TOTAL_ENERGY:
310                         moldyn->ewrite=timer;
311                         snprintf(filename,127,"%s/energy",moldyn->vlsdir);
312                         moldyn->efd=open(filename,
313                                          O_WRONLY|O_CREAT|O_EXCL,
314                                          S_IRUSR|S_IWUSR);
315                         if(moldyn->efd<0) {
316                                 perror("[moldyn] energy log fd open");
317                                 return moldyn->efd;
318                         }
319                         dprintf(moldyn->efd,"# total energy log file\n");
320                         printf("total energy (%d)\n",timer);
321                         break;
322                 case LOG_TOTAL_MOMENTUM:
323                         moldyn->mwrite=timer;
324                         snprintf(filename,127,"%s/momentum",moldyn->vlsdir);
325                         moldyn->mfd=open(filename,
326                                          O_WRONLY|O_CREAT|O_EXCL,
327                                          S_IRUSR|S_IWUSR);
328                         if(moldyn->mfd<0) {
329                                 perror("[moldyn] momentum log fd open");
330                                 return moldyn->mfd;
331                         }
332                         dprintf(moldyn->efd,"# total momentum log file\n");
333                         printf("total momentum (%d)\n",timer);
334                         break;
335                 case LOG_PRESSURE:
336                         moldyn->pwrite=timer;
337                         snprintf(filename,127,"%s/pressure",moldyn->vlsdir);
338                         moldyn->pfd=open(filename,
339                                          O_WRONLY|O_CREAT|O_EXCL,
340                                          S_IRUSR|S_IWUSR);
341                         if(moldyn->pfd<0) {
342                                 perror("[moldyn] pressure log file\n");
343                                 return moldyn->pfd;
344                         }
345                         dprintf(moldyn->pfd,"# pressure log file\n");
346                         printf("pressure (%d)\n",timer);
347                         break;
348                 case LOG_TEMPERATURE:
349                         moldyn->twrite=timer;
350                         snprintf(filename,127,"%s/temperature",moldyn->vlsdir);
351                         moldyn->tfd=open(filename,
352                                          O_WRONLY|O_CREAT|O_EXCL,
353                                          S_IRUSR|S_IWUSR);
354                         if(moldyn->tfd<0) {
355                                 perror("[moldyn] temperature log file\n");
356                                 return moldyn->tfd;
357                         }
358                         dprintf(moldyn->tfd,"# temperature log file\n");
359                         printf("temperature (%d)\n",timer);
360                         break;
361                 case SAVE_STEP:
362                         moldyn->swrite=timer;
363                         printf("save file (%d)\n",timer);
364                         break;
365                 case VISUAL_STEP:
366                         moldyn->vwrite=timer;
367                         ret=visual_init(&(moldyn->vis),moldyn->vlsdir);
368                         if(ret<0) {
369                                 printf("[moldyn] visual init failure\n");
370                                 return ret;
371                         }
372                         printf("visual file (%d)\n",timer);
373                         break;
374                 case CREATE_REPORT:
375                         snprintf(filename,127,"%s/report.tex",moldyn->vlsdir);
376                         moldyn->rfd=open(filename,
377                                          O_WRONLY|O_CREAT|O_EXCL,
378                                          S_IRUSR|S_IWUSR);
379                         if(moldyn->rfd<0) {
380                                 perror("[moldyn] report fd open");      
381                                 return moldyn->rfd;
382                         }
383                         printf("report -> ");
384                         if(moldyn->efd) {
385                                 snprintf(filename,127,"%s/e_plot.scr",
386                                          moldyn->vlsdir);
387                                 moldyn->epfd=open(filename,
388                                                  O_WRONLY|O_CREAT|O_EXCL,
389                                                  S_IRUSR|S_IWUSR);
390                                 if(moldyn->epfd<0) {
391                                         perror("[moldyn] energy plot fd open");
392                                         return moldyn->epfd;
393                                 }
394                                 dprintf(moldyn->epfd,e_plot_script);
395                                 close(moldyn->epfd);
396                                 printf("energy ");
397                         }
398                         if(moldyn->pfd) {
399                                 snprintf(filename,127,"%s/pressure_plot.scr",
400                                          moldyn->vlsdir);
401                                 moldyn->ppfd=open(filename,
402                                                   O_WRONLY|O_CREAT|O_EXCL,
403                                                   S_IRUSR|S_IWUSR);
404                                 if(moldyn->ppfd<0) {
405                                         perror("[moldyn] p plot fd open");
406                                         return moldyn->ppfd;
407                                 }
408                                 dprintf(moldyn->ppfd,pressure_plot_script);
409                                 close(moldyn->ppfd);
410                                 printf("pressure ");
411                         }
412                         if(moldyn->tfd) {
413                                 snprintf(filename,127,"%s/temperature_plot.scr",
414                                          moldyn->vlsdir);
415                                 moldyn->tpfd=open(filename,
416                                                   O_WRONLY|O_CREAT|O_EXCL,
417                                                   S_IRUSR|S_IWUSR);
418                                 if(moldyn->tpfd<0) {
419                                         perror("[moldyn] t plot fd open");
420                                         return moldyn->tpfd;
421                                 }
422                                 dprintf(moldyn->tpfd,temperature_plot_script);
423                                 close(moldyn->tpfd);
424                                 printf("temperature ");
425                         }
426                         dprintf(moldyn->rfd,report_start,
427                                 moldyn->rauthor,moldyn->rtitle);
428                         printf("\n");
429                         break;
430                 default:
431                         printf("unknown log type: %02x\n",type);
432                         return -1;
433         }
434
435         return 0;
436 }
437
438 int moldyn_log_shutdown(t_moldyn *moldyn) {
439
440         char sc[256];
441
442         printf("[moldyn] log shutdown\n");
443         if(moldyn->efd) {
444                 close(moldyn->efd);
445                 if(moldyn->rfd) {
446                         dprintf(moldyn->rfd,report_energy);
447                         snprintf(sc,255,"cd %s && gnuplot e_plot.scr",
448                                  moldyn->vlsdir);
449                         system(sc);
450                 }
451         }
452         if(moldyn->mfd) close(moldyn->mfd);
453         if(moldyn->pfd) {
454                 close(moldyn->pfd);
455                 if(moldyn->rfd)
456                         dprintf(moldyn->rfd,report_pressure);
457                         snprintf(sc,255,"cd %s && gnuplot pressure_plot.scr",
458                                  moldyn->vlsdir);
459                         system(sc);
460         }
461         if(moldyn->tfd) {
462                 close(moldyn->tfd);
463                 if(moldyn->rfd)
464                         dprintf(moldyn->rfd,report_temperature);
465                         snprintf(sc,255,"cd %s && gnuplot temperature_plot.scr",
466                                  moldyn->vlsdir);
467                         system(sc);
468         }
469         if(moldyn->rfd) {
470                 dprintf(moldyn->rfd,report_end);
471                 close(moldyn->rfd);
472                 snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1",
473                          moldyn->vlsdir);
474                 system(sc);
475                 snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1",
476                          moldyn->vlsdir);
477                 system(sc);
478                 snprintf(sc,255,"cd %s && dvipdf report >/dev/null 2>&1",
479                          moldyn->vlsdir);
480                 system(sc);
481         }
482
483         return 0;
484 }
485
486 /*
487  * creating lattice functions
488  */
489
490 int create_lattice(t_moldyn *moldyn,u8 type,double lc,int element,double mass,
491                    u8 attr,u8 brand,int a,int b,int c,t_3dvec *origin) {
492
493         int new,count;
494         int ret;
495         t_3dvec orig;
496         void *ptr;
497         t_atom *atom;
498
499         new=a*b*c;
500         count=moldyn->count;
501
502         /* how many atoms do we expect */
503         if(type==CUBIC) new*=1;
504         if(type==FCC) new*=4;
505         if(type==DIAMOND) new*=8;
506
507         /* allocate space for atoms */
508         ptr=realloc(moldyn->atom,(count+new)*sizeof(t_atom));
509         if(!ptr) {
510                 perror("[moldyn] realloc (create lattice)");
511                 return -1;
512         }
513         moldyn->atom=ptr;
514         atom=&(moldyn->atom[count]);
515
516         /* no atoms on the boundaries (only reason: it looks better!) */
517         if(!origin) {
518                 orig.x=0.5*lc;
519                 orig.y=0.5*lc;
520                 orig.z=0.5*lc;
521         }
522         else {
523                 orig.x=origin->x;
524                 orig.y=origin->y;
525                 orig.z=origin->z;
526         }
527
528         switch(type) {
529                 case CUBIC:
530                         set_nn_dist(moldyn,lc);
531                         ret=cubic_init(a,b,c,lc,atom,&orig);
532                         break;
533                 case FCC:
534                         if(!origin)
535                                 v3_scale(&orig,&orig,0.5);
536                         set_nn_dist(moldyn,0.5*sqrt(2.0)*lc);
537                         ret=fcc_init(a,b,c,lc,atom,&orig);
538                         break;
539                 case DIAMOND:
540                         if(!origin)
541                                 v3_scale(&orig,&orig,0.25);
542                         set_nn_dist(moldyn,0.25*sqrt(3.0)*lc);
543                         ret=diamond_init(a,b,c,lc,atom,&orig);
544                         break;
545                 default:
546                         printf("unknown lattice type (%02x)\n",type);
547                         return -1;
548         }
549
550         /* debug */
551         if(ret!=new) {
552                 printf("[moldyn] creating lattice failed\n");
553                 printf("  amount of atoms\n");
554                 printf("  - expected: %d\n",new);
555                 printf("  - created: %d\n",ret);
556                 return -1;
557         }
558
559         moldyn->count+=new;
560         printf("[moldyn] created lattice with %d atoms\n",new);
561
562         for(ret=0;ret<new;ret++) {
563                 atom[ret].element=element;
564                 atom[ret].mass=mass;
565                 atom[ret].attr=attr;
566                 atom[ret].brand=brand;
567                 atom[ret].tag=count+ret;
568                 check_per_bound(moldyn,&(atom[ret].r));
569                 atom[ret].r_0=atom[ret].r;
570         }
571
572         /* update total system mass */
573         total_mass_calc(moldyn);
574
575         return ret;
576 }
577
578 int add_atom(t_moldyn *moldyn,int element,double mass,u8 brand,u8 attr,
579              t_3dvec *r,t_3dvec *v) {
580
581         t_atom *atom;
582         void *ptr;
583         int count;
584         
585         atom=moldyn->atom;
586         count=(moldyn->count)++;
587
588         ptr=realloc(atom,(count+1)*sizeof(t_atom));
589         if(!ptr) {
590                 perror("[moldyn] realloc (add atom)");
591                 return -1;
592         }
593         moldyn->atom=ptr;
594
595         atom=moldyn->atom;
596         atom[count].r=*r;
597         atom[count].v=*v;
598         atom[count].element=element;
599         atom[count].mass=mass;
600         atom[count].brand=brand;
601         atom[count].tag=count;
602         atom[count].attr=attr;
603         check_per_bound(moldyn,&(atom[count].r));
604         atom[count].r_0=atom[count].r;
605
606         /* update total system mass */
607         total_mass_calc(moldyn);
608
609         return 0;
610 }
611
612 int del_atom(t_moldyn *moldyn,int tag) {
613
614         t_atom *new,*old;
615         int cnt;
616
617         old=moldyn->atom;
618
619         new=(t_atom *)malloc((moldyn->count-1)*sizeof(t_atom));
620         if(!new) {
621                 perror("[moldyn]malloc (del atom)");
622                 return -1;
623         }
624
625         for(cnt=0;cnt<tag;cnt++)
626                 new[cnt]=old[cnt];
627         
628         for(cnt=tag+1;cnt<moldyn->count;cnt++) {
629                 new[cnt-1]=old[cnt];
630                 new[cnt-1].tag=cnt-1;
631         }
632
633         moldyn->count-=1;
634         moldyn->atom=new;
635
636         free(old);
637
638         return 0;
639 }
640
641 /* cubic init */
642 int cubic_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
643
644         int count;
645         t_3dvec r;
646         int i,j,k;
647         t_3dvec o;
648
649         count=0;
650         if(origin)
651                 v3_copy(&o,origin);
652         else
653                 v3_zero(&o);
654
655         r.x=o.x;
656         for(i=0;i<a;i++) {
657                 r.y=o.y;
658                 for(j=0;j<b;j++) {
659                         r.z=o.z;
660                         for(k=0;k<c;k++) {
661                                 v3_copy(&(atom[count].r),&r);
662                                 count+=1;
663                                 r.z+=lc;
664                         }
665                         r.y+=lc;
666                 }
667                 r.x+=lc;
668         }
669
670         for(i=0;i<count;i++) {
671                 atom[i].r.x-=(a*lc)/2.0;
672                 atom[i].r.y-=(b*lc)/2.0;
673                 atom[i].r.z-=(c*lc)/2.0;
674         }
675
676         return count;
677 }
678
679 /* fcc lattice init */
680 int fcc_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
681
682         int count;
683         int i,j,k,l;
684         t_3dvec o,r,n;
685         t_3dvec basis[3];
686
687         count=0;
688         if(origin)
689                 v3_copy(&o,origin);
690         else
691                 v3_zero(&o);
692
693         /* construct the basis */
694         memset(basis,0,3*sizeof(t_3dvec));
695         basis[0].x=0.5*lc;
696         basis[0].y=0.5*lc;
697         basis[1].x=0.5*lc;
698         basis[1].z=0.5*lc;
699         basis[2].y=0.5*lc;
700         basis[2].z=0.5*lc;
701
702         /* fill up the room */
703         r.x=o.x;
704         for(i=0;i<a;i++) {
705                 r.y=o.y;
706                 for(j=0;j<b;j++) {
707                         r.z=o.z;
708                         for(k=0;k<c;k++) {
709                                 /* first atom */
710                                 v3_copy(&(atom[count].r),&r);
711                                 count+=1;
712                                 r.z+=lc;
713                                 /* the three face centered atoms */
714                                 for(l=0;l<3;l++) {
715                                         v3_add(&n,&r,&basis[l]);
716                                         v3_copy(&(atom[count].r),&n);
717                                         count+=1;
718                                 }
719                         }
720                         r.y+=lc;
721                 }
722                 r.x+=lc;
723         }
724                                 
725         /* coordinate transformation */
726         for(i=0;i<count;i++) {
727                 atom[i].r.x-=(a*lc)/2.0;
728                 atom[i].r.y-=(b*lc)/2.0;
729                 atom[i].r.z-=(c*lc)/2.0;
730         }
731
732         return count;
733 }
734
735 int diamond_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin) {
736
737         int count;
738         t_3dvec o;
739
740         count=fcc_init(a,b,c,lc,atom,origin);
741
742         o.x=0.25*lc;
743         o.y=0.25*lc;
744         o.z=0.25*lc;
745
746         if(origin) v3_add(&o,&o,origin);
747
748         count+=fcc_init(a,b,c,lc,&atom[count],&o);
749
750         return count;
751 }
752
753 int destroy_atoms(t_moldyn *moldyn) {
754
755         if(moldyn->atom) free(moldyn->atom);
756
757         return 0;
758 }
759
760 int thermal_init(t_moldyn *moldyn,u8 equi_init) {
761
762         /*
763          * - gaussian distribution of velocities
764          * - zero total momentum
765          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
766          */
767
768         int i;
769         double v,sigma;
770         t_3dvec p_total,delta;
771         t_atom *atom;
772         t_random *random;
773
774         atom=moldyn->atom;
775         random=&(moldyn->random);
776
777         printf("[moldyn] thermal init (equi init: %s)\n",equi_init?"yes":"no");
778
779         /* gaussian distribution of velocities */
780         v3_zero(&p_total);
781         for(i=0;i<moldyn->count;i++) {
782                 sigma=sqrt(2.0*K_BOLTZMANN*moldyn->t_ref/atom[i].mass);
783                 /* x direction */
784                 v=sigma*rand_get_gauss(random);
785                 atom[i].v.x=v;
786                 p_total.x+=atom[i].mass*v;
787                 /* y direction */
788                 v=sigma*rand_get_gauss(random);
789                 atom[i].v.y=v;
790                 p_total.y+=atom[i].mass*v;
791                 /* z direction */
792                 v=sigma*rand_get_gauss(random);
793                 atom[i].v.z=v;
794                 p_total.z+=atom[i].mass*v;
795         }
796
797         /* zero total momentum */
798         v3_scale(&p_total,&p_total,1.0/moldyn->count);
799         for(i=0;i<moldyn->count;i++) {
800                 v3_scale(&delta,&p_total,1.0/atom[i].mass);
801                 v3_sub(&(atom[i].v),&(atom[i].v),&delta);
802         }
803
804         /* velocity scaling */
805         scale_velocity(moldyn,equi_init);
806
807         return 0;
808 }
809
810 double total_mass_calc(t_moldyn *moldyn) {
811
812         int i;
813
814         moldyn->mass=0.0;
815
816         for(i=0;i<moldyn->count;i++)
817                 moldyn->mass+=moldyn->atom[i].mass;
818
819         return moldyn->mass;
820 }
821
822 double temperature_calc(t_moldyn *moldyn) {
823
824         /* assume up to date kinetic energy, which is 3/2 N k_B T */
825
826         moldyn->t=(2.0*moldyn->ekin)/(3.0*K_BOLTZMANN*moldyn->count);
827
828         return moldyn->t;
829 }
830
831 double get_temperature(t_moldyn *moldyn) {
832
833         return moldyn->t;
834 }
835
836 int scale_velocity(t_moldyn *moldyn,u8 equi_init) {
837
838         int i;
839         double e,scale;
840         t_atom *atom;
841         int count;
842
843         atom=moldyn->atom;
844
845         /*
846          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
847          */
848
849         /* get kinetic energy / temperature & count involved atoms */
850         e=0.0;
851         count=0;
852         for(i=0;i<moldyn->count;i++) {
853                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB)) {
854                         e+=atom[i].mass*v3_absolute_square(&(atom[i].v));
855                         count+=1;
856                 }
857         }
858         e*=0.5;
859         if(count!=0) moldyn->t=e/(1.5*count*K_BOLTZMANN);
860         else return 0;  /* no atoms involved in scaling! */
861         
862         /* (temporary) hack for e,t = 0 */
863         if(e==0.0) {
864         moldyn->t=0.0;
865                 if(moldyn->t_ref!=0.0) {
866                         thermal_init(moldyn,equi_init);
867                         return 0;
868                 }
869                 else
870                         return 0; /* no scaling needed */
871         }
872
873
874         /* get scaling factor */
875         scale=moldyn->t_ref/moldyn->t;
876         if(equi_init&TRUE)
877                 scale*=2.0;
878         else
879                 if(moldyn->pt_scale&T_SCALE_BERENDSEN)
880                         scale=1.0+(scale-1.0)/moldyn->t_tc;
881         scale=sqrt(scale);
882
883         /* velocity scaling */
884         for(i=0;i<moldyn->count;i++) {
885                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB))
886                         v3_scale(&(atom[i].v),&(atom[i].v),scale);
887         }
888
889         return 0;
890 }
891
892 double ideal_gas_law_pressure(t_moldyn *moldyn) {
893
894         double p;
895
896         p=moldyn->count*moldyn->t*K_BOLTZMANN/moldyn->volume;
897
898         return p;
899 }
900
901 double virial_sum(t_moldyn *moldyn) {
902
903         int i;
904         double v;
905         t_virial *virial;
906
907         /* virial (sum over atom virials) */
908         v=0.0;
909         for(i=0;i<moldyn->count;i++) {
910                 virial=&(moldyn->atom[i].virial);
911                 v+=(virial->xx+virial->yy+virial->zz);
912         }
913         moldyn->virial=v;
914
915         /* global virial (absolute coordinates) */
916         virial=&(moldyn->gvir);
917         moldyn->gv=virial->xx+virial->yy+virial->zz;
918
919         return moldyn->virial;
920 }
921
922 double pressure_calc(t_moldyn *moldyn) {
923
924         /*
925          * PV = NkT + <W>
926          * with W = 1/3 sum_i f_i r_i (- skipped!)
927          * virial = sum_i f_i r_i
928          * 
929          * => P = (2 Ekin + virial) / (3V)
930          */
931
932         /* assume up to date virial & up to date kinetic energy */
933
934         /* pressure (atom virials) */
935         moldyn->p=2.0*moldyn->ekin+moldyn->virial;
936         moldyn->p/=(3.0*moldyn->volume);
937
938         /* pressure (absolute coordinates) */
939         moldyn->gp=2.0*moldyn->ekin+moldyn->gv;
940         moldyn->gp/=(3.0*moldyn->volume);
941
942         return moldyn->p;
943 }
944
945 int average_and_fluctuation_calc(t_moldyn *moldyn) {
946
947         if(moldyn->total_steps<moldyn->avg_skip)
948                 return 0;
949
950         int denom=moldyn->total_steps+1-moldyn->avg_skip;
951
952         /* assume up to date energies, temperature, pressure etc */
953
954         /* kinetic energy */
955         moldyn->k_sum+=moldyn->ekin;
956         moldyn->k2_sum+=(moldyn->ekin*moldyn->ekin);
957         moldyn->k_avg=moldyn->k_sum/denom;
958         moldyn->k2_avg=moldyn->k2_sum/denom;
959         moldyn->dk2_avg=moldyn->k2_avg-(moldyn->k_avg*moldyn->k_avg);
960
961         /* potential energy */
962         moldyn->v_sum+=moldyn->energy;
963         moldyn->v2_sum+=(moldyn->energy*moldyn->energy);
964         moldyn->v_avg=moldyn->v_sum/denom;
965         moldyn->v2_avg=moldyn->v2_sum/denom;
966         moldyn->dv2_avg=moldyn->v2_avg-(moldyn->v_avg*moldyn->v_avg);
967
968         /* temperature */
969         moldyn->t_sum+=moldyn->t;
970         moldyn->t_avg=moldyn->t_sum/denom;
971
972         /* virial */
973         moldyn->virial_sum+=moldyn->virial;
974         moldyn->virial_avg=moldyn->virial_sum/denom;
975         moldyn->gv_sum+=moldyn->gv;
976         moldyn->gv_avg=moldyn->gv_sum/denom;
977
978         /* pressure */
979         moldyn->p_sum+=moldyn->p;
980         moldyn->p_avg=moldyn->p_sum/denom;
981         moldyn->gp_sum+=moldyn->gp;
982         moldyn->gp_avg=moldyn->gp_sum/denom;
983
984         return 0;
985 }
986
987 int get_heat_capacity(t_moldyn *moldyn) {
988
989         double temp2,ighc;
990
991         /* averages needed for heat capacity calc */
992         if(moldyn->total_steps<moldyn->avg_skip)
993                 return 0;
994
995         /* (temperature average)^2 */
996         temp2=moldyn->t_avg*moldyn->t_avg;
997         printf("[moldyn] specific heat capacity for T=%f K [J/(kg K)]\n",
998                moldyn->t_avg);
999
1000         /* ideal gas contribution */
1001         ighc=3.0*moldyn->count*K_BOLTZMANN/2.0;
1002         printf("  ideal gas contribution: %f\n",
1003                ighc/moldyn->mass*KILOGRAM/JOULE);
1004
1005         /* specific heat for nvt ensemble */
1006         moldyn->c_v_nvt=moldyn->dv2_avg/(K_BOLTZMANN*temp2)+ighc;
1007         moldyn->c_v_nvt/=moldyn->mass;
1008
1009         /* specific heat for nve ensemble */
1010         moldyn->c_v_nve=ighc/(1.0-(moldyn->dv2_avg/(ighc*K_BOLTZMANN*temp2)));
1011         moldyn->c_v_nve/=moldyn->mass;
1012
1013         printf("  NVE: %f\n",moldyn->c_v_nve*KILOGRAM/JOULE);
1014         printf("  NVT: %f\n",moldyn->c_v_nvt*KILOGRAM/JOULE);
1015 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)));
1016
1017         return 0;
1018 }
1019
1020 double thermodynamic_pressure_calc(t_moldyn *moldyn) {
1021
1022         t_3dvec dim,*tp;
1023         double u_up,u_down,dv;
1024         double scale,p;
1025         t_atom *store;
1026
1027         /*
1028          * dU = - p dV
1029          *
1030          * => p = - dU/dV
1031          *
1032          */
1033
1034         scale=0.00001;
1035         dv=8*scale*scale*scale*moldyn->volume;
1036
1037         store=malloc(moldyn->count*sizeof(t_atom));
1038         if(store==NULL) {
1039                 printf("[moldyn] allocating store mem failed\n");
1040                 return -1;
1041         }
1042
1043         /* save unscaled potential energy + atom/dim configuration */
1044         memcpy(store,moldyn->atom,moldyn->count*sizeof(t_atom));
1045         dim=moldyn->dim;
1046
1047         /* scale up dimension and atom positions */
1048         scale_dim(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
1049         scale_atoms(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
1050         link_cell_shutdown(moldyn);
1051         link_cell_init(moldyn,QUIET);
1052         potential_force_calc(moldyn);
1053         u_up=moldyn->energy;
1054
1055         /* restore atomic configuration + dim */
1056         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1057         moldyn->dim=dim;
1058
1059         /* scale down dimension and atom positions */
1060         scale_dim(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
1061         scale_atoms(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
1062         link_cell_shutdown(moldyn);
1063         link_cell_init(moldyn,QUIET);
1064         potential_force_calc(moldyn);
1065         u_down=moldyn->energy;
1066         
1067         /* calculate pressure */
1068         p=-(u_up-u_down)/dv;
1069 printf("-------> %.10f %.10f %f\n",u_up/EV/moldyn->count,u_down/EV/moldyn->count,p/BAR);
1070
1071         /* restore atomic configuration + dim */
1072         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1073         moldyn->dim=dim;
1074
1075         /* restore energy */
1076         potential_force_calc(moldyn);
1077
1078         link_cell_shutdown(moldyn);
1079         link_cell_init(moldyn,QUIET);
1080
1081         return p;
1082 }
1083
1084 double get_pressure(t_moldyn *moldyn) {
1085
1086         return moldyn->p;
1087
1088 }
1089
1090 int scale_dim(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1091
1092         t_3dvec *dim;
1093
1094         dim=&(moldyn->dim);
1095
1096         if(dir==SCALE_UP)
1097                 scale=1.0+scale;
1098
1099         if(dir==SCALE_DOWN)
1100                 scale=1.0-scale;
1101
1102         if(x) dim->x*=scale;
1103         if(y) dim->y*=scale;
1104         if(z) dim->z*=scale;
1105
1106         return 0;
1107 }
1108
1109 int scale_atoms(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1110
1111         int i;
1112         t_3dvec *r;
1113
1114         if(dir==SCALE_UP)
1115                 scale=1.0+scale;
1116
1117         if(dir==SCALE_DOWN)
1118                 scale=1.0-scale;
1119
1120         for(i=0;i<moldyn->count;i++) {
1121                 r=&(moldyn->atom[i].r);
1122                 if(x) r->x*=scale;
1123                 if(y) r->y*=scale;
1124                 if(z) r->z*=scale;
1125         }
1126
1127         return 0;
1128 }
1129
1130 int scale_volume(t_moldyn *moldyn) {
1131
1132         t_3dvec *dim,*vdim;
1133         double scale;
1134         t_linkcell *lc;
1135
1136         vdim=&(moldyn->vis.dim);
1137         dim=&(moldyn->dim);
1138         lc=&(moldyn->lc);
1139
1140         /* scaling factor */
1141         if(moldyn->pt_scale&P_SCALE_BERENDSEN) {
1142                 scale=1.0-(moldyn->p_ref-moldyn->p)/moldyn->p_tc;
1143                 scale=pow(scale,ONE_THIRD);
1144         }
1145         else {
1146                 scale=pow(moldyn->p/moldyn->p_ref,ONE_THIRD);
1147         }
1148 moldyn->debug=scale;
1149
1150         /* scale the atoms and dimensions */
1151         scale_atoms(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1152         scale_dim(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1153
1154         /* visualize dimensions */
1155         if(vdim->x!=0) {
1156                 vdim->x=dim->x;
1157                 vdim->y=dim->y;
1158                 vdim->z=dim->z;
1159         }
1160
1161         /* recalculate scaled volume */
1162         moldyn->volume=dim->x*dim->y*dim->z;
1163
1164         /* adjust/reinit linkcell */
1165         if(((int)(dim->x/moldyn->cutoff)!=lc->nx)||
1166            ((int)(dim->y/moldyn->cutoff)!=lc->ny)||
1167            ((int)(dim->z/moldyn->cutoff)!=lc->nx)) {
1168                 link_cell_shutdown(moldyn);
1169                 link_cell_init(moldyn,QUIET);
1170         } else {
1171                 lc->x*=scale;
1172                 lc->y*=scale;
1173                 lc->z*=scale;
1174         }
1175
1176         return 0;
1177
1178 }
1179
1180 double e_kin_calc(t_moldyn *moldyn) {
1181
1182         int i;
1183         t_atom *atom;
1184
1185         atom=moldyn->atom;
1186         moldyn->ekin=0.0;
1187
1188         for(i=0;i<moldyn->count;i++) {
1189                 atom[i].ekin=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v));
1190                 moldyn->ekin+=atom[i].ekin;
1191         }
1192
1193         return moldyn->ekin;
1194 }
1195
1196 double get_total_energy(t_moldyn *moldyn) {
1197
1198         return(moldyn->ekin+moldyn->energy);
1199 }
1200
1201 t_3dvec get_total_p(t_moldyn *moldyn) {
1202
1203         t_3dvec p,p_total;
1204         int i;
1205         t_atom *atom;
1206
1207         atom=moldyn->atom;
1208
1209         v3_zero(&p_total);
1210         for(i=0;i<moldyn->count;i++) {
1211                 v3_scale(&p,&(atom[i].v),atom[i].mass);
1212                 v3_add(&p_total,&p_total,&p);
1213         }
1214
1215         return p_total;
1216 }
1217
1218 double estimate_time_step(t_moldyn *moldyn,double nn_dist) {
1219
1220         double tau;
1221
1222         /* nn_dist is the nearest neighbour distance */
1223
1224         tau=(0.05*nn_dist*moldyn->atom[0].mass)/sqrt(3.0*K_BOLTZMANN*moldyn->t);
1225
1226         return tau;     
1227 }
1228
1229 /*
1230  * numerical tricks
1231  */
1232
1233 /* linked list / cell method */
1234
1235 int link_cell_init(t_moldyn *moldyn,u8 vol) {
1236
1237         t_linkcell *lc;
1238         int i;
1239
1240         lc=&(moldyn->lc);
1241
1242         /* partitioning the md cell */
1243         lc->nx=moldyn->dim.x/moldyn->cutoff;
1244         lc->x=moldyn->dim.x/lc->nx;
1245         lc->ny=moldyn->dim.y/moldyn->cutoff;
1246         lc->y=moldyn->dim.y/lc->ny;
1247         lc->nz=moldyn->dim.z/moldyn->cutoff;
1248         lc->z=moldyn->dim.z/lc->nz;
1249
1250         lc->cells=lc->nx*lc->ny*lc->nz;
1251         lc->subcell=malloc(lc->cells*sizeof(t_list));
1252
1253         if(lc->cells<27)
1254                 printf("[moldyn] FATAL: less then 27 subcells!\n");
1255
1256         if(vol) {
1257                 printf("[moldyn] initializing linked cells (%d)\n",lc->cells);
1258                 printf("  x: %d x %f A\n",lc->nx,lc->x);
1259                 printf("  y: %d x %f A\n",lc->ny,lc->y);
1260                 printf("  z: %d x %f A\n",lc->nz,lc->z);
1261         }
1262
1263         for(i=0;i<lc->cells;i++)
1264                 list_init_f(&(lc->subcell[i]));
1265
1266         link_cell_update(moldyn);
1267         
1268         return 0;
1269 }
1270
1271 int link_cell_update(t_moldyn *moldyn) {
1272
1273         int count,i,j,k;
1274         int nx,ny;
1275         t_atom *atom;
1276         t_linkcell *lc;
1277         double x,y,z;
1278
1279         atom=moldyn->atom;
1280         lc=&(moldyn->lc);
1281
1282         nx=lc->nx;
1283         ny=lc->ny;
1284
1285         x=moldyn->dim.x/2;
1286         y=moldyn->dim.y/2;
1287         z=moldyn->dim.z/2;
1288
1289         for(i=0;i<lc->cells;i++)
1290                 list_destroy_f(&(lc->subcell[i]));
1291         
1292         for(count=0;count<moldyn->count;count++) {
1293                 i=((atom[count].r.x+(moldyn->dim.x/2))/lc->x);
1294                 j=((atom[count].r.y+(moldyn->dim.y/2))/lc->y);
1295                 k=((atom[count].r.z+(moldyn->dim.z/2))/lc->z);
1296                 list_add_immediate_f(&(lc->subcell[i+j*nx+k*nx*ny]),
1297                                      &(atom[count]));
1298         }
1299
1300         return 0;
1301 }
1302
1303 int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,t_list *cell) {
1304
1305         t_linkcell *lc;
1306         int a;
1307         int count1,count2;
1308         int ci,cj,ck;
1309         int nx,ny,nz;
1310         int x,y,z;
1311         u8 bx,by,bz;
1312
1313         lc=&(moldyn->lc);
1314         nx=lc->nx;
1315         ny=lc->ny;
1316         nz=lc->nz;
1317         count1=1;
1318         count2=27;
1319         a=nx*ny;
1320
1321         cell[0]=lc->subcell[i+j*nx+k*a];
1322         for(ci=-1;ci<=1;ci++) {
1323                 bx=0;
1324                 x=i+ci;
1325                 if((x<0)||(x>=nx)) {
1326                         x=(x+nx)%nx;
1327                         bx=1;
1328                 }
1329                 for(cj=-1;cj<=1;cj++) {
1330                         by=0;
1331                         y=j+cj;
1332                         if((y<0)||(y>=ny)) {
1333                                 y=(y+ny)%ny;
1334                                 by=1;
1335                         }
1336                         for(ck=-1;ck<=1;ck++) {
1337                                 bz=0;
1338                                 z=k+ck;
1339                                 if((z<0)||(z>=nz)) {
1340                                         z=(z+nz)%nz;
1341                                         bz=1;
1342                                 }
1343                                 if(!(ci|cj|ck)) continue;
1344                                 if(bx|by|bz) {
1345                                         cell[--count2]=lc->subcell[x+y*nx+z*a];
1346                                 }
1347                                 else {
1348                                         cell[count1++]=lc->subcell[x+y*nx+z*a];
1349                                 }
1350                         }
1351                 }
1352         }
1353
1354         lc->dnlc=count1;
1355
1356         return count1;
1357 }
1358
1359 int link_cell_shutdown(t_moldyn *moldyn) {
1360
1361         int i;
1362         t_linkcell *lc;
1363
1364         lc=&(moldyn->lc);
1365
1366         for(i=0;i<lc->nx*lc->ny*lc->nz;i++)
1367                 list_destroy_f(&(moldyn->lc.subcell[i]));
1368
1369         free(lc->subcell);
1370
1371         return 0;
1372 }
1373
1374 int moldyn_add_schedule(t_moldyn *moldyn,int runs,double tau) {
1375
1376         int count;
1377         void *ptr;
1378         t_moldyn_schedule *schedule;
1379
1380         schedule=&(moldyn->schedule);
1381         count=++(schedule->total_sched);
1382
1383         ptr=realloc(schedule->runs,count*sizeof(int));
1384         if(!ptr) {
1385                 perror("[moldyn] realloc (runs)");
1386                 return -1;
1387         }
1388         schedule->runs=ptr;
1389         schedule->runs[count-1]=runs;
1390
1391         ptr=realloc(schedule->tau,count*sizeof(double));
1392         if(!ptr) {
1393                 perror("[moldyn] realloc (tau)");
1394                 return -1;
1395         }
1396         schedule->tau=ptr;
1397         schedule->tau[count-1]=tau;
1398
1399         printf("[moldyn] schedule added:\n");
1400         printf("  number: %d | runs: %d | tau: %f\n",count-1,runs,tau);
1401                                        
1402
1403         return 0;
1404 }
1405
1406 int moldyn_set_schedule_hook(t_moldyn *moldyn,set_hook hook,void *hook_params) {
1407
1408         moldyn->schedule.hook=hook;
1409         moldyn->schedule.hook_params=hook_params;
1410         
1411         return 0;
1412 }
1413
1414 /*
1415  *
1416  * 'integration of newtons equation' - algorithms
1417  *
1418  */
1419
1420 /* start the integration */
1421
1422 int moldyn_integrate(t_moldyn *moldyn) {
1423
1424         int i;
1425         unsigned int e,m,s,v,p,t;
1426         t_3dvec momentum;
1427         t_moldyn_schedule *sched;
1428         t_atom *atom;
1429         int fd;
1430         char dir[128];
1431         double ds;
1432         double energy_scale;
1433         struct timeval t1,t2;
1434         //double tp;
1435
1436         sched=&(moldyn->schedule);
1437         atom=moldyn->atom;
1438
1439         /* initialize linked cell method */
1440         link_cell_init(moldyn,VERBOSE);
1441
1442         /* logging & visualization */
1443         e=moldyn->ewrite;
1444         m=moldyn->mwrite;
1445         s=moldyn->swrite;
1446         v=moldyn->vwrite;
1447         p=moldyn->pwrite;
1448         t=moldyn->twrite;
1449
1450         /* sqaure of some variables */
1451         moldyn->tau_square=moldyn->tau*moldyn->tau;
1452         moldyn->cutoff_square=moldyn->cutoff*moldyn->cutoff;
1453
1454         /* get current time */
1455         gettimeofday(&t1,NULL);
1456
1457         /* calculate initial forces */
1458         potential_force_calc(moldyn);
1459 #ifdef DEBUG
1460 return 0;
1461 #endif
1462
1463         /* some stupid checks before we actually start calculating bullshit */
1464         if(moldyn->cutoff>0.5*moldyn->dim.x)
1465                 printf("[moldyn] warning: cutoff > 0.5 x dim.x\n");
1466         if(moldyn->cutoff>0.5*moldyn->dim.y)
1467                 printf("[moldyn] warning: cutoff > 0.5 x dim.y\n");
1468         if(moldyn->cutoff>0.5*moldyn->dim.z)
1469                 printf("[moldyn] warning: cutoff > 0.5 x dim.z\n");
1470         ds=0.5*atom[0].f.x*moldyn->tau_square/atom[0].mass;
1471         if(ds>0.05*moldyn->nnd)
1472                 printf("[moldyn] warning: forces too high / tau too small!\n");
1473
1474         /* zero absolute time */
1475         moldyn->time=0.0;
1476         moldyn->total_steps=0;
1477
1478         /* debugging, ignore */
1479         moldyn->debug=0;
1480
1481         /* tell the world */
1482         printf("[moldyn] integration start, go get a coffee ...\n");
1483
1484         /* executing the schedule */
1485         sched->count=0;
1486         while(sched->count<sched->total_sched) {
1487
1488                 /* setting amount of runs and finite time step size */
1489                 moldyn->tau=sched->tau[sched->count];
1490                 moldyn->tau_square=moldyn->tau*moldyn->tau;
1491                 moldyn->time_steps=sched->runs[sched->count];
1492
1493                 /* energy scaling factor (might change!) */
1494                 energy_scale=moldyn->count*EV;
1495
1496         /* integration according to schedule */
1497
1498         for(i=0;i<moldyn->time_steps;i++) {
1499
1500                 /* integration step */
1501                 moldyn->integrate(moldyn);
1502
1503                 /* calculate kinetic energy, temperature and pressure */
1504                 e_kin_calc(moldyn);
1505                 temperature_calc(moldyn);
1506                 virial_sum(moldyn);
1507                 pressure_calc(moldyn);
1508                 average_and_fluctuation_calc(moldyn);
1509
1510                 /* p/t scaling */
1511                 if(moldyn->pt_scale&(T_SCALE_BERENDSEN|T_SCALE_DIRECT))
1512                         scale_velocity(moldyn,FALSE);
1513                 if(moldyn->pt_scale&(P_SCALE_BERENDSEN|P_SCALE_DIRECT))
1514                         scale_volume(moldyn);
1515
1516                 /* check for log & visualization */
1517                 if(e) {
1518                         if(!(moldyn->total_steps%e))
1519                                 dprintf(moldyn->efd,
1520                                         "%f %f %f %f\n",
1521                                         moldyn->time,moldyn->ekin/energy_scale,
1522                                         moldyn->energy/energy_scale,
1523                                         get_total_energy(moldyn)/energy_scale);
1524                 }
1525                 if(m) {
1526                         if(!(moldyn->total_steps%m)) {
1527                                 momentum=get_total_p(moldyn);
1528                                 dprintf(moldyn->mfd,
1529                                         "%f %f %f %f %f\n",moldyn->time,
1530                                         momentum.x,momentum.y,momentum.z,
1531                                         v3_norm(&momentum));
1532                         }
1533                 }
1534                 if(p) {
1535                         if(!(moldyn->total_steps%p)) {
1536                                 dprintf(moldyn->pfd,
1537                                         "%f %f %f %f %f\n",moldyn->time,
1538                                          moldyn->p/BAR,moldyn->p_avg/BAR,
1539                                          moldyn->gp/BAR,moldyn->gp_avg/BAR);
1540                         }
1541                 }
1542                 if(t) {
1543                         if(!(moldyn->total_steps%t)) {
1544                                 dprintf(moldyn->tfd,
1545                                         "%f %f %f\n",
1546                                         moldyn->time,moldyn->t,moldyn->t_avg);
1547                         }
1548                 }
1549                 if(s) {
1550                         if(!(moldyn->total_steps%s)) {
1551                                 snprintf(dir,128,"%s/s-%07.f.save",
1552                                          moldyn->vlsdir,moldyn->time);
1553                                 fd=open(dir,O_WRONLY|O_TRUNC|O_CREAT,
1554                                         S_IRUSR|S_IWUSR);
1555                                 if(fd<0) perror("[moldyn] save fd open");
1556                                 else {
1557                                         write(fd,moldyn,sizeof(t_moldyn));
1558                                         write(fd,moldyn->atom,
1559                                               moldyn->count*sizeof(t_atom));
1560                                 }
1561                                 close(fd);
1562                         }       
1563                 }
1564                 if(v) {
1565                         if(!(moldyn->total_steps%v)) {
1566                                 visual_atoms(&(moldyn->vis),moldyn->time,
1567                                              moldyn->atom,moldyn->count);
1568                         }
1569                 }
1570
1571                 /* display progress */
1572                 if(!(moldyn->total_steps%10)) {
1573                         /* get current time */
1574                         gettimeofday(&t2,NULL);
1575
1576         printf("\rsched:%d, steps:%d, T:%3.1f/%3.1f P:%4.1f/%4.1f V:%6.1f (%d)",
1577                sched->count,i,
1578                moldyn->t,moldyn->t_avg,
1579                moldyn->p_avg/BAR,moldyn->gp_avg/BAR,
1580                moldyn->volume,
1581                (int)(t2.tv_sec-t1.tv_sec));
1582         fflush(stdout);
1583
1584                         /* copy over time */
1585                         t1=t2;
1586                 }
1587
1588                 /* increase absolute time */
1589                 moldyn->time+=moldyn->tau;
1590                 moldyn->total_steps+=1;
1591
1592         }
1593
1594                 /* check for hooks */
1595                 if(sched->hook) {
1596                         printf("\n ## schedule hook %d/%d start ##\n",
1597                                sched->count+1,sched->total_sched-1);
1598                         sched->hook(moldyn,sched->hook_params);
1599                         printf(" ## schedule hook end ##\n");
1600                 }
1601
1602                 /* increase the schedule counter */
1603                 sched->count+=1;
1604
1605         }
1606
1607         return 0;
1608 }
1609
1610 /* velocity verlet */
1611
1612 int velocity_verlet(t_moldyn *moldyn) {
1613
1614         int i,count;
1615         double tau,tau_square,h;
1616         t_3dvec delta;
1617         t_atom *atom;
1618
1619         atom=moldyn->atom;
1620         count=moldyn->count;
1621         tau=moldyn->tau;
1622         tau_square=moldyn->tau_square;
1623
1624         for(i=0;i<count;i++) {
1625                 /* new positions */
1626                 h=0.5/atom[i].mass;
1627                 v3_scale(&delta,&(atom[i].v),tau);
1628                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
1629                 v3_scale(&delta,&(atom[i].f),h*tau_square);
1630                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
1631                 check_per_bound(moldyn,&(atom[i].r));
1632
1633                 /* velocities [actually v(t+tau/2)] */
1634                 v3_scale(&delta,&(atom[i].f),h*tau);
1635                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
1636         }
1637
1638         /* neighbour list update */
1639         link_cell_update(moldyn);
1640
1641         /* forces depending on chosen potential */
1642         potential_force_calc(moldyn);
1643
1644         for(i=0;i<count;i++) {
1645                 /* again velocities [actually v(t+tau)] */
1646                 v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass);
1647                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
1648         }
1649
1650         return 0;
1651 }
1652
1653
1654 /*
1655  *
1656  * potentials & corresponding forces & virial routine
1657  * 
1658  */
1659
1660 /* generic potential and force calculation */
1661
1662 int potential_force_calc(t_moldyn *moldyn) {
1663
1664         int i,j,k,count;
1665         t_atom *itom,*jtom,*ktom;
1666         t_virial *virial;
1667         t_linkcell *lc;
1668         t_list neighbour_i[27];
1669         t_list neighbour_i2[27];
1670         t_list *this,*that;
1671         u8 bc_ij,bc_ik;
1672         int dnlc;
1673
1674         count=moldyn->count;
1675         itom=moldyn->atom;
1676         lc=&(moldyn->lc);
1677
1678         /* reset energy */
1679         moldyn->energy=0.0;
1680
1681         /* reset global virial */
1682         memset(&(moldyn->gvir),0,sizeof(t_virial));
1683
1684         /* reset force, site energy and virial of every atom */
1685         for(i=0;i<count;i++) {
1686
1687                 /* reset force */
1688                 v3_zero(&(itom[i].f));
1689
1690                 /* reset virial */
1691                 virial=(&(itom[i].virial));
1692                 virial->xx=0.0;
1693                 virial->yy=0.0;
1694                 virial->zz=0.0;
1695                 virial->xy=0.0;
1696                 virial->xz=0.0;
1697                 virial->yz=0.0;
1698         
1699                 /* reset site energy */
1700                 itom[i].e=0.0;
1701
1702         }
1703
1704         /* get energy, force and virial of every atom */
1705
1706         /* first (and only) loop over atoms i */
1707         for(i=0;i<count;i++) {
1708
1709                 /* single particle potential/force */
1710                 if(itom[i].attr&ATOM_ATTR_1BP)
1711                         if(moldyn->func1b)
1712                                 moldyn->func1b(moldyn,&(itom[i]));
1713
1714                 if(!(itom[i].attr&(ATOM_ATTR_2BP|ATOM_ATTR_3BP)))
1715                         continue;
1716
1717                 /* 2 body pair potential/force */
1718         
1719                 link_cell_neighbour_index(moldyn,
1720                                           (itom[i].r.x+moldyn->dim.x/2)/lc->x,
1721                                           (itom[i].r.y+moldyn->dim.y/2)/lc->y,
1722                                           (itom[i].r.z+moldyn->dim.z/2)/lc->z,
1723                                           neighbour_i);
1724
1725                 dnlc=lc->dnlc;
1726
1727                 /* first loop over atoms j */
1728                 if(moldyn->func2b) {
1729                         for(j=0;j<27;j++) {
1730
1731                                 this=&(neighbour_i[j]);
1732                                 list_reset_f(this);
1733
1734                                 if(this->start==NULL)
1735                                         continue;
1736
1737                                 bc_ij=(j<dnlc)?0:1;
1738
1739                                 do {
1740                                         jtom=this->current->data;
1741
1742                                         if(jtom==&(itom[i]))
1743                                                 continue;
1744
1745                                         if((jtom->attr&ATOM_ATTR_2BP)&
1746                                            (itom[i].attr&ATOM_ATTR_2BP)) {
1747                                                 moldyn->func2b(moldyn,
1748                                                                &(itom[i]),
1749                                                                jtom,
1750                                                                bc_ij);
1751                                         }
1752                                 } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
1753
1754                         }
1755                 }
1756
1757                 /* 3 body potential/force */
1758
1759                 if(!(itom[i].attr&ATOM_ATTR_3BP))
1760                         continue;
1761
1762                 /* copy the neighbour lists */
1763                 memcpy(neighbour_i2,neighbour_i,27*sizeof(t_list));
1764
1765                 /* second loop over atoms j */
1766                 for(j=0;j<27;j++) {
1767
1768                         this=&(neighbour_i[j]);
1769                         list_reset_f(this);
1770
1771                         if(this->start==NULL)
1772                                 continue;
1773
1774                         bc_ij=(j<dnlc)?0:1;
1775
1776                         do {
1777                                 jtom=this->current->data;
1778
1779                                 if(jtom==&(itom[i]))
1780                                         continue;
1781
1782                                 if(!(jtom->attr&ATOM_ATTR_3BP))
1783                                         continue;
1784
1785                                 /* reset 3bp run */
1786                                 moldyn->run3bp=1;
1787
1788                                 if(moldyn->func3b_j1)
1789                                         moldyn->func3b_j1(moldyn,
1790                                                           &(itom[i]),
1791                                                           jtom,
1792                                                           bc_ij);
1793
1794                                 /* in first j loop, 3bp run can be skipped */
1795                                 if(!(moldyn->run3bp))
1796                                         continue;
1797                         
1798                                 /* first loop over atoms k */
1799                                 if(moldyn->func3b_k1) {
1800
1801                                 for(k=0;k<27;k++) {
1802
1803                                         that=&(neighbour_i2[k]);
1804                                         list_reset_f(that);
1805                                         
1806                                         if(that->start==NULL)
1807                                                 continue;
1808
1809                                         bc_ik=(k<dnlc)?0:1;
1810
1811                                         do {
1812
1813                                                 ktom=that->current->data;
1814
1815                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
1816                                                         continue;
1817
1818                                                 if(ktom==jtom)
1819                                                         continue;
1820
1821                                                 if(ktom==&(itom[i]))
1822                                                         continue;
1823
1824                                                 moldyn->func3b_k1(moldyn,
1825                                                                   &(itom[i]),
1826                                                                   jtom,
1827                                                                   ktom,
1828                                                                   bc_ik|bc_ij);
1829
1830                                         } while(list_next_f(that)!=\
1831                                                 L_NO_NEXT_ELEMENT);
1832
1833                                 }
1834
1835                                 }
1836
1837                                 if(moldyn->func3b_j2)
1838                                         moldyn->func3b_j2(moldyn,
1839                                                           &(itom[i]),
1840                                                           jtom,
1841                                                           bc_ij);
1842
1843                                 /* second loop over atoms k */
1844                                 if(moldyn->func3b_k2) {
1845
1846                                 for(k=0;k<27;k++) {
1847
1848                                         that=&(neighbour_i2[k]);
1849                                         list_reset_f(that);
1850                                         
1851                                         if(that->start==NULL)
1852                                                 continue;
1853
1854                                         bc_ik=(k<dnlc)?0:1;
1855
1856                                         do {
1857
1858                                                 ktom=that->current->data;
1859
1860                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
1861                                                         continue;
1862
1863                                                 if(ktom==jtom)
1864                                                         continue;
1865
1866                                                 if(ktom==&(itom[i]))
1867                                                         continue;
1868
1869                                                 moldyn->func3b_k2(moldyn,
1870                                                                   &(itom[i]),
1871                                                                   jtom,
1872                                                                   ktom,
1873                                                                   bc_ik|bc_ij);
1874
1875                                         } while(list_next_f(that)!=\
1876                                                 L_NO_NEXT_ELEMENT);
1877
1878                                 }
1879                                 
1880                                 }
1881
1882                                 /* 2bp post function */
1883                                 if(moldyn->func3b_j3) {
1884                                         moldyn->func3b_j3(moldyn,
1885                                                           &(itom[i]),
1886                                                           jtom,bc_ij);
1887                                 }
1888                                         
1889                         } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
1890                 
1891                 }
1892                 
1893 #ifdef DEBUG
1894         //printf("\n\n");
1895 #endif
1896 #ifdef VDEBUG
1897         printf("\n\n");
1898 #endif
1899
1900         }
1901
1902 #ifdef DEBUG
1903         printf("\nATOM 0: %f %f %f\n\n",itom->f.x,itom->f.y,itom->f.z);
1904 #endif
1905
1906         /* calculate global virial */
1907         for(i=0;i<count;i++) {
1908                 moldyn->gvir.xx+=moldyn->atom[i].r.x*moldyn->atom[i].f.x;
1909                 moldyn->gvir.yy+=moldyn->atom[i].r.y*moldyn->atom[i].f.y;
1910                 moldyn->gvir.zz+=moldyn->atom[i].r.z*moldyn->atom[i].f.z;
1911                 moldyn->gvir.xy+=moldyn->atom[i].r.y*moldyn->atom[i].f.x;
1912                 moldyn->gvir.xz+=moldyn->atom[i].r.z*moldyn->atom[i].f.x;
1913                 moldyn->gvir.yz+=moldyn->atom[i].r.z*moldyn->atom[i].f.y;
1914         }
1915
1916         return 0;
1917 }
1918
1919 /*
1920  * virial calculation
1921  */
1922
1923 //inline int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
1924 int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
1925
1926         a->virial.xx+=f->x*d->x;
1927         a->virial.yy+=f->y*d->y;
1928         a->virial.zz+=f->z*d->z;
1929         a->virial.xy+=f->x*d->y;
1930         a->virial.xz+=f->x*d->z;
1931         a->virial.yz+=f->y*d->z;
1932
1933         return 0;
1934 }
1935
1936 /*
1937  * periodic boundary checking
1938  */
1939
1940 //inline int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
1941 int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
1942         
1943         double x,y,z;
1944         t_3dvec *dim;
1945
1946         dim=&(moldyn->dim);
1947
1948         x=dim->x/2;
1949         y=dim->y/2;
1950         z=dim->z/2;
1951
1952         if(moldyn->status&MOLDYN_STAT_PBX) {
1953                 if(a->x>=x) a->x-=dim->x;
1954                 else if(-a->x>x) a->x+=dim->x;
1955         }
1956         if(moldyn->status&MOLDYN_STAT_PBY) {
1957                 if(a->y>=y) a->y-=dim->y;
1958                 else if(-a->y>y) a->y+=dim->y;
1959         }
1960         if(moldyn->status&MOLDYN_STAT_PBZ) {
1961                 if(a->z>=z) a->z-=dim->z;
1962                 else if(-a->z>z) a->z+=dim->z;
1963         }
1964
1965         return 0;
1966 }
1967         
1968 /*
1969  * debugging / critical check functions
1970  */
1971
1972 int moldyn_bc_check(t_moldyn *moldyn) {
1973
1974         t_atom *atom;
1975         t_3dvec *dim;
1976         int i;
1977         double x;
1978         u8 byte;
1979         int j,k;
1980
1981         atom=moldyn->atom;
1982         dim=&(moldyn->dim);
1983         x=dim->x/2;
1984
1985         for(i=0;i<moldyn->count;i++) {
1986                 if(atom[i].r.x>=dim->x/2||-atom[i].r.x>dim->x/2) {
1987                         printf("FATAL: atom %d: x: %.20f (%.20f)\n",
1988                                i,atom[i].r.x,dim->x/2);
1989                         printf("diagnostic:\n");
1990                         printf("-----------\natom.r.x:\n");
1991                         for(j=0;j<8;j++) {
1992                                 memcpy(&byte,(u8 *)(&(atom[i].r.x))+j,1);
1993                                 for(k=0;k<8;k++)
1994                                         printf("%d%c",
1995                                         ((byte)&(1<<k))?1:0,
1996                                         (k==7)?'\n':'|');
1997                         }
1998                         printf("---------------\nx=dim.x/2:\n");
1999                         for(j=0;j<8;j++) {
2000                                 memcpy(&byte,(u8 *)(&x)+j,1);
2001                                 for(k=0;k<8;k++)
2002                                         printf("%d%c",
2003                                         ((byte)&(1<<k))?1:0,
2004                                         (k==7)?'\n':'|');
2005                         }
2006                         if(atom[i].r.x==x) printf("the same!\n");
2007                         else printf("different!\n");
2008                 }
2009                 if(atom[i].r.y>=dim->y/2||-atom[i].r.y>dim->y/2)
2010                         printf("FATAL: atom %d: y: %.20f (%.20f)\n",
2011                                i,atom[i].r.y,dim->y/2);
2012                 if(atom[i].r.z>=dim->z/2||-atom[i].r.z>dim->z/2)
2013                         printf("FATAL: atom %d: z: %.20f (%.20f)\n",
2014                                i,atom[i].r.z,dim->z/2);
2015         }
2016
2017         return 0;
2018 }
2019
2020 /*
2021  * restore function
2022  */
2023
2024 int moldyn_load(t_moldyn *moldyn) {
2025
2026         // later ...
2027
2028         return 0;
2029 }
2030
2031 /*
2032  * post processing functions
2033  */
2034
2035 int get_line(int fd,char *line,int max) {
2036
2037         int count,ret;
2038
2039         count=0;
2040
2041         while(1) {
2042                 if(count==max) return count;
2043                 ret=read(fd,line+count,1);
2044                 if(ret<=0) return ret;
2045                 if(line[count]=='\n') {
2046                         line[count]='\0';
2047                         return count+1;
2048                 }
2049                 count+=1;
2050         }
2051 }
2052
2053 int analyze_bonds(t_moldyn *moldyn) {
2054
2055         
2056         
2057
2058         return 0;
2059 }
2060
2061 /*
2062  * visualization code
2063  */
2064
2065 int visual_init(t_visual *v,char *filebase) {
2066
2067         char file[128+8];
2068
2069         strncpy(v->fb,filebase,128);
2070         memset(file,0,128+8);
2071
2072         return 0;
2073 }
2074
2075 int visual_atoms(t_visual *v,double time,t_atom *atom,int n) {
2076
2077         int i,fd;
2078         char file[128+64];
2079         t_3dvec dim;
2080         double help;
2081
2082         dim.x=v->dim.x;
2083         dim.y=v->dim.y;
2084         dim.z=v->dim.z;
2085
2086         help=(dim.x+dim.y);
2087
2088         sprintf(file,"%s/atomic_conf_%07.f.xyz",v->fb,time);
2089         fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
2090         if(fd<0) {
2091                 perror("open visual save file fd");
2092                 return -1;
2093         }
2094
2095         /* write the actual data file */
2096         dprintf(fd,"# [P] %d %07.f <%f,%f,%f>\n",
2097                 n,time,help/40.0,help/40.0,-0.8*help);
2098         for(i=0;i<n;i++)
2099                 dprintf(fd,"%s %f %f %f %s %f\n",pse_name[atom[i].element],
2100                                                  atom[i].r.x,
2101                                                  atom[i].r.y,
2102                                                  atom[i].r.z,
2103                                                  pse_col[atom[i].element],
2104                                                  atom[i].ekin);
2105         if(dim.x) {
2106                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2107                         -dim.x/2,-dim.y/2,-dim.z/2,
2108                         dim.x/2,-dim.y/2,-dim.z/2);
2109                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2110                         -dim.x/2,-dim.y/2,-dim.z/2,
2111                         -dim.x/2,dim.y/2,-dim.z/2);
2112                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2113                         dim.x/2,dim.y/2,-dim.z/2,
2114                         dim.x/2,-dim.y/2,-dim.z/2);
2115                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2116                         -dim.x/2,dim.y/2,-dim.z/2,
2117                         dim.x/2,dim.y/2,-dim.z/2);
2118
2119                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2120                         -dim.x/2,-dim.y/2,dim.z/2,
2121                         dim.x/2,-dim.y/2,dim.z/2);
2122                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2123                         -dim.x/2,-dim.y/2,dim.z/2,
2124                         -dim.x/2,dim.y/2,dim.z/2);
2125                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2126                         dim.x/2,dim.y/2,dim.z/2,
2127                         dim.x/2,-dim.y/2,dim.z/2);
2128                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2129                         -dim.x/2,dim.y/2,dim.z/2,
2130                         dim.x/2,dim.y/2,dim.z/2);
2131
2132                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2133                         -dim.x/2,-dim.y/2,dim.z/2,
2134                         -dim.x/2,-dim.y/2,-dim.z/2);
2135                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2136                         -dim.x/2,dim.y/2,dim.z/2,
2137                         -dim.x/2,dim.y/2,-dim.z/2);
2138                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2139                         dim.x/2,-dim.y/2,dim.z/2,
2140                         dim.x/2,-dim.y/2,-dim.z/2);
2141                 dprintf(fd,"# [D] %f %f %f %f %f %f\n",
2142                         dim.x/2,dim.y/2,dim.z/2,
2143                         dim.x/2,dim.y/2,-dim.z/2);
2144         }
2145
2146         close(fd);
2147
2148         return 0;
2149 }
2150