e7879e7ca0bf613b5e3b4d7a4fb90c75f9b0e235
[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
49 #ifdef GMX_OPENMP
50 #include <omp.h>
51 #endif
52
53 void check_binwidth(real binwidth) {
54     real smallest_bin=0.1;
55     if (binwidth<smallest_bin)
56         gmx_fatal(FARGS,"Binwidth shouldnt be smaller then smallest bond length (H-H bond ~0.1nm) in a box");
57 }
58
59 void check_mcover(real mcover) {
60     if (mcover>1.0) {
61         gmx_fatal(FARGS,"mcover should be -1 or (0,1]");
62     } else if ((mcover<0)&(mcover != -1)) {
63         gmx_fatal(FARGS,"mcover should be -1 or (0,1]");
64     } else {
65         return;
66     }
67 }
68
69 void normalize_probability(int n,double *a){
70     int i;
71     double norm=0.0;
72     for (i=0;i<n;i++) norm +=a[i];
73     for (i=0;i<n;i++) a[i]/=norm;
74 }
75
76 gmx_nentron_atomic_structurefactors_t *gmx_neutronstructurefactors_init(const char *datfn) {
77     /* read nsfactor.dat */
78     FILE    *fp;
79     char    line[STRLEN];
80     int     nralloc=10;
81     int     n,p;
82     int     i, line_no;
83     char    atomnm[8];
84     double  slength;
85     gmx_nentron_atomic_structurefactors_t   *gnsf;
86
87     fp=libopen(datfn);
88     line_no = 0;
89     /* allocate memory for structure */
90     snew(gnsf,nralloc);
91     snew(gnsf->atomnm,nralloc);
92     snew(gnsf->p,nralloc);
93     snew(gnsf->n,nralloc);
94     snew(gnsf->slength,nralloc);
95
96     gnsf->nratoms=line_no;
97
98     while(get_a_line(fp,line,STRLEN)) {
99         i=line_no;
100         if (sscanf(line,"%s %d %d %lf",atomnm,&p,&n,&slength) == 4) {
101             gnsf->atomnm[i]=strdup(atomnm);
102             gnsf->n[i]=n;
103             gnsf->p[i]=p;
104             gnsf->slength[i]=slength;
105             line_no++;
106             gnsf->nratoms=line_no;
107             if (line_no==nralloc){
108                 nralloc++;
109                 srenew(gnsf->atomnm,nralloc);
110                 srenew(gnsf->p,nralloc);
111                 srenew(gnsf->n,nralloc);
112                 srenew(gnsf->slength,nralloc);
113             }
114         } else
115             fprintf(stderr,"WARNING: Error in file %s at line %d ignored\n",
116                     datfn,line_no);
117     }
118     srenew(gnsf->atomnm,gnsf->nratoms);
119     srenew(gnsf->p,gnsf->nratoms);
120     srenew(gnsf->n,gnsf->nratoms);
121     srenew(gnsf->slength,gnsf->nratoms);
122
123     fclose(fp);
124
125     return (gmx_nentron_atomic_structurefactors_t *) gnsf;
126 }
127
128 gmx_sans_t *gmx_sans_init (t_topology *top, gmx_nentron_atomic_structurefactors_t *gnsf) {
129     gmx_sans_t    *gsans=NULL;
130     int     i,j;
131     /* Try to assing scattering length from nsfactor.dat */
132     snew(gsans,1);
133     snew(gsans->slength,top->atoms.nr);
134     /* copy topology data */
135     gsans->top = top;
136     for(i=0;i<top->atoms.nr;i++) {
137         for(j=0;j<gnsf->nratoms;j++) {
138             if(top->atoms.atom[i].atomnumber == gnsf->p[j]) {
139                 /* we need special case for H and D */
140                 if(top->atoms.atom[i].atomnumber == 1) {
141                     if(top->atoms.atom[i].m == 1.008000) {
142                         gsans->slength[i] = gnsf->slength[0];
143                     } else
144                         gsans->slength[i] = gnsf->slength[1];
145                 } else
146                     gsans->slength[i] = gnsf->slength[j];
147             }
148         }
149     }
150
151     return (gmx_sans_t *) gsans;
152 }
153
154 gmx_radial_distribution_histogram_t *calc_radial_distribution_histogram (
155                             gmx_sans_t *gsans,
156                             rvec *x,
157                             matrix box,
158                             atom_id *index,
159                             int isize,
160                             double binwidth,
161                             gmx_bool bMC,
162                             real mcover,
163                             unsigned int seed) {
164     gmx_radial_distribution_histogram_t    *pr=NULL;
165     rvec            dist;
166     double          rmax;
167     int             i,j;
168 #ifdef GMX_OPENMP
169     double          **tgr;
170     int             tid;
171     int             nthreads;
172     gmx_rng_t       *trng=NULL;
173 #endif
174     gmx_large_int_t mc=0,max;
175     gmx_rng_t       rng=NULL;
176
177     /* allocate memory for pr */
178     snew(pr,1);
179     /* set some fields */
180     pr->binwidth=binwidth;
181
182     /*
183     * create max dist rvec
184     * dist = box[xx] + box[yy] + box[zz]
185     */
186     rvec_add(box[XX],box[YY],dist);
187     rvec_add(box[ZZ],dist,dist);
188
189     rmax=norm(dist);
190
191     pr->grn=(int)floor(rmax/pr->binwidth)+1;
192     rmax=pr->grn*pr->binwidth;
193
194     snew(pr->gr,pr->grn);
195
196     if(bMC) {
197         /* Special case for setting automaticaly number of mc iterations to 1% of total number of direct iterations */
198         if (mcover==-1) {
199             max=(gmx_large_int_t)floor(0.5*0.01*isize*(isize-1));
200         } else {
201             max=(gmx_large_int_t)floor(0.5*mcover*isize*(isize-1));
202         }
203         rng=gmx_rng_init(seed);
204 #ifdef GMX_OPENMP
205         nthreads = omp_get_max_threads();
206         snew(tgr,nthreads);
207         snew(trng,nthreads);
208         for(i=0;i<nthreads;i++){
209             snew(tgr[i],pr->grn);
210             trng[i]=gmx_rng_init(gmx_rng_uniform_uint32(rng));
211         }
212         #pragma omp parallel shared(tgr,trng,mc) private(tid,i,j)
213         {
214             tid = omp_get_thread_num();
215             /* now starting parallel threads */
216             #pragma omp for
217             for(mc=0;mc<max;mc++) {
218                 i=(int)floor(gmx_rng_uniform_real(trng[tid])*isize);
219                 j=(int)floor(gmx_rng_uniform_real(trng[tid])*isize);
220                 if(i!=j) {
221                     tgr[tid][(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
222                 }
223             }
224         }
225         /* collecting data from threads */
226         for(i=0;i<pr->grn;i++) {
227             for(j=0;j<nthreads;j++) {
228                 pr->gr[i] += tgr[j][i];
229             }
230         }
231         /* freeing memory for tgr and destroying trng */
232         for(i=0;i<nthreads;i++) {
233             sfree(tgr[i]);
234             gmx_rng_destroy(trng[i]);
235         }
236         sfree(tgr);
237         sfree(trng);
238 #else
239         for(mc=0;mc<max;mc++) {
240             i=(int)floor(gmx_rng_uniform_real(rng)*isize);
241             j=(int)floor(gmx_rng_uniform_real(rng)*isize);
242             if(i!=j)
243                 pr->gr[(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
244         }
245 #endif
246         gmx_rng_destroy(rng);
247     } else {
248 #ifdef GMX_OPENMP
249         nthreads = omp_get_max_threads();
250         /* Allocating memory for tgr arrays */
251         snew(tgr,nthreads);
252         for(i=0;i<nthreads;i++) {
253             snew(tgr[i],pr->grn);
254         }
255         #pragma omp parallel shared(tgr) private(tid,i,j)
256         {
257             tid = omp_get_thread_num();
258             /* starting parallel threads */
259             #pragma omp for
260             for(i=0;i<isize;i++) {
261                 for(j=0;j<i;j++) {
262                     tgr[tid][(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
263                 }
264             }
265         }
266         /* collecating data for pr->gr */
267         for(i=0;i<pr->grn;i++) {
268             for(j=0;j<nthreads;j++) {
269                 pr->gr[i] += tgr[j][i];
270             }
271         }
272         /* freeing memory for tgr */
273         for(i=0;i<nthreads;i++) {
274             sfree(tgr[i]);
275         }
276         sfree(tgr);
277 #else
278         for(i=0;i<isize;i++) {
279             for(j=0;j<i;j++) {
280                 pr->gr[(int)floor(sqrt(distance2(x[index[i]],x[index[j]]))/binwidth)]+=gsans->slength[index[i]]*gsans->slength[index[j]];
281             }
282         }
283 #endif
284     }
285
286     /* normalize */
287     normalize_probability(pr->grn,pr->gr);
288     snew(pr->r,pr->grn);
289     for(i=0;i<pr->grn;i++)
290         pr->r[i]=(pr->binwidth*i+pr->binwidth*0.5);
291
292     return (gmx_radial_distribution_histogram_t *) pr;
293 }
294
295 gmx_static_structurefator_t *convert_histogram_to_intensity_curve (gmx_radial_distribution_histogram_t *pr, double start_q, double end_q, double q_step) {
296     gmx_static_structurefator_t    *sq=NULL;
297     int         i,j;
298     /* init data */
299     snew(sq,1);
300     sq->qn=(int)floor((end_q-start_q)/q_step);
301     snew(sq->q,sq->qn);
302     snew(sq->s,sq->qn);
303     for(i=0;i<sq->qn;i++)
304         sq->q[i]=start_q+i*q_step;
305
306     if(start_q==0.0) {
307         sq->s[0]=1.0;
308         for(i=1;i<sq->qn;i++) {
309             for(j=0;j<pr->grn;j++)
310                 sq->s[i]+=(pr->gr[j]/pr->r[j])*sin(sq->q[i]*pr->r[j]);
311             sq->s[i] /= sq->q[i];
312         }
313     } else {
314         for(i=0;i<sq->qn;i++) {
315             for(j=0;j<pr->grn;j++)
316                 sq->s[i]+=(pr->gr[j]/pr->r[j])*sin(sq->q[i]*pr->r[j]);
317             sq->s[i] /= sq->q[i];
318         }
319     }
320
321     return (gmx_static_structurefator_t *) sq;
322 }