added partition support in create_lattice function
[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 <fpu_control.h>
21
22 #ifdef PARALLEL
23 #include <omp.h>
24 #endif
25
26 #if defined PTHREADS || defined VISUAL_THREAD
27 #include <pthread.h>
28 #endif
29
30 #include "moldyn.h"
31 #include "report/report.h"
32
33 /* potential includes */
34 #include "potentials/harmonic_oscillator.h"
35 #include "potentials/lennard_jones.h"
36 #include "potentials/albe.h"
37 #ifdef TERSOFF_ORIG
38 #include "potentials/tersoff_orig.h"
39 #else
40 #include "potentials/tersoff.h"
41 #endif
42
43 /* pse */
44 #define PSE_NAME
45 #define PSE_COL
46 #include "pse.h"
47 #undef PSE_NAME
48 #undef PSE_COL
49
50 #ifdef PTHREADS
51 /* global mutexes */
52 pthread_mutex_t *amutex;
53 pthread_mutex_t emutex;
54 #endif
55
56 /*
57  * the moldyn functions
58  */
59
60 int moldyn_init(t_moldyn *moldyn,int argc,char **argv) {
61
62         printf("[moldyn] init\n");
63
64         /* only needed if compiled without -msse2 (float-store prob!) */
65         //fpu_set_rtd();
66
67         memset(moldyn,0,sizeof(t_moldyn));
68
69         moldyn->argc=argc;
70         moldyn->args=argv;
71
72         rand_init(&(moldyn->random),NULL,1);
73         moldyn->random.status|=RAND_STAT_VERBOSE;
74
75 #ifdef PTHREADS
76         pthread_mutex_init(&emutex,NULL);
77 #endif
78
79         return 0;
80 }
81
82 int moldyn_shutdown(t_moldyn *moldyn) {
83
84 #ifdef PTHREADS
85         int i;
86 #endif
87
88         printf("[moldyn] shutdown\n");
89
90 #ifdef PTHREADS
91         for(i=0;i<moldyn->count;i++)
92                 pthread_mutex_destroy(&(amutex[i]));
93         free(amutex);
94         pthread_mutex_destroy(&emutex);
95 #endif
96
97         moldyn_log_shutdown(moldyn);
98         link_cell_shutdown(moldyn);
99         rand_close(&(moldyn->random));
100         free(moldyn->atom);
101
102         return 0;
103 }
104
105 int set_int_alg(t_moldyn *moldyn,u8 algo) {
106
107         printf("[moldyn] integration algorithm: ");
108
109         switch(algo) {
110                 case MOLDYN_INTEGRATE_VERLET:
111                         moldyn->integrate=velocity_verlet;
112                         printf("velocity verlet\n");
113                         break;
114                 default:
115                         printf("unknown integration algorithm: %02x\n",algo);
116                         printf("unknown\n");
117                         return -1;
118         }
119
120         return 0;
121 }
122
123 int set_cutoff(t_moldyn *moldyn,double cutoff) {
124
125         moldyn->cutoff=cutoff;
126         moldyn->cutoff_square=cutoff*cutoff;
127
128         printf("[moldyn] cutoff [A]: %f\n",moldyn->cutoff);
129
130         return 0;
131 }
132
133 int set_temperature(t_moldyn *moldyn,double t_ref) {
134
135         moldyn->t_ref=t_ref;
136
137         printf("[moldyn] temperature [K]: %f\n",moldyn->t_ref);
138
139         return 0;
140 }
141
142 int set_pressure(t_moldyn *moldyn,double p_ref) {
143
144         moldyn->p_ref=p_ref;
145
146         printf("[moldyn] pressure [bar]: %f\n",moldyn->p_ref/BAR);
147
148         return 0;
149 }
150
151 int set_p_scale(t_moldyn *moldyn,u8 ptype,double ptc) {
152
153         moldyn->pt_scale&=(~(P_SCALE_MASK));
154         moldyn->pt_scale|=ptype;
155         moldyn->p_tc=ptc;
156
157         printf("[moldyn] p scaling:\n");
158
159         printf("  p: %s",ptype?"yes":"no ");
160         if(ptype)
161                 printf(" | type: %02x | factor: %f",ptype,ptc);
162         printf("\n");
163
164         return 0;
165 }
166
167 int set_t_scale(t_moldyn *moldyn,u8 ttype,double ttc) {
168
169         moldyn->pt_scale&=(~(T_SCALE_MASK));
170         moldyn->pt_scale|=ttype;
171         moldyn->t_tc=ttc;
172
173         printf("[moldyn] t scaling:\n");
174
175         printf("  t: %s",ttype?"yes":"no ");
176         if(ttype)
177                 printf(" | type: %02x | factor: %f",ttype,ttc);
178         printf("\n");
179
180         return 0;
181 }
182
183 int set_pt_scale(t_moldyn *moldyn,u8 ptype,double ptc,u8 ttype,double ttc) {
184
185         moldyn->pt_scale=(ptype|ttype);
186         moldyn->t_tc=ttc;
187         moldyn->p_tc=ptc;
188
189         printf("[moldyn] p/t scaling:\n");
190
191         printf("  p: %s",ptype?"yes":"no ");
192         if(ptype)
193                 printf(" | type: %02x | factor: %f",ptype,ptc);
194         printf("\n");
195
196         printf("  t: %s",ttype?"yes":"no ");
197         if(ttype)
198                 printf(" | type: %02x | factor: %f",ttype,ttc);
199         printf("\n");
200
201         return 0;
202 }
203
204 int set_dim(t_moldyn *moldyn,double x,double y,double z,u8 visualize) {
205
206         moldyn->dim.x=x;
207         moldyn->dim.y=y;
208         moldyn->dim.z=z;
209
210         moldyn->volume=x*y*z;
211
212         if(visualize) {
213                 moldyn->vis.dim.x=x;
214                 moldyn->vis.dim.y=y;
215                 moldyn->vis.dim.z=z;
216         }
217
218         printf("[moldyn] dimensions in A and A^3 respectively:\n");
219         printf("  x: %f\n",moldyn->dim.x);
220         printf("  y: %f\n",moldyn->dim.y);
221         printf("  z: %f\n",moldyn->dim.z);
222         printf("  volume: %f\n",moldyn->volume);
223         printf("  visualize simulation box: %s\n",visualize?"yes":"no");
224
225         return 0;
226 }
227
228 int set_nn_dist(t_moldyn *moldyn,double dist) {
229
230         moldyn->nnd=dist;
231
232         return 0;
233 }
234
235 int set_pbc(t_moldyn *moldyn,u8 x,u8 y,u8 z) {
236
237         printf("[moldyn] periodic boundary conditions:\n");
238
239         if(x)
240                 moldyn->status|=MOLDYN_STAT_PBX;
241
242         if(y)
243                 moldyn->status|=MOLDYN_STAT_PBY;
244
245         if(z)
246                 moldyn->status|=MOLDYN_STAT_PBZ;
247
248         printf("  x: %s\n",x?"yes":"no");
249         printf("  y: %s\n",y?"yes":"no");
250         printf("  z: %s\n",z?"yes":"no");
251
252         return 0;
253 }
254
255 int set_potential(t_moldyn *moldyn,u8 type) {
256
257         switch(type) {
258                 case MOLDYN_POTENTIAL_TM:
259                         moldyn->func1b=tersoff_mult_1bp;
260                         moldyn->func3b_j1=tersoff_mult_3bp_j1;
261                         moldyn->func3b_k1=tersoff_mult_3bp_k1;
262                         moldyn->func3b_j2=tersoff_mult_3bp_j2;
263                         moldyn->func3b_k2=tersoff_mult_3bp_k2;
264                         moldyn->check_2b_bond=tersoff_mult_check_2b_bond;
265                         break;
266                 case MOLDYN_POTENTIAL_AM:
267                         moldyn->func3b_j1=albe_mult_3bp_j1;
268                         moldyn->func3b_k1=albe_mult_3bp_k1;
269                         moldyn->func3b_j2=albe_mult_3bp_j2;
270                         moldyn->func3b_k2=albe_mult_3bp_k2;
271                         moldyn->check_2b_bond=albe_mult_check_2b_bond;
272                         break;
273                 case MOLDYN_POTENTIAL_HO:
274                         moldyn->func2b=harmonic_oscillator;
275                         moldyn->check_2b_bond=harmonic_oscillator_check_2b_bond;
276                         break;
277                 case MOLDYN_POTENTIAL_LJ:
278                         moldyn->func2b=lennard_jones;
279                         moldyn->check_2b_bond=lennard_jones_check_2b_bond;
280                         break;
281                 default:
282                         printf("[moldyn] set potential: unknown type %02x\n",
283                                type);
284                         return -1;
285         }
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 LOG_VOLUME:
374                         moldyn->vwrite=timer;
375                         snprintf(filename,127,"%s/volume",moldyn->vlsdir);
376                         moldyn->vfd=open(filename,
377                                          O_WRONLY|O_CREAT|O_EXCL,
378                                          S_IRUSR|S_IWUSR);
379                         if(moldyn->vfd<0) {
380                                 perror("[moldyn] volume log file\n");
381                                 return moldyn->vfd;
382                         }
383                         dprintf(moldyn->vfd,"# volume log file\n");
384                         printf("volume (%d)\n",timer);
385                         break;
386                 case SAVE_STEP:
387                         moldyn->swrite=timer;
388                         printf("save file (%d)\n",timer);
389                         break;
390                 case VISUAL_STEP:
391                         moldyn->awrite=timer;
392                         ret=visual_init(moldyn,moldyn->vlsdir);
393                         if(ret<0) {
394                                 printf("[moldyn] visual init failure\n");
395                                 return ret;
396                         }
397                         printf("visual file (%d)\n",timer);
398                         break;
399                 case CREATE_REPORT:
400                         snprintf(filename,127,"%s/report.tex",moldyn->vlsdir);
401                         moldyn->rfd=open(filename,
402                                          O_WRONLY|O_CREAT|O_EXCL,
403                                          S_IRUSR|S_IWUSR);
404                         if(moldyn->rfd<0) {
405                                 perror("[moldyn] report fd open");      
406                                 return moldyn->rfd;
407                         }
408                         printf("report -> ");
409                         if(moldyn->efd) {
410                                 snprintf(filename,127,"%s/e_plot.scr",
411                                          moldyn->vlsdir);
412                                 moldyn->epfd=open(filename,
413                                                  O_WRONLY|O_CREAT|O_EXCL,
414                                                  S_IRUSR|S_IWUSR);
415                                 if(moldyn->epfd<0) {
416                                         perror("[moldyn] energy plot fd open");
417                                         return moldyn->epfd;
418                                 }
419                                 dprintf(moldyn->epfd,e_plot_script);
420                                 close(moldyn->epfd);
421                                 printf("energy ");
422                         }
423                         if(moldyn->pfd) {
424                                 snprintf(filename,127,"%s/pressure_plot.scr",
425                                          moldyn->vlsdir);
426                                 moldyn->ppfd=open(filename,
427                                                   O_WRONLY|O_CREAT|O_EXCL,
428                                                   S_IRUSR|S_IWUSR);
429                                 if(moldyn->ppfd<0) {
430                                         perror("[moldyn] p plot fd open");
431                                         return moldyn->ppfd;
432                                 }
433                                 dprintf(moldyn->ppfd,pressure_plot_script);
434                                 close(moldyn->ppfd);
435                                 printf("pressure ");
436                         }
437                         if(moldyn->tfd) {
438                                 snprintf(filename,127,"%s/temperature_plot.scr",
439                                          moldyn->vlsdir);
440                                 moldyn->tpfd=open(filename,
441                                                   O_WRONLY|O_CREAT|O_EXCL,
442                                                   S_IRUSR|S_IWUSR);
443                                 if(moldyn->tpfd<0) {
444                                         perror("[moldyn] t plot fd open");
445                                         return moldyn->tpfd;
446                                 }
447                                 dprintf(moldyn->tpfd,temperature_plot_script);
448                                 close(moldyn->tpfd);
449                                 printf("temperature ");
450                         }
451                         dprintf(moldyn->rfd,report_start,
452                                 moldyn->rauthor,moldyn->rtitle);
453                         printf("\n");
454                         break;
455                 default:
456                         printf("unknown log type: %02x\n",type);
457                         return -1;
458         }
459
460         return 0;
461 }
462
463 int moldyn_log_shutdown(t_moldyn *moldyn) {
464
465         char sc[256];
466
467         printf("[moldyn] log shutdown\n");
468         if(moldyn->efd) {
469                 close(moldyn->efd);
470                 if(moldyn->rfd) {
471                         dprintf(moldyn->rfd,report_energy);
472                         snprintf(sc,255,"cd %s && gnuplot e_plot.scr",
473                                  moldyn->vlsdir);
474                         system(sc);
475                 }
476         }
477         if(moldyn->mfd) close(moldyn->mfd);
478         if(moldyn->pfd) {
479                 close(moldyn->pfd);
480                 if(moldyn->rfd)
481                         dprintf(moldyn->rfd,report_pressure);
482                         snprintf(sc,255,"cd %s && gnuplot pressure_plot.scr",
483                                  moldyn->vlsdir);
484                         system(sc);
485         }
486         if(moldyn->tfd) {
487                 close(moldyn->tfd);
488                 if(moldyn->rfd)
489                         dprintf(moldyn->rfd,report_temperature);
490                         snprintf(sc,255,"cd %s && gnuplot temperature_plot.scr",
491                                  moldyn->vlsdir);
492                         system(sc);
493         }
494         if(moldyn->rfd) {
495                 dprintf(moldyn->rfd,report_end);
496                 close(moldyn->rfd);
497                 snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1",
498                          moldyn->vlsdir);
499                 system(sc);
500                 snprintf(sc,255,"cd %s && pdflatex report >/dev/null 2>&1",
501                          moldyn->vlsdir);
502                 system(sc);
503                 snprintf(sc,255,"cd %s && dvipdf report >/dev/null 2>&1",
504                          moldyn->vlsdir);
505                 system(sc);
506         }
507
508         return 0;
509 }
510
511 /*
512  * creating lattice functions
513  */
514
515 int create_lattice(t_moldyn *moldyn,u8 type,double lc,int element,double mass,
516                    u8 attr,u8 brand,int a,int b,int c,t_3dvec *origin,
517                    u8 p_type,t_part_vals *p_vals) {
518
519         int new,count;
520         int ret;
521         t_3dvec orig;
522         void *ptr;
523         t_atom *atom;
524         char name[16];
525 #ifdef PTHREADS
526         pthread_mutex_t *mutex;
527 #endif
528
529         new=a*b*c;
530         count=moldyn->count;
531
532         /* how many atoms do we expect */
533         if(type==NONE) {
534                 new*=1;
535                 printf("[moldyn] WARNING: create 'none' lattice called");
536         }
537         if(type==CUBIC) new*=1;
538         if(type==FCC) new*=4;
539         if(type==DIAMOND) new*=8;
540
541         /* allocate space for atoms */
542         ptr=realloc(moldyn->atom,(count+new)*sizeof(t_atom));
543         if(!ptr) {
544                 perror("[moldyn] realloc (create lattice)");
545                 return -1;
546         }
547         moldyn->atom=ptr;
548         atom=&(moldyn->atom[count]);
549
550 #ifdef PTHREADS
551         ptr=realloc(amutex,(count+new)*sizeof(pthread_mutex_t));
552         if(!ptr) {
553                 perror("[moldyn] mutex realloc (add atom)");
554                 return -1;
555         }
556         amutex=ptr;
557         mutex=&(amutex[count]);
558 #endif
559
560         /* no atoms on the boundaries (only reason: it looks better!) */
561         if(!origin) {
562                 orig.x=0.5*lc;
563                 orig.y=0.5*lc;
564                 orig.z=0.5*lc;
565         }
566         else {
567                 orig.x=origin->x;
568                 orig.y=origin->y;
569                 orig.z=origin->z;
570         }
571
572         switch(type) {
573                 case CUBIC:
574                         set_nn_dist(moldyn,lc);
575                         ret=cubic_init(a,b,c,lc,atom,&orig,p_type,p_vals);
576                         strcpy(name,"cubic");
577                         break;
578                 case FCC:
579                         if(!origin)
580                                 v3_scale(&orig,&orig,0.5);
581                         set_nn_dist(moldyn,0.5*sqrt(2.0)*lc);
582                         ret=fcc_init(a,b,c,lc,atom,&orig,p_type,p_vals);
583                         strcpy(name,"fcc");
584                         break;
585                 case DIAMOND:
586                         if(!origin)
587                                 v3_scale(&orig,&orig,0.25);
588                         set_nn_dist(moldyn,0.25*sqrt(3.0)*lc);
589                         ret=diamond_init(a,b,c,lc,atom,&orig,p_type,p_vals);
590                         strcpy(name,"diamond");
591                         break;
592                 default:
593                         printf("unknown lattice type (%02x)\n",type);
594                         return -1;
595         }
596
597         /* debug */
598         if(ret!=new) {
599                 printf("[moldyn] creating lattice failed\n");
600                 printf("  amount of atoms\n");
601                 printf("  - expected: %d\n",new);
602                 printf("  - created: %d\n",ret);
603                 return -1;
604         }
605
606         moldyn->count+=new;
607         printf("[moldyn] created %s lattice with %d atoms\n",name,new);
608
609         for(ret=0;ret<new;ret++) {
610                 atom[ret].element=element;
611                 atom[ret].mass=mass;
612                 atom[ret].attr=attr;
613                 atom[ret].brand=brand;
614                 atom[ret].tag=count+ret;
615                 check_per_bound(moldyn,&(atom[ret].r));
616                 atom[ret].r_0=atom[ret].r;
617 #ifdef PTHREADS
618                 pthread_mutex_init(&(mutex[ret]),NULL);
619 #endif
620         }
621
622         /* update total system mass */
623         total_mass_calc(moldyn);
624
625         return ret;
626 }
627
628 int add_atom(t_moldyn *moldyn,int element,double mass,u8 brand,u8 attr,
629              t_3dvec *r,t_3dvec *v) {
630
631         t_atom *atom;
632         void *ptr;
633         int count;
634         
635         atom=moldyn->atom;
636         count=(moldyn->count)++;        // asshole style!
637
638         ptr=realloc(atom,(count+1)*sizeof(t_atom));
639         if(!ptr) {
640                 perror("[moldyn] realloc (add atom)");
641                 return -1;
642         }
643         moldyn->atom=ptr;
644
645 #ifdef LOWMEM_LISTS
646         ptr=realloc(moldyn->lc.subcell->list,(count+1)*sizeof(int));
647         if(!ptr) {
648                 perror("[moldyn] list realloc (add atom)");
649                 return -1;
650         }
651         moldyn->lc.subcell->list=ptr;
652 #endif
653
654 #ifdef PTHREADS
655         ptr=realloc(amutex,(count+1)*sizeof(pthread_mutex_t));
656         if(!ptr) {
657                 perror("[moldyn] mutex realloc (add atom)");
658                 return -1;
659         }
660         amutex=ptr;
661         pthread_mutex_init(&(amutex[count]),NULL);
662 #endif
663
664         atom=moldyn->atom;
665
666         /* initialize new atom */
667         memset(&(atom[count]),0,sizeof(t_atom));
668         atom[count].r=*r;
669         atom[count].v=*v;
670         atom[count].element=element;
671         atom[count].mass=mass;
672         atom[count].brand=brand;
673         atom[count].tag=count;
674         atom[count].attr=attr;
675         check_per_bound(moldyn,&(atom[count].r));
676         atom[count].r_0=atom[count].r;
677
678         /* update total system mass */
679         total_mass_calc(moldyn);
680
681         return 0;
682 }
683
684 int del_atom(t_moldyn *moldyn,int tag) {
685
686         t_atom *new,*old;
687         int cnt;
688
689         old=moldyn->atom;
690
691         new=(t_atom *)malloc((moldyn->count-1)*sizeof(t_atom));
692         if(!new) {
693                 perror("[moldyn]malloc (del atom)");
694                 return -1;
695         }
696
697         for(cnt=0;cnt<tag;cnt++)
698                 new[cnt]=old[cnt];
699         
700         for(cnt=tag+1;cnt<moldyn->count;cnt++) {
701                 new[cnt-1]=old[cnt];
702                 new[cnt-1].tag=cnt-1;
703         }
704
705         moldyn->count-=1;
706         moldyn->atom=new;
707
708         free(old);
709
710         return 0;
711 }
712
713 /* cubic init */
714 int cubic_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin,
715                u8 p_type,t_part_vals *p_vals) {
716
717         int count;
718         t_3dvec r;
719         int i,j,k;
720         t_3dvec o;
721         t_3dvec dist;
722
723         count=0;
724         if(origin)
725                 v3_copy(&o,origin);
726         else
727                 v3_zero(&o);
728
729         /* shift partition values */
730         if(p_type) {
731                 p_vals->p.x+=(a*lc)/2.0;
732                 p_vals->p.y+=(b*lc)/2.0;
733                 p_vals->p.z+=(c*lc)/2.0;
734         }
735
736         r.x=o.x;
737         for(i=0;i<a;i++) {
738                 r.y=o.y;
739                 for(j=0;j<b;j++) {
740                         r.z=o.z;
741                         for(k=0;k<c;k++) {
742                                 switch(p_type) {
743                                         case PART_INSIDE_R:
744                                                 v3_sub(&dist,&r,&(p_vals->p));
745                         if(v3_absolute_square(&dist)<(p_vals->r*p_vals->r)) {
746                                 v3_copy(&(atom[count].r),&r);
747                                 count+=1;
748                         }
749                                                 break;
750                                         case PART_OUTSIDE_R:
751                                                 v3_sub(&dist,&r,&(p_vals->p));
752                         if(v3_absolute_square(&dist)>=(p_vals->r*p_vals->r)) {
753                                 v3_copy(&(atom[count].r),&r);
754                                 count+=1;
755                         }
756                                                 break;
757                                         default:        
758                                                 v3_copy(&(atom[count].r),&r);
759                                                 count+=1;
760                                                 break;
761                                 }
762                                 r.z+=lc;
763                         }
764                         r.y+=lc;
765                 }
766                 r.x+=lc;
767         }
768
769         for(i=0;i<count;i++) {
770                 atom[i].r.x-=(a*lc)/2.0;
771                 atom[i].r.y-=(b*lc)/2.0;
772                 atom[i].r.z-=(c*lc)/2.0;
773         }
774
775         return count;
776 }
777
778 /* fcc lattice init */
779 int fcc_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin,
780              u8 p_type,t_part_vals *p_vals) {
781
782         int count;
783         int i,j,k,l;
784         t_3dvec o,r,n;
785         t_3dvec basis[3];
786         t_3dvec dist;
787
788         count=0;
789         if(origin)
790                 v3_copy(&o,origin);
791         else
792                 v3_zero(&o);
793
794         /* construct the basis */
795         memset(basis,0,3*sizeof(t_3dvec));
796         basis[0].x=0.5*lc;
797         basis[0].y=0.5*lc;
798         basis[1].x=0.5*lc;
799         basis[1].z=0.5*lc;
800         basis[2].y=0.5*lc;
801         basis[2].z=0.5*lc;
802
803         /* shift partition values */
804         if(p_type) {
805                 p_vals->p.x+=(a*lc)/2.0;
806                 p_vals->p.y+=(b*lc)/2.0;
807                 p_vals->p.z+=(c*lc)/2.0;
808         }
809
810         /* fill up the room */
811         r.x=o.x;
812         for(i=0;i<a;i++) {
813                 r.y=o.y;
814                 for(j=0;j<b;j++) {
815                         r.z=o.z;
816                         for(k=0;k<c;k++) {
817                                 /* first atom */
818                                 switch(p_type) {
819                                         case PART_INSIDE_R:
820                                                 v3_sub(&dist,&r,&(p_vals->p));
821                         if(v3_absolute_square(&dist)<(p_vals->r*p_vals->r)) {
822                                 v3_copy(&(atom[count].r),&r);
823                                 count+=1;
824                         }
825                                                 break;
826                                         case PART_OUTSIDE_R:
827                                                 v3_sub(&dist,&r,&(p_vals->p));
828                         if(v3_absolute_square(&dist)>=(p_vals->r*p_vals->r)) {
829                                 v3_copy(&(atom[count].r),&r);
830                                 count+=1;
831                         }
832                                                 break;
833                                         default:
834                                                 v3_copy(&(atom[count].r),&r);
835                                                 count+=1;
836                                                 break;
837                                 }
838                                 /* the three face centered atoms */
839                                 for(l=0;l<3;l++) {
840                                         v3_add(&n,&r,&basis[l]);
841                                         switch(p_type) {
842                                                 case PART_INSIDE_R:
843                         v3_sub(&dist,&n,&(p_vals->p));
844                         if(v3_absolute_square(&dist)<(p_vals->r*p_vals->r)) {
845                                 v3_copy(&(atom[count].r),&r);
846                                 count+=1;
847                         }
848                                                         break;
849                                                 case PART_OUTSIDE_R:
850                         v3_sub(&dist,&n,&(p_vals->p));
851                         if(v3_absolute_square(&dist)>=(p_vals->r*p_vals->r)) {
852                                 v3_copy(&(atom[count].r),&r);
853                                 count+=1;
854                         }
855                                                         break;
856                                                 default:
857                                         v3_copy(&(atom[count].r),&n);
858                                         count+=1;
859                                                         break;
860                                         }
861                                 }
862                                 r.z+=lc;
863                         }
864                         r.y+=lc;
865                 }
866                 r.x+=lc;
867         }
868                                 
869         /* coordinate transformation */
870         for(i=0;i<count;i++) {
871                 atom[i].r.x-=(a*lc)/2.0;
872                 atom[i].r.y-=(b*lc)/2.0;
873                 atom[i].r.z-=(c*lc)/2.0;
874         }
875
876         return count;
877 }
878
879 int diamond_init(int a,int b,int c,double lc,t_atom *atom,t_3dvec *origin,
880                  u8 p_type,t_part_vals *p_vals) {
881
882         int count;
883         t_3dvec o;
884
885         count=fcc_init(a,b,c,lc,atom,origin,p_type,p_vals);
886
887         o.x=0.25*lc;
888         o.y=0.25*lc;
889         o.z=0.25*lc;
890
891         if(origin) v3_add(&o,&o,origin);
892
893         count+=fcc_init(a,b,c,lc,&atom[count],&o,p_type,p_vals);
894
895         return count;
896 }
897
898 int destroy_atoms(t_moldyn *moldyn) {
899
900         if(moldyn->atom) free(moldyn->atom);
901
902         return 0;
903 }
904
905 int thermal_init(t_moldyn *moldyn,u8 equi_init) {
906
907         /*
908          * - gaussian distribution of velocities
909          * - zero total momentum
910          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
911          */
912
913         int i;
914         double v,sigma;
915         t_3dvec p_total,delta;
916         t_atom *atom;
917         t_random *random;
918
919         atom=moldyn->atom;
920         random=&(moldyn->random);
921
922         printf("[moldyn] thermal init (equi init: %s)\n",equi_init?"yes":"no");
923
924         /* gaussian distribution of velocities */
925         v3_zero(&p_total);
926         for(i=0;i<moldyn->count;i++) {
927                 sigma=sqrt(2.0*K_BOLTZMANN*moldyn->t_ref/atom[i].mass);
928                 /* x direction */
929                 v=sigma*rand_get_gauss(random);
930                 atom[i].v.x=v;
931                 p_total.x+=atom[i].mass*v;
932                 /* y direction */
933                 v=sigma*rand_get_gauss(random);
934                 atom[i].v.y=v;
935                 p_total.y+=atom[i].mass*v;
936                 /* z direction */
937                 v=sigma*rand_get_gauss(random);
938                 atom[i].v.z=v;
939                 p_total.z+=atom[i].mass*v;
940         }
941
942         /* zero total momentum */
943         v3_scale(&p_total,&p_total,1.0/moldyn->count);
944         for(i=0;i<moldyn->count;i++) {
945                 v3_scale(&delta,&p_total,1.0/atom[i].mass);
946                 v3_sub(&(atom[i].v),&(atom[i].v),&delta);
947         }
948
949         /* velocity scaling */
950         scale_velocity(moldyn,equi_init);
951
952         return 0;
953 }
954
955 double total_mass_calc(t_moldyn *moldyn) {
956
957         int i;
958
959         moldyn->mass=0.0;
960
961         for(i=0;i<moldyn->count;i++)
962                 moldyn->mass+=moldyn->atom[i].mass;
963
964         return moldyn->mass;
965 }
966
967 double temperature_calc(t_moldyn *moldyn) {
968
969         /* assume up to date kinetic energy, which is 3/2 N k_B T */
970
971         moldyn->t=(2.0*moldyn->ekin)/(3.0*K_BOLTZMANN*moldyn->count);
972
973         return moldyn->t;
974 }
975
976 double get_temperature(t_moldyn *moldyn) {
977
978         return moldyn->t;
979 }
980
981 int scale_velocity(t_moldyn *moldyn,u8 equi_init) {
982
983         int i;
984         double e,scale;
985         t_atom *atom;
986         int count;
987
988         atom=moldyn->atom;
989
990         /*
991          * - velocity scaling (E = 3/2 N k T), E: kinetic energy
992          */
993
994         /* get kinetic energy / temperature & count involved atoms */
995         e=0.0;
996         count=0;
997         for(i=0;i<moldyn->count;i++) {
998                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB)) {
999                         e+=atom[i].mass*v3_absolute_square(&(atom[i].v));
1000                         count+=1;
1001                 }
1002         }
1003         e*=0.5;
1004         if(count!=0) moldyn->t=e/(1.5*count*K_BOLTZMANN);
1005         else return 0;  /* no atoms involved in scaling! */
1006         
1007         /* (temporary) hack for e,t = 0 */
1008         if(e==0.0) {
1009         moldyn->t=0.0;
1010                 if(moldyn->t_ref!=0.0) {
1011                         thermal_init(moldyn,equi_init);
1012                         return 0;
1013                 }
1014                 else
1015                         return 0; /* no scaling needed */
1016         }
1017
1018
1019         /* get scaling factor */
1020         scale=moldyn->t_ref/moldyn->t;
1021         if(equi_init&TRUE)
1022                 scale*=2.0;
1023         else
1024                 if(moldyn->pt_scale&T_SCALE_BERENDSEN)
1025                         scale=1.0+(scale-1.0)*moldyn->tau/moldyn->t_tc;
1026         scale=sqrt(scale);
1027
1028         /* velocity scaling */
1029         for(i=0;i<moldyn->count;i++) {
1030                 if((equi_init&TRUE)||(atom[i].attr&ATOM_ATTR_HB))
1031                         v3_scale(&(atom[i].v),&(atom[i].v),scale);
1032         }
1033
1034         return 0;
1035 }
1036
1037 double ideal_gas_law_pressure(t_moldyn *moldyn) {
1038
1039         double p;
1040
1041         p=moldyn->count*moldyn->t*K_BOLTZMANN/moldyn->volume;
1042
1043         return p;
1044 }
1045
1046 double virial_sum(t_moldyn *moldyn) {
1047
1048         int i;
1049         t_virial *virial;
1050
1051         /* virial (sum over atom virials) */
1052         moldyn->virial=0.0;
1053         moldyn->vir.xx=0.0;
1054         moldyn->vir.yy=0.0;
1055         moldyn->vir.zz=0.0;
1056         moldyn->vir.xy=0.0;
1057         moldyn->vir.xz=0.0;
1058         moldyn->vir.yz=0.0;
1059         for(i=0;i<moldyn->count;i++) {
1060                 virial=&(moldyn->atom[i].virial);
1061                 moldyn->virial+=(virial->xx+virial->yy+virial->zz);
1062                 moldyn->vir.xx+=virial->xx;
1063                 moldyn->vir.yy+=virial->yy;
1064                 moldyn->vir.zz+=virial->zz;
1065                 moldyn->vir.xy+=virial->xy;
1066                 moldyn->vir.xz+=virial->xz;
1067                 moldyn->vir.yz+=virial->yz;
1068         }
1069
1070         /* global virial (absolute coordinates) */
1071         virial=&(moldyn->gvir);
1072         moldyn->gv=virial->xx+virial->yy+virial->zz;
1073
1074         return moldyn->virial;
1075 }
1076
1077 double pressure_calc(t_moldyn *moldyn) {
1078
1079         /*
1080          * PV = NkT + <W>
1081          * with W = 1/3 sum_i f_i r_i (- skipped!)
1082          * virial = sum_i f_i r_i
1083          * 
1084          * => P = (2 Ekin + virial) / (3V)
1085          */
1086
1087         /* assume up to date virial & up to date kinetic energy */
1088
1089         /* pressure (atom virials) */
1090         moldyn->p=2.0*moldyn->ekin+moldyn->virial;
1091         moldyn->p/=(3.0*moldyn->volume);
1092
1093         /* pressure (absolute coordinates) */
1094         moldyn->gp=2.0*moldyn->ekin+moldyn->gv;
1095         moldyn->gp/=(3.0*moldyn->volume);
1096
1097         return moldyn->p;
1098 }
1099
1100 int average_reset(t_moldyn *moldyn) {
1101
1102         printf("[moldyn] average reset\n");
1103
1104         /* update skip value */
1105         moldyn->avg_skip=moldyn->total_steps;
1106
1107         /* kinetic energy */
1108         moldyn->k_sum=0.0;
1109         moldyn->k2_sum=0.0;
1110         
1111         /* potential energy */
1112         moldyn->v_sum=0.0;
1113         moldyn->v2_sum=0.0;
1114
1115         /* temperature */
1116         moldyn->t_sum=0.0;
1117
1118         /* virial */
1119         moldyn->virial_sum=0.0;
1120         moldyn->gv_sum=0.0;
1121
1122         /* pressure */
1123         moldyn->p_sum=0.0;
1124         moldyn->gp_sum=0.0;
1125         moldyn->tp_sum=0.0;
1126
1127         return 0;
1128 }
1129
1130 int average_and_fluctuation_calc(t_moldyn *moldyn) {
1131
1132         int denom;
1133
1134         if(moldyn->total_steps<moldyn->avg_skip)
1135                 return 0;
1136
1137         denom=moldyn->total_steps+1-moldyn->avg_skip;
1138
1139         /* assume up to date energies, temperature, pressure etc */
1140
1141         /* kinetic energy */
1142         moldyn->k_sum+=moldyn->ekin;
1143         moldyn->k2_sum+=(moldyn->ekin*moldyn->ekin);
1144         moldyn->k_avg=moldyn->k_sum/denom;
1145         moldyn->k2_avg=moldyn->k2_sum/denom;
1146         moldyn->dk2_avg=moldyn->k2_avg-(moldyn->k_avg*moldyn->k_avg);
1147
1148         /* potential energy */
1149         moldyn->v_sum+=moldyn->energy;
1150         moldyn->v2_sum+=(moldyn->energy*moldyn->energy);
1151         moldyn->v_avg=moldyn->v_sum/denom;
1152         moldyn->v2_avg=moldyn->v2_sum/denom;
1153         moldyn->dv2_avg=moldyn->v2_avg-(moldyn->v_avg*moldyn->v_avg);
1154
1155         /* temperature */
1156         moldyn->t_sum+=moldyn->t;
1157         moldyn->t_avg=moldyn->t_sum/denom;
1158
1159         /* virial */
1160         moldyn->virial_sum+=moldyn->virial;
1161         moldyn->virial_avg=moldyn->virial_sum/denom;
1162         moldyn->gv_sum+=moldyn->gv;
1163         moldyn->gv_avg=moldyn->gv_sum/denom;
1164
1165         /* pressure */
1166         moldyn->p_sum+=moldyn->p;
1167         moldyn->p_avg=moldyn->p_sum/denom;
1168         moldyn->gp_sum+=moldyn->gp;
1169         moldyn->gp_avg=moldyn->gp_sum/denom;
1170         moldyn->tp_sum+=moldyn->tp;
1171         moldyn->tp_avg=moldyn->tp_sum/denom;
1172
1173         return 0;
1174 }
1175
1176 int get_heat_capacity(t_moldyn *moldyn) {
1177
1178         double temp2,ighc;
1179
1180         /* averages needed for heat capacity calc */
1181         if(moldyn->total_steps<moldyn->avg_skip)
1182                 return 0;
1183
1184         /* (temperature average)^2 */
1185         temp2=moldyn->t_avg*moldyn->t_avg;
1186         printf("[moldyn] specific heat capacity for T=%f K [J/(kg K)]\n",
1187                moldyn->t_avg);
1188
1189         /* ideal gas contribution */
1190         ighc=3.0*moldyn->count*K_BOLTZMANN/2.0;
1191         printf("  ideal gas contribution: %f\n",
1192                ighc/moldyn->mass*KILOGRAM/JOULE);
1193
1194         /* specific heat for nvt ensemble */
1195         moldyn->c_v_nvt=moldyn->dv2_avg/(K_BOLTZMANN*temp2)+ighc;
1196         moldyn->c_v_nvt/=moldyn->mass;
1197
1198         /* specific heat for nve ensemble */
1199         moldyn->c_v_nve=ighc/(1.0-(moldyn->dv2_avg/(ighc*K_BOLTZMANN*temp2)));
1200         moldyn->c_v_nve/=moldyn->mass;
1201
1202         printf("  NVE: %f\n",moldyn->c_v_nve*KILOGRAM/JOULE);
1203         printf("  NVT: %f\n",moldyn->c_v_nvt*KILOGRAM/JOULE);
1204 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)));
1205
1206         return 0;
1207 }
1208
1209 double thermodynamic_pressure_calc(t_moldyn *moldyn) {
1210
1211         t_3dvec dim;
1212         //t_3dvec *tp;
1213         double h,dv;
1214         double y0,y1;
1215         double su,sd;
1216         t_atom *store;
1217
1218         /*
1219          * dU = - p dV
1220          *
1221          * => p = - dU/dV
1222          *
1223          */
1224
1225         /* store atomic configuration + dimension */
1226         store=malloc(moldyn->count*sizeof(t_atom));
1227         if(store==NULL) {
1228                 printf("[moldyn] allocating store mem failed\n");
1229                 return -1;
1230         }
1231         memcpy(store,moldyn->atom,moldyn->count*sizeof(t_atom));
1232         dim=moldyn->dim;
1233
1234         /* x1, y1 */
1235         sd=0.00001;
1236         h=(1.0-sd)*(1.0-sd)*(1.0-sd);
1237         su=pow(2.0-h,ONE_THIRD)-1.0;
1238         dv=(1.0-h)*moldyn->volume;
1239
1240         /* scale up dimension and atom positions */
1241         scale_dim(moldyn,SCALE_UP,su,TRUE,TRUE,TRUE);
1242         scale_atoms(moldyn,SCALE_UP,su,TRUE,TRUE,TRUE);
1243         link_cell_shutdown(moldyn);
1244         link_cell_init(moldyn,QUIET);
1245         potential_force_calc(moldyn);
1246         y1=moldyn->energy;
1247
1248         /* restore atomic configuration + dim */
1249         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1250         moldyn->dim=dim;
1251
1252         /* scale down dimension and atom positions */
1253         scale_dim(moldyn,SCALE_DOWN,sd,TRUE,TRUE,TRUE);
1254         scale_atoms(moldyn,SCALE_DOWN,sd,TRUE,TRUE,TRUE);
1255         link_cell_shutdown(moldyn);
1256         link_cell_init(moldyn,QUIET);
1257         potential_force_calc(moldyn);
1258         y0=moldyn->energy;
1259         
1260         /* calculate pressure */
1261         moldyn->tp=-(y1-y0)/(2.0*dv);
1262
1263         /* restore atomic configuration */
1264         memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
1265         moldyn->dim=dim;
1266         link_cell_shutdown(moldyn);
1267         link_cell_init(moldyn,QUIET);
1268         //potential_force_calc(moldyn);
1269
1270         /* free store buffer */
1271         if(store)
1272                 free(store);
1273
1274         return moldyn->tp;
1275 }
1276
1277 double get_pressure(t_moldyn *moldyn) {
1278
1279         return moldyn->p;
1280
1281 }
1282
1283 int scale_dim(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1284
1285         t_3dvec *dim;
1286
1287         dim=&(moldyn->dim);
1288
1289         if(dir==SCALE_UP)
1290                 scale=1.0+scale;
1291
1292         if(dir==SCALE_DOWN)
1293                 scale=1.0-scale;
1294
1295         if(x) dim->x*=scale;
1296         if(y) dim->y*=scale;
1297         if(z) dim->z*=scale;
1298
1299         return 0;
1300 }
1301
1302 int scale_atoms(t_moldyn *moldyn,u8 dir,double scale,u8 x,u8 y,u8 z) {
1303
1304         int i;
1305         t_3dvec *r;
1306
1307         if(dir==SCALE_UP)
1308                 scale=1.0+scale;
1309
1310         if(dir==SCALE_DOWN)
1311                 scale=1.0-scale;
1312
1313         for(i=0;i<moldyn->count;i++) {
1314                 r=&(moldyn->atom[i].r);
1315                 if(x) r->x*=scale;
1316                 if(y) r->y*=scale;
1317                 if(z) r->z*=scale;
1318         }
1319
1320         return 0;
1321 }
1322
1323 int scale_volume(t_moldyn *moldyn) {
1324
1325         t_3dvec *dim,*vdim;
1326         double scale;
1327         t_linkcell *lc;
1328
1329         vdim=&(moldyn->vis.dim);
1330         dim=&(moldyn->dim);
1331         lc=&(moldyn->lc);
1332
1333         /* scaling factor */
1334         if(moldyn->pt_scale&P_SCALE_BERENDSEN) {
1335                 scale=1.0-(moldyn->p_ref-moldyn->p)*moldyn->p_tc*moldyn->tau;
1336                 scale=pow(scale,ONE_THIRD);
1337         }
1338         else {
1339                 scale=pow(moldyn->p/moldyn->p_ref,ONE_THIRD);
1340         }
1341
1342         /* scale the atoms and dimensions */
1343         scale_atoms(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1344         scale_dim(moldyn,SCALE_DIRECT,scale,TRUE,TRUE,TRUE);
1345
1346         /* visualize dimensions */
1347         if(vdim->x!=0) {
1348                 vdim->x=dim->x;
1349                 vdim->y=dim->y;
1350                 vdim->z=dim->z;
1351         }
1352
1353         /* recalculate scaled volume */
1354         moldyn->volume=dim->x*dim->y*dim->z;
1355
1356         /* adjust/reinit linkcell */
1357         if(((int)(dim->x/moldyn->cutoff)!=lc->nx)||
1358            ((int)(dim->y/moldyn->cutoff)!=lc->ny)||
1359            ((int)(dim->z/moldyn->cutoff)!=lc->nx)) {
1360                 link_cell_shutdown(moldyn);
1361                 link_cell_init(moldyn,QUIET);
1362         } else {
1363                 lc->x*=scale;
1364                 lc->y*=scale;
1365                 lc->z*=scale;
1366         }
1367
1368         return 0;
1369
1370 }
1371
1372 double e_kin_calc(t_moldyn *moldyn) {
1373
1374         int i;
1375         t_atom *atom;
1376
1377         atom=moldyn->atom;
1378         moldyn->ekin=0.0;
1379
1380         for(i=0;i<moldyn->count;i++) {
1381                 atom[i].ekin=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v));
1382                 moldyn->ekin+=atom[i].ekin;
1383         }
1384
1385         return moldyn->ekin;
1386 }
1387
1388 double get_total_energy(t_moldyn *moldyn) {
1389
1390         return(moldyn->ekin+moldyn->energy);
1391 }
1392
1393 t_3dvec get_total_p(t_moldyn *moldyn) {
1394
1395         t_3dvec p,p_total;
1396         int i;
1397         t_atom *atom;
1398
1399         atom=moldyn->atom;
1400
1401         v3_zero(&p_total);
1402         for(i=0;i<moldyn->count;i++) {
1403                 v3_scale(&p,&(atom[i].v),atom[i].mass);
1404                 v3_add(&p_total,&p_total,&p);
1405         }
1406
1407         return p_total;
1408 }
1409
1410 double estimate_time_step(t_moldyn *moldyn,double nn_dist) {
1411
1412         double tau;
1413
1414         /* nn_dist is the nearest neighbour distance */
1415
1416         tau=(0.05*nn_dist*moldyn->atom[0].mass)/sqrt(3.0*K_BOLTZMANN*moldyn->t);
1417
1418         return tau;     
1419 }
1420
1421 /*
1422  * numerical tricks
1423  */
1424
1425 /* linked list / cell method */
1426
1427 int link_cell_init(t_moldyn *moldyn,u8 vol) {
1428
1429         t_linkcell *lc;
1430 #ifndef LOWMEM_LISTS
1431         int i;
1432 #endif
1433
1434         lc=&(moldyn->lc);
1435
1436         /* partitioning the md cell */
1437         lc->nx=moldyn->dim.x/moldyn->cutoff;
1438         lc->x=moldyn->dim.x/lc->nx;
1439         lc->ny=moldyn->dim.y/moldyn->cutoff;
1440         lc->y=moldyn->dim.y/lc->ny;
1441         lc->nz=moldyn->dim.z/moldyn->cutoff;
1442         lc->z=moldyn->dim.z/lc->nz;
1443         lc->cells=lc->nx*lc->ny*lc->nz;
1444
1445 #ifdef STATIC_LISTS
1446         lc->subcell=malloc(lc->cells*sizeof(int*));
1447 #elif LOWMEM_LISTS
1448         lc->subcell=malloc(sizeof(t_lowmem_list));
1449 #else
1450         lc->subcell=malloc(lc->cells*sizeof(t_list));
1451 #endif
1452
1453         if(lc->subcell==NULL) {
1454                 perror("[moldyn] cell init (malloc)");
1455                 return -1;
1456         }
1457
1458         if(lc->cells<27)
1459                 printf("[moldyn] FATAL: less then 27 subcells! (%d)\n",
1460                        lc->cells);
1461
1462         if(vol) {
1463 #ifdef STATIC_LISTS
1464                 printf("[moldyn] initializing 'static' linked cells (%d)\n",
1465                        lc->cells);
1466 #elif LOWMEM_LISTS
1467                 printf("[moldyn] initializing 'lowmem' linked cells (%d)\n",
1468                        lc->cells);
1469 #else
1470                 printf("[moldyn] initializing 'dynamic' linked cells (%d)\n",
1471                        lc->cells);
1472 #endif
1473                 printf("  x: %d x %f A\n",lc->nx,lc->x);
1474                 printf("  y: %d x %f A\n",lc->ny,lc->y);
1475                 printf("  z: %d x %f A\n",lc->nz,lc->z);
1476         }
1477
1478 #ifdef STATIC_LISTS
1479         /* list init */
1480         for(i=0;i<lc->cells;i++) {
1481                 lc->subcell[i]=malloc((MAX_ATOMS_PER_LIST+1)*sizeof(int));
1482                 if(lc->subcell[i]==NULL) {
1483                         perror("[moldyn] list init (malloc)");
1484                         return -1;
1485                 }
1486                 /*
1487                 if(i==0)
1488                         printf(" ---> %d malloc %p (%p)\n",
1489                                i,lc->subcell[0],lc->subcell);
1490                 */
1491         }
1492 #elif LOWMEM_LISTS
1493         lc->subcell->head=malloc(lc->cells*sizeof(int));
1494         if(lc->subcell->head==NULL) {
1495                 perror("[moldyn] head init (malloc)");
1496                 return -1;
1497         }
1498         lc->subcell->list=malloc(moldyn->count*sizeof(int));
1499         if(lc->subcell->list==NULL) {
1500                 perror("[moldyn] list init (malloc)");
1501                 return -1;
1502         }
1503 #else
1504         for(i=0;i<lc->cells;i++)
1505                 list_init_f(&(lc->subcell[i]));
1506 #endif
1507
1508         /* update the list */
1509         link_cell_update(moldyn);
1510
1511         return 0;
1512 }
1513
1514 int link_cell_update(t_moldyn *moldyn) {
1515
1516         int count,i,j,k;
1517         int nx,nxy;
1518         t_atom *atom;
1519         t_linkcell *lc;
1520 #ifdef STATIC_LISTS
1521         int p;
1522 #elif LOWMEM_LISTS
1523         int p;
1524 #endif
1525
1526         atom=moldyn->atom;
1527         lc=&(moldyn->lc);
1528
1529         nx=lc->nx;
1530         nxy=nx*lc->ny;
1531
1532         for(i=0;i<lc->cells;i++)
1533 #ifdef STATIC_LISTS
1534                 memset(lc->subcell[i],-1,(MAX_ATOMS_PER_LIST+1)*sizeof(int));
1535 #elif LOWMEM_LISTS
1536                 lc->subcell->head[i]=-1;
1537 #else
1538                 list_destroy_f(&(lc->subcell[i]));
1539 #endif
1540
1541         for(count=0;count<moldyn->count;count++) {
1542                 i=((atom[count].r.x+(moldyn->dim.x/2))/lc->x);
1543                 j=((atom[count].r.y+(moldyn->dim.y/2))/lc->y);
1544                 k=((atom[count].r.z+(moldyn->dim.z/2))/lc->z);
1545         
1546 #ifdef STATIC_LISTS
1547                 p=0;
1548                 while(lc->subcell[i+j*nx+k*nxy][p]!=-1)
1549                         p++;
1550
1551                 if(p>=MAX_ATOMS_PER_LIST) {
1552                         printf("[moldyn] FATAL: amount of atoms too high!\n");
1553                         return -1;
1554                 }
1555
1556                 lc->subcell[i+j*nx+k*nxy][p]=count;
1557 #elif LOWMEM_LISTS
1558                 p=i+j*nx+k*nxy;
1559                 lc->subcell->list[count]=lc->subcell->head[p];
1560                 lc->subcell->head[p]=count;
1561 #else
1562                 list_add_immediate_f(&(lc->subcell[i+j*nx+k*nxy]),
1563                                      &(atom[count]));
1564                 /*
1565                 if(j==0&&k==0)
1566                         printf(" ---> %d %d malloc %p (%p)\n",
1567                                i,count,lc->subcell[i].current,lc->subcell);
1568                 */
1569 #endif
1570         }
1571
1572         return 0;
1573 }
1574
1575 int link_cell_neighbour_index(t_moldyn *moldyn,int i,int j,int k,
1576 #ifdef STATIC_LISTS
1577                               int **cell
1578 #elif LOWMEM_LISTS
1579                               int *cell
1580 #else
1581                               t_list *cell
1582 #endif
1583                              ) {
1584
1585         t_linkcell *lc;
1586         int a;
1587         int count1,count2;
1588         int ci,cj,ck;
1589         int nx,ny,nz;
1590         int x,y,z;
1591         u8 bx,by,bz;
1592
1593         lc=&(moldyn->lc);
1594         nx=lc->nx;
1595         ny=lc->ny;
1596         nz=lc->nz;
1597         count1=1;
1598         count2=27;
1599         a=nx*ny;
1600
1601         if(i>=nx||j>=ny||k>=nz)
1602                 printf("[moldyn] WARNING: lcni %d/%d %d/%d %d/%d\n",
1603                        i,nx,j,ny,k,nz);
1604
1605 #ifndef LOWMEM_LISTS
1606         cell[0]=lc->subcell[i+j*nx+k*a];
1607 #else
1608         cell[0]=lc->subcell->head[i+j*nx+k*a];
1609 #endif
1610         for(ci=-1;ci<=1;ci++) {
1611                 bx=0;
1612                 x=i+ci;
1613                 if((x<0)||(x>=nx)) {
1614                         x=(x+nx)%nx;
1615                         bx=1;
1616                 }
1617                 for(cj=-1;cj<=1;cj++) {
1618                         by=0;
1619                         y=j+cj;
1620                         if((y<0)||(y>=ny)) {
1621                                 y=(y+ny)%ny;
1622                                 by=1;
1623                         }
1624                         for(ck=-1;ck<=1;ck++) {
1625                                 bz=0;
1626                                 z=k+ck;
1627                                 if((z<0)||(z>=nz)) {
1628                                         z=(z+nz)%nz;
1629                                         bz=1;
1630                                 }
1631                                 if(!(ci|cj|ck)) continue;
1632                                 if(bx|by|bz) {
1633 #ifndef LOWMEM_LISTS
1634                                         cell[--count2]=lc->subcell[x+y*nx+z*a];
1635 #else
1636                                 cell[--count2]=lc->subcell->head[x+y*nx+z*a];
1637 #endif
1638                                         
1639                                 }
1640                                 else {
1641 #ifndef LOWMEM_LISTS
1642                                         cell[count1++]=lc->subcell[x+y*nx+z*a];
1643 #else
1644                                 cell[count1++]=lc->subcell->head[x+y*nx+z*a];
1645 #endif
1646                                 }
1647                         }
1648                 }
1649         }
1650
1651         lc->dnlc=count1;
1652
1653         return count1;
1654 }
1655
1656 int link_cell_shutdown(t_moldyn *moldyn) {
1657
1658 #ifndef LOWMEM_LISTS
1659         int i;
1660 #endif
1661         t_linkcell *lc;
1662
1663         lc=&(moldyn->lc);
1664
1665 #if LOWMEM_LISTS
1666         free(lc->subcell->head);
1667         free(lc->subcell->list);
1668
1669 #else
1670
1671         for(i=0;i<lc->cells;i++) {
1672 #ifdef STATIC_LISTS
1673                 free(lc->subcell[i]);
1674 #else
1675                 //printf(" ---> %d free %p\n",i,lc->subcell[i].start);
1676                 list_destroy_f(&(lc->subcell[i]));
1677 #endif
1678         }
1679 #endif
1680
1681         free(lc->subcell);
1682
1683         return 0;
1684 }
1685
1686 int moldyn_add_schedule(t_moldyn *moldyn,int runs,double tau) {
1687
1688         int count;
1689         void *ptr;
1690         t_moldyn_schedule *schedule;
1691
1692         schedule=&(moldyn->schedule);
1693         count=++(schedule->total_sched);
1694
1695         ptr=realloc(schedule->runs,count*sizeof(int));
1696         if(!ptr) {
1697                 perror("[moldyn] realloc (runs)");
1698                 return -1;
1699         }
1700         schedule->runs=ptr;
1701         schedule->runs[count-1]=runs;
1702
1703         ptr=realloc(schedule->tau,count*sizeof(double));
1704         if(!ptr) {
1705                 perror("[moldyn] realloc (tau)");
1706                 return -1;
1707         }
1708         schedule->tau=ptr;
1709         schedule->tau[count-1]=tau;
1710
1711         printf("[moldyn] schedule added:\n");
1712         printf("  number: %d | runs: %d | tau: %f\n",count-1,runs,tau);
1713                                        
1714
1715         return 0;
1716 }
1717
1718 int moldyn_set_schedule_hook(t_moldyn *moldyn,set_hook hook,void *hook_params) {
1719
1720         moldyn->schedule.hook=hook;
1721         moldyn->schedule.hook_params=hook_params;
1722         
1723         return 0;
1724 }
1725
1726 /*
1727  *
1728  * 'integration of newtons equation' - algorithms
1729  *
1730  */
1731
1732 /* start the integration */
1733
1734 int moldyn_integrate(t_moldyn *moldyn) {
1735
1736         int i;
1737         unsigned int e,m,s,v,p,t,a;
1738         t_3dvec momentum;
1739         t_moldyn_schedule *sched;
1740         t_atom *atom;
1741         int fd;
1742         char dir[128];
1743         double ds;
1744         double energy_scale;
1745         struct timeval t1,t2;
1746         //double tp;
1747
1748 #ifdef VISUAL_THREAD
1749         u8 first,change;
1750         pthread_t io_thread;
1751         int ret;
1752         t_moldyn md_copy;
1753         t_atom *atom_copy;
1754
1755         first=1;
1756         change=0;
1757 #endif
1758
1759         sched=&(moldyn->schedule);
1760         atom=moldyn->atom;
1761
1762         /* initialize linked cell method */
1763         link_cell_init(moldyn,VERBOSE);
1764
1765         /* logging & visualization */
1766         e=moldyn->ewrite;
1767         m=moldyn->mwrite;
1768         s=moldyn->swrite;
1769         v=moldyn->vwrite;
1770         a=moldyn->awrite;
1771         p=moldyn->pwrite;
1772         t=moldyn->twrite;
1773
1774         /* sqaure of some variables */
1775         moldyn->tau_square=moldyn->tau*moldyn->tau;
1776
1777         /* get current time */
1778         gettimeofday(&t1,NULL);
1779
1780         /* calculate initial forces */
1781         potential_force_calc(moldyn);
1782 #ifdef DEBUG
1783 //return 0;
1784 #endif
1785
1786         /* some stupid checks before we actually start calculating bullshit */
1787         if(moldyn->cutoff>0.5*moldyn->dim.x)
1788                 printf("[moldyn] WARNING: cutoff > 0.5 x dim.x\n");
1789         if(moldyn->cutoff>0.5*moldyn->dim.y)
1790                 printf("[moldyn] WARNING: cutoff > 0.5 x dim.y\n");
1791         if(moldyn->cutoff>0.5*moldyn->dim.z)
1792                 printf("[moldyn] WARNING: cutoff > 0.5 x dim.z\n");
1793         if(moldyn->count) {
1794                 ds=0.5*atom[0].f.x*moldyn->tau_square/atom[0].mass;
1795                 if(ds>0.05*moldyn->nnd)
1796                 printf("[moldyn] WARNING: forces too high / tau too small!\n");
1797         }
1798
1799         /* zero absolute time */
1800         // should have right values!
1801         //moldyn->time=0.0;
1802         //moldyn->total_steps=0;
1803
1804         /* debugging, ignore */
1805         moldyn->debug=0;
1806
1807         /* zero & init moldyn copy */
1808 #ifdef VISUAL_THREAD
1809         memset(&md_copy,0,sizeof(t_moldyn));
1810         atom_copy=malloc(moldyn->count*sizeof(t_atom));
1811         if(atom_copy==NULL) {
1812                 perror("[moldyn] malloc atom copy (init)");
1813                 return -1;
1814         }
1815 #endif
1816
1817 #ifdef PTHREADS
1818         printf("##################\n");
1819         printf("# USING PTHREADS #\n");
1820         printf("##################\n");
1821 #endif
1822         /* tell the world */
1823         printf("[moldyn] integration start, go get a coffee ...\n");
1824
1825         /* executing the schedule */
1826         sched->count=0;
1827         while(sched->count<sched->total_sched) {
1828
1829                 /* setting amount of runs and finite time step size */
1830                 moldyn->tau=sched->tau[sched->count];
1831                 moldyn->tau_square=moldyn->tau*moldyn->tau;
1832                 moldyn->time_steps=sched->runs[sched->count];
1833
1834                 /* energy scaling factor (might change!) */
1835                 energy_scale=moldyn->count*EV;
1836
1837         /* integration according to schedule */
1838
1839         for(i=0;i<moldyn->time_steps;i++) {
1840
1841                 /* integration step */
1842                 moldyn->integrate(moldyn);
1843
1844                 /* calculate kinetic energy, temperature and pressure */
1845                 e_kin_calc(moldyn);
1846                 temperature_calc(moldyn);
1847                 virial_sum(moldyn);
1848                 pressure_calc(moldyn);
1849                 /*
1850                 thermodynamic_pressure_calc(moldyn);
1851                 printf("\n\nDEBUG: numeric pressure calc: %f\n\n",
1852                        moldyn->tp/BAR);
1853                 */
1854
1855                 /* calculate fluctuations + averages */
1856                 average_and_fluctuation_calc(moldyn);
1857
1858                 /* p/t scaling */
1859                 if(moldyn->pt_scale&(T_SCALE_BERENDSEN|T_SCALE_DIRECT))
1860                         scale_velocity(moldyn,FALSE);
1861                 if(moldyn->pt_scale&(P_SCALE_BERENDSEN|P_SCALE_DIRECT))
1862                         scale_volume(moldyn);
1863
1864                 /* check for log & visualization */
1865                 if(e) {
1866                         if(!(moldyn->total_steps%e))
1867                                 dprintf(moldyn->efd,
1868                                         "%f %f %f %f\n",
1869                                         moldyn->time,moldyn->ekin/energy_scale,
1870                                         moldyn->energy/energy_scale,
1871                                         get_total_energy(moldyn)/energy_scale);
1872                 }
1873                 if(m) {
1874                         if(!(moldyn->total_steps%m)) {
1875                                 momentum=get_total_p(moldyn);
1876                                 dprintf(moldyn->mfd,
1877                                         "%f %f %f %f %f\n",moldyn->time,
1878                                         momentum.x,momentum.y,momentum.z,
1879                                         v3_norm(&momentum));
1880                         }
1881                 }
1882                 if(p) {
1883                         if(!(moldyn->total_steps%p)) {
1884                                 dprintf(moldyn->pfd,
1885                                         "%f %f %f %f %f %f %f\n",moldyn->time,
1886                                          moldyn->p/BAR,moldyn->p_avg/BAR,
1887                                          moldyn->gp/BAR,moldyn->gp_avg/BAR,
1888                                          moldyn->tp/BAR,moldyn->tp_avg/BAR);
1889                         }
1890                 }
1891                 if(t) {
1892                         if(!(moldyn->total_steps%t)) {
1893                                 dprintf(moldyn->tfd,
1894                                         "%f %f %f\n",
1895                                         moldyn->time,moldyn->t,moldyn->t_avg);
1896                         }
1897                 }
1898                 if(v) {
1899                         if(!(moldyn->total_steps%v)) {
1900                                 dprintf(moldyn->vfd,
1901                                         "%f %f\n",moldyn->time,moldyn->volume);
1902                         }
1903                 }
1904                 if(s) {
1905                         if(!(moldyn->total_steps%s)) {
1906                                 snprintf(dir,128,"%s/s-%08.f.save",
1907                                          moldyn->vlsdir,moldyn->time);
1908                                 fd=open(dir,O_WRONLY|O_TRUNC|O_CREAT,
1909                                         S_IRUSR|S_IWUSR);
1910                                 if(fd<0) perror("[moldyn] save fd open");
1911                                 else {
1912                                         write(fd,moldyn,sizeof(t_moldyn));
1913                                         write(fd,moldyn->atom,
1914                                               moldyn->count*sizeof(t_atom));
1915                                 }
1916                                 close(fd);
1917                         }       
1918                 }
1919                 if(a) {
1920                         if(!(moldyn->total_steps%a)) {
1921 #ifdef VISUAL_THREAD
1922         /* check whether thread has not terminated yet */
1923         if(!first) {
1924                 ret=pthread_join(io_thread,NULL);
1925         }
1926         first=0;
1927         /* prepare and start thread */
1928         if(moldyn->count!=md_copy.count) {
1929                 free(atom_copy);
1930                 change=1;
1931         }
1932         memcpy(&md_copy,moldyn,sizeof(t_moldyn));
1933         if(change) {
1934                 atom_copy=malloc(moldyn->count*sizeof(t_atom));
1935                 if(atom_copy==NULL) {
1936                         perror("[moldyn] malloc atom copy (change)");
1937                         return -1;
1938                 }
1939         }
1940         md_copy.atom=atom_copy;
1941         memcpy(atom_copy,moldyn->atom,moldyn->count*sizeof(t_atom));
1942         change=0;
1943         ret=pthread_create(&io_thread,NULL,visual_atoms,&md_copy);
1944         if(ret) {
1945                 perror("[moldyn] create visual atoms thread\n");
1946                 return -1;
1947         }
1948 #else
1949                                 visual_atoms(moldyn);
1950 #endif
1951                         }
1952                 }
1953
1954                 /* display progress */
1955                 if(!(i%10)) {
1956                         /* get current time */
1957                         gettimeofday(&t2,NULL);
1958
1959 printf("sched:%d, steps:%d/%d, T:%4.1f/%4.1f P:%4.1f/%4.1f V:%6.1f (%d)\n",
1960        sched->count,i,moldyn->total_steps,
1961        moldyn->t,moldyn->t_avg,
1962        moldyn->p/BAR,moldyn->p_avg/BAR,
1963        //moldyn->p/BAR,(moldyn->p-2.0*moldyn->ekin/(3.0*moldyn->volume))/BAR,
1964        moldyn->volume,
1965        (int)(t2.tv_sec-t1.tv_sec));
1966
1967                         fflush(stdout);
1968
1969                         /* copy over time */
1970                         t1=t2;
1971                 }
1972
1973                 /* increase absolute time */
1974                 moldyn->time+=moldyn->tau;
1975                 moldyn->total_steps+=1;
1976
1977         }
1978
1979                 /* check for hooks */
1980                 if(sched->hook) {
1981                         printf("\n ## schedule hook %d start ##\n",
1982                                sched->count);
1983                         sched->hook(moldyn,sched->hook_params);
1984                         printf(" ## schedule hook end ##\n");
1985                 }
1986
1987                 /* increase the schedule counter */
1988                 sched->count+=1;
1989
1990         }
1991
1992         return 0;
1993 }
1994
1995 /* velocity verlet */
1996
1997 int velocity_verlet(t_moldyn *moldyn) {
1998
1999         int i,count;
2000         double tau,tau_square,h;
2001         t_3dvec delta;
2002         t_atom *atom;
2003
2004         atom=moldyn->atom;
2005         count=moldyn->count;
2006         tau=moldyn->tau;
2007         tau_square=moldyn->tau_square;
2008
2009         for(i=0;i<count;i++) {
2010                 /* check whether fixed atom */
2011                 if(atom[i].attr&ATOM_ATTR_FP)
2012                         continue;
2013                 /* new positions */
2014                 h=0.5/atom[i].mass;
2015                 v3_scale(&delta,&(atom[i].v),tau);
2016                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
2017                 v3_scale(&delta,&(atom[i].f),h*tau_square);
2018                 v3_add(&(atom[i].r),&(atom[i].r),&delta);
2019                 check_per_bound(moldyn,&(atom[i].r));
2020
2021                 /* velocities [actually v(t+tau/2)] */
2022                 v3_scale(&delta,&(atom[i].f),h*tau);
2023                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
2024         }
2025
2026         /* criticial check */
2027         moldyn_bc_check(moldyn);
2028
2029         /* neighbour list update */
2030         link_cell_update(moldyn);
2031
2032         /* forces depending on chosen potential */
2033 #ifndef ALBE_FAST
2034         potential_force_calc(moldyn);
2035 #else
2036         albe_potential_force_calc(moldyn);
2037 #endif
2038
2039         for(i=0;i<count;i++) {
2040                 /* check whether fixed atom */
2041                 if(atom[i].attr&ATOM_ATTR_FP)
2042                         continue;
2043                 /* again velocities [actually v(t+tau)] */
2044                 v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass);
2045                 v3_add(&(atom[i].v),&(atom[i].v),&delta);
2046         }
2047
2048         return 0;
2049 }
2050
2051
2052 /*
2053  *
2054  * potentials & corresponding forces & virial routine
2055  * 
2056  */
2057
2058 /* generic potential and force calculation */
2059
2060 int potential_force_calc(t_moldyn *moldyn) {
2061
2062         int i,j,k,count;
2063         t_atom *itom,*jtom,*ktom;
2064         t_virial *virial;
2065         t_linkcell *lc;
2066 #ifdef STATIC_LISTS
2067         int *neighbour_i[27];
2068         int p,q;
2069         t_atom *atom;
2070 #elif LOWMEM_LISTS
2071         int neighbour_i[27];
2072         int p,q;
2073 #else
2074         t_list neighbour_i[27];
2075         t_list neighbour_i2[27];
2076         t_list *this,*that;
2077 #endif
2078         u8 bc_ij,bc_ik;
2079         int dnlc;
2080
2081         count=moldyn->count;
2082         itom=moldyn->atom;
2083         lc=&(moldyn->lc);
2084 #ifdef STATIC_LISTS
2085         atom=moldyn->atom;
2086 #endif
2087
2088         /* reset energy */
2089         moldyn->energy=0.0;
2090
2091         /* reset global virial */
2092         memset(&(moldyn->gvir),0,sizeof(t_virial));
2093
2094         /* reset force, site energy and virial of every atom */
2095 #ifdef PARALLEL
2096         i=omp_get_thread_num();
2097         #pragma omp parallel for private(virial)
2098 #endif
2099         for(i=0;i<count;i++) {
2100
2101                 /* reset force */
2102                 v3_zero(&(itom[i].f));
2103
2104                 /* reset virial */
2105                 virial=(&(itom[i].virial));
2106                 virial->xx=0.0;
2107                 virial->yy=0.0;
2108                 virial->zz=0.0;
2109                 virial->xy=0.0;
2110                 virial->xz=0.0;
2111                 virial->yz=0.0;
2112         
2113                 /* reset site energy */
2114                 itom[i].e=0.0;
2115
2116         }
2117
2118         /* get energy, force and virial of every atom */
2119
2120         /* first (and only) loop over atoms i */
2121         for(i=0;i<count;i++) {
2122
2123                 /* single particle potential/force */
2124                 if(itom[i].attr&ATOM_ATTR_1BP)
2125                         if(moldyn->func1b)
2126                                 moldyn->func1b(moldyn,&(itom[i]));
2127
2128                 if(!(itom[i].attr&(ATOM_ATTR_2BP|ATOM_ATTR_3BP)))
2129                         continue;
2130
2131                 /* 2 body pair potential/force */
2132         
2133                 link_cell_neighbour_index(moldyn,
2134                                           (itom[i].r.x+moldyn->dim.x/2)/lc->x,
2135                                           (itom[i].r.y+moldyn->dim.y/2)/lc->y,
2136                                           (itom[i].r.z+moldyn->dim.z/2)/lc->z,
2137                                           neighbour_i);
2138
2139                 dnlc=lc->dnlc;
2140
2141                 /* first loop over atoms j */
2142                 if(moldyn->func2b) {
2143                         for(j=0;j<27;j++) {
2144
2145                                 bc_ij=(j<dnlc)?0:1;
2146 #ifdef STATIC_LISTS
2147                                 p=0;
2148
2149                                 while(neighbour_i[j][p]!=-1) {
2150
2151                                         jtom=&(atom[neighbour_i[j][p]]);
2152                                         p++;
2153 #elif LOWMEM_LISTS
2154                                 p=neighbour_i[j];
2155
2156                                 while(p!=-1) {
2157
2158                                         jtom=&(itom[p]);
2159                                         p=lc->subcell->list[p];
2160 #else
2161                                 this=&(neighbour_i[j]);
2162                                 list_reset_f(this);
2163
2164                                 if(this->start==NULL)
2165                                         continue;
2166
2167                                 do {
2168                                         jtom=this->current->data;
2169 #endif
2170
2171                                         if(jtom==&(itom[i]))
2172                                                 continue;
2173
2174                                         if((jtom->attr&ATOM_ATTR_2BP)&
2175                                            (itom[i].attr&ATOM_ATTR_2BP)) {
2176                                                 moldyn->func2b(moldyn,
2177                                                                &(itom[i]),
2178                                                                jtom,
2179                                                                bc_ij);
2180                                         }
2181 #ifdef STATIC_LISTS
2182                                 }
2183 #elif LOWMEM_LISTS
2184                                 }
2185 #else
2186                                 } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2187 #endif
2188
2189                         }
2190                 }
2191
2192                 /* 3 body potential/force */
2193
2194                 if(!(itom[i].attr&ATOM_ATTR_3BP))
2195                         continue;
2196
2197                 /* copy the neighbour lists */
2198 #ifdef STATIC_LISTS
2199                 /* no copy needed for static lists */
2200 #elif LOWMEM_LISTS
2201                 /* no copy needed for lowmem lists */
2202 #else
2203                 memcpy(neighbour_i2,neighbour_i,27*sizeof(t_list));
2204 #endif
2205
2206                 /* second loop over atoms j */
2207                 for(j=0;j<27;j++) {
2208
2209                         bc_ij=(j<dnlc)?0:1;
2210 #ifdef STATIC_LISTS
2211                         p=0;
2212
2213                         while(neighbour_i[j][p]!=-1) {
2214
2215                                 jtom=&(atom[neighbour_i[j][p]]);
2216                                 p++;
2217 #elif LOWMEM_LISTS
2218                                 p=neighbour_i[j];
2219
2220                                 while(p!=-1) {
2221
2222                                         jtom=&(itom[p]);
2223                                         p=lc->subcell->list[p];
2224 #else
2225                         this=&(neighbour_i[j]);
2226                         list_reset_f(this);
2227
2228                         if(this->start==NULL)
2229                                 continue;
2230
2231                         do {
2232
2233                                 jtom=this->current->data;
2234 #endif
2235
2236                                 if(jtom==&(itom[i]))
2237                                         continue;
2238
2239                                 if(!(jtom->attr&ATOM_ATTR_3BP))
2240                                         continue;
2241
2242                                 /* reset 3bp run */
2243                                 moldyn->run3bp=1;
2244
2245                                 if(moldyn->func3b_j1)
2246                                         moldyn->func3b_j1(moldyn,
2247                                                           &(itom[i]),
2248                                                           jtom,
2249                                                           bc_ij);
2250
2251                                 /* in first j loop, 3bp run can be skipped */
2252                                 if(!(moldyn->run3bp))
2253                                         continue;
2254                         
2255                                 /* first loop over atoms k */
2256                                 if(moldyn->func3b_k1) {
2257
2258                                 for(k=0;k<27;k++) {
2259
2260                                         bc_ik=(k<dnlc)?0:1;
2261 #ifdef STATIC_LISTS
2262                                         q=0;
2263
2264                                         while(neighbour_i[k][q]!=-1) {
2265
2266                                                 ktom=&(atom[neighbour_i[k][q]]);
2267                                                 q++;
2268 #elif LOWMEM_LISTS
2269                                         q=neighbour_i[k];
2270
2271                                         while(q!=-1) {
2272
2273                                                 ktom=&(itom[q]);
2274                                                 q=lc->subcell->list[q];
2275 #else
2276                                         that=&(neighbour_i2[k]);
2277                                         list_reset_f(that);
2278                                         
2279                                         if(that->start==NULL)
2280                                                 continue;
2281
2282                                         do {
2283                                                 ktom=that->current->data;
2284 #endif
2285
2286                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
2287                                                         continue;
2288
2289                                                 if(ktom==jtom)
2290                                                         continue;
2291
2292                                                 if(ktom==&(itom[i]))
2293                                                         continue;
2294
2295                                                 moldyn->func3b_k1(moldyn,
2296                                                                   &(itom[i]),
2297                                                                   jtom,
2298                                                                   ktom,
2299                                                                   bc_ik|bc_ij);
2300
2301 #ifdef STATIC_LISTS
2302                                         }
2303 #elif LOWMEM_LISTS
2304                                         }
2305 #else
2306                                         } while(list_next_f(that)!=\
2307                                                 L_NO_NEXT_ELEMENT);
2308 #endif
2309
2310                                 }
2311
2312                                 }
2313
2314                                 if(moldyn->func3b_j2)
2315                                         moldyn->func3b_j2(moldyn,
2316                                                           &(itom[i]),
2317                                                           jtom,
2318                                                           bc_ij);
2319
2320                                 /* second loop over atoms k */
2321                                 if(moldyn->func3b_k2) {
2322
2323                                 for(k=0;k<27;k++) {
2324
2325                                         bc_ik=(k<dnlc)?0:1;
2326 #ifdef STATIC_LISTS
2327                                         q=0;
2328
2329                                         while(neighbour_i[k][q]!=-1) {
2330
2331                                                 ktom=&(atom[neighbour_i[k][q]]);
2332                                                 q++;
2333 #elif LOWMEM_LISTS
2334                                         q=neighbour_i[k];
2335
2336                                         while(q!=-1) {
2337
2338                                                 ktom=&(itom[q]);
2339                                                 q=lc->subcell->list[q];
2340 #else
2341                                         that=&(neighbour_i2[k]);
2342                                         list_reset_f(that);
2343                                         
2344                                         if(that->start==NULL)
2345                                                 continue;
2346
2347                                         do {
2348                                                 ktom=that->current->data;
2349 #endif
2350
2351                                                 if(!(ktom->attr&ATOM_ATTR_3BP))
2352                                                         continue;
2353
2354                                                 if(ktom==jtom)
2355                                                         continue;
2356
2357                                                 if(ktom==&(itom[i]))
2358                                                         continue;
2359
2360                                                 moldyn->func3b_k2(moldyn,
2361                                                                   &(itom[i]),
2362                                                                   jtom,
2363                                                                   ktom,
2364                                                                   bc_ik|bc_ij);
2365
2366 #ifdef STATIC_LISTS
2367                                         }
2368 #elif LOWMEM_LISTS
2369                                         }
2370 #else
2371                                         } while(list_next_f(that)!=\
2372                                                 L_NO_NEXT_ELEMENT);
2373 #endif
2374
2375                                 }
2376                                 
2377                                 }
2378
2379                                 /* 2bp post function */
2380                                 if(moldyn->func3b_j3) {
2381                                         moldyn->func3b_j3(moldyn,
2382                                                           &(itom[i]),
2383                                                           jtom,bc_ij);
2384                                 }
2385 #ifdef STATIC_LISTS
2386                         }
2387 #elif LOWMEM_LISTS
2388                         }
2389 #else
2390                         } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2391 #endif
2392                 
2393                 }
2394                 
2395 #ifdef DEBUG
2396         //printf("\n\n");
2397 #endif
2398 #ifdef VDEBUG
2399         printf("\n\n");
2400 #endif
2401
2402         }
2403
2404 #ifdef DEBUG
2405         //printf("\nATOM 0: %f %f %f\n\n",itom->f.x,itom->f.y,itom->f.z);
2406         if(moldyn->time>DSTART&&moldyn->time<DEND) {
2407                 printf("force:\n");
2408                 printf("  x: %0.40f\n",moldyn->atom[DATOM].f.x);
2409                 printf("  y: %0.40f\n",moldyn->atom[DATOM].f.y);
2410                 printf("  z: %0.40f\n",moldyn->atom[DATOM].f.z);
2411         }
2412 #endif
2413
2414         /* some postprocessing */
2415 #ifdef PARALLEL
2416         #pragma omp parallel for
2417 #endif
2418         for(i=0;i<count;i++) {
2419                 /* calculate global virial */
2420                 moldyn->gvir.xx+=itom[i].r.x*itom[i].f.x;
2421                 moldyn->gvir.yy+=itom[i].r.y*itom[i].f.y;
2422                 moldyn->gvir.zz+=itom[i].r.z*itom[i].f.z;
2423                 moldyn->gvir.xy+=itom[i].r.y*itom[i].f.x;
2424                 moldyn->gvir.xz+=itom[i].r.z*itom[i].f.x;
2425                 moldyn->gvir.yz+=itom[i].r.z*itom[i].f.y;
2426
2427                 /* check forces regarding the given timestep */
2428                 if(v3_norm(&(itom[i].f))>\
2429                    0.1*moldyn->nnd*itom[i].mass/moldyn->tau_square)
2430                         printf("[moldyn] WARNING: pfc (high force: atom %d)\n",
2431                                i);
2432         }
2433
2434         return 0;
2435 }
2436
2437 /*
2438  * virial calculation
2439  */
2440
2441 //inline int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
2442 int virial_calc(t_atom *a,t_3dvec *f,t_3dvec *d) {
2443
2444         a->virial.xx+=f->x*d->x;
2445         a->virial.yy+=f->y*d->y;
2446         a->virial.zz+=f->z*d->z;
2447         a->virial.xy+=f->x*d->y;
2448         a->virial.xz+=f->x*d->z;
2449         a->virial.yz+=f->y*d->z;
2450
2451         return 0;
2452 }
2453
2454 /*
2455  * periodic boundary checking
2456  */
2457
2458 //inline int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
2459 int check_per_bound(t_moldyn *moldyn,t_3dvec *a) {
2460         
2461         double x,y,z;
2462         t_3dvec *dim;
2463
2464         dim=&(moldyn->dim);
2465
2466         x=dim->x/2;
2467         y=dim->y/2;
2468         z=dim->z/2;
2469
2470         if(moldyn->status&MOLDYN_STAT_PBX) {
2471                 if(a->x>=x) a->x-=dim->x;
2472                 else if(-a->x>x) a->x+=dim->x;
2473         }
2474         if(moldyn->status&MOLDYN_STAT_PBY) {
2475                 if(a->y>=y) a->y-=dim->y;
2476                 else if(-a->y>y) a->y+=dim->y;
2477         }
2478         if(moldyn->status&MOLDYN_STAT_PBZ) {
2479                 if(a->z>=z) a->z-=dim->z;
2480                 else if(-a->z>z) a->z+=dim->z;
2481         }
2482
2483         return 0;
2484 }
2485         
2486 /*
2487  * debugging / critical check functions
2488  */
2489
2490 int moldyn_bc_check(t_moldyn *moldyn) {
2491
2492         t_atom *atom;
2493         t_3dvec *dim;
2494         int i;
2495         double x;
2496         u8 byte;
2497         int j,k;
2498
2499         atom=moldyn->atom;
2500         dim=&(moldyn->dim);
2501         x=dim->x/2;
2502
2503         for(i=0;i<moldyn->count;i++) {
2504                 if(atom[i].r.x>=dim->x/2||-atom[i].r.x>dim->x/2) {
2505                         printf("FATAL: atom %d: x: %.20f (%.20f)\n",
2506                                i,atom[i].r.x,dim->x/2);
2507                         printf("diagnostic:\n");
2508                         printf("-----------\natom.r.x:\n");
2509                         for(j=0;j<8;j++) {
2510                                 memcpy(&byte,(u8 *)(&(atom[i].r.x))+j,1);
2511                                 for(k=0;k<8;k++)
2512                                         printf("%d%c",
2513                                         ((byte)&(1<<k))?1:0,
2514                                         (k==7)?'\n':'|');
2515                         }
2516                         printf("---------------\nx=dim.x/2:\n");
2517                         for(j=0;j<8;j++) {
2518                                 memcpy(&byte,(u8 *)(&x)+j,1);
2519                                 for(k=0;k<8;k++)
2520                                         printf("%d%c",
2521                                         ((byte)&(1<<k))?1:0,
2522                                         (k==7)?'\n':'|');
2523                         }
2524                         if(atom[i].r.x==x) printf("the same!\n");
2525                         else printf("different!\n");
2526                 }
2527                 if(atom[i].r.y>=dim->y/2||-atom[i].r.y>dim->y/2)
2528                         printf("FATAL: atom %d: y: %.20f (%.20f)\n",
2529                                i,atom[i].r.y,dim->y/2);
2530                 if(atom[i].r.z>=dim->z/2||-atom[i].r.z>dim->z/2)
2531                         printf("FATAL: atom %d: z: %.20f (%.20f)\n",
2532                                i,atom[i].r.z,dim->z/2);
2533         }
2534
2535         return 0;
2536 }
2537
2538 /*
2539  * restore function
2540  */
2541
2542 int moldyn_read_save_file(t_moldyn *moldyn,char *file) {
2543
2544         int fd;
2545         int cnt,size;
2546         int fsize;
2547         int corr;
2548
2549         fd=open(file,O_RDONLY);
2550         if(fd<0) {
2551                 perror("[moldyn] load save file open");
2552                 return fd;
2553         }
2554
2555         fsize=lseek(fd,0,SEEK_END);
2556         lseek(fd,0,SEEK_SET);
2557
2558         size=sizeof(t_moldyn);
2559
2560         while(size) {
2561                 cnt=read(fd,moldyn,size);
2562                 if(cnt<0) {
2563                         perror("[moldyn] load save file read (moldyn)");
2564                         return cnt;
2565                 }
2566                 size-=cnt;
2567         }
2568
2569         size=moldyn->count*sizeof(t_atom);
2570
2571         /* correcting possible atom data offset */
2572         corr=0;
2573         if(fsize!=sizeof(t_moldyn)+size) {
2574                 corr=fsize-sizeof(t_moldyn)-size;
2575                 printf("[moldyn] WARNING: lsf (illegal file size)\n");
2576                 printf("  moifying offset:\n");
2577                 printf("  - current pos: %d\n",sizeof(t_moldyn));
2578                 printf("  - atom size: %d\n",size);
2579                 printf("  - file size: %d\n",fsize);
2580                 printf("  => correction: %d\n",corr);
2581                 lseek(fd,corr,SEEK_CUR);
2582         }
2583
2584         moldyn->atom=(t_atom *)malloc(size);
2585         if(moldyn->atom==NULL) {
2586                 perror("[moldyn] load save file malloc (atoms)");
2587                 return -1;
2588         }
2589
2590         while(size) {
2591                 cnt=read(fd,moldyn->atom,size);
2592                 if(cnt<0) {
2593                         perror("[moldyn] load save file read (atoms)");
2594                         return cnt;
2595                 }
2596                 size-=cnt;
2597         }
2598
2599         // hooks etc ...
2600
2601         return 0;
2602 }
2603
2604 int moldyn_free_save_file(t_moldyn *moldyn) {
2605
2606         free(moldyn->atom);
2607
2608         return 0;
2609 }
2610
2611 int moldyn_load(t_moldyn *moldyn) {
2612
2613         // later ...
2614
2615         return 0;
2616 }
2617
2618 /*
2619  * function to find/callback all combinations of 2 body bonds
2620  */
2621
2622 int process_2b_bonds(t_moldyn *moldyn,void *data,
2623                      int (*process)(t_moldyn *moldyn,t_atom *itom,t_atom *jtom,
2624                                     void *data,u8 bc)) {
2625
2626         t_linkcell *lc;
2627 #ifdef STATIC_LISTS
2628         int *neighbour[27];
2629         int p;
2630 #elif LOWMEM_LISTS
2631         int neighbour[27];
2632         int p;
2633 #else
2634         t_list neighbour[27];
2635         t_list *this;
2636 #endif
2637         u8 bc;
2638         t_atom *itom,*jtom;
2639         int i,j;
2640
2641         lc=&(moldyn->lc);
2642         itom=moldyn->atom;
2643         
2644         for(i=0;i<moldyn->count;i++) {
2645                 /* neighbour indexing */
2646                 link_cell_neighbour_index(moldyn,
2647                                           (itom[i].r.x+moldyn->dim.x/2)/lc->x,
2648                                           (itom[i].r.y+moldyn->dim.y/2)/lc->x,
2649                                           (itom[i].r.z+moldyn->dim.z/2)/lc->x,
2650                                           neighbour);
2651
2652                 for(j=0;j<27;j++) {
2653
2654                         bc=(j<lc->dnlc)?0:1;
2655
2656 #ifdef STATIC_LISTS
2657                         p=0;
2658
2659                         while(neighbour[j][p]!=-1) {
2660
2661                                 jtom=&(moldyn->atom[neighbour[j][p]]);
2662                                 p++;
2663 #elif LOWMEM_LISTS
2664                         p=neighbour[j];
2665
2666                         while(p!=-1) {
2667
2668                                 jtom=&(itom[p]);
2669                                 p=lc->subcell->list[p];
2670 #else
2671                         this=&(neighbour[j]);
2672                         list_reset_f(this);
2673
2674                         if(this->start==NULL)
2675                                 continue;
2676
2677                         do {
2678
2679                                 jtom=this->current->data;
2680 #endif
2681
2682                                 /* process bond */
2683                                 process(moldyn,&(itom[i]),jtom,data,bc);
2684
2685 #ifdef STATIC_LISTS
2686                         }
2687 #elif LOWMEM_LISTS
2688                         }
2689 #else
2690                         } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2691 #endif
2692                 }
2693         }
2694
2695         return 0;
2696
2697 }
2698
2699 /*
2700  * function to find neighboured atoms
2701  */
2702
2703 int process_neighbours(t_moldyn *moldyn,void *data,t_atom *atom,
2704                        int (*process)(t_moldyn *moldyn,t_atom *atom,t_atom *natom,
2705                                       void *data,u8 bc)) {
2706
2707         t_linkcell *lc;
2708 #ifdef STATIC_LISTS
2709         int *neighbour[27];
2710         int p;
2711 #elif LOWMEM_LISTS
2712         int neighbour[27];
2713         int p;
2714 #else
2715         t_list neighbour[27];
2716         t_list *this;
2717 #endif
2718         u8 bc;
2719         t_atom *natom;
2720         int j;
2721
2722         lc=&(moldyn->lc);
2723         
2724         /* neighbour indexing */
2725         link_cell_neighbour_index(moldyn,
2726                                   (atom->r.x+moldyn->dim.x/2)/lc->x,
2727                                   (atom->r.y+moldyn->dim.y/2)/lc->x,
2728                                   (atom->r.z+moldyn->dim.z/2)/lc->x,
2729                                   neighbour);
2730
2731         for(j=0;j<27;j++) {
2732
2733                 bc=(j<lc->dnlc)?0:1;
2734
2735 #ifdef STATIC_LISTS
2736                 p=0;
2737
2738                 while(neighbour[j][p]!=-1) {
2739
2740                         natom=&(moldyn->atom[neighbour[j][p]]);
2741                         p++;
2742 #elif LOWMEM_LISTS
2743                 p=neighbour[j];
2744
2745                 while(p!=-1) {
2746
2747                         natom=&(moldyn->atom[p]);
2748                         p=lc->subcell->list[p];
2749 #else
2750                 this=&(neighbour[j]);
2751                 list_reset_f(this);
2752
2753                 if(this->start==NULL)
2754                         continue;
2755
2756                 do {
2757
2758                         natom=this->current->data;
2759 #endif
2760
2761                         /* process bond */
2762                         process(moldyn,atom,natom,data,bc);
2763
2764 #ifdef STATIC_LISTS
2765                 }
2766 #elif LOWMEM_LISTS
2767                 }
2768 #else
2769                 } while(list_next_f(this)!=L_NO_NEXT_ELEMENT);
2770 #endif
2771         }
2772
2773         return 0;
2774
2775 }
2776
2777 /*
2778  * post processing functions
2779  */
2780
2781 int get_line(int fd,char *line,int max) {
2782
2783         int count,ret;
2784
2785         count=0;
2786
2787         while(1) {
2788                 if(count==max) return count;
2789                 ret=read(fd,line+count,1);
2790                 if(ret<=0) return ret;
2791                 if(line[count]=='\n') {
2792                         memset(line+count,0,max-count-1);
2793                         //line[count]='\0';
2794                         return count+1;
2795                 }
2796                 count+=1;
2797         }
2798 }
2799
2800 int pair_correlation_init(t_moldyn *moldyn,double dr) {
2801
2802         
2803         return 0;
2804 }
2805
2806 int calculate_diffusion_coefficient(t_moldyn *moldyn,double *dc) {
2807
2808         int i;
2809         t_atom *atom;
2810         t_3dvec dist;
2811         double d2;
2812         int a_cnt;
2813         int b_cnt;
2814
2815         atom=moldyn->atom;
2816         dc[0]=0;
2817         dc[1]=0;
2818         dc[2]=0;
2819         a_cnt=0;
2820         b_cnt=0;
2821
2822         for(i=0;i<moldyn->count;i++) {
2823
2824                 v3_sub(&dist,&(atom[i].r),&(atom[i].r_0));
2825                 check_per_bound(moldyn,&dist);
2826                 d2=v3_absolute_square(&dist);
2827
2828                 if(atom[i].brand) {
2829                         b_cnt+=1;
2830                         dc[1]+=d2;
2831                 }
2832                 else {
2833                         a_cnt+=1;
2834                         dc[0]+=d2;
2835                 }
2836
2837                 dc[2]+=d2;
2838         }
2839
2840         dc[0]*=(1.0/(6.0*moldyn->time*a_cnt));
2841         dc[1]*=(1.0/(6.0*moldyn->time*b_cnt));
2842         dc[2]*=(1.0/(6.0*moldyn->time*moldyn->count));
2843                 
2844         return 0;
2845 }
2846
2847 int bonding_analyze(t_moldyn *moldyn,double *cnt) {
2848
2849         return 0;
2850 }
2851
2852 int calculate_pair_correlation_process(t_moldyn *moldyn,t_atom *itom,
2853                                        t_atom *jtom,void *data,u8 bc) {
2854
2855         t_3dvec dist;
2856         double d;
2857         int s;
2858         t_pcc *pcc;
2859
2860         /* only count pairs once,
2861          * skip same atoms */
2862         if(itom->tag>=jtom->tag)
2863                 return 0;
2864
2865         /*
2866          * pair correlation calc
2867          */
2868
2869         /* get pcc data */
2870         pcc=data;
2871
2872         /* distance */
2873         v3_sub(&dist,&(jtom->r),&(itom->r));
2874         if(bc) check_per_bound(moldyn,&dist);
2875         d=v3_absolute_square(&dist);
2876
2877         /* ignore if greater cutoff */
2878         if(d>moldyn->cutoff_square)
2879                 return 0;
2880
2881         /* fill the slots */
2882         d=sqrt(d);
2883         s=(int)(d/pcc->dr);
2884
2885         /* should never happen but it does 8) -
2886          * related to -ffloat-store problem! */
2887         if(s>=pcc->o1) {
2888                 printf("[moldyn] WARNING: pcc (%d/%d)",
2889                        s,pcc->o1);
2890                 printf("\n");
2891                 s=pcc->o1-1;
2892         }
2893
2894         if(itom->brand!=jtom->brand) {
2895                 /* mixed */
2896                 pcc->stat[s]+=1;
2897         }
2898         else {
2899                 /* type a - type a bonds */
2900                 if(itom->brand==0)
2901                         pcc->stat[s+pcc->o1]+=1;
2902                 else
2903                 /* type b - type b bonds */
2904                         pcc->stat[s+pcc->o2]+=1;
2905         }
2906
2907         return 0;
2908 }
2909
2910 int calculate_pair_correlation(t_moldyn *moldyn,double dr,void *ptr) {
2911
2912         t_pcc pcc;
2913         double norm;
2914         int i;
2915
2916         pcc.dr=dr;
2917         pcc.o1=moldyn->cutoff/dr;
2918         pcc.o2=2*pcc.o1;
2919
2920         if(pcc.o1*dr<=moldyn->cutoff)
2921                 printf("[moldyn] WARNING: pcc (low #slots)\n");
2922
2923         printf("[moldyn] pair correlation calc info:\n");
2924         printf("  time: %f\n",moldyn->time);
2925         printf("  count: %d\n",moldyn->count);
2926         printf("  cutoff: %f\n",moldyn->cutoff);
2927         printf("  temperature: cur=%f avg=%f\n",moldyn->t,moldyn->t_avg);
2928
2929         if(ptr!=NULL) {
2930                 pcc.stat=(double *)ptr;
2931         }
2932         else {
2933                 pcc.stat=(double *)malloc(3*pcc.o1*sizeof(double));
2934                 if(pcc.stat==NULL) {
2935                         perror("[moldyn] pair correlation malloc");
2936                         return -1;
2937                 }
2938         }
2939
2940         memset(pcc.stat,0,3*pcc.o1*sizeof(double));
2941
2942         /* process */
2943         process_2b_bonds(moldyn,&pcc,calculate_pair_correlation_process);
2944
2945         /* normalization */
2946         for(i=1;i<pcc.o1;i++) {
2947                  // normalization: 4 pi r^2 dr
2948                  // here: not double counting pairs -> 2 pi r r dr
2949                  // ... and actually it's a constant times r^2
2950                 norm=i*i*dr*dr;
2951                 pcc.stat[i]/=norm;
2952                 pcc.stat[pcc.o1+i]/=norm;
2953                 pcc.stat[pcc.o2+i]/=norm;
2954         }
2955         /* */
2956
2957         if(ptr==NULL) {
2958                 /* todo: store/print pair correlation function */
2959                 free(pcc.stat);
2960         }
2961
2962         return 0;
2963 }
2964
2965 int bond_analyze_process(t_moldyn *moldyn,t_atom *itom,t_atom *jtom,
2966                          void *data,u8 bc) {
2967
2968         t_ba *ba;
2969         t_3dvec dist;
2970         double d;
2971
2972         if(itom->tag>=jtom->tag)
2973                 return 0;
2974
2975         /* distance */
2976         v3_sub(&dist,&(jtom->r),&(itom->r));
2977         if(bc) check_per_bound(moldyn,&dist);
2978         d=v3_absolute_square(&dist);
2979
2980         /* ignore if greater or equal cutoff */
2981         if(d>moldyn->cutoff_square)
2982                 return 0;
2983
2984         /* check for potential bond */
2985         if(moldyn->check_2b_bond(moldyn,itom,jtom,bc)==FALSE)
2986                 return 0;
2987
2988         /* now count this bonding ... */
2989         ba=data;
2990
2991         /* increase total bond counter
2992          * ... double counting!
2993          */
2994         ba->tcnt+=2;
2995
2996         if(itom->brand==0)
2997                 ba->acnt[jtom->tag]+=1;
2998         else
2999                 ba->bcnt[jtom->tag]+=1;
3000         
3001         if(jtom->brand==0)
3002                 ba->acnt[itom->tag]+=1;
3003         else
3004                 ba->bcnt[itom->tag]+=1;
3005
3006         return 0;
3007 }
3008
3009 int bond_analyze(t_moldyn *moldyn,double *quality) {
3010
3011         // by now: # bonds of type 'a-4b' and 'b-4a' / # bonds total
3012
3013         int qcnt;
3014         int ccnt,cset;
3015         t_ba ba;
3016         int i;
3017         t_atom *atom;
3018
3019         ba.acnt=malloc(moldyn->count*sizeof(int));
3020         if(ba.acnt==NULL) {
3021                 perror("[moldyn] bond analyze malloc (a)");
3022                 return -1;
3023         }
3024         memset(ba.acnt,0,moldyn->count*sizeof(int));
3025
3026         ba.bcnt=malloc(moldyn->count*sizeof(int));
3027         if(ba.bcnt==NULL) {
3028                 perror("[moldyn] bond analyze malloc (b)");
3029                 return -1;
3030         }
3031         memset(ba.bcnt,0,moldyn->count*sizeof(int));
3032
3033         ba.tcnt=0;
3034         qcnt=0;
3035         ccnt=0;
3036         cset=0;
3037
3038         atom=moldyn->atom;
3039
3040         process_2b_bonds(moldyn,&ba,bond_analyze_process);
3041
3042         for(i=0;i<moldyn->count;i++) {
3043                 if(atom[i].brand==0) {
3044                         if((ba.acnt[i]==0)&(ba.bcnt[i]==4))
3045                                 qcnt+=4;
3046                 }
3047                 else {
3048                         if((ba.acnt[i]==4)&(ba.bcnt[i]==0)) {
3049                                 qcnt+=4;
3050                                 ccnt+=1;
3051                         }
3052                         cset+=1;
3053                 }
3054         }
3055
3056         printf("[moldyn] bond analyze: c_cnt=%d | set=%d\n",ccnt,cset);
3057         printf("[moldyn] bond analyze: q_cnt=%d | tot=%d\n",qcnt,ba.tcnt);
3058
3059         if(quality) {
3060                 quality[0]=1.0*ccnt/cset;
3061                 quality[1]=1.0*qcnt/ba.tcnt;
3062         }
3063         else {
3064                 printf("[moldyn] bond analyze: c_bnd_q=%f\n",1.0*qcnt/ba.tcnt);
3065                 printf("[moldyn] bond analyze:   tot_q=%f\n",1.0*qcnt/ba.tcnt);
3066         }
3067
3068         return 0;
3069 }
3070
3071 /*
3072  * visualization code
3073  */
3074
3075 int visual_init(t_moldyn *moldyn,char *filebase) {
3076
3077         strncpy(moldyn->vis.fb,filebase,128);
3078
3079         return 0;
3080 }
3081
3082 int visual_bonds_process(t_moldyn *moldyn,t_atom *itom,t_atom *jtom,
3083                          void *data,u8 bc) {
3084
3085         t_vb *vb;
3086
3087         vb=data;
3088
3089         if(itom->tag>=jtom->tag)
3090                 return 0;
3091         
3092         if(moldyn->check_2b_bond(moldyn,itom,jtom,bc)==FALSE)
3093                 return 0;
3094
3095         if((itom->attr&ATOM_ATTR_VB)|(jtom->attr&ATOM_ATTR_VB))
3096                 dprintf(vb->fd,"# [B] %f %f %f %f %f %f\n",
3097                         itom->r.x,itom->r.y,itom->r.z,
3098                         jtom->r.x,jtom->r.y,jtom->r.z);
3099
3100         return 0;
3101 }
3102
3103 #ifdef VISUAL_THREAD
3104 void *visual_atoms(void *ptr) {
3105 #else
3106 int visual_atoms(t_moldyn *moldyn) {
3107 #endif
3108
3109         int i;
3110         char file[128+64];
3111         t_3dvec dim;
3112         double help;
3113         t_visual *v;
3114         t_atom *atom;
3115         t_vb vb;
3116 #ifdef VISUAL_THREAD
3117         t_moldyn *moldyn;
3118
3119         moldyn=ptr;
3120 #endif
3121
3122         v=&(moldyn->vis);
3123         dim.x=v->dim.x;
3124         dim.y=v->dim.y;
3125         dim.z=v->dim.z;
3126         atom=moldyn->atom;
3127
3128         help=(dim.x+dim.y);
3129
3130         sprintf(file,"%s/atomic_conf_%08.f.xyz",v->fb,moldyn->time);
3131         vb.fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
3132         if(vb.fd<0) {
3133                 perror("open visual save file fd");
3134 #ifndef VISUAL_THREAD
3135                 return -1;
3136 #endif
3137         }
3138
3139         /* write the actual data file */
3140
3141         // povray header
3142         dprintf(vb.fd,"# [P] %d %08.f <%f,%f,%f>\n",
3143                 moldyn->count,moldyn->time,help/40.0,help/40.0,-0.8*help);
3144
3145         // atomic configuration
3146         for(i=0;i<moldyn->count;i++)
3147                 // atom type, positions, color and kinetic energy
3148                 dprintf(vb.fd,"%s %f %f %f %s %f\n",pse_name[atom[i].element],
3149                                                     atom[i].r.x,
3150                                                     atom[i].r.y,
3151                                                     atom[i].r.z,
3152                                                     pse_col[atom[i].element],
3153                                                     atom[i].ekin);
3154         
3155         // bonds between atoms
3156 #ifndef VISUAL_THREAD
3157         process_2b_bonds(moldyn,&vb,visual_bonds_process);
3158 #endif
3159         
3160         // boundaries
3161         if(dim.x) {
3162                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3163                         -dim.x/2,-dim.y/2,-dim.z/2,
3164                         dim.x/2,-dim.y/2,-dim.z/2);
3165                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3166                         -dim.x/2,-dim.y/2,-dim.z/2,
3167                         -dim.x/2,dim.y/2,-dim.z/2);
3168                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3169                         dim.x/2,dim.y/2,-dim.z/2,
3170                         dim.x/2,-dim.y/2,-dim.z/2);
3171                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3172                         -dim.x/2,dim.y/2,-dim.z/2,
3173                         dim.x/2,dim.y/2,-dim.z/2);
3174
3175                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3176                         -dim.x/2,-dim.y/2,dim.z/2,
3177                         dim.x/2,-dim.y/2,dim.z/2);
3178                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3179                         -dim.x/2,-dim.y/2,dim.z/2,
3180                         -dim.x/2,dim.y/2,dim.z/2);
3181                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3182                         dim.x/2,dim.y/2,dim.z/2,
3183                         dim.x/2,-dim.y/2,dim.z/2);
3184                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3185                         -dim.x/2,dim.y/2,dim.z/2,
3186                         dim.x/2,dim.y/2,dim.z/2);
3187
3188                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3189                         -dim.x/2,-dim.y/2,dim.z/2,
3190                         -dim.x/2,-dim.y/2,-dim.z/2);
3191                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3192                         -dim.x/2,dim.y/2,dim.z/2,
3193                         -dim.x/2,dim.y/2,-dim.z/2);
3194                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3195                         dim.x/2,-dim.y/2,dim.z/2,
3196                         dim.x/2,-dim.y/2,-dim.z/2);
3197                 dprintf(vb.fd,"# [D] %f %f %f %f %f %f\n",
3198                         dim.x/2,dim.y/2,dim.z/2,
3199                         dim.x/2,dim.y/2,-dim.z/2);
3200         }
3201
3202         close(vb.fd);
3203
3204 #ifdef VISUAL_THREAD
3205         pthread_exit(NULL);
3206
3207 }
3208 #else
3209
3210         return 0;
3211 }
3212 #endif
3213
3214 /*
3215  * fpu cntrol functions
3216  */
3217
3218 // set rounding to double (eliminates -ffloat-store!)
3219 int fpu_set_rtd(void) {
3220
3221         fpu_control_t ctrl;
3222
3223         _FPU_GETCW(ctrl);
3224
3225         ctrl&=~_FPU_EXTENDED;
3226         ctrl|=_FPU_DOUBLE;
3227
3228         _FPU_SETCW(ctrl);
3229
3230         return 0;
3231 }
3232