[tools] g_sans - add trajectory avereging
[alexxy/gromacs.git] / src / tools / nsfactor.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <ctype.h>
40 #include <string.h>
41 #include "futil.h"
42 #include "gmx_random.h"
43 #include "smalloc.h"
44 #include "sysstuff.h"
45 #include "strdb.h"
46 #include "vec.h"
47 #include "nsfactor.h"
48 #include "gmx_omp.h"
49
50 void check_binwidth(real binwidth) {
51     real smallest_bin=0.1;
52     if (binwidth<smallest_bin)
53         gmx_fatal(FARGS,"Binwidth shouldnt be smaller then smallest bond length (H-H bond ~0.1nm) in a box");
54 }
55
56 void check_mcover(real mcover) {
57     if (mcover>1.0) {
58         gmx_fatal(FARGS,"mcover should be -1 or (0,1]");
59     } else if ((mcover<0)&(mcover != -1)) {
60         gmx_fatal(FARGS,"mcover should be -1 or (0,1]");
61     } else {
62         return;
63     }
64 }
65
66 void normalize_probability(int n,double *a) {
67     int i;
68     double norm=0.0;
69     for (i=0;i<n;i++) norm +=a[i];
70     for (i=0;i<n;i++) a[i]/=norm;
71 }
72
73 gmx_neutron_atomic_structurefactors_t *gmx_neutronstructurefactors_init(const char *datfn) {
74     /* read nsfactor.dat */
75     FILE    *fp;
76     char    line[STRLEN];
77     int     nralloc=10;
78     int     n,p;
79     int     i, line_no;
80     char    atomnm[8];
81     double  slength;
82     gmx_neutron_atomic_structurefactors_t   *gnsf;
83
84     fp=libopen(datfn);
85     line_no = 0;
86     /* allocate memory for structure */
87     snew(gnsf,nralloc);
88     snew(gnsf->atomnm,nralloc);
89     snew(gnsf->p,nralloc);
90     snew(gnsf->n,nralloc);
91     snew(gnsf->slength,nralloc);
92
93     gnsf->nratoms=line_no;
94
95     while(get_a_line(fp,line,STRLEN)) {
96         i=line_no;
97         if (sscanf(line,"%s %d %d %lf",atomnm,&p,&n,&slength) == 4) {
98             gnsf->atomnm[i]=strdup(atomnm);
99             gnsf->n[i]=n;
100             gnsf->p[i]=p;
101             gnsf->slength[i]=slength;
102             line_no++;
103             gnsf->nratoms=line_no;
104             if (line_no==nralloc){
105                 nralloc++;
106                 srenew(gnsf->atomnm,nralloc);
107                 srenew(gnsf->p,nralloc);
108                 srenew(gnsf->n,nralloc);
109                 srenew(gnsf->slength,nralloc);
110             }
111         } else
112             fprintf(stderr,"WARNING: Error in file %s at line %d ignored\n",
113                     datfn,line_no);
114     }
115     srenew(gnsf->atomnm,gnsf->nratoms);
116     srenew(gnsf->p,gnsf->nratoms);
117     srenew(gnsf->n,gnsf->nratoms);
118     srenew(gnsf->slength,gnsf->nratoms);
119
120     fclose(fp);
121
122     return (gmx_neutron_atomic_structurefactors_t *) gnsf;
123 }
124
125 gmx_sans_t *gmx_sans_init (t_topology *top, gmx_neutron_atomic_structurefactors_t *gnsf) {
126     gmx_sans_t    *gsans=NULL;
127     int     i,j;
128     /* Try to assing scattering length from nsfactor.dat */
129     snew(gsans,1);
130     snew(gsans->slength,top->atoms.nr);
131     /* copy topology data */
132     gsans->top = top;
133     for(i=0;i<top->atoms.nr;i++) {
134         for(j=0;j<gnsf->nratoms;j++) {
135             if(top->atoms.atom[i].atomnumber == gnsf->p[j]) {
136                 /* we need special case for H and D */
137                 if(top->atoms.atom[i].atomnumber == 1) {
138                     if(top->atoms.atom[i].m == 1.008000) {
139                         gsans->slength[i] = gnsf->slength[0];
140                     } else
141                         gsans->slength[i] = gnsf->slength[1];
142                 } else
143                     gsans->slength[i] = gnsf->slength[j];
144             }
145         }
146     }
147
148     return (gmx_sans_t *) gsans;
149 }
150
151 gmx_radial_distribution_histogram_t *calc_radial_distribution_histogram (
152                             gmx_sans_t *gsans,
153                             rvec *x,
154                             matrix box,
155                             atom_id *index,
156                             int isize,
157                             double binwidth,
158                             gmx_bool bMC,
159                             gmx_bool bNORM,
160                             real mcover,
161                             unsigned int seed) {
162     gmx_radial_distribution_histogram_t    *pr=NULL;
163     rvec            dist;
164     double          rmax;
165     int             i,j;
166 #ifdef GMX_OPENMP
167     double          **tgr;
168     int             tid;
169     int             nthreads;
170     gmx_rng_t       *trng=NULL;
171 #endif
172     gmx_large_int_t mc=0,max;
173     gmx_rng_t       rng=NULL;
174
175     /* allocate memory for pr */
176     snew(pr,1);
177     /* set some fields */
178     pr->binwidth=binwidth;
179
180     /*
181     * create max dist rvec
182     * dist = box[xx] + box[yy] + box[zz]
183     */
184     rvec_add(box[XX],box[YY],dist);
185     rvec_add(box[ZZ],dist,dist);
186
187     rmax=norm(dist);
188
189     pr->grn=(int)floor(rmax/pr->binwidth)+1;
190     rmax=pr->grn*pr->binwidth;
191
192     snew(pr->gr,pr->grn);
193
194     if(bMC) {
195         /* Special case for setting automaticaly number of mc iterations to 1% of total number of direct iterations */
196         if (mcover==-1) {
197             max=(gmx_large_int_t)floor(0.5*0.01*isize*(isize-1));
198         } else {
199             max=(gmx_large_int_t)floor(0.5*mcover*isize*(isize-1));
200         }
201         rng=gmx_rng_init(seed);
202 #ifdef GMX_OPENMP
203         nthreads = gmx_omp_get_max_threads();
204         snew(tgr,nthreads);
205         snew(trng,nthreads);
206         for(i=0;i<nthreads;i++){
207             snew(tgr[i],pr->grn);
208             trng[i]=gmx_rng_init(gmx_rng_uniform_uint32(rng));
209         }
210         #pragma omp parallel shared(tgr,trng,mc) private(tid,i,j)
211         {
212             tid = gmx_omp_get_thread_num();
213             /* now starting parallel threads */
214             #pragma omp for
215             for(mc=0;mc<max;mc++) {
216                 i=(int)floor(gmx_rng_uniform_real(trng[tid])*isize);
217                 j=(int)floor(gmx_rng_uniform_real(trng[tid])*isize);
218                 if(i!=j) {
219                     tgr[tid][(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
220                 }
221             }
222         }
223         /* collecting data from threads */
224         for(i=0;i<pr->grn;i++) {
225             for(j=0;j<nthreads;j++) {
226                 pr->gr[i] += tgr[j][i];
227             }
228         }
229         /* freeing memory for tgr and destroying trng */
230         for(i=0;i<nthreads;i++) {
231             sfree(tgr[i]);
232             gmx_rng_destroy(trng[i]);
233         }
234         sfree(tgr);
235         sfree(trng);
236 #else
237         for(mc=0;mc<max;mc++) {
238             i=(int)floor(gmx_rng_uniform_real(rng)*isize);
239             j=(int)floor(gmx_rng_uniform_real(rng)*isize);
240             if(i!=j)
241                 pr->gr[(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
242         }
243 #endif
244         gmx_rng_destroy(rng);
245     } else {
246 #ifdef GMX_OPENMP
247         nthreads = gmx_omp_get_max_threads();
248         /* Allocating memory for tgr arrays */
249         snew(tgr,nthreads);
250         for(i=0;i<nthreads;i++) {
251             snew(tgr[i],pr->grn);
252         }
253         #pragma omp parallel shared(tgr) private(tid,i,j)
254         {
255             tid = gmx_omp_get_thread_num();
256             /* starting parallel threads */
257             #pragma omp for
258             for(i=0;i<isize;i++) {
259                 for(j=0;j<i;j++) {
260                     tgr[tid][(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
261                 }
262             }
263         }
264         /* collecating data for pr->gr */
265         for(i=0;i<pr->grn;i++) {
266             for(j=0;j<nthreads;j++) {
267                 pr->gr[i] += tgr[j][i];
268             }
269         }
270         /* freeing memory for tgr */
271         for(i=0;i<nthreads;i++) {
272             sfree(tgr[i]);
273         }
274         sfree(tgr);
275 #else
276         for(i=0;i<isize;i++) {
277             for(j=0;j<i;j++) {
278                 pr->gr[(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
279             }
280         }
281 #endif
282     }
283
284     /* normalize if needed */
285     if (bNORM) {
286         normalize_probability(pr->grn,pr->gr);
287     }
288
289     snew(pr->r,pr->grn);
290     for(i=0;i<pr->grn;i++)
291         pr->r[i]=(pr->binwidth*i+pr->binwidth*0.5);
292
293     return (gmx_radial_distribution_histogram_t *) pr;
294 }
295
296 gmx_static_structurefactor_t *convert_histogram_to_intensity_curve (gmx_radial_distribution_histogram_t *pr, double start_q, double end_q, double q_step) {
297     gmx_static_structurefactor_t    *sq=NULL;
298     int         i,j;
299     /* init data */
300     snew(sq,1);
301     sq->qn=(int)floor((end_q-start_q)/q_step);
302     snew(sq->q,sq->qn);
303     snew(sq->s,sq->qn);
304     for(i=0;i<sq->qn;i++)
305         sq->q[i]=start_q+i*q_step;
306
307     if(start_q==0.0) {
308         sq->s[0]=1.0;
309         for(i=1;i<sq->qn;i++) {
310             for(j=0;j<pr->grn;j++)
311                 sq->s[i]+=(pr->gr[j]/pr->r[j])*sin(sq->q[i]*pr->r[j]);
312             sq->s[i] /= sq->q[i];
313         }
314     } else {
315         for(i=0;i<sq->qn;i++) {
316             for(j=0;j<pr->grn;j++)
317                 sq->s[i]+=(pr->gr[j]/pr->r[j])*sin(sq->q[i]*pr->r[j]);
318             sq->s[i] /= sq->q[i];
319         }
320     }
321
322     return (gmx_static_structurefactor_t *) sq;
323 }