Remove support for Intel classic compiler
[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, The GROMACS development team.
5  * Copyright (c) 2017,2018,2019,2020,2021, 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/basedefinitions.h"
50 #include "gromacs/utility/cstringutil.h"
51 #include "gromacs/utility/exceptions.h"
52 #include "gromacs/utility/fatalerror.h"
53 #include "gromacs/utility/futil.h"
54 #include "gromacs/utility/gmxomp.h"
55 #include "gromacs/utility/smalloc.h"
56 #include "gromacs/utility/strdb.h"
57
58 void check_binwidth(real binwidth)
59 {
60     real smallest_bin = 0.1;
61     if (binwidth < smallest_bin)
62     {
63         gmx_fatal(FARGS,
64                   "Binwidth shouldn't be smaller then smallest bond length (H-H bond ~0.1nm) in a "
65                   "box");
66     }
67 }
68
69 void check_mcover(real mcover)
70 {
71     if (mcover > 1.0)
72     {
73         gmx_fatal(FARGS, "mcover should be -1 or (0,1]");
74     }
75     else if ((mcover < 0) && (mcover != -1))
76     {
77         gmx_fatal(FARGS, "mcover should be -1 or (0,1]");
78     }
79     else
80     {
81         return;
82     }
83 }
84
85 void normalize_probability(int n, double* a)
86 {
87     int    i;
88     double norm = 0.0;
89     for (i = 0; i < n; i++)
90     {
91         norm += a[i];
92     }
93     for (i = 0; i < n; i++)
94     {
95         a[i] /= norm;
96     }
97 }
98
99 gmx_neutron_atomic_structurefactors_t* gmx_neutronstructurefactors_init(const char* datfn)
100 {
101     /* read nsfactor.dat */
102     char                                   line[STRLEN];
103     int                                    nralloc = 10;
104     int                                    n, p;
105     int                                    i, line_no;
106     char                                   atomnm[8];
107     double                                 slength;
108     gmx_neutron_atomic_structurefactors_t* gnsf;
109
110     gmx::FilePtr fp = gmx::openLibraryFile(datfn);
111     line_no         = 0;
112     /* allocate memory for structure */
113     snew(gnsf, nralloc);
114     snew(gnsf->atomnm, nralloc);
115     snew(gnsf->p, nralloc);
116     snew(gnsf->n, nralloc);
117     snew(gnsf->slength, nralloc);
118
119     gnsf->nratoms = line_no;
120
121     while (get_a_line(fp.get(), line, STRLEN))
122     {
123         i = line_no;
124         if (sscanf(line, "%s %d %d %lf", atomnm, &p, &n, &slength) == 4)
125         {
126             gnsf->atomnm[i]  = gmx_strdup(atomnm);
127             gnsf->n[i]       = n;
128             gnsf->p[i]       = p;
129             gnsf->slength[i] = slength;
130             line_no++;
131             gnsf->nratoms = line_no;
132             if (line_no == nralloc)
133             {
134                 nralloc++;
135                 srenew(gnsf->atomnm, nralloc);
136                 srenew(gnsf->p, nralloc);
137                 srenew(gnsf->n, nralloc);
138                 srenew(gnsf->slength, nralloc);
139             }
140         }
141         else
142         {
143             fprintf(stderr, "WARNING: Error in file %s at line %d ignored\n", datfn, line_no);
144         }
145     }
146     srenew(gnsf->atomnm, gnsf->nratoms);
147     srenew(gnsf->p, gnsf->nratoms);
148     srenew(gnsf->n, gnsf->nratoms);
149     srenew(gnsf->slength, gnsf->nratoms);
150
151     return gnsf;
152 }
153
154 gmx_sans_t* gmx_sans_init(const t_topology* top, gmx_neutron_atomic_structurefactors_t* gnsf)
155 {
156     gmx_sans_t* gsans = nullptr;
157     int         i, j;
158     /* Try to assing scattering length from nsfactor.dat */
159     snew(gsans, 1);
160     snew(gsans->slength, top->atoms.nr);
161     /* copy topology data */
162     gsans->top = top;
163     for (i = 0; i < top->atoms.nr; i++)
164     {
165         for (j = 0; j < gnsf->nratoms; j++)
166         {
167             if (top->atoms.atom[i].atomnumber == gnsf->p[j])
168             {
169                 /* we need special case for H and D */
170                 if (top->atoms.atom[i].atomnumber == 1)
171                 {
172                     if (top->atoms.atom[i].m == 1.008000)
173                     {
174                         gsans->slength[i] = gnsf->slength[0];
175                     }
176                     else
177                     {
178                         gsans->slength[i] = gnsf->slength[1];
179                     }
180                 }
181                 else
182                 {
183                     gsans->slength[i] = gnsf->slength[j];
184                 }
185             }
186         }
187     }
188
189     return gsans;
190 }
191
192 gmx_radial_distribution_histogram_t* calc_radial_distribution_histogram(gmx_sans_t*  gsans,
193                                                                         rvec*        x,
194                                                                         matrix       box,
195                                                                         const int*   index,
196                                                                         int          isize,
197                                                                         double       binwidth,
198                                                                         gmx_bool     bMC,
199                                                                         gmx_bool     bNORM,
200                                                                         real         mcover,
201                                                                         unsigned int seed)
202 {
203     gmx_radial_distribution_histogram_t* pr = nullptr;
204     rvec                                 dist;
205     double                               rmax;
206     int                                  i, j;
207 #if GMX_OPENMP
208     double**                  tgr;
209     int                       tid;
210     int                       nthreads;
211     gmx::DefaultRandomEngine* trng = nullptr;
212 #endif
213     int64_t                  mc_max;
214     gmx::DefaultRandomEngine rng(seed);
215
216     /* allocate memory for pr */
217     snew(pr, 1);
218     /* set some fields */
219     pr->binwidth = binwidth;
220
221     /*
222      * create max dist rvec
223      * dist = box[xx] + box[yy] + box[zz]
224      */
225     rvec_add(box[XX], box[YY], dist);
226     rvec_add(box[ZZ], dist, dist);
227
228     rmax = norm(dist);
229
230     pr->grn = static_cast<int>(std::floor(rmax / pr->binwidth) + 1);
231
232     snew(pr->gr, pr->grn);
233
234     if (bMC)
235     {
236         /* Special case for setting automaticaly number of mc iterations to 1% of total number of direct iterations */
237         if (mcover == -1)
238         {
239             mc_max = static_cast<int64_t>(std::floor(0.5 * 0.01 * isize * (isize - 1)));
240         }
241         else
242         {
243             mc_max = static_cast<int64_t>(std::floor(0.5 * mcover * isize * (isize - 1)));
244         }
245 #if GMX_OPENMP
246         nthreads = gmx_omp_get_max_threads();
247         snew(tgr, nthreads);
248         trng = new gmx::DefaultRandomEngine[nthreads];
249         for (i = 0; i < nthreads; i++)
250         {
251             snew(tgr[i], pr->grn);
252             trng[i].seed(rng());
253         }
254 #    pragma omp parallel shared(tgr, trng) private(tid, i, j)
255         {
256             gmx::UniformIntDistribution<int> tdist(0, isize - 1);
257             tid = gmx_omp_get_thread_num();
258             /* now starting parallel threads */
259 #    pragma omp for
260             for (int64_t mc = 0; mc < mc_max; mc++)
261             {
262                 try
263                 {
264                     i = tdist(trng[tid]); // [0,isize-1]
265                     j = tdist(trng[tid]); // [0,isize-1]
266                     if (i != j)
267                     {
268                         tgr[tid][static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
269                                 gsans->slength[index[i]] * gsans->slength[index[j]];
270                     }
271                 }
272                 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
273             }
274         }
275         /* collecting data from threads */
276         for (i = 0; i < pr->grn; i++)
277         {
278             for (j = 0; j < nthreads; j++)
279             {
280                 pr->gr[i] += tgr[j][i];
281             }
282         }
283         /* freeing memory for tgr and destroying trng */
284         for (i = 0; i < nthreads; i++)
285         {
286             sfree(tgr[i]);
287         }
288         sfree(tgr);
289         delete[] trng;
290 #else
291         gmx::UniformIntDistribution<int> dist(0, isize - 1);
292         for (int64_t mc = 0; mc < mc_max; mc++)
293         {
294             i = dist(rng); // [0,isize-1]
295             j = dist(rng); // [0,isize-1]
296             if (i != j)
297             {
298                 pr->gr[static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
299                         gsans->slength[index[i]] * gsans->slength[index[j]];
300             }
301         }
302 #endif
303     }
304     else
305     {
306 #if GMX_OPENMP
307         nthreads = gmx_omp_get_max_threads();
308         /* Allocating memory for tgr arrays */
309         snew(tgr, nthreads);
310         for (i = 0; i < nthreads; i++)
311         {
312             snew(tgr[i], pr->grn);
313         }
314 #    pragma omp parallel shared(tgr) private(tid, i, j)
315         {
316             tid = gmx_omp_get_thread_num();
317 /* starting parallel threads */
318 #    pragma omp for
319             for (i = 0; i < isize; i++)
320             {
321                 try
322                 {
323                     for (j = 0; j < i; j++)
324                     {
325                         tgr[tid][static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
326                                 gsans->slength[index[i]] * gsans->slength[index[j]];
327                     }
328                 }
329                 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
330             }
331         }
332         /* collecating data for pr->gr */
333         for (i = 0; i < pr->grn; i++)
334         {
335             for (j = 0; j < nthreads; j++)
336             {
337                 pr->gr[i] += tgr[j][i];
338             }
339         }
340         /* freeing memory for tgr */
341         for (i = 0; i < nthreads; i++)
342         {
343             sfree(tgr[i]);
344         }
345         sfree(tgr);
346 #else
347         for (i = 0; i < isize; i++)
348         {
349             for (j = 0; j < i; j++)
350             {
351                 pr->gr[static_cast<int>(std::floor(std::sqrt(distance2(x[index[i]], x[index[j]])) / binwidth))] +=
352                         gsans->slength[index[i]] * gsans->slength[index[j]];
353             }
354         }
355 #endif
356     }
357
358     /* normalize if needed */
359     if (bNORM)
360     {
361         normalize_probability(pr->grn, pr->gr);
362     }
363
364     snew(pr->r, pr->grn);
365     for (i = 0; i < pr->grn; i++)
366     {
367         pr->r[i] = (pr->binwidth * i + pr->binwidth * 0.5);
368     }
369
370     return pr;
371 }
372
373 gmx_static_structurefactor_t* convert_histogram_to_intensity_curve(gmx_radial_distribution_histogram_t* pr,
374                                                                    double start_q,
375                                                                    double end_q,
376                                                                    double q_step)
377 {
378     gmx_static_structurefactor_t* sq = nullptr;
379     int                           i, j;
380     /* init data */
381     snew(sq, 1);
382     sq->qn = static_cast<int>(std::floor((end_q - start_q) / q_step));
383     snew(sq->q, sq->qn);
384     snew(sq->s, sq->qn);
385     for (i = 0; i < sq->qn; i++)
386     {
387         sq->q[i] = start_q + i * q_step;
388     }
389
390     if (start_q == 0.0)
391     {
392         sq->s[0] = 1.0;
393         for (i = 1; i < sq->qn; i++)
394         {
395             for (j = 0; j < pr->grn; j++)
396             {
397                 sq->s[i] += (pr->gr[j] / pr->r[j]) * std::sin(sq->q[i] * pr->r[j]);
398             }
399             sq->s[i] /= sq->q[i];
400         }
401     }
402     else
403     {
404         for (i = 0; i < sq->qn; i++)
405         {
406             for (j = 0; j < pr->grn; j++)
407             {
408                 sq->s[i] += (pr->gr[j] / pr->r[j]) * std::sin(sq->q[i] * pr->r[j]);
409             }
410             sq->s[i] /= sq->q[i];
411         }
412     }
413
414     return sq;
415 }