more testing
[physik/posic.git] / moldyn.c
index ba3c1a3..0fd1aca 100644 (file)
--- a/moldyn.c
+++ b/moldyn.c
  *
  */
 
-#include "moldyn.h"
-
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+
+#include "moldyn.h"
 
 #include "math/math.h"
 #include "init/init.h"
+#include "random/random.h"
+#include "visual/visual.h"
+
+int moldyn_usage(char **argv) {
+
+       printf("\n%s usage:\n\n",argv[0]);
+       printf("--- general options ---\n");
+       printf("-E <steps> <file> (log total energy)\n");
+       printf("-M <steps> <file> (log total momentum)\n");
+       printf("-D <steps> <file> (dump total information)\n");
+       printf("-S <steps> <filebase> (single save file)\n");
+       printf("-V <steps> <filebase> (rasmol file)\n");
+       printf("--- physics options ---\n");
+       printf("-T <temperature> [K] (%f)\n",MOLDYN_TEMP);
+       printf("-t <timestep tau> [s] (%f)\n",MOLDYN_TAU);
+       printf("-R <runs> (%d)\n",MOLDYN_RUNS);
+       printf("\n");
+
+       return 0;
+}
+
+int moldyn_parse_argv(t_moldyn *moldyn,int argc,char **argv) {
+
+       int i;
 
+       memset(moldyn,0,sizeof(t_moldyn));
+
+       /* default values */
+       moldyn->t=MOLDYN_TEMP;
+       moldyn->tau=MOLDYN_TAU;
+       moldyn->time_steps=MOLDYN_RUNS;
+
+       /* parse argv */
+       for(i=1;i<argc;i++) {
+               if(argv[i][0]=='-') {
+                       switch(argv[i][1]){
+                               case 'E':
+                                       moldyn->ewrite=atoi(argv[++i]);
+                                       strncpy(moldyn->efb,argv[++i],64);
+                                       break;
+                               case 'M':
+                                       moldyn->mwrite=atoi(argv[++i]);
+                                       strncpy(moldyn->mfb,argv[++i],64);
+                                       break;
+                               case 'D':
+                                       moldyn->dwrite=atoi(argv[++i]);
+                                       strncpy(moldyn->dfb,argv[++i],64);
+                                       break;
+                               case 'S':
+                                       moldyn->swrite=atoi(argv[++i]);
+                                       strncpy(moldyn->sfb,argv[++i],64);
+                                       break;
+                               case 'V':
+                                       moldyn->vwrite=atoi(argv[++i]);
+                                       strncpy(moldyn->vfb,argv[++i],64);
+                                       break;
+                               case 'T':
+                                       moldyn->t=atof(argv[++i]);
+                                       break;
+                               case 't':
+                                       moldyn->tau=atof(argv[++i]);
+                                       break;
+                               case 'R':
+                                       moldyn->time_steps=atoi(argv[++i]);
+                                       break;
+                               default:
+                                       printf("unknown option %s\n",argv[i]);
+                                       moldyn_usage(argv);
+                                       return -1;
+                       }
+               } else {
+                       moldyn_usage(argv);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int moldyn_log_init(t_moldyn *moldyn,void *v) {
+
+       moldyn->lvstat=0;
+       t_visual *vis;
+
+       vis=v;
+
+       if(moldyn->ewrite) {
+               moldyn->efd=open(moldyn->efb,O_WRONLY|O_CREAT|O_TRUNC);
+               if(moldyn->efd<0) {
+                       perror("[moldyn] efd open");
+                       return moldyn->efd;
+               }
+               dprintf(moldyn->efd,"# moldyn total energy logfile\n");
+               moldyn->lvstat|=MOLDYN_LVSTAT_TOTAL_E;
+       }
+
+       if(moldyn->mwrite) {
+               moldyn->mfd=open(moldyn->mfb,O_WRONLY|O_CREAT|O_TRUNC);
+               if(moldyn->mfd<0) {
+                       perror("[moldyn] mfd open");
+                       return moldyn->mfd;
+               }
+               dprintf(moldyn->mfd,"# moldyn total momentum logfile\n");
+               moldyn->lvstat|=MOLDYN_LVSTAT_TOTAL_M;
+       }
+
+       if(moldyn->swrite)
+               moldyn->lvstat|=MOLDYN_LVSTAT_SAVE;
+
+       if(moldyn->dwrite) {
+               moldyn->dfd=open(moldyn->dfb,O_WRONLY|O_CREAT|O_TRUNC);
+                if(moldyn->dfd<0) {
+                       perror("[moldyn] dfd open");
+                       return moldyn->dfd;
+               }
+               write(moldyn->dfd,moldyn,sizeof(t_moldyn));
+               moldyn->lvstat|=MOLDYN_LVSTAT_DUMP;
+       }
+
+       if((moldyn->vwrite)&&(vis)) {
+               moldyn->visual=vis;
+               visual_init(vis,moldyn->vfb);
+               moldyn->lvstat|=MOLDYN_LVSTAT_VISUAL;
+       }
+
+       moldyn->lvstat|=MOLDYN_LVSTAT_INITIALIZED;
+
+       return 0;
+}
+
+int moldyn_shutdown(t_moldyn *moldyn) {
+
+       if(moldyn->efd) close(moldyn->efd);
+       if(moldyn->mfd) close(moldyn->efd);
+       if(moldyn->dfd) close(moldyn->efd);
+       if(moldyn->visual) visual_tini(moldyn->visual);
+
+       return 0;
+}
 
 int create_lattice(unsigned char type,int element,double mass,double lc,
                    int a,int b,int c,t_atom **atom) {
@@ -42,8 +187,8 @@ int create_lattice(unsigned char type,int element,double mass,double lc,
                        ret=diamond_init(a,b,c,lc,*atom,&origin);
                        break;
                default:
-                       ret=-1;
                        printf("unknown lattice type (%02x)\n",type);
+                       return -1;
        }
 
        /* debug */
@@ -51,6 +196,7 @@ int create_lattice(unsigned char type,int element,double mass,double lc,
                printf("ok, there is something wrong ...\n");
                printf("calculated -> %d atoms\n",count);
                printf("created -> %d atoms\n",ret);
+               return -1;
        }
 
        while(count) {
@@ -62,3 +208,405 @@ int create_lattice(unsigned char type,int element,double mass,double lc,
        return ret;
 }
 
+int destroy_lattice(t_atom *atom) {
+
+       if(atom) free(atom);
+
+       return 0;
+}
+
+int thermal_init(t_moldyn *moldyn,t_random *random,int count) {
+
+       /*
+        * - gaussian distribution of velocities
+        * - zero total momentum
+        * - velocity scaling (E = 3/2 N k T), E: kinetic energy
+        */
+
+       int i;
+       double v,sigma;
+       t_3dvec p_total,delta;
+       t_atom *atom;
+
+       atom=moldyn->atom;
+
+       /* gaussian distribution of velocities */
+       v3_zero(&p_total);
+       for(i=0;i<count;i++) {
+               sigma=sqrt(2.0*K_BOLTZMANN*moldyn->t/atom[i].mass);
+               /* x direction */
+               v=sigma*rand_get_gauss(random);
+               atom[i].v.x=v;
+               p_total.x+=atom[i].mass*v;
+               /* y direction */
+               v=sigma*rand_get_gauss(random);
+               atom[i].v.y=v;
+               p_total.y+=atom[i].mass*v;
+               /* z direction */
+               v=sigma*rand_get_gauss(random);
+               atom[i].v.z=v;
+               p_total.z+=atom[i].mass*v;
+       }
+
+       /* zero total momentum */
+       v3_scale(&p_total,&p_total,1.0/count);
+       for(i=0;i<count;i++) {
+               v3_scale(&delta,&p_total,1.0/atom[i].mass);
+               v3_sub(&(atom[i].v),&(atom[i].v),&delta);
+       }
+
+       /* velocity scaling */
+       scale_velocity(moldyn,count);
+
+       return 0;
+}
+
+int scale_velocity(t_moldyn *moldyn,int count) {
+
+       int i;
+       double e,c;
+       t_atom *atom;
+
+       atom=moldyn->atom;
+
+       /*
+        * - velocity scaling (E = 3/2 N k T), E: kinetic energy
+        */
+       e=0.0;
+       for(i=0;i<count;i++)
+               e+=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v));
+       c=sqrt((2.0*e)/(3.0*count*K_BOLTZMANN*moldyn->t));
+       for(i=0;i<count;i++)
+               v3_scale(&(atom[i].v),&(atom[i].v),(1.0/c));
+
+       return 0;
+}
+
+double get_e_kin(t_atom *atom,int count) {
+
+       int i;
+       double e;
+
+       e=0.0;
+
+       for(i=0;i<count;i++) {
+               e+=0.5*atom[i].mass*v3_absolute_square(&(atom[i].v));
+       }
+
+       return e;
+}
+
+double get_e_pot(t_moldyn *moldyn) {
+
+       return(moldyn->potential(moldyn));
+}
+
+double get_total_energy(t_moldyn *moldyn) {
+
+       double e;
+
+       e=get_e_kin(moldyn->atom,moldyn->count);
+       e+=get_e_pot(moldyn);
+
+       return e;
+}
+
+t_3dvec get_total_p(t_atom *atom, int count) {
+
+       t_3dvec p,p_total;
+       int i;
+
+       v3_zero(&p_total);
+       for(i=0;i<count;i++) {
+               v3_scale(&p,&(atom[i].v),atom[i].mass);
+               v3_add(&p_total,&p_total,&p);
+       }
+
+       return p_total;
+}
+
+double estimate_time_step(t_moldyn *moldyn,double nn_dist,double t) {
+
+       double tau;
+
+       tau=0.05*nn_dist/(sqrt(3.0*K_BOLTZMANN*t/moldyn->atom[0].mass));
+       tau*=1.0E-9;
+       if(tau<moldyn->tau)
+               printf("[moldyn] warning: time step  (%f > %.15f)\n",
+                      moldyn->tau,tau);
+
+       return tau;     
+}
+
+
+/*
+ *
+ * 'integration of newtons equation' - algorithms
+ *
+ */
+
+/* start the integration */
+
+int moldyn_integrate(t_moldyn *moldyn) {
+
+       int i;
+       unsigned int e,m,s,d,v;
+       t_3dvec p;
+
+       int fd;
+       char fb[128];
+
+       e=moldyn->ewrite;
+       m=moldyn->mwrite;
+       s=moldyn->swrite;
+       d=moldyn->dwrite;
+       v=moldyn->vwrite;
+
+       if(!(moldyn->lvstat&MOLDYN_LVSTAT_INITIALIZED)) {
+               printf("[moldyn] warning, lv system not initialized\n");
+               return -1;
+       }
+
+       /* calculate initial forces */
+       moldyn->force(moldyn);
+
+       for(i=0;i<moldyn->time_steps;i++) {
+               /* integration step */
+               moldyn->integrate(moldyn);
+
+               /* check for log & visualiziation */
+               if(e) {
+                       if(!(i%e))
+                               dprintf(moldyn->efd,
+                                       "%.15f %.45f\n",i*moldyn->tau,
+                                       get_total_energy(moldyn));
+               }
+               if(m) {
+                       if(!(i%m)) {
+                               p=get_total_p(moldyn->atom,moldyn->count);
+                               dprintf(moldyn->mfd,
+                                       "%.15f %.45f\n",i*moldyn->tau,
+                                       v3_norm(&p));
+                       }
+               }
+               if(s) {
+                       if(!(i%s)) {
+                               snprintf(fb,128,"%s-%f-%.15f.save",moldyn->sfb,
+                                        moldyn->t,i*moldyn->tau);
+                               fd=open(fb,O_WRONLY|O_TRUNC|O_CREAT);
+                               if(fd<0) perror("[moldyn] save fd open");
+                               else {
+                                       write(fd,moldyn,sizeof(t_moldyn));
+                                       write(fd,moldyn->atom,
+                                             moldyn->count*sizeof(t_atom));
+                               }
+                       }       
+               }
+               if(d) {
+                       if(!(i%d))
+                               write(moldyn->dfd,moldyn->atom,
+                                     moldyn->count*sizeof(t_atom));
+
+               }
+               if(v) {
+                       if(!(i%v))
+                               visual_atoms(moldyn->visual,i*moldyn->tau,
+                                            moldyn->atom,moldyn->count);
+               }
+       }
+
+       return 0;
+}
+
+/* velocity verlet */
+
+int velocity_verlet(t_moldyn *moldyn) {
+
+       int i,count;
+       double tau,tau_square;
+       t_3dvec delta;
+       t_atom *atom;
+
+       atom=moldyn->atom;
+       count=moldyn->count;
+       tau=moldyn->tau;
+
+       tau_square=tau*tau;
+
+       for(i=0;i<count;i++) {
+               /* new positions */
+               v3_scale(&delta,&(atom[i].v),tau);
+               v3_add(&(atom[i].r),&(atom[i].r),&delta);
+               v3_scale(&delta,&(atom[i].f),0.5*tau_square/atom[i].mass);
+               v3_add(&(atom[i].r),&(atom[i].r),&delta);
+               v3_per_bound(&(atom[i].r),&(moldyn->dim));
+
+               /* velocities */
+               v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass);
+               v3_add(&(atom[i].v),&(atom[i].v),&delta);
+       }
+
+       /* forces depending on chosen potential */
+       moldyn->force(moldyn);
+
+       for(i=0;i<count;i++) {
+               /* again velocities */
+               v3_scale(&delta,&(atom[i].f),0.5*tau/atom[i].mass);
+               v3_add(&(atom[i].v),&(atom[i].v),&delta);
+       }
+
+       return 0;
+}
+
+
+/*
+ *
+ * potentials & corresponding forces
+ * 
+ */
+
+/* harmonic oscillator potential and force */
+
+double potential_harmonic_oscillator(t_moldyn *moldyn) {
+
+       t_ho_params *params;
+       t_atom *atom;
+       int i,j;
+       int count;
+       t_3dvec distance;
+       double d,u;
+       double sc,equi_dist;
+
+       params=moldyn->pot_params;
+       atom=moldyn->atom;
+       sc=params->spring_constant;
+       equi_dist=params->equilibrium_distance;
+       count=moldyn->count;
+
+       u=0.0;
+       for(i=0;i<count;i++) {
+               for(j=0;j<i;j++) {
+                       v3_sub(&distance,&(atom[i].r),&(atom[j].r));
+                       d=v3_norm(&distance);
+                       u+=(0.5*sc*(d-equi_dist)*(d-equi_dist));
+               }
+       }
+
+       return u;
+}
+
+int force_harmonic_oscillator(t_moldyn *moldyn) {
+
+       t_ho_params *params;
+       int i,j,count;
+       t_atom *atom;
+       t_3dvec distance;
+       t_3dvec force;
+       double d;
+       double sc,equi_dist;
+
+       atom=moldyn->atom;      
+       count=moldyn->count;
+       params=moldyn->pot_params;
+       sc=params->spring_constant;
+       equi_dist=params->equilibrium_distance;
+
+       for(i=0;i<count;i++) v3_zero(&(atom[i].f));
+
+       for(i=0;i<count;i++) {
+               for(j=0;j<i;j++) {
+                       v3_sub(&distance,&(atom[i].r),&(atom[j].r));
+                       v3_per_bound(&distance,&(moldyn->dim));
+                       d=v3_norm(&distance);
+                       if(d<=moldyn->cutoff) {
+                               v3_scale(&force,&distance,
+                                        (-sc*(1.0-(equi_dist/d))));
+                               v3_add(&(atom[i].f),&(atom[i].f),&force);
+                               v3_sub(&(atom[j].f),&(atom[j].f),&force);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+/* lennard jones potential & force for one sort of atoms */
+double potential_lennard_jones(t_moldyn *moldyn) {
+
+       t_lj_params *params;
+       t_atom *atom;
+       int i,j;
+       int count;
+       t_3dvec distance;
+       double d,help;
+       double u;
+       double eps,sig6,sig12;
+
+       params=moldyn->pot_params;
+       atom=moldyn->atom;
+       count=moldyn->count;
+       eps=params->epsilon;
+       sig6=params->sigma6;
+       sig12=params->sigma12;
+
+       u=0.0;
+       for(i=0;i<count;i++) {
+               for(j=0;j<i;j++) {
+                       v3_sub(&distance,&(atom[j].r),&(atom[i].r));
+                       d=1.0/v3_absolute_square(&distance);    /* 1/r^2 */
+                       help=d*d;                               /* 1/r^4 */
+                       help*=d;                                /* 1/r^6 */
+                       d=help*help;                            /* 1/r^12 */
+                       u+=eps*(sig12*d-sig6*help);
+               }
+       }
+       
+       return u;
+}
+
+int force_lennard_jones(t_moldyn *moldyn) {
+
+       t_lj_params *params;
+       int i,j,count;
+       t_atom *atom;
+       t_3dvec distance;
+       t_3dvec force;
+       double d,h1,h2;
+       double eps,sig6,sig12;
+
+       atom=moldyn->atom;      
+       count=moldyn->count;
+       params=moldyn->pot_params;
+       eps=params->epsilon;
+       sig6=params->sigma6;
+       sig12=params->sigma12;
+
+       for(i=0;i<count;i++) v3_zero(&(atom[i].f));
+
+       for(i=0;i<count;i++) {
+               for(j=0;j<i;j++) {
+                       v3_sub(&distance,&(atom[j].r),&(atom[i].r));
+                       v3_per_bound(&distance,&(moldyn->dim));
+                       d=v3_absolute_square(&distance);
+                       if(d<=moldyn->cutoff_square) {
+                               h1=1.0/d;                       /* 1/r^2 */
+                               d=h1*h1;                        /* 1/r^4 */
+                               h2=d*d;                         /* 1/r^8 */
+                               h1*=d;                          /* 1/r^6 */
+                               h1*=h2;                         /* 1/r^14 */
+                               h1*=sig12;
+                               h2*=sig6;
+                               d=12.0*h1-6.0*h2;
+                               d*=eps;
+                               v3_scale(&force,&distance,d);
+                               v3_add(&(atom[j].f),&(atom[j].f),&force);
+                               v3_sub(&(atom[i].f),&(atom[i].f),&force);
+                       }
+               }
+       }
+
+       return 0;
+}
+