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