Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / gmxana / nsfactor.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 #include "gmxpre.h"
36
37 #include "nsfactor.h"
38
39 #include "config.h"
40
41 #include <cmath>
42 #include <cstring>
43
44 #include "gromacs/math/vec.h"
45 #include "gromacs/random/threefry.h"
46 #include "gromacs/random/uniformintdistribution.h"
47 #include "gromacs/topology/topology.h"
48 #include "gromacs/utility/cstringutil.h"
49 #include "gromacs/utility/exceptions.h"
50 #include "gromacs/utility/fatalerror.h"
51 #include "gromacs/utility/futil.h"
52 #include "gromacs/utility/gmxomp.h"
53 #include "gromacs/utility/smalloc.h"
54 #include "gromacs/utility/strdb.h"
55
56 void check_binwidth(real binwidth)
57 {
58     real smallest_bin = 0.1;
59     if (binwidth < smallest_bin)
60     {
61         gmx_fatal(FARGS,
62                   "Binwidth shouldn't be smaller then smallest bond length (H-H bond ~0.1nm) in a "
63                   "box");
64     }
65 }
66
67 void check_mcover(real mcover)
68 {
69     if (mcover > 1.0)
70     {
71         gmx_fatal(FARGS, "mcover should be -1 or (0,1]");
72     }
73     else if ((mcover < 0) && (mcover != -1))
74     {
75         gmx_fatal(FARGS, "mcover should be -1 or (0,1]");
76     }
77     else
78     {
79         return;
80     }
81 }
82
83 void normalize_probability(int n, double* a)
84 {
85     int    i;
86     double norm = 0.0;
87     for (i = 0; i < n; i++)
88     {
89         norm += a[i];
90     }
91     for (i = 0; i < n; i++)
92     {
93         a[i] /= norm;
94     }
95 }
96
97 gmx_neutron_atomic_structurefactors_t* gmx_neutronstructurefactors_init(const char* datfn)
98 {
99     /* read nsfactor.dat */
100     char                                   line[STRLEN];
101     int                                    nralloc = 10;
102     int                                    n, p;
103     int                                    i, line_no;
104     char                                   atomnm[8];
105     double                                 slength;
106     gmx_neutron_atomic_structurefactors_t* gnsf;
107
108     gmx::FilePtr fp = gmx::openLibraryFile(datfn);
109     line_no         = 0;
110     /* allocate memory for structure */
111     snew(gnsf, nralloc);
112     snew(gnsf->atomnm, nralloc);
113     snew(gnsf->p, nralloc);
114     snew(gnsf->n, nralloc);
115     snew(gnsf->slength, nralloc);
116
117     gnsf->nratoms = line_no;
118
119     while (get_a_line(fp.get(), line, STRLEN))
120     {
121         i = line_no;
122         if (sscanf(line, "%s %d %d %lf", atomnm, &p, &n, &slength) == 4)
123         {
124             gnsf->atomnm[i]  = gmx_strdup(atomnm);
125             gnsf->n[i]       = n;
126             gnsf->p[i]       = p;
127             gnsf->slength[i] = slength;
128             line_no++;
129             gnsf->nratoms = line_no;
130             if (line_no == nralloc)
131             {
132                 nralloc++;
133                 srenew(gnsf->atomnm, nralloc);
134                 srenew(gnsf->p, nralloc);
135                 srenew(gnsf->n, nralloc);
136                 srenew(gnsf->slength, nralloc);
137             }
138         }
139         else
140         {
141             fprintf(stderr, "WARNING: Error in file %s at line %d ignored\n", datfn, line_no);
142         }
143     }
144     srenew(gnsf->atomnm, gnsf->nratoms);
145     srenew(gnsf->p, gnsf->nratoms);
146     srenew(gnsf->n, gnsf->nratoms);
147     srenew(gnsf->slength, gnsf->nratoms);
148
149     return gnsf;
150 }
151
152 gmx_sans_t* gmx_sans_init(const t_topology* top, gmx_neutron_atomic_structurefactors_t* gnsf)
153 {
154     gmx_sans_t* gsans = nullptr;
155     int         i, j;
156     /* Try to assing scattering length from nsfactor.dat */
157     snew(gsans, 1);
158     snew(gsans->slength, top->atoms.nr);
159     /* copy topology data */
160     gsans->top = top;
161     for (i = 0; i < top->atoms.nr; i++)
162     {
163         for (j = 0; j < gnsf->nratoms; j++)
164         {
165             if (top->atoms.atom[i].atomnumber == gnsf->p[j])
166             {
167                 /* we need special case for H and D */
168                 if (top->atoms.atom[i].atomnumber == 1)
169                 {
170                     if (top->atoms.atom[i].m == 1.008000)
171                     {
172                         gsans->slength[i] = gnsf->slength[0];
173                     }
174                     else
175                     {
176                         gsans->slength[i] = gnsf->slength[1];
177                     }
178                 }
179                 else
180                 {
181                     gsans->slength[i] = gnsf->slength[j];
182                 }
183             }
184         }
185     }
186
187     return gsans;
188 }
189
190 gmx_radial_distribution_histogram_t* calc_radial_distribution_histogram(gmx_sans_t*  gsans,
191                                                                         rvec*        x,
192                                                                         matrix       box,
193                                                                         const int*   index,
194                                                                         int          isize,
195                                                                         double       binwidth,
196                                                                         gmx_bool     bMC,
197                                                                         gmx_bool     bNORM,
198                                                                         real         mcover,
199                                                                         unsigned int seed)
200 {
201     gmx_radial_distribution_histogram_t* pr = nullptr;
202     rvec                                 dist;
203     double                               rmax;
204     int                                  i, j;
205 #if GMX_OPENMP
206     double**                  tgr;
207     int                       tid;
208     int                       nthreads;
209     gmx::DefaultRandomEngine* trng = nullptr;
210 #endif
211     int64_t                  mc = 0, mc_max;
212     gmx::DefaultRandomEngine rng(seed);
213
214     /* allocate memory for pr */
215     snew(pr, 1);
216     /* set some fields */
217     pr->binwidth = binwidth;
218
219     /*
220      * create max dist rvec
221      * dist = box[xx] + box[yy] + box[zz]
222      */
223     rvec_add(box[XX], box[YY], dist);
224     rvec_add(box[ZZ], dist, dist);
225
226     rmax = norm(dist);
227
228     pr->grn = static_cast<int>(std::floor(rmax / pr->binwidth) + 1);
229
230     snew(pr->gr, pr->grn);
231
232     if (bMC)
233     {
234         /* Special case for setting automaticaly number of mc iterations to 1% of total number of direct iterations */
235         if (mcover == -1)
236         {
237             mc_max = static_cast<int64_t>(std::floor(0.5 * 0.01 * isize * (isize - 1)));
238         }
239         else
240         {
241             mc_max = static_cast<int64_t>(std::floor(0.5 * mcover * isize * (isize - 1)));
242         }
243 #if GMX_OPENMP
244         nthreads = gmx_omp_get_max_threads();
245         snew(tgr, nthreads);
246         trng = new gmx::DefaultRandomEngine[nthreads];
247         for (i = 0; i < nthreads; i++)
248         {
249             snew(tgr[i], pr->grn);
250             trng[i].seed(rng());
251         }
252 #    pragma omp parallel shared(tgr, trng, mc) private(tid, i, j)
253         {
254             gmx::UniformIntDistribution<int> tdist(0, isize - 1);
255             tid = gmx_omp_get_thread_num();
256 /* now starting parallel threads */
257 #    pragma omp for
258             for (mc = 0; mc < mc_max; mc++)
259             {
260                 try
261                 {
262                     i = tdist(trng[tid]); // [0,isize-1]
263                     j = tdist(trng[tid]); // [0,isize-1]
264                     if (i != j)
265                     {
266                         tgr[tid][static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
267                                 gsans->slength[index[i]] * gsans->slength[index[j]];
268                     }
269                 }
270                 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
271             }
272         }
273         /* collecting data from threads */
274         for (i = 0; i < pr->grn; i++)
275         {
276             for (j = 0; j < nthreads; j++)
277             {
278                 pr->gr[i] += tgr[j][i];
279             }
280         }
281         /* freeing memory for tgr and destroying trng */
282         for (i = 0; i < nthreads; i++)
283         {
284             sfree(tgr[i]);
285         }
286         sfree(tgr);
287         delete[] trng;
288 #else
289         gmx::UniformIntDistribution<int> dist(0, isize - 1);
290         for (mc = 0; mc < mc_max; mc++)
291         {
292             i = dist(rng); // [0,isize-1]
293             j = dist(rng); // [0,isize-1]
294             if (i != j)
295             {
296                 pr->gr[static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
297                         gsans->slength[index[i]] * gsans->slength[index[j]];
298             }
299         }
300 #endif
301     }
302     else
303     {
304 #if GMX_OPENMP
305         nthreads = gmx_omp_get_max_threads();
306         /* Allocating memory for tgr arrays */
307         snew(tgr, nthreads);
308         for (i = 0; i < nthreads; i++)
309         {
310             snew(tgr[i], pr->grn);
311         }
312 #    pragma omp parallel shared(tgr) private(tid, i, j)
313         {
314             tid = gmx_omp_get_thread_num();
315 /* starting parallel threads */
316 #    pragma omp for
317             for (i = 0; i < isize; i++)
318             {
319                 try
320                 {
321                     for (j = 0; j < i; j++)
322                     {
323                         tgr[tid][static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
324                                 gsans->slength[index[i]] * gsans->slength[index[j]];
325                     }
326                 }
327                 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
328             }
329         }
330         /* collecating data for pr->gr */
331         for (i = 0; i < pr->grn; i++)
332         {
333             for (j = 0; j < nthreads; j++)
334             {
335                 pr->gr[i] += tgr[j][i];
336             }
337         }
338         /* freeing memory for tgr */
339         for (i = 0; i < nthreads; i++)
340         {
341             sfree(tgr[i]);
342         }
343         sfree(tgr);
344 #else
345         for (i = 0; i < isize; i++)
346         {
347             for (j = 0; j < i; j++)
348             {
349                 pr->gr[static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
350                         gsans->slength[index[i]] * gsans->slength[index[j]];
351             }
352         }
353 #endif
354     }
355
356     /* normalize if needed */
357     if (bNORM)
358     {
359         normalize_probability(pr->grn, pr->gr);
360     }
361
362     snew(pr->r, pr->grn);
363     for (i = 0; i < pr->grn; i++)
364     {
365         pr->r[i] = (pr->binwidth * i + pr->binwidth * 0.5);
366     }
367
368     return pr;
369 }
370
371 gmx_static_structurefactor_t* convert_histogram_to_intensity_curve(gmx_radial_distribution_histogram_t* pr,
372                                                                    double start_q,
373                                                                    double end_q,
374                                                                    double q_step)
375 {
376     gmx_static_structurefactor_t* sq = nullptr;
377     int                           i, j;
378     /* init data */
379     snew(sq, 1);
380     sq->qn = static_cast<int>(std::floor((end_q - start_q) / q_step));
381     snew(sq->q, sq->qn);
382     snew(sq->s, sq->qn);
383     for (i = 0; i < sq->qn; i++)
384     {
385         sq->q[i] = start_q + i * q_step;
386     }
387
388     if (start_q == 0.0)
389     {
390         sq->s[0] = 1.0;
391         for (i = 1; i < sq->qn; i++)
392         {
393             for (j = 0; j < pr->grn; j++)
394             {
395                 sq->s[i] += (pr->gr[j] / pr->r[j]) * std::sin(sq->q[i] * pr->r[j]);
396             }
397             sq->s[i] /= sq->q[i];
398         }
399     }
400     else
401     {
402         for (i = 0; i < sq->qn; i++)
403         {
404             for (j = 0; j < pr->grn; j++)
405             {
406                 sq->s[i] += (pr->gr[j] / pr->r[j]) * std::sin(sq->q[i] * pr->r[j]);
407             }
408             sq->s[i] /= sq->q[i];
409         }
410     }
411
412     return sq;
413 }