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