Update instructions in containers.rst
[gromacs.git] / src / gromacs / gmxana / gmx_disre.cpp
blob045481ac3ec5fb4412e8bf856f3fda804b389090
1 /*
2 * This file is part of the GROMACS molecular simulation package.
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 The GROMACS development team.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
38 #include "gmxpre.h"
40 #include <cmath>
41 #include <cstdlib>
42 #include <cstring>
44 #include <algorithm>
45 #include <unordered_map>
47 #include "gromacs/commandline/pargs.h"
48 #include "gromacs/commandline/viewit.h"
49 #include "gromacs/fileio/confio.h"
50 #include "gromacs/fileio/matio.h"
51 #include "gromacs/fileio/pdbio.h"
52 #include "gromacs/fileio/tpxio.h"
53 #include "gromacs/fileio/trxio.h"
54 #include "gromacs/fileio/xvgr.h"
55 #include "gromacs/gmxana/gmx_ana.h"
56 #include "gromacs/gmxana/gstat.h"
57 #include "gromacs/listed_forces/disre.h"
58 #include "gromacs/math/do_fit.h"
59 #include "gromacs/math/functions.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/mdlib/force.h"
62 #include "gromacs/mdlib/mdatoms.h"
63 #include "gromacs/mdtypes/commrec.h"
64 #include "gromacs/mdtypes/fcdata.h"
65 #include "gromacs/mdtypes/inputrec.h"
66 #include "gromacs/mdtypes/md_enums.h"
67 #include "gromacs/mdtypes/mdatom.h"
68 #include "gromacs/pbcutil/ishift.h"
69 #include "gromacs/pbcutil/pbc.h"
70 #include "gromacs/pbcutil/rmpbc.h"
71 #include "gromacs/topology/index.h"
72 #include "gromacs/topology/mtop_util.h"
73 #include "gromacs/topology/topology.h"
74 #include "gromacs/trajectoryanalysis/topologyinformation.h"
75 #include "gromacs/utility/arraysize.h"
76 #include "gromacs/utility/fatalerror.h"
77 #include "gromacs/utility/futil.h"
78 #include "gromacs/utility/smalloc.h"
80 typedef struct
82 int n;
83 real v;
84 } t_toppop;
86 static t_toppop* top = nullptr;
87 static int ntop = 0;
89 typedef struct
91 int nv, nframes;
92 real sumv, averv, maxv;
93 real *aver1, *aver2, *aver_3, *aver_6;
94 } t_dr_result;
96 static void init5(int n)
98 ntop = n;
99 snew(top, ntop);
102 static void reset5()
104 int i;
106 for (i = 0; (i < ntop); i++)
108 top[i].n = -1;
109 top[i].v = 0;
113 static void add5(int ndr, real viol)
115 int i, mini;
117 mini = 0;
118 for (i = 1; (i < ntop); i++)
120 if (top[i].v < top[mini].v)
122 mini = i;
125 if (viol > top[mini].v)
127 top[mini].v = viol;
128 top[mini].n = ndr;
132 static void print5(FILE* fp)
134 int i;
136 std::sort(top, top + ntop, [](const t_toppop& a, const t_toppop& b) { return a.v > b.v; }); // reverse sort
137 fprintf(fp, "Index:");
138 for (i = 0; (i < ntop); i++)
140 fprintf(fp, " %6d", top[i].n);
142 fprintf(fp, "\nViol: ");
143 for (i = 0; (i < ntop); i++)
145 fprintf(fp, " %6.3f", top[i].v);
147 fprintf(fp, "\n");
150 static void check_viol(FILE* log,
151 const InteractionList& disres,
152 gmx::ArrayRef<const t_iparams> forceparams,
153 rvec x[],
154 rvec4 f[],
155 t_pbc* pbc,
156 t_dr_result dr[],
157 int clust_id,
158 int isize,
159 const int index[],
160 real vvindex[],
161 t_disresdata* disresdata)
163 int i, j, nat, n, type, nviol, ndr, label;
164 real rt, mviol, tviol, viol, lam, dvdl, drt;
165 rvec* fshift;
166 static gmx_bool bFirst = TRUE;
168 lam = 0;
169 dvdl = 0;
170 tviol = 0;
171 nviol = 0;
172 mviol = 0;
173 ndr = 0;
174 if (ntop)
176 reset5();
178 gmx::ArrayRef<const int> forceatoms = disres.iatoms;
179 for (j = 0; (j < isize); j++)
181 vvindex[j] = 0;
183 nat = interaction_function[F_DISRES].nratoms + 1;
184 // Check internal consistency of disres.label
185 // The label for a distance restraint should be at most one larger
186 // than the previous label.
187 int label_old = forceparams[forceatoms[0]].disres.label;
188 for (i = 0; (i < disres.size()); i += nat)
190 type = forceatoms[i];
191 label = forceparams[type].disres.label;
192 if ((label == label_old) || (label == label_old + 1))
194 label_old = label;
196 else
198 gmx_fatal(FARGS,
199 "Label mismatch in distance restrains. Label for restraint %d is %d, "
200 "expected it to be either %d or %d",
201 i / nat, label, label_old, label_old + 1);
205 // Set up t_fcdata, only needed for calling ta_disres()
206 t_fcdata fcd;
207 fcd.disres = disresdata;
209 // Get offset for label index
210 label_old = forceparams[forceatoms[0]].disres.label;
211 for (i = 0; (i < disres.size());)
213 type = forceatoms[i];
214 n = 0;
215 label = forceparams[type].disres.label - label_old;
216 if (debug)
218 fprintf(debug, "DISRE: ndr = %d, label = %d i=%d, n =%d\n", ndr, label, i, n);
222 n += nat;
223 } while (((i + n) < disres.size())
224 && (forceparams[forceatoms[i + n]].disres.label == label + label_old));
226 calc_disres_R_6(nullptr, nullptr, n, &forceatoms[i], x, pbc, disresdata, nullptr);
228 if (disresdata->Rt_6[label] <= 0)
230 gmx_fatal(FARGS, "ndr = %d, rt_6 = %f", ndr, disresdata->Rt_6[label]);
233 rt = gmx::invsixthroot(disresdata->Rt_6[label]);
234 dr[clust_id].aver1[ndr] += rt;
235 dr[clust_id].aver2[ndr] += gmx::square(rt);
236 drt = 1.0 / gmx::power3(rt);
237 dr[clust_id].aver_3[ndr] += drt;
238 dr[clust_id].aver_6[ndr] += disresdata->Rt_6[label];
240 snew(fshift, SHIFTS);
241 ta_disres(n, &forceatoms[i], forceparams.data(), x, f, fshift, pbc, lam, &dvdl, nullptr,
242 &fcd, nullptr);
243 sfree(fshift);
244 viol = disresdata->sumviol;
246 if (viol > 0)
248 nviol++;
249 if (ntop)
251 add5(forceparams[type].disres.label, viol);
253 if (viol > mviol)
255 mviol = viol;
257 tviol += viol;
258 for (j = 0; (j < isize); j++)
260 if (index[j] == forceparams[type].disres.label)
262 vvindex[j] = gmx::invsixthroot(disresdata->Rt_6[label]);
266 ndr++;
267 i += n;
269 dr[clust_id].nv = nviol;
270 dr[clust_id].maxv = mviol;
271 dr[clust_id].sumv = tviol;
272 dr[clust_id].averv = tviol / ndr;
273 dr[clust_id].nframes++;
275 if (bFirst)
277 fprintf(stderr, "\nThere are %d restraints and %d pairs\n", ndr, disres.size() / nat);
278 bFirst = FALSE;
280 if (ntop)
282 print5(log);
286 typedef struct
288 int label;
289 gmx_bool bCore;
290 real up1, r, rT3, rT6, viol, violT3, violT6;
291 } t_dr_stats;
293 static void dump_dump(FILE* log, int ndr, t_dr_stats drs[])
295 static const char* core[] = { "All restraints", "Core restraints" };
296 static const char* tp[] = { "linear", "third power", "sixth power" };
297 real viol_tot, viol_max, viol = 0;
298 gmx_bool bCore;
299 int nviol, nrestr;
300 int i, kkk;
302 for (int iCore = 0; iCore < 2; iCore++)
304 bCore = (iCore == 1);
305 for (kkk = 0; (kkk < 3); kkk++)
307 viol_tot = 0;
308 viol_max = 0;
309 nviol = 0;
310 nrestr = 0;
311 for (i = 0; (i < ndr); i++)
313 if (!bCore || drs[i].bCore)
315 switch (kkk)
317 case 0: viol = drs[i].viol; break;
318 case 1: viol = drs[i].violT3; break;
319 case 2: viol = drs[i].violT6; break;
320 default: gmx_incons("Dumping violations");
322 viol_max = std::max(viol_max, viol);
323 if (viol > 0)
325 nviol++;
327 viol_tot += viol;
328 nrestr++;
331 if ((nrestr > 0) || (bCore && (nrestr < ndr)))
333 fprintf(log, "\n");
334 fprintf(log, "+++++++ %s ++++++++\n", core[bCore]);
335 fprintf(log, "+++++++ Using %s averaging: ++++++++\n", tp[kkk]);
336 fprintf(log, "Sum of violations: %8.3f nm\n", viol_tot);
337 if (nrestr > 0)
339 fprintf(log, "Average violation: %8.3f nm\n", viol_tot / nrestr);
341 fprintf(log, "Largest violation: %8.3f nm\n", viol_max);
342 fprintf(log, "Number of violated restraints: %d/%d\n", nviol, nrestr);
348 static void dump_viol(FILE* log, int ndr, t_dr_stats* drs, gmx_bool bLinear)
350 int i;
352 fprintf(log, "Restr. Core Up1 <r> <rT3> <rT6> <viol><violT3><violT6>\n");
353 for (i = 0; (i < ndr); i++)
355 if (bLinear && (drs[i].viol == 0))
357 break;
359 fprintf(log, "%6d%5s%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f\n", drs[i].label,
360 yesno_names[drs[i].bCore], drs[i].up1, drs[i].r, drs[i].rT3, drs[i].rT6,
361 drs[i].viol, drs[i].violT3, drs[i].violT6);
365 static gmx_bool is_core(int i, int isize, const int index[])
367 int kk;
368 gmx_bool bIC = FALSE;
370 for (kk = 0; !bIC && (kk < isize); kk++)
372 bIC = (index[kk] == i);
375 return bIC;
378 static void dump_stats(FILE* log,
379 int nsteps,
380 const t_disresdata& dd,
381 const InteractionList& disres,
382 gmx::ArrayRef<const t_iparams> ip,
383 t_dr_result* dr,
384 int isize,
385 int index[],
386 t_atoms* atoms)
388 t_dr_stats* drs;
390 fprintf(log, "\n");
391 fprintf(log, "++++++++++++++ STATISTICS ++++++++++++++++++++++++\n");
392 snew(drs, dd.nres);
393 const int nra = interaction_function[F_DISRES].nratoms + 1;
394 for (int j = 0; j < disres.size(); j += nra)
396 // Note that the restraint i can be used by multiple pairs
397 const int i = disres.iatoms[j] - dd.type_min;
398 GMX_RELEASE_ASSERT(i >= 0 && i < dd.nres, "The restraint index should be in range");
400 drs[i].label = ip[disres.iatoms[j]].disres.label;
401 drs[i].bCore = is_core(drs[i].label, isize, index);
402 drs[i].up1 = ip[disres.iatoms[j]].disres.up1;
403 drs[i].r = dr->aver1[i] / nsteps;
404 drs[i].rT3 = gmx::invcbrt(dr->aver_3[i] / nsteps);
405 drs[i].rT6 = gmx::invsixthroot(dr->aver_6[i] / nsteps);
406 drs[i].viol = std::max(0.0, static_cast<double>(drs[i].r - drs[i].up1));
407 drs[i].violT3 = std::max(0.0, static_cast<double>(drs[i].rT3 - drs[i].up1));
408 drs[i].violT6 = std::max(0.0, static_cast<double>(drs[i].rT6 - drs[i].up1));
409 if (atoms)
411 int j1 = disres.iatoms[j + 1];
412 int j2 = disres.iatoms[j + 2];
413 atoms->pdbinfo[j1].bfac += drs[i].violT3 * 5;
414 atoms->pdbinfo[j2].bfac += drs[i].violT3 * 5;
417 dump_viol(log, dd.nres, drs, FALSE);
419 fprintf(log, "+++ Sorted by linear averaged violations: +++\n");
420 std::sort(drs, drs + dd.nres,
421 [](const t_dr_stats& a, const t_dr_stats& b) { return a.viol > b.viol; }); // Reverse sort
422 dump_viol(log, dd.nres, drs, TRUE);
424 dump_dump(log, dd.nres, drs);
426 sfree(drs);
429 static void dump_clust_stats(FILE* fp,
430 const t_disresdata& dd,
431 const InteractionList& disres,
432 gmx::ArrayRef<const t_iparams> ip,
433 t_blocka* clust,
434 t_dr_result dr[],
435 char* clust_name[],
436 int isize,
437 int index[])
439 int k, nra, mmm = 0;
440 double sumV, maxV, sumVT3, sumVT6, maxVT3, maxVT6;
441 t_dr_stats* drs;
443 fprintf(fp, "\n");
444 fprintf(fp, "++++++++++++++ STATISTICS ++++++++++++++++++++++\n");
445 fprintf(fp, "Cluster NFrames SumV MaxV SumVT MaxVT SumVS MaxVS\n");
447 snew(drs, dd.nres);
449 for (k = 0; (k < clust->nr); k++)
451 if (dr[k].nframes == 0)
453 continue;
455 if (dr[k].nframes != (clust->index[k + 1] - clust->index[k]))
457 gmx_fatal(FARGS,
458 "Inconsistency in cluster %s.\n"
459 "Found %d frames in trajectory rather than the expected %d\n",
460 clust_name[k], dr[k].nframes, clust->index[k + 1] - clust->index[k]);
462 if (!clust_name[k])
464 gmx_fatal(FARGS, "Inconsistency with cluster %d. Invalid name", k);
466 nra = interaction_function[F_DISRES].nratoms + 1;
467 sumV = sumVT3 = sumVT6 = maxV = maxVT3 = maxVT6 = 0;
469 // Use a map to process each restraint only once while looping over all pairs
470 std::unordered_map<int, bool> restraintHasBeenProcessed;
471 for (int j = 0; j < dd.nres; j += nra)
473 // Note that the restraint i can be used by multiple pairs
474 const int i = disres.iatoms[j] - dd.type_min;
476 if (restraintHasBeenProcessed[i])
478 continue;
481 drs[i].label = ip[disres.iatoms[j]].disres.label;
482 drs[i].bCore = is_core(drs[i].label, isize, index);
483 drs[i].up1 = ip[disres.iatoms[j]].disres.up1;
484 drs[i].r = dr[k].aver1[i] / dr[k].nframes;
485 if ((dr[k].aver_3[i] <= 0) || !std::isfinite(dr[k].aver_3[i]))
487 gmx_fatal(FARGS, "dr[%d].aver_3[%d] = %f", k, i, dr[k].aver_3[i]);
489 drs[i].rT3 = gmx::invcbrt(dr[k].aver_3[i] / dr[k].nframes);
490 drs[i].rT6 = gmx::invsixthroot(dr[k].aver_6[i] / dr[k].nframes);
491 drs[i].viol = std::max(0.0, static_cast<double>(drs[i].r - drs[i].up1));
492 drs[i].violT3 = std::max(0.0, static_cast<double>(drs[i].rT3 - drs[i].up1));
493 drs[i].violT6 = std::max(0.0, static_cast<double>(drs[i].rT6 - drs[i].up1));
494 sumV += drs[i].viol;
495 sumVT3 += drs[i].violT3;
496 sumVT6 += drs[i].violT6;
497 maxV = std::max(maxV, static_cast<double>(drs[i].viol));
498 maxVT3 = std::max(maxVT3, static_cast<double>(drs[i].violT3));
499 maxVT6 = std::max(maxVT6, static_cast<double>(drs[i].violT6));
501 // We have processed restraint i, mark it as such
502 restraintHasBeenProcessed[i] = true;
504 if (std::strcmp(clust_name[k], "1000") == 0)
506 mmm++;
508 fprintf(fp, "%-10s%6d%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n", clust_name[k],
509 dr[k].nframes, sumV, maxV, sumVT3, maxVT3, sumVT6, maxVT6);
511 fflush(fp);
512 sfree(drs);
515 static void init_dr_res(t_dr_result* dr, int ndr)
517 snew(dr->aver1, ndr + 1);
518 snew(dr->aver2, ndr + 1);
519 snew(dr->aver_3, ndr + 1);
520 snew(dr->aver_6, ndr + 1);
521 dr->nv = 0;
522 dr->nframes = 0;
523 dr->sumv = 0;
524 dr->maxv = 0;
525 dr->averv = 0;
528 static void dump_disre_matrix(const char* fn,
529 t_dr_result* dr,
530 int ndr,
531 int nsteps,
532 const InteractionDefinitions& idef,
533 const gmx_mtop_t* mtop,
534 real max_dr,
535 int nlevels,
536 gmx_bool bThird)
538 FILE* fp;
539 int* resnr;
540 int n_res, a_offset, mol, a;
541 int i, j, nra, nratoms, tp, ri, rj, index, nlabel, label;
542 int ai, aj, *ptr;
543 real **matrix, *t_res, hi, *w_dr, rav, rviol;
544 t_rgb rlo = { 1, 1, 1 };
545 t_rgb rhi = { 0, 0, 0 };
546 if (fn == nullptr)
548 return;
551 snew(resnr, mtop->natoms);
552 n_res = 0;
553 a_offset = 0;
554 for (const gmx_molblock_t& molb : mtop->molblock)
556 const t_atoms& atoms = mtop->moltype[molb.type].atoms;
557 for (mol = 0; mol < molb.nmol; mol++)
559 for (a = 0; a < atoms.nr; a++)
561 resnr[a_offset + a] = n_res + atoms.atom[a].resind;
563 n_res += atoms.nres;
564 a_offset += atoms.nr;
568 snew(t_res, n_res);
569 for (i = 0; (i < n_res); i++)
571 t_res[i] = i + 1;
573 snew(matrix, n_res);
574 for (i = 0; (i < n_res); i++)
576 snew(matrix[i], n_res);
578 nratoms = interaction_function[F_DISRES].nratoms;
579 nra = (idef.il[F_DISRES].size() / (nratoms + 1));
580 snew(ptr, nra + 1);
581 index = 0;
582 nlabel = 0;
583 ptr[0] = 0;
584 snew(w_dr, ndr);
585 for (i = 0; (i < idef.il[F_DISRES].size()); i += nratoms + 1)
587 tp = idef.il[F_DISRES].iatoms[i];
588 label = idef.iparams[tp].disres.label;
590 if (label != index)
592 /* Set index pointer */
593 ptr[index + 1] = i;
594 if (nlabel <= 0)
596 gmx_fatal(FARGS, "nlabel is %d, label = %d", nlabel, label);
598 if (index >= ndr)
600 gmx_fatal(FARGS, "ndr = %d, index = %d", ndr, index);
602 /* Update the weight */
603 w_dr[index] = 1.0 / nlabel;
604 index = label;
605 nlabel = 1;
607 else
609 nlabel++;
612 printf("nlabel = %d, index = %d, ndr = %d\n", nlabel, index, ndr);
613 hi = 0;
614 for (i = 0; (i < ndr); i++)
616 for (j = ptr[i]; (j < ptr[i + 1]); j += nratoms + 1)
618 tp = idef.il[F_DISRES].iatoms[j];
619 ai = idef.il[F_DISRES].iatoms[j + 1];
620 aj = idef.il[F_DISRES].iatoms[j + 2];
622 ri = resnr[ai];
623 rj = resnr[aj];
624 if (bThird)
626 rav = gmx::invcbrt(dr->aver_3[i] / nsteps);
628 else
630 rav = dr->aver1[i] / nsteps;
632 if (debug)
634 fprintf(debug, "DR %d, atoms %d, %d, distance %g\n", i, ai, aj, rav);
636 rviol = std::max(0.0_real, rav - idef.iparams[tp].disres.up1);
637 matrix[ri][rj] += w_dr[i] * rviol;
638 matrix[rj][ri] += w_dr[i] * rviol;
639 hi = std::max(hi, matrix[ri][rj]);
640 hi = std::max(hi, matrix[rj][ri]);
644 sfree(resnr);
646 if (max_dr > 0)
648 if (hi > max_dr)
650 printf("Warning: the maxdr that you have specified (%g) is smaller than\nthe largest "
651 "value in your simulation (%g)\n",
652 max_dr, hi);
654 hi = max_dr;
656 printf("Highest level in the matrix will be %g\n", hi);
657 fp = gmx_ffopen(fn, "w");
658 write_xpm(fp, 0, "Distance Violations", "<V> (nm)", "Residue", "Residue", n_res, n_res, t_res,
659 t_res, matrix, 0, hi, rlo, rhi, &nlevels);
660 gmx_ffclose(fp);
663 int gmx_disre(int argc, char* argv[])
665 const char* desc[] = {
666 "[THISMODULE] computes violations of distance restraints.",
667 "The program always",
668 "computes the instantaneous violations rather than time-averaged,",
669 "because this analysis is done from a trajectory file afterwards",
670 "it does not make sense to use time averaging. However,",
671 "the time averaged values per restraint are given in the log file.[PAR]",
672 "An index file may be used to select specific restraints by index group label for",
673 "printing.[PAR]",
674 "When the optional [TT]-q[tt] flag is given a [REF].pdb[ref] file coloured by the",
675 "amount of average violations.[PAR]",
676 "When the [TT]-c[tt] option is given, an index file will be read",
677 "containing the frames in your trajectory corresponding to the clusters",
678 "(defined in another manner) that you want to analyze. For these clusters",
679 "the program will compute average violations using the third power",
680 "averaging algorithm and print them in the log file."
682 static int ntop = 0;
683 static int nlevels = 20;
684 static real max_dr = 0;
685 static gmx_bool bThird = TRUE;
686 t_pargs pa[] = {
687 { "-ntop",
688 FALSE,
689 etINT,
690 { &ntop },
691 "Number of large violations that are stored in the log file every step" },
692 { "-maxdr",
693 FALSE,
694 etREAL,
695 { &max_dr },
696 "Maximum distance violation in matrix output. If less than or equal to 0 the "
697 "maximum will be determined by the data." },
698 { "-nlevels", FALSE, etINT, { &nlevels }, "Number of levels in the matrix output" },
699 { "-third",
700 FALSE,
701 etBOOL,
702 { &bThird },
703 "Use inverse third power averaging or linear for matrix output" }
706 FILE * out = nullptr, *aver = nullptr, *numv = nullptr, *maxxv = nullptr, *xvg = nullptr;
707 int i, j, kkk;
708 t_trxstatus* status;
709 real t;
710 rvec * x, *xav = nullptr;
711 rvec4* f;
712 matrix box;
713 gmx_bool bPDB;
714 int isize;
715 int * index = nullptr, *ind_fit = nullptr;
716 char* grpname;
717 t_cluster_ndx* clust = nullptr;
718 t_dr_result dr, *dr_clust = nullptr;
719 char** leg;
720 real * vvindex = nullptr, *w_rls = nullptr;
721 t_pbc pbc, *pbc_null;
722 int my_clust;
723 FILE* fplog;
724 gmx_output_env_t* oenv;
725 gmx_rmpbc_t gpbc = nullptr;
727 t_filenm fnm[] = { { efTPR, nullptr, nullptr, ffREAD }, { efTRX, "-f", nullptr, ffREAD },
728 { efXVG, "-ds", "drsum", ffWRITE }, { efXVG, "-da", "draver", ffWRITE },
729 { efXVG, "-dn", "drnum", ffWRITE }, { efXVG, "-dm", "drmax", ffWRITE },
730 { efXVG, "-dr", "restr", ffWRITE }, { efLOG, "-l", "disres", ffWRITE },
731 { efNDX, nullptr, "viol", ffOPTRD }, { efPDB, "-q", "viol", ffOPTWR },
732 { efNDX, "-c", "clust", ffOPTRD }, { efXPM, "-x", "matrix", ffOPTWR } };
733 #define NFILE asize(fnm)
735 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
736 asize(desc), desc, 0, nullptr, &oenv))
738 return 0;
741 fplog = ftp2FILE(efLOG, NFILE, fnm, "w");
743 if (ntop)
745 init5(ntop);
748 t_inputrec irInstance;
749 t_inputrec* ir = &irInstance;
751 gmx::TopologyInformation topInfo;
752 topInfo.fillFromInputFile(ftp2fn(efTPR, NFILE, fnm));
753 int ntopatoms = topInfo.mtop()->natoms;
754 AtomsDataPtr atoms;
755 bPDB = opt2bSet("-q", NFILE, fnm);
756 if (bPDB)
758 snew(xav, ntopatoms);
759 snew(ind_fit, ntopatoms);
760 snew(w_rls, ntopatoms);
761 for (kkk = 0; (kkk < ntopatoms); kkk++)
763 w_rls[kkk] = 1;
764 ind_fit[kkk] = kkk;
767 atoms = topInfo.copyAtoms();
769 if (atoms->pdbinfo == nullptr)
771 snew(atoms->pdbinfo, atoms->nr);
773 atoms->havePdbInfo = TRUE;
776 gmx_localtop_t top(topInfo.mtop()->ffparams);
777 gmx_mtop_generate_local_top(*topInfo.mtop(), &top, ir->efep != efepNO);
778 const InteractionDefinitions& idef = top.idef;
780 pbc_null = nullptr;
781 if (ir->pbcType != PbcType::No)
783 pbc_null = &pbc;
786 if (ftp2bSet(efNDX, NFILE, fnm))
788 /* TODO: Nothing is written to this file if -c is provided, but it is
789 * still opened... */
790 rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &isize, &index, &grpname);
791 xvg = xvgropen(opt2fn("-dr", NFILE, fnm), "Individual Restraints", "Time (ps)", "nm", oenv);
792 snew(vvindex, isize);
793 snew(leg, isize);
794 for (i = 0; (i < isize); i++)
796 index[i]++;
797 snew(leg[i], 12);
798 sprintf(leg[i], "index %d", index[i]);
800 xvgr_legend(xvg, isize, leg, oenv);
802 else
804 isize = 0;
807 ir->dr_tau = 0.0;
808 t_disresdata disresdata;
809 init_disres(fplog, topInfo.mtop(), ir, DisResRunMode::AnalysisTool, DDRole::Master,
810 NumRanks::Single, MPI_COMM_NULL, nullptr, &disresdata, nullptr, FALSE);
812 int natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
813 snew(f, 5 * natoms);
815 init_dr_res(&dr, disresdata.nres);
816 if (opt2bSet("-c", NFILE, fnm))
818 clust = cluster_index(fplog, opt2fn("-c", NFILE, fnm));
819 snew(dr_clust, clust->clust->nr + 1);
820 for (i = 0; (i <= clust->clust->nr); i++)
822 init_dr_res(&dr_clust[i], disresdata.nres);
825 else
827 out = xvgropen(opt2fn("-ds", NFILE, fnm), "Sum of Violations", "Time (ps)", "nm", oenv);
828 aver = xvgropen(opt2fn("-da", NFILE, fnm), "Average Violation", "Time (ps)", "nm", oenv);
829 numv = xvgropen(opt2fn("-dn", NFILE, fnm), "# Violations", "Time (ps)", "#", oenv);
830 maxxv = xvgropen(opt2fn("-dm", NFILE, fnm), "Largest Violation", "Time (ps)", "nm", oenv);
833 auto mdAtoms = gmx::makeMDAtoms(fplog, *topInfo.mtop(), *ir, false);
834 atoms2md(topInfo.mtop(), ir, -1, {}, ntopatoms, mdAtoms.get());
835 update_mdatoms(mdAtoms->mdatoms(), ir->fepvals->init_lambda);
836 if (ir->pbcType != PbcType::No)
838 gpbc = gmx_rmpbc_init(idef, ir->pbcType, natoms);
841 j = 0;
844 if (ir->pbcType != PbcType::No)
846 if (ir->bPeriodicMols)
848 set_pbc(&pbc, ir->pbcType, box);
850 else
852 gmx_rmpbc(gpbc, natoms, box, x);
856 if (clust)
858 if (j > clust->maxframe)
860 gmx_fatal(FARGS,
861 "There are more frames in the trajectory than in the cluster index file. "
862 "t = %8f\n",
865 my_clust = clust->inv_clust[j];
866 range_check(my_clust, 0, clust->clust->nr);
867 check_viol(fplog, idef.il[F_DISRES], idef.iparams, x, f, pbc_null, dr_clust, my_clust,
868 isize, index, vvindex, &disresdata);
870 else
872 check_viol(fplog, idef.il[F_DISRES], idef.iparams, x, f, pbc_null, &dr, 0, isize, index,
873 vvindex, &disresdata);
875 if (bPDB)
877 reset_x(atoms->nr, ind_fit, atoms->nr, nullptr, x, w_rls);
878 do_fit(atoms->nr, w_rls, x, x);
879 if (j == 0)
881 /* Store the first frame of the trajectory as 'characteristic'
882 * for colouring with violations.
884 for (kkk = 0; (kkk < atoms->nr); kkk++)
886 copy_rvec(x[kkk], xav[kkk]);
890 if (!clust)
892 if (isize > 0)
894 fprintf(xvg, "%10g", t);
895 for (i = 0; (i < isize); i++)
897 fprintf(xvg, " %10g", vvindex[i]);
899 fprintf(xvg, "\n");
901 fprintf(out, "%10g %10g\n", t, dr.sumv);
902 fprintf(aver, "%10g %10g\n", t, dr.averv);
903 fprintf(maxxv, "%10g %10g\n", t, dr.maxv);
904 fprintf(numv, "%10g %10d\n", t, dr.nv);
906 j++;
907 } while (read_next_x(oenv, status, &t, x, box));
908 close_trx(status);
909 if (ir->pbcType != PbcType::No)
911 gmx_rmpbc_done(gpbc);
914 if (clust)
916 dump_clust_stats(fplog, disresdata, idef.il[F_DISRES], idef.iparams, clust->clust, dr_clust,
917 clust->grpname, isize, index);
919 else
921 dump_stats(fplog, j, disresdata, idef.il[F_DISRES], idef.iparams, &dr, isize, index,
922 bPDB ? atoms.get() : nullptr);
923 if (bPDB)
925 write_sto_conf(opt2fn("-q", NFILE, fnm), "Coloured by average violation in Angstrom",
926 atoms.get(), xav, nullptr, ir->pbcType, box);
928 dump_disre_matrix(opt2fn_null("-x", NFILE, fnm), &dr, disresdata.nres, j, idef,
929 topInfo.mtop(), max_dr, nlevels, bThird);
930 xvgrclose(out);
931 xvgrclose(aver);
932 xvgrclose(numv);
933 xvgrclose(maxxv);
934 do_view(oenv, opt2fn("-dn", NFILE, fnm), "-nxy");
935 do_view(oenv, opt2fn("-da", NFILE, fnm), "-nxy");
936 do_view(oenv, opt2fn("-ds", NFILE, fnm), "-nxy");
937 do_view(oenv, opt2fn("-dm", NFILE, fnm), "-nxy");
939 if (isize > 0)
941 xvgrclose(xvg);
942 if (!clust)
944 do_view(oenv, opt2fn("-dr", NFILE, fnm), "-nxy");
948 gmx_ffclose(fplog);
950 return 0;