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,2018,2019, 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.
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.
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.
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.
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.
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.
44 #include <unordered_map>
46 #include "gromacs/commandline/pargs.h"
47 #include "gromacs/commandline/viewit.h"
48 #include "gromacs/fileio/confio.h"
49 #include "gromacs/fileio/matio.h"
50 #include "gromacs/fileio/pdbio.h"
51 #include "gromacs/fileio/tpxio.h"
52 #include "gromacs/fileio/trxio.h"
53 #include "gromacs/fileio/xvgr.h"
54 #include "gromacs/gmxana/gmx_ana.h"
55 #include "gromacs/gmxana/gstat.h"
56 #include "gromacs/listed_forces/disre.h"
57 #include "gromacs/math/do_fit.h"
58 #include "gromacs/math/functions.h"
59 #include "gromacs/math/vec.h"
60 #include "gromacs/mdlib/force.h"
61 #include "gromacs/mdlib/mdatoms.h"
62 #include "gromacs/mdtypes/fcdata.h"
63 #include "gromacs/mdtypes/inputrec.h"
64 #include "gromacs/mdtypes/md_enums.h"
65 #include "gromacs/pbcutil/ishift.h"
66 #include "gromacs/pbcutil/mshift.h"
67 #include "gromacs/pbcutil/pbc.h"
68 #include "gromacs/pbcutil/rmpbc.h"
69 #include "gromacs/topology/index.h"
70 #include "gromacs/topology/mtop_util.h"
71 #include "gromacs/topology/topology.h"
72 #include "gromacs/trajectoryanalysis/topologyinformation.h"
73 #include "gromacs/utility/arraysize.h"
74 #include "gromacs/utility/fatalerror.h"
75 #include "gromacs/utility/futil.h"
76 #include "gromacs/utility/smalloc.h"
84 static t_toppop* top = nullptr;
90 real sumv, averv, maxv;
91 real *aver1, *aver2, *aver_3, *aver_6;
94 static void init5(int n)
104 for (i = 0; (i < ntop); i++)
111 static void add5(int ndr, real viol)
116 for (i = 1; (i < ntop); i++)
118 if (top[i].v < top[mini].v)
123 if (viol > top[mini].v)
130 static void print5(FILE* fp)
134 std::sort(top, top + ntop, [](const t_toppop& a, const t_toppop& b) { return a.v > b.v; }); // reverse sort
135 fprintf(fp, "Index:");
136 for (i = 0; (i < ntop); i++)
138 fprintf(fp, " %6d", top[i].n);
140 fprintf(fp, "\nViol: ");
141 for (i = 0; (i < ntop); i++)
143 fprintf(fp, " %6.3f", top[i].v);
148 static void check_viol(FILE* log,
150 t_iparams forceparams[],
163 int i, j, nat, n, type, nviol, ndr, label;
164 real rt, mviol, tviol, viol, lam, dvdl, drt;
166 static gmx_bool bFirst = TRUE;
178 forceatoms = disres->iatoms;
179 for (j = 0; (j < isize); j++)
183 nat = interaction_function[F_DISRES].nratoms + 1;
184 for (i = 0; (i < disres->nr);)
186 type = forceatoms[i];
188 label = forceparams[type].disres.label;
191 fprintf(debug, "DISRE: ndr = %d, label = %d i=%d, n =%d\n", ndr, label, i, n);
196 } while (((i + n) < disres->nr) && (forceparams[forceatoms[i + n]].disres.label == label));
198 calc_disres_R_6(nullptr, nullptr, n, &forceatoms[i], x, pbc, fcd, nullptr);
200 if (fcd->disres.Rt_6[label] <= 0)
202 gmx_fatal(FARGS, "ndr = %d, rt_6 = %f", ndr, fcd->disres.Rt_6[label]);
205 rt = gmx::invsixthroot(fcd->disres.Rt_6[label]);
206 dr[clust_id].aver1[ndr] += rt;
207 dr[clust_id].aver2[ndr] += gmx::square(rt);
208 drt = 1.0 / gmx::power3(rt);
209 dr[clust_id].aver_3[ndr] += drt;
210 dr[clust_id].aver_6[ndr] += fcd->disres.Rt_6[label];
212 snew(fshift, SHIFTS);
213 ta_disres(n, &forceatoms[i], forceparams, x, f, fshift, pbc, g, lam, &dvdl, nullptr, fcd, nullptr);
215 viol = fcd->disres.sumviol;
222 add5(forceparams[type].disres.label, viol);
229 for (j = 0; (j < isize); j++)
231 if (index[j] == forceparams[type].disres.label)
233 vvindex[j] = gmx::invsixthroot(fcd->disres.Rt_6[label]);
240 dr[clust_id].nv = nviol;
241 dr[clust_id].maxv = mviol;
242 dr[clust_id].sumv = tviol;
243 dr[clust_id].averv = tviol / ndr;
244 dr[clust_id].nframes++;
248 fprintf(stderr, "\nThere are %d restraints and %d pairs\n", ndr, disres->nr / nat);
261 real up1, r, rT3, rT6, viol, violT3, violT6;
264 static void dump_dump(FILE* log, int ndr, t_dr_stats drs[])
266 static const char* core[] = { "All restraints", "Core restraints" };
267 static const char* tp[] = { "linear", "third power", "sixth power" };
268 real viol_tot, viol_max, viol = 0;
273 for (int iCore = 0; iCore < 2; iCore++)
275 bCore = (iCore == 1);
276 for (kkk = 0; (kkk < 3); kkk++)
282 for (i = 0; (i < ndr); i++)
284 if (!bCore || drs[i].bCore)
288 case 0: viol = drs[i].viol; break;
289 case 1: viol = drs[i].violT3; break;
290 case 2: viol = drs[i].violT6; break;
291 default: gmx_incons("Dumping violations");
293 viol_max = std::max(viol_max, viol);
302 if ((nrestr > 0) || (bCore && (nrestr < ndr)))
305 fprintf(log, "+++++++ %s ++++++++\n", core[bCore]);
306 fprintf(log, "+++++++ Using %s averaging: ++++++++\n", tp[kkk]);
307 fprintf(log, "Sum of violations: %8.3f nm\n", viol_tot);
310 fprintf(log, "Average violation: %8.3f nm\n", viol_tot / nrestr);
312 fprintf(log, "Largest violation: %8.3f nm\n", viol_max);
313 fprintf(log, "Number of violated restraints: %d/%d\n", nviol, nrestr);
319 static void dump_viol(FILE* log, int ndr, t_dr_stats* drs, gmx_bool bLinear)
323 fprintf(log, "Restr. Core Up1 <r> <rT3> <rT6> <viol><violT3><violT6>\n");
324 for (i = 0; (i < ndr); i++)
326 if (bLinear && (drs[i].viol == 0))
330 fprintf(log, "%6d%5s%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f\n", drs[i].label,
331 yesno_names[drs[i].bCore], drs[i].up1, drs[i].r, drs[i].rT3, drs[i].rT6,
332 drs[i].viol, drs[i].violT3, drs[i].violT6);
336 static gmx_bool is_core(int i, int isize, const int index[])
339 gmx_bool bIC = FALSE;
341 for (kk = 0; !bIC && (kk < isize); kk++)
343 bIC = (index[kk] == i);
349 static void dump_stats(FILE* log,
351 const t_disresdata& dd,
352 const t_ilist* disres,
362 fprintf(log, "++++++++++++++ STATISTICS ++++++++++++++++++++++++\n");
364 const int nra = interaction_function[F_DISRES].nratoms + 1;
365 for (int j = 0; j < disres->nr; j += nra)
367 // Note that the restraint i can be used by multiple pairs
368 const int i = disres->iatoms[j] - dd.type_min;
369 GMX_RELEASE_ASSERT(i >= 0 && i < dd.nres, "The restraint index should be in range");
371 drs[i].label = ip[disres->iatoms[j]].disres.label;
372 drs[i].bCore = is_core(drs[i].label, isize, index);
373 drs[i].up1 = ip[disres->iatoms[j]].disres.up1;
374 drs[i].r = dr->aver1[i] / nsteps;
375 drs[i].rT3 = gmx::invcbrt(dr->aver_3[i] / nsteps);
376 drs[i].rT6 = gmx::invsixthroot(dr->aver_6[i] / nsteps);
377 drs[i].viol = std::max(0.0, static_cast<double>(drs[i].r - drs[i].up1));
378 drs[i].violT3 = std::max(0.0, static_cast<double>(drs[i].rT3 - drs[i].up1));
379 drs[i].violT6 = std::max(0.0, static_cast<double>(drs[i].rT6 - drs[i].up1));
382 int j1 = disres->iatoms[j + 1];
383 int j2 = disres->iatoms[j + 2];
384 atoms->pdbinfo[j1].bfac += drs[i].violT3 * 5;
385 atoms->pdbinfo[j2].bfac += drs[i].violT3 * 5;
388 dump_viol(log, dd.nres, drs, FALSE);
390 fprintf(log, "+++ Sorted by linear averaged violations: +++\n");
391 std::sort(drs, drs + dd.nres,
392 [](const t_dr_stats& a, const t_dr_stats& b) { return a.viol > b.viol; }); // Reverse sort
393 dump_viol(log, dd.nres, drs, TRUE);
395 dump_dump(log, dd.nres, drs);
400 static void dump_clust_stats(FILE* fp,
401 const t_disresdata& dd,
402 const t_ilist* disres,
411 double sumV, maxV, sumVT3, sumVT6, maxVT3, maxVT6;
415 fprintf(fp, "++++++++++++++ STATISTICS ++++++++++++++++++++++\n");
416 fprintf(fp, "Cluster NFrames SumV MaxV SumVT MaxVT SumVS MaxVS\n");
420 for (k = 0; (k < clust->nr); k++)
422 if (dr[k].nframes == 0)
426 if (dr[k].nframes != (clust->index[k + 1] - clust->index[k]))
429 "Inconsistency in cluster %s.\n"
430 "Found %d frames in trajectory rather than the expected %d\n",
431 clust_name[k], dr[k].nframes, clust->index[k + 1] - clust->index[k]);
435 gmx_fatal(FARGS, "Inconsistency with cluster %d. Invalid name", k);
437 nra = interaction_function[F_DISRES].nratoms + 1;
438 sumV = sumVT3 = sumVT6 = maxV = maxVT3 = maxVT6 = 0;
440 // Use a map to process each restraint only once while looping over all pairs
441 std::unordered_map<int, bool> restraintHasBeenProcessed;
442 for (int j = 0; j < dd.nres; j += nra)
444 // Note that the restraint i can be used by multiple pairs
445 const int i = disres->iatoms[j] - dd.type_min;
447 if (restraintHasBeenProcessed[i])
452 drs[i].label = ip[disres->iatoms[j]].disres.label;
453 drs[i].bCore = is_core(drs[i].label, isize, index);
454 drs[i].up1 = ip[disres->iatoms[j]].disres.up1;
455 drs[i].r = dr[k].aver1[i] / dr[k].nframes;
456 if ((dr[k].aver_3[i] <= 0) || !std::isfinite(dr[k].aver_3[i]))
458 gmx_fatal(FARGS, "dr[%d].aver_3[%d] = %f", k, i, dr[k].aver_3[i]);
460 drs[i].rT3 = gmx::invcbrt(dr[k].aver_3[i] / dr[k].nframes);
461 drs[i].rT6 = gmx::invsixthroot(dr[k].aver_6[i] / dr[k].nframes);
462 drs[i].viol = std::max(0.0, static_cast<double>(drs[i].r - drs[i].up1));
463 drs[i].violT3 = std::max(0.0, static_cast<double>(drs[i].rT3 - drs[i].up1));
464 drs[i].violT6 = std::max(0.0, static_cast<double>(drs[i].rT6 - drs[i].up1));
466 sumVT3 += drs[i].violT3;
467 sumVT6 += drs[i].violT6;
468 maxV = std::max(maxV, static_cast<double>(drs[i].viol));
469 maxVT3 = std::max(maxVT3, static_cast<double>(drs[i].violT3));
470 maxVT6 = std::max(maxVT6, static_cast<double>(drs[i].violT6));
472 // We have processed restraint i, mark it as such
473 restraintHasBeenProcessed[i] = true;
475 if (std::strcmp(clust_name[k], "1000") == 0)
479 fprintf(fp, "%-10s%6d%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n", clust_name[k],
480 dr[k].nframes, sumV, maxV, sumVT3, maxVT3, sumVT6, maxVT6);
486 static void init_dr_res(t_dr_result* dr, int ndr)
488 snew(dr->aver1, ndr + 1);
489 snew(dr->aver2, ndr + 1);
490 snew(dr->aver_3, ndr + 1);
491 snew(dr->aver_6, ndr + 1);
499 static void dump_disre_matrix(const char* fn,
504 const gmx_mtop_t* mtop,
511 int n_res, a_offset, mol, a;
512 int i, j, nra, nratoms, tp, ri, rj, index, nlabel, label;
514 real **matrix, *t_res, hi, *w_dr, rav, rviol;
515 t_rgb rlo = { 1, 1, 1 };
516 t_rgb rhi = { 0, 0, 0 };
522 snew(resnr, mtop->natoms);
525 for (const gmx_molblock_t& molb : mtop->molblock)
527 const t_atoms& atoms = mtop->moltype[molb.type].atoms;
528 for (mol = 0; mol < molb.nmol; mol++)
530 for (a = 0; a < atoms.nr; a++)
532 resnr[a_offset + a] = n_res + atoms.atom[a].resind;
535 a_offset += atoms.nr;
540 for (i = 0; (i < n_res); i++)
545 for (i = 0; (i < n_res); i++)
547 snew(matrix[i], n_res);
549 nratoms = interaction_function[F_DISRES].nratoms;
550 nra = (idef->il[F_DISRES].nr / (nratoms + 1));
556 for (i = 0; (i < idef->il[F_DISRES].nr); i += nratoms + 1)
558 tp = idef->il[F_DISRES].iatoms[i];
559 label = idef->iparams[tp].disres.label;
563 /* Set index pointer */
567 gmx_fatal(FARGS, "nlabel is %d, label = %d", nlabel, label);
571 gmx_fatal(FARGS, "ndr = %d, index = %d", ndr, index);
573 /* Update the weight */
574 w_dr[index] = 1.0 / nlabel;
583 printf("nlabel = %d, index = %d, ndr = %d\n", nlabel, index, ndr);
585 for (i = 0; (i < ndr); i++)
587 for (j = ptr[i]; (j < ptr[i + 1]); j += nratoms + 1)
589 tp = idef->il[F_DISRES].iatoms[j];
590 ai = idef->il[F_DISRES].iatoms[j + 1];
591 aj = idef->il[F_DISRES].iatoms[j + 2];
597 rav = gmx::invcbrt(dr->aver_3[i] / nsteps);
601 rav = dr->aver1[i] / nsteps;
605 fprintf(debug, "DR %d, atoms %d, %d, distance %g\n", i, ai, aj, rav);
607 rviol = std::max(0.0_real, rav - idef->iparams[tp].disres.up1);
608 matrix[ri][rj] += w_dr[i] * rviol;
609 matrix[rj][ri] += w_dr[i] * rviol;
610 hi = std::max(hi, matrix[ri][rj]);
611 hi = std::max(hi, matrix[rj][ri]);
621 printf("Warning: the maxdr that you have specified (%g) is smaller than\nthe largest "
622 "value in your simulation (%g)\n",
627 printf("Highest level in the matrix will be %g\n", hi);
628 fp = gmx_ffopen(fn, "w");
629 write_xpm(fp, 0, "Distance Violations", "<V> (nm)", "Residue", "Residue", n_res, n_res, t_res,
630 t_res, matrix, 0, hi, rlo, rhi, &nlevels);
634 int gmx_disre(int argc, char* argv[])
636 const char* desc[] = {
637 "[THISMODULE] computes violations of distance restraints.",
638 "The program always",
639 "computes the instantaneous violations rather than time-averaged,",
640 "because this analysis is done from a trajectory file afterwards",
641 "it does not make sense to use time averaging. However,",
642 "the time averaged values per restraint are given in the log file.[PAR]",
643 "An index file may be used to select specific restraints by index group label for",
645 "When the optional [TT]-q[tt] flag is given a [REF].pdb[ref] file coloured by the",
646 "amount of average violations.[PAR]",
647 "When the [TT]-c[tt] option is given, an index file will be read",
648 "containing the frames in your trajectory corresponding to the clusters",
649 "(defined in another manner) that you want to analyze. For these clusters",
650 "the program will compute average violations using the third power",
651 "averaging algorithm and print them in the log file."
654 static int nlevels = 20;
655 static real max_dr = 0;
656 static gmx_bool bThird = TRUE;
662 "Number of large violations that are stored in the log file every step" },
667 "Maximum distance violation in matrix output. If less than or equal to 0 the "
668 "maximum will be determined by the data." },
669 { "-nlevels", FALSE, etINT, { &nlevels }, "Number of levels in the matrix output" },
674 "Use inverse third power averaging or linear for matrix output" }
677 FILE *out = nullptr, *aver = nullptr, *numv = nullptr, *maxxv = nullptr, *xvg = nullptr;
684 rvec * x, *xav = nullptr;
689 int * index = nullptr, *ind_fit = nullptr;
691 t_cluster_ndx* clust = nullptr;
692 t_dr_result dr, *dr_clust = nullptr;
694 real * vvindex = nullptr, *w_rls = nullptr;
695 t_pbc pbc, *pbc_null;
698 gmx_output_env_t* oenv;
699 gmx_rmpbc_t gpbc = nullptr;
701 t_filenm fnm[] = { { efTPR, nullptr, nullptr, ffREAD }, { efTRX, "-f", nullptr, ffREAD },
702 { efXVG, "-ds", "drsum", ffWRITE }, { efXVG, "-da", "draver", ffWRITE },
703 { efXVG, "-dn", "drnum", ffWRITE }, { efXVG, "-dm", "drmax", ffWRITE },
704 { efXVG, "-dr", "restr", ffWRITE }, { efLOG, "-l", "disres", ffWRITE },
705 { efNDX, nullptr, "viol", ffOPTRD }, { efPDB, "-q", "viol", ffOPTWR },
706 { efNDX, "-c", "clust", ffOPTRD }, { efXPM, "-x", "matrix", ffOPTWR } };
707 #define NFILE asize(fnm)
709 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
710 asize(desc), desc, 0, nullptr, &oenv))
715 fplog = ftp2FILE(efLOG, NFILE, fnm, "w");
722 t_inputrec irInstance;
723 t_inputrec* ir = &irInstance;
725 gmx::TopologyInformation topInfo;
726 topInfo.fillFromInputFile(ftp2fn(efTPR, NFILE, fnm));
727 int ntopatoms = topInfo.mtop()->natoms;
729 bPDB = opt2bSet("-q", NFILE, fnm);
732 snew(xav, ntopatoms);
733 snew(ind_fit, ntopatoms);
734 snew(w_rls, ntopatoms);
735 for (kkk = 0; (kkk < ntopatoms); kkk++)
741 atoms = topInfo.copyAtoms();
743 if (atoms->pdbinfo == nullptr)
745 snew(atoms->pdbinfo, atoms->nr);
747 atoms->havePdbInfo = TRUE;
750 gmx_mtop_generate_local_top(*topInfo.mtop(), &top, ir->efep != efepNO);
754 if (ir->ePBC != epbcNONE)
756 if (ir->bPeriodicMols)
762 g = mk_graph(fplog, &top.idef, 0, ntopatoms, FALSE, FALSE);
766 if (ftp2bSet(efNDX, NFILE, fnm))
768 /* TODO: Nothing is written to this file if -c is provided, but it is
770 rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &isize, &index, &grpname);
771 xvg = xvgropen(opt2fn("-dr", NFILE, fnm), "Individual Restraints", "Time (ps)", "nm", oenv);
772 snew(vvindex, isize);
774 for (i = 0; (i < isize); i++)
778 sprintf(leg[i], "index %d", index[i]);
780 xvgr_legend(xvg, isize, leg, oenv);
788 init_disres(fplog, topInfo.mtop(), ir, nullptr, nullptr, &fcd, nullptr, FALSE);
790 int natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
793 init_dr_res(&dr, fcd.disres.nres);
794 if (opt2bSet("-c", NFILE, fnm))
796 clust = cluster_index(fplog, opt2fn("-c", NFILE, fnm));
797 snew(dr_clust, clust->clust->nr + 1);
798 for (i = 0; (i <= clust->clust->nr); i++)
800 init_dr_res(&dr_clust[i], fcd.disres.nres);
805 out = xvgropen(opt2fn("-ds", NFILE, fnm), "Sum of Violations", "Time (ps)", "nm", oenv);
806 aver = xvgropen(opt2fn("-da", NFILE, fnm), "Average Violation", "Time (ps)", "nm", oenv);
807 numv = xvgropen(opt2fn("-dn", NFILE, fnm), "# Violations", "Time (ps)", "#", oenv);
808 maxxv = xvgropen(opt2fn("-dm", NFILE, fnm), "Largest Violation", "Time (ps)", "nm", oenv);
811 auto mdAtoms = gmx::makeMDAtoms(fplog, *topInfo.mtop(), *ir, false);
812 atoms2md(topInfo.mtop(), ir, -1, nullptr, ntopatoms, mdAtoms.get());
813 update_mdatoms(mdAtoms->mdatoms(), ir->fepvals->init_lambda);
814 if (ir->ePBC != epbcNONE)
816 gpbc = gmx_rmpbc_init(&top.idef, ir->ePBC, natoms);
822 if (ir->ePBC != epbcNONE)
824 if (ir->bPeriodicMols)
826 set_pbc(&pbc, ir->ePBC, box);
830 gmx_rmpbc(gpbc, natoms, box, x);
836 if (j > clust->maxframe)
839 "There are more frames in the trajectory than in the cluster index file. "
843 my_clust = clust->inv_clust[j];
844 range_check(my_clust, 0, clust->clust->nr);
845 check_viol(fplog, &(top.idef.il[F_DISRES]), top.idef.iparams, x, f, pbc_null, g,
846 dr_clust, my_clust, isize, index, vvindex, &fcd);
850 check_viol(fplog, &(top.idef.il[F_DISRES]), top.idef.iparams, x, f, pbc_null, g, &dr, 0,
851 isize, index, vvindex, &fcd);
855 reset_x(atoms->nr, ind_fit, atoms->nr, nullptr, x, w_rls);
856 do_fit(atoms->nr, w_rls, x, x);
859 /* Store the first frame of the trajectory as 'characteristic'
860 * for colouring with violations.
862 for (kkk = 0; (kkk < atoms->nr); kkk++)
864 copy_rvec(x[kkk], xav[kkk]);
872 fprintf(xvg, "%10g", t);
873 for (i = 0; (i < isize); i++)
875 fprintf(xvg, " %10g", vvindex[i]);
879 fprintf(out, "%10g %10g\n", t, dr.sumv);
880 fprintf(aver, "%10g %10g\n", t, dr.averv);
881 fprintf(maxxv, "%10g %10g\n", t, dr.maxv);
882 fprintf(numv, "%10g %10d\n", t, dr.nv);
885 } while (read_next_x(oenv, status, &t, x, box));
887 if (ir->ePBC != epbcNONE)
889 gmx_rmpbc_done(gpbc);
894 dump_clust_stats(fplog, fcd.disres, &(top.idef.il[F_DISRES]), top.idef.iparams,
895 clust->clust, dr_clust, clust->grpname, isize, index);
899 dump_stats(fplog, j, fcd.disres, &(top.idef.il[F_DISRES]), top.idef.iparams, &dr, isize,
900 index, bPDB ? atoms.get() : nullptr);
903 write_sto_conf(opt2fn("-q", NFILE, fnm), "Coloured by average violation in Angstrom",
904 atoms.get(), xav, nullptr, ir->ePBC, box);
906 dump_disre_matrix(opt2fn_null("-x", NFILE, fnm), &dr, fcd.disres.nres, j, &top.idef,
907 topInfo.mtop(), max_dr, nlevels, bThird);
912 do_view(oenv, opt2fn("-dn", NFILE, fnm), "-nxy");
913 do_view(oenv, opt2fn("-da", NFILE, fnm), "-nxy");
914 do_view(oenv, opt2fn("-ds", NFILE, fnm), "-nxy");
915 do_view(oenv, opt2fn("-dm", NFILE, fnm), "-nxy");
922 do_view(oenv, opt2fn("-dr", NFILE, fnm), "-nxy");