Add C++ version of t_ilist
[alexxy/gromacs.git] / src / gromacs / listed-forces / disre.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 /* This file is completely threadsafe - keep it that way! */
38 #include "gmxpre.h"
39
40 #include "disre.h"
41
42 #include "config.h"
43
44 #include <cmath>
45 #include <cstdlib>
46 #include <cstring>
47
48 #include <algorithm>
49
50 #include "gromacs/gmxlib/network.h"
51 #include "gromacs/math/functions.h"
52 #include "gromacs/math/vec.h"
53 #include "gromacs/mdtypes/commrec.h"
54 #include "gromacs/mdtypes/fcdata.h"
55 #include "gromacs/mdtypes/inputrec.h"
56 #include "gromacs/mdtypes/md_enums.h"
57 #include "gromacs/mdtypes/state.h"
58 #include "gromacs/pbcutil/ishift.h"
59 #include "gromacs/pbcutil/mshift.h"
60 #include "gromacs/pbcutil/pbc.h"
61 #include "gromacs/topology/mtop_util.h"
62 #include "gromacs/topology/topology.h"
63 #include "gromacs/utility/fatalerror.h"
64 #include "gromacs/utility/futil.h"
65 #include "gromacs/utility/gmxassert.h"
66 #include "gromacs/utility/pleasecite.h"
67 #include "gromacs/utility/smalloc.h"
68
69 void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
70                  t_inputrec *ir, const t_commrec *cr,
71                  const gmx_multisim_t *ms,
72                  t_fcdata *fcd, t_state *state, gmx_bool bIsREMD)
73 {
74     int                    fa, nmol, npair, np;
75     t_disresdata          *dd;
76     history_t             *hist;
77     gmx_mtop_ilistloop_t   iloop;
78     const InteractionList *il;
79     char                  *ptr;
80     int                    type_min, type_max;
81
82     dd = &(fcd->disres);
83
84     if (gmx_mtop_ftype_count(mtop, F_DISRES) == 0)
85     {
86         dd->nres = 0;
87
88         return;
89     }
90
91     if (fplog)
92     {
93         fprintf(fplog, "Initializing the distance restraints\n");
94     }
95
96     dd->dr_weighting = ir->eDisreWeighting;
97     dd->dr_fc        = ir->dr_fc;
98     if (EI_DYNAMICS(ir->eI))
99     {
100         dd->dr_tau   = ir->dr_tau;
101     }
102     else
103     {
104         dd->dr_tau   = 0.0;
105     }
106     if (dd->dr_tau == 0.0)
107     {
108         dd->dr_bMixed = FALSE;
109         dd->ETerm     = 0.0;
110     }
111     else
112     {
113         /* We store the r^-6 time averages in an array that is indexed
114          * with the local disres iatom index, so this doesn't work with DD.
115          * Note that DD is not initialized yet here, so we check for PAR(cr),
116          * but there are probably also issues with e.g. NM MPI parallelization.
117          */
118         if (cr && PAR(cr))
119         {
120             gmx_fatal(FARGS, "Time-averaged distance restraints are not supported with MPI parallelization. You can use OpenMP parallelization on a single node.");
121         }
122
123         dd->dr_bMixed = ir->bDisreMixed;
124         dd->ETerm     = std::exp(-(ir->delta_t/ir->dr_tau));
125     }
126     dd->ETerm1        = 1.0 - dd->ETerm;
127
128     dd->nres  = 0;
129     dd->npair = 0;
130     type_min  = INT_MAX;
131     type_max  = 0;
132     iloop     = gmx_mtop_ilistloop_init(mtop);
133     while (gmx_mtop_ilistloop_next(iloop, &il, &nmol))
134     {
135         if (nmol > 1 && il[F_DISRES].size() > 0 && ir->eDisre != edrEnsemble)
136         {
137             gmx_fatal(FARGS, "NMR distance restraints with multiple copies of the same molecule are currently only supported with ensemble averaging. If you just want to restrain distances between atom pairs using a flat-bottomed potential, use a restraint potential (bonds type 10) instead.");
138         }
139
140         np = 0;
141         for (fa = 0; fa < il[F_DISRES].size(); fa += 3)
142         {
143             int type;
144
145             type  = il[F_DISRES].iatoms[fa];
146
147             np++;
148             npair = mtop->ffparams.iparams[type].disres.npair;
149             if (np == npair)
150             {
151                 dd->nres  += (ir->eDisre == edrEnsemble ? 1 : nmol);
152                 dd->npair += nmol*npair;
153                 np         = 0;
154
155                 type_min   = std::min(type_min, type);
156                 type_max   = std::max(type_max, type);
157             }
158         }
159     }
160
161     if (cr && PAR(cr) && ir->nstdisreout > 0)
162     {
163         /* With DD we currently only have local pair information available */
164         gmx_fatal(FARGS, "With MPI parallelization distance-restraint pair output is not supported. Use nstdisreout=0 or use OpenMP parallelization on a single node.");
165     }
166
167     /* For communicating and/or reducing (sums of) r^-6 for pairs over threads
168      * we use multiple arrays in t_disresdata. We need to have unique indices
169      * for each restraint that work over threads and MPI ranks. To this end
170      * we use the type index. These should all be in one block and there should
171      * be dd->nres types, but we check for this here.
172      * This setup currently does not allow for multiple copies of the same
173      * molecule without ensemble averaging, this is check for above.
174      */
175     GMX_RELEASE_ASSERT(type_max - type_min + 1 == dd->nres, "All distance restraint parameter entries in the topology should be consecutive");
176
177     dd->type_min = type_min;
178
179     snew(dd->rt, dd->npair);
180
181     if (dd->dr_tau != 0.0)
182     {
183         GMX_RELEASE_ASSERT(state != nullptr, "We need a valid state when using time-averaged distance restraints");
184
185         hist = &state->hist;
186         /* Set the "history lack" factor to 1 */
187         state->flags     |= (1<<estDISRE_INITF);
188         hist->disre_initf = 1.0;
189         /* Allocate space for the r^-3 time averages */
190         state->flags     |= (1<<estDISRE_RM3TAV);
191         hist->ndisrepairs = dd->npair;
192         snew(hist->disre_rm3tav, hist->ndisrepairs);
193     }
194     /* Allocate space for a copy of rm3tav,
195      * so we can call do_force without modifying the state.
196      */
197     snew(dd->rm3tav, dd->npair);
198
199     /* Allocate Rt_6 and Rtav_6 consecutively in memory so they can be
200      * averaged over the processors in one call (in calc_disre_R_6)
201      */
202     snew(dd->Rt_6, 2*dd->nres);
203     dd->Rtav_6 = &(dd->Rt_6[dd->nres]);
204
205     ptr = getenv("GMX_DISRE_ENSEMBLE_SIZE");
206     if (cr && ms != nullptr && ptr != nullptr && !bIsREMD)
207     {
208 #if GMX_MPI
209         dd->nsystems = 0;
210         sscanf(ptr, "%d", &dd->nsystems);
211         if (fplog)
212         {
213             fprintf(fplog, "Found GMX_DISRE_ENSEMBLE_SIZE set to %d systems per ensemble\n", dd->nsystems);
214         }
215         /* This check is only valid on MASTER(cr), so probably
216          * ensemble-averaged distance restraints are broken on more
217          * than one processor per simulation system. */
218         if (MASTER(cr))
219         {
220             check_multi_int(fplog, ms, dd->nsystems,
221                             "the number of systems per ensemble",
222                             FALSE);
223         }
224         gmx_bcast_sim(sizeof(int), &dd->nsystems, cr);
225
226         /* We use to allow any value of nsystems which was a divisor
227          * of ms->nsim. But this required an extra communicator which
228          * was stored in t_fcdata. This pulled in mpi.h in nearly all C files.
229          */
230         if (!(ms->nsim == 1 || ms->nsim == dd->nsystems))
231         {
232             gmx_fatal(FARGS, "GMX_DISRE_ENSEMBLE_SIZE (%d) is not equal to 1 or the number of systems (option -multidir) %d", dd->nsystems, ms->nsim);
233         }
234         if (fplog)
235         {
236             fprintf(fplog, "Our ensemble consists of systems:");
237             for (int i = 0; i < dd->nsystems; i++)
238             {
239                 fprintf(fplog, " %d",
240                         (ms->sim/dd->nsystems)*dd->nsystems+i);
241             }
242             fprintf(fplog, "\n");
243         }
244 #endif
245     }
246     else
247     {
248         dd->nsystems = 1;
249     }
250
251     if (dd->nsystems == 1)
252     {
253         dd->Rtl_6    = dd->Rt_6;
254     }
255     else
256     {
257         snew(dd->Rtl_6, dd->nres);
258     }
259
260     if (dd->npair > 0)
261     {
262         if (fplog)
263         {
264             fprintf(fplog, "There are %d distance restraints involving %d atom pairs\n", dd->nres, dd->npair);
265         }
266         /* Have to avoid g_disre de-referencing cr blindly, mdrun not
267          * doing consistency checks for ensemble-averaged distance
268          * restraints when that's not happening, and only doing those
269          * checks from appropriate processes (since check_multi_int is
270          * too broken to check whether the communication will
271          * succeed...) */
272         if (cr && ms && dd->nsystems > 1 && MASTER(cr))
273         {
274             check_multi_int(fplog, ms, fcd->disres.nres,
275                             "the number of distance restraints",
276                             FALSE);
277         }
278         please_cite(fplog, "Tropp80a");
279         please_cite(fplog, "Torda89a");
280     }
281 }
282
283 void calc_disres_R_6(const t_commrec *cr,
284                      const gmx_multisim_t *ms,
285                      int nfa, const t_iatom forceatoms[],
286                      const rvec x[], const t_pbc *pbc,
287                      t_fcdata *fcd, history_t *hist)
288 {
289     rvec            dx;
290     real           *rt, *rm3tav, *Rtl_6, *Rt_6, *Rtav_6;
291     t_disresdata   *dd;
292     real            ETerm, ETerm1, cf1 = 0, cf2 = 0;
293     gmx_bool        bTav;
294
295     dd           = &(fcd->disres);
296     bTav         = (dd->dr_tau != 0);
297     ETerm        = dd->ETerm;
298     ETerm1       = dd->ETerm1;
299     rt           = dd->rt;
300     rm3tav       = dd->rm3tav;
301     Rtl_6        = dd->Rtl_6;
302     Rt_6         = dd->Rt_6;
303     Rtav_6       = dd->Rtav_6;
304
305     if (bTav)
306     {
307         /* scaling factor to smoothly turn on the restraint forces *
308          * when using time averaging                               */
309         dd->exp_min_t_tau = hist->disre_initf*ETerm;
310
311         cf1 = dd->exp_min_t_tau;
312         cf2 = 1.0/(1.0 - dd->exp_min_t_tau);
313     }
314
315     for (int res = 0; res < dd->nres; res++)
316     {
317         Rtav_6[res] = 0.0;
318         Rt_6[res]   = 0.0;
319     }
320
321     /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, *
322      * the total number of atoms pairs is nfa/3                          */
323     for (int fa = 0; fa < nfa; fa += 3)
324     {
325         int type = forceatoms[fa];
326         int res  = type - dd->type_min;
327         int pair = fa/3;
328         int ai   = forceatoms[fa+1];
329         int aj   = forceatoms[fa+2];
330
331         if (pbc)
332         {
333             pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
334         }
335         else
336         {
337             rvec_sub(x[ai], x[aj], dx);
338         }
339         real rt2  = iprod(dx, dx);
340         real rt_1 = gmx::invsqrt(rt2);
341         real rt_3 = rt_1*rt_1*rt_1;
342
343         rt[pair]  = rt2*rt_1;
344         if (bTav)
345         {
346             /* Here we update rm3tav in t_fcdata using the data
347              * in history_t.
348              * Thus the results stay correct when this routine
349              * is called multiple times.
350              */
351             rm3tav[pair] = cf2*((ETerm - cf1)*hist->disre_rm3tav[pair] +
352                                 ETerm1*rt_3);
353         }
354         else
355         {
356             rm3tav[pair] = rt_3;
357         }
358
359         /* Currently divide_bondeds_over_threads() ensures that pairs within
360          * the same restraint get assigned to the same thread, so we could
361          * run this loop thread-parallel.
362          */
363         Rt_6[res]       += rt_3*rt_3;
364         Rtav_6[res]     += rm3tav[pair]*rm3tav[pair];
365     }
366
367     /* NOTE: Rt_6 and Rtav_6 are stored consecutively in memory */
368     if (cr && DOMAINDECOMP(cr))
369     {
370         gmx_sum(2*dd->nres, dd->Rt_6, cr);
371     }
372
373     if (fcd->disres.nsystems > 1)
374     {
375         real invn = 1.0/dd->nsystems;
376
377         for (int res = 0; res < dd->nres; res++)
378         {
379             Rtl_6[res]   = Rt_6[res];
380             Rt_6[res]   *= invn;
381             Rtav_6[res] *= invn;
382         }
383
384         GMX_ASSERT(cr != nullptr && ms != nullptr, "We need multisim with nsystems>1");
385         gmx_sum_sim(2*dd->nres, dd->Rt_6, ms);
386
387         if (DOMAINDECOMP(cr))
388         {
389             gmx_bcast(2*dd->nres, dd->Rt_6, cr);
390         }
391     }
392
393     /* Store the base forceatoms pointer, so we can re-calculate the pair
394      * index in ta_disres() for indexing pair data in t_disresdata when
395      * using thread parallelization.
396      */
397     dd->forceatomsStart = forceatoms;
398
399     dd->sumviol         = 0;
400 }
401
402 real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
403                const rvec x[], rvec4 f[], rvec fshift[],
404                const t_pbc *pbc, const t_graph *g,
405                real gmx_unused lambda, real gmx_unused *dvdlambda,
406                const t_mdatoms gmx_unused *md, t_fcdata *fcd,
407                int gmx_unused *global_atom_index)
408 {
409     const real      seven_three = 7.0/3.0;
410
411     rvec            dx;
412     real            weight_rt_1;
413     real            smooth_fc, Rt, Rtav, rt2, *Rtl_6, *Rt_6, *Rtav_6;
414     real            k0, f_scal = 0, fmax_scal, fk_scal, fij;
415     real            tav_viol, instant_viol, mixed_viol, violtot, vtot;
416     real            tav_viol_Rtav7, instant_viol_Rtav7;
417     real            up1, up2, low;
418     gmx_bool        bConservative, bMixed, bViolation;
419     ivec            dt;
420     t_disresdata   *dd;
421     int             dr_weighting;
422     gmx_bool        dr_bMixed;
423
424     dd           = &(fcd->disres);
425     dr_weighting = dd->dr_weighting;
426     dr_bMixed    = dd->dr_bMixed;
427     Rtl_6        = dd->Rtl_6;
428     Rt_6         = dd->Rt_6;
429     Rtav_6       = dd->Rtav_6;
430
431     tav_viol = instant_viol = mixed_viol = tav_viol_Rtav7 = instant_viol_Rtav7 = 0;
432
433     smooth_fc = dd->dr_fc;
434     if (dd->dr_tau != 0)
435     {
436         /* scaling factor to smoothly turn on the restraint forces *
437          * when using time averaging                               */
438         smooth_fc *= (1.0 - dd->exp_min_t_tau);
439     }
440
441     violtot = 0;
442     vtot    = 0;
443
444     /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, *
445      * the total number of atoms pairs is nfa/3                          */
446     int faOffset = static_cast<int>(forceatoms - dd->forceatomsStart);
447     for (int fa = 0; fa < nfa; fa += 3)
448     {
449         int type  = forceatoms[fa];
450         int npair = ip[type].disres.npair;
451         up1       = ip[type].disres.up1;
452         up2       = ip[type].disres.up2;
453         low       = ip[type].disres.low;
454         k0        = smooth_fc*ip[type].disres.kfac;
455
456         int res   = type - dd->type_min;
457
458         /* save some flops when there is only one pair */
459         if (ip[type].disres.type != 2)
460         {
461             bConservative = (dr_weighting == edrwConservative) && (npair > 1);
462             bMixed        = dr_bMixed;
463             Rt            = gmx::invsixthroot(Rt_6[res]);
464             Rtav          = gmx::invsixthroot(Rtav_6[res]);
465         }
466         else
467         {
468             /* When rtype=2 use instantaneous not ensemble averaged distance */
469             bConservative = (npair > 1);
470             bMixed        = FALSE;
471             Rt            = gmx::invsixthroot(Rtl_6[res]);
472             Rtav          = Rt;
473         }
474
475         if (Rtav > up1)
476         {
477             bViolation = TRUE;
478             tav_viol   = Rtav - up1;
479         }
480         else if (Rtav < low)
481         {
482             bViolation = TRUE;
483             tav_viol   = Rtav - low;
484         }
485         else
486         {
487             bViolation = FALSE;
488         }
489
490         if (bViolation)
491         {
492             /* Add 1/npair energy and violation for each of the npair pairs */
493             real pairFac = 1/static_cast<real>(npair);
494
495             /* NOTE:
496              * there is no real potential when time averaging is applied
497              */
498             vtot += 0.5*k0*gmx::square(tav_viol)*pairFac;
499             if (!bMixed)
500             {
501                 f_scal   = -k0*tav_viol;
502                 violtot += fabs(tav_viol)*pairFac;
503             }
504             else
505             {
506                 if (Rt > up1)
507                 {
508                     if (tav_viol > 0)
509                     {
510                         instant_viol = Rt - up1;
511                     }
512                     else
513                     {
514                         bViolation = FALSE;
515                     }
516                 }
517                 else if (Rt < low)
518                 {
519                     if (tav_viol < 0)
520                     {
521                         instant_viol = Rt - low;
522                     }
523                     else
524                     {
525                         bViolation = FALSE;
526                     }
527                 }
528                 else
529                 {
530                     bViolation = FALSE;
531                 }
532                 if (bViolation)
533                 {
534                     mixed_viol = std::sqrt(tav_viol*instant_viol);
535                     f_scal     = -k0*mixed_viol;
536                     violtot   += mixed_viol*pairFac;
537                 }
538             }
539         }
540
541         if (bViolation)
542         {
543             fmax_scal = -k0*(up2-up1);
544             /* Correct the force for the number of restraints */
545             if (bConservative)
546             {
547                 f_scal  = std::max(f_scal, fmax_scal);
548                 if (!bMixed)
549                 {
550                     f_scal *= Rtav/Rtav_6[res];
551                 }
552                 else
553                 {
554                     f_scal            /= 2*mixed_viol;
555                     tav_viol_Rtav7     = tav_viol*Rtav/Rtav_6[res];
556                     instant_viol_Rtav7 = instant_viol*Rt/Rt_6[res];
557                 }
558             }
559             else
560             {
561                 f_scal /= npair;
562                 f_scal  = std::max(f_scal, fmax_scal);
563             }
564
565             /* Exert the force ... */
566
567             int pair = (faOffset + fa)/3;
568             int ai   = forceatoms[fa+1];
569             int aj   = forceatoms[fa+2];
570             int ki   = CENTRAL;
571             if (pbc)
572             {
573                 ki = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
574             }
575             else
576             {
577                 rvec_sub(x[ai], x[aj], dx);
578             }
579             rt2 = iprod(dx, dx);
580
581             weight_rt_1 = gmx::invsqrt(rt2);
582
583             if (bConservative)
584             {
585                 if (!dr_bMixed)
586                 {
587                     weight_rt_1 *= std::pow(dd->rm3tav[pair], seven_three);
588                 }
589                 else
590                 {
591                     weight_rt_1 *= tav_viol_Rtav7*std::pow(dd->rm3tav[pair], seven_three)+
592                         instant_viol_Rtav7/(dd->rt[pair]*gmx::power6(dd->rt[pair]));
593                 }
594             }
595
596             fk_scal  = f_scal*weight_rt_1;
597
598             if (g)
599             {
600                 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
601                 ki = IVEC2IS(dt);
602             }
603
604             for (int m = 0; m < DIM; m++)
605             {
606                 fij            = fk_scal*dx[m];
607
608                 f[ai][m]           += fij;
609                 f[aj][m]           -= fij;
610                 fshift[ki][m]      += fij;
611                 fshift[CENTRAL][m] -= fij;
612             }
613         }
614     }
615
616 #pragma omp atomic
617     dd->sumviol += violtot;
618
619     /* Return energy */
620     return vtot;
621 }
622
623 void update_disres_history(const t_fcdata *fcd, history_t *hist)
624 {
625     const t_disresdata *dd;
626     int                 pair;
627
628     dd = &(fcd->disres);
629     if (dd->dr_tau != 0)
630     {
631         /* Copy the new time averages that have been calculated
632          * in calc_disres_R_6.
633          */
634         hist->disre_initf = dd->exp_min_t_tau;
635         for (pair = 0; pair < dd->npair; pair++)
636         {
637             hist->disre_rm3tav[pair] = dd->rm3tav[pair];
638         }
639     }
640 }