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.
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/fcdata.h"
64 #include "gromacs/mdtypes/inputrec.h"
65 #include "gromacs/mdtypes/md_enums.h"
66 #include "gromacs/mdtypes/mdatom.h"
67 #include "gromacs/pbcutil/ishift.h"
68 #include "gromacs/pbcutil/pbc.h"
69 #include "gromacs/pbcutil/rmpbc.h"
70 #include "gromacs/topology/index.h"
71 #include "gromacs/topology/mtop_util.h"
72 #include "gromacs/topology/topology.h"
73 #include "gromacs/trajectoryanalysis/topologyinformation.h"
74 #include "gromacs/utility/arraysize.h"
75 #include "gromacs/utility/fatalerror.h"
76 #include "gromacs/utility/futil.h"
77 #include "gromacs/utility/smalloc.h"
85 static t_toppop* top = nullptr;
91 real sumv, averv, maxv;
92 real *aver1, *aver2, *aver_3, *aver_6;
95 static void init5(int n)
105 for (i = 0; (i < ntop); i++)
112 static void add5(int ndr, real viol)
117 for (i = 1; (i < ntop); i++)
119 if (top[i].v < top[mini].v)
124 if (viol > top[mini].v)
131 static void print5(FILE* fp)
135 std::sort(top, top + ntop, [](const t_toppop& a, const t_toppop& b) { return a.v > b.v; }); // reverse sort
136 fprintf(fp, "Index:");
137 for (i = 0; (i < ntop); i++)
139 fprintf(fp, " %6d", top[i].n);
141 fprintf(fp, "\nViol: ");
142 for (i = 0; (i < ntop); i++)
144 fprintf(fp, " %6.3f", top[i].v);
149 static void check_viol(FILE* log,
150 const InteractionList& disres,
151 gmx::ArrayRef<const t_iparams> forceparams,
162 int i, j, nat, n, type, nviol, ndr, label;
163 real rt, mviol, tviol, viol, lam, dvdl, drt;
165 static gmx_bool bFirst = TRUE;
177 gmx::ArrayRef<const int> forceatoms = disres.iatoms;
178 for (j = 0; (j < isize); j++)
182 nat = interaction_function[F_DISRES].nratoms + 1;
183 // Check internal consistency of disres.label
184 // The label for a distance restraint should be at most one larger
185 // than the previous label.
186 int label_old = forceparams[forceatoms[0]].disres.label;
187 for (i = 0; (i < disres.size()); i += nat)
189 type = forceatoms[i];
190 label = forceparams[type].disres.label;
191 if ((label == label_old) || (label == label_old + 1))
198 "Label mismatch in distance restrains. Label for restraint %d is %d, "
199 "expected it to be either %d or %d",
200 i / nat, label, label_old, label_old + 1);
203 // Get offset for label index
204 label_old = forceparams[forceatoms[0]].disres.label;
205 for (i = 0; (i < disres.size());)
207 type = forceatoms[i];
209 label = forceparams[type].disres.label - label_old;
212 fprintf(debug, "DISRE: ndr = %d, label = %d i=%d, n =%d\n", ndr, label, i, n);
217 } while (((i + n) < disres.size())
218 && (forceparams[forceatoms[i + n]].disres.label == label + label_old));
220 calc_disres_R_6(nullptr, nullptr, n, &forceatoms[i], x, pbc, fcd, nullptr);
222 if (fcd->disres.Rt_6[label] <= 0)
224 gmx_fatal(FARGS, "ndr = %d, rt_6 = %f", ndr, fcd->disres.Rt_6[label]);
227 rt = gmx::invsixthroot(fcd->disres.Rt_6[label]);
228 dr[clust_id].aver1[ndr] += rt;
229 dr[clust_id].aver2[ndr] += gmx::square(rt);
230 drt = 1.0 / gmx::power3(rt);
231 dr[clust_id].aver_3[ndr] += drt;
232 dr[clust_id].aver_6[ndr] += fcd->disres.Rt_6[label];
234 snew(fshift, SHIFTS);
235 ta_disres(n, &forceatoms[i], forceparams.data(), x, f, fshift, pbc, lam, &dvdl, nullptr,
238 viol = fcd->disres.sumviol;
245 add5(forceparams[type].disres.label, viol);
252 for (j = 0; (j < isize); j++)
254 if (index[j] == forceparams[type].disres.label)
256 vvindex[j] = gmx::invsixthroot(fcd->disres.Rt_6[label]);
263 dr[clust_id].nv = nviol;
264 dr[clust_id].maxv = mviol;
265 dr[clust_id].sumv = tviol;
266 dr[clust_id].averv = tviol / ndr;
267 dr[clust_id].nframes++;
271 fprintf(stderr, "\nThere are %d restraints and %d pairs\n", ndr, disres.size() / nat);
284 real up1, r, rT3, rT6, viol, violT3, violT6;
287 static void dump_dump(FILE* log, int ndr, t_dr_stats drs[])
289 static const char* core[] = { "All restraints", "Core restraints" };
290 static const char* tp[] = { "linear", "third power", "sixth power" };
291 real viol_tot, viol_max, viol = 0;
296 for (int iCore = 0; iCore < 2; iCore++)
298 bCore = (iCore == 1);
299 for (kkk = 0; (kkk < 3); kkk++)
305 for (i = 0; (i < ndr); i++)
307 if (!bCore || drs[i].bCore)
311 case 0: viol = drs[i].viol; break;
312 case 1: viol = drs[i].violT3; break;
313 case 2: viol = drs[i].violT6; break;
314 default: gmx_incons("Dumping violations");
316 viol_max = std::max(viol_max, viol);
325 if ((nrestr > 0) || (bCore && (nrestr < ndr)))
328 fprintf(log, "+++++++ %s ++++++++\n", core[bCore]);
329 fprintf(log, "+++++++ Using %s averaging: ++++++++\n", tp[kkk]);
330 fprintf(log, "Sum of violations: %8.3f nm\n", viol_tot);
333 fprintf(log, "Average violation: %8.3f nm\n", viol_tot / nrestr);
335 fprintf(log, "Largest violation: %8.3f nm\n", viol_max);
336 fprintf(log, "Number of violated restraints: %d/%d\n", nviol, nrestr);
342 static void dump_viol(FILE* log, int ndr, t_dr_stats* drs, gmx_bool bLinear)
346 fprintf(log, "Restr. Core Up1 <r> <rT3> <rT6> <viol><violT3><violT6>\n");
347 for (i = 0; (i < ndr); i++)
349 if (bLinear && (drs[i].viol == 0))
353 fprintf(log, "%6d%5s%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f\n", drs[i].label,
354 yesno_names[drs[i].bCore], drs[i].up1, drs[i].r, drs[i].rT3, drs[i].rT6,
355 drs[i].viol, drs[i].violT3, drs[i].violT6);
359 static gmx_bool is_core(int i, int isize, const int index[])
362 gmx_bool bIC = FALSE;
364 for (kk = 0; !bIC && (kk < isize); kk++)
366 bIC = (index[kk] == i);
372 static void dump_stats(FILE* log,
374 const t_disresdata& dd,
375 const InteractionList& disres,
376 gmx::ArrayRef<const t_iparams> ip,
385 fprintf(log, "++++++++++++++ STATISTICS ++++++++++++++++++++++++\n");
387 const int nra = interaction_function[F_DISRES].nratoms + 1;
388 for (int j = 0; j < disres.size(); j += nra)
390 // Note that the restraint i can be used by multiple pairs
391 const int i = disres.iatoms[j] - dd.type_min;
392 GMX_RELEASE_ASSERT(i >= 0 && i < dd.nres, "The restraint index should be in range");
394 drs[i].label = ip[disres.iatoms[j]].disres.label;
395 drs[i].bCore = is_core(drs[i].label, isize, index);
396 drs[i].up1 = ip[disres.iatoms[j]].disres.up1;
397 drs[i].r = dr->aver1[i] / nsteps;
398 drs[i].rT3 = gmx::invcbrt(dr->aver_3[i] / nsteps);
399 drs[i].rT6 = gmx::invsixthroot(dr->aver_6[i] / nsteps);
400 drs[i].viol = std::max(0.0, static_cast<double>(drs[i].r - drs[i].up1));
401 drs[i].violT3 = std::max(0.0, static_cast<double>(drs[i].rT3 - drs[i].up1));
402 drs[i].violT6 = std::max(0.0, static_cast<double>(drs[i].rT6 - drs[i].up1));
405 int j1 = disres.iatoms[j + 1];
406 int j2 = disres.iatoms[j + 2];
407 atoms->pdbinfo[j1].bfac += drs[i].violT3 * 5;
408 atoms->pdbinfo[j2].bfac += drs[i].violT3 * 5;
411 dump_viol(log, dd.nres, drs, FALSE);
413 fprintf(log, "+++ Sorted by linear averaged violations: +++\n");
414 std::sort(drs, drs + dd.nres,
415 [](const t_dr_stats& a, const t_dr_stats& b) { return a.viol > b.viol; }); // Reverse sort
416 dump_viol(log, dd.nres, drs, TRUE);
418 dump_dump(log, dd.nres, drs);
423 static void dump_clust_stats(FILE* fp,
424 const t_disresdata& dd,
425 const InteractionList& disres,
426 gmx::ArrayRef<const t_iparams> ip,
434 double sumV, maxV, sumVT3, sumVT6, maxVT3, maxVT6;
438 fprintf(fp, "++++++++++++++ STATISTICS ++++++++++++++++++++++\n");
439 fprintf(fp, "Cluster NFrames SumV MaxV SumVT MaxVT SumVS MaxVS\n");
443 for (k = 0; (k < clust->nr); k++)
445 if (dr[k].nframes == 0)
449 if (dr[k].nframes != (clust->index[k + 1] - clust->index[k]))
452 "Inconsistency in cluster %s.\n"
453 "Found %d frames in trajectory rather than the expected %d\n",
454 clust_name[k], dr[k].nframes, clust->index[k + 1] - clust->index[k]);
458 gmx_fatal(FARGS, "Inconsistency with cluster %d. Invalid name", k);
460 nra = interaction_function[F_DISRES].nratoms + 1;
461 sumV = sumVT3 = sumVT6 = maxV = maxVT3 = maxVT6 = 0;
463 // Use a map to process each restraint only once while looping over all pairs
464 std::unordered_map<int, bool> restraintHasBeenProcessed;
465 for (int j = 0; j < dd.nres; j += nra)
467 // Note that the restraint i can be used by multiple pairs
468 const int i = disres.iatoms[j] - dd.type_min;
470 if (restraintHasBeenProcessed[i])
475 drs[i].label = ip[disres.iatoms[j]].disres.label;
476 drs[i].bCore = is_core(drs[i].label, isize, index);
477 drs[i].up1 = ip[disres.iatoms[j]].disres.up1;
478 drs[i].r = dr[k].aver1[i] / dr[k].nframes;
479 if ((dr[k].aver_3[i] <= 0) || !std::isfinite(dr[k].aver_3[i]))
481 gmx_fatal(FARGS, "dr[%d].aver_3[%d] = %f", k, i, dr[k].aver_3[i]);
483 drs[i].rT3 = gmx::invcbrt(dr[k].aver_3[i] / dr[k].nframes);
484 drs[i].rT6 = gmx::invsixthroot(dr[k].aver_6[i] / dr[k].nframes);
485 drs[i].viol = std::max(0.0, static_cast<double>(drs[i].r - drs[i].up1));
486 drs[i].violT3 = std::max(0.0, static_cast<double>(drs[i].rT3 - drs[i].up1));
487 drs[i].violT6 = std::max(0.0, static_cast<double>(drs[i].rT6 - drs[i].up1));
489 sumVT3 += drs[i].violT3;
490 sumVT6 += drs[i].violT6;
491 maxV = std::max(maxV, static_cast<double>(drs[i].viol));
492 maxVT3 = std::max(maxVT3, static_cast<double>(drs[i].violT3));
493 maxVT6 = std::max(maxVT6, static_cast<double>(drs[i].violT6));
495 // We have processed restraint i, mark it as such
496 restraintHasBeenProcessed[i] = true;
498 if (std::strcmp(clust_name[k], "1000") == 0)
502 fprintf(fp, "%-10s%6d%8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n", clust_name[k],
503 dr[k].nframes, sumV, maxV, sumVT3, maxVT3, sumVT6, maxVT6);
509 static void init_dr_res(t_dr_result* dr, int ndr)
511 snew(dr->aver1, ndr + 1);
512 snew(dr->aver2, ndr + 1);
513 snew(dr->aver_3, ndr + 1);
514 snew(dr->aver_6, ndr + 1);
522 static void dump_disre_matrix(const char* fn,
526 const InteractionDefinitions& idef,
527 const gmx_mtop_t* mtop,
534 int n_res, a_offset, mol, a;
535 int i, j, nra, nratoms, tp, ri, rj, index, nlabel, label;
537 real **matrix, *t_res, hi, *w_dr, rav, rviol;
538 t_rgb rlo = { 1, 1, 1 };
539 t_rgb rhi = { 0, 0, 0 };
545 snew(resnr, mtop->natoms);
548 for (const gmx_molblock_t& molb : mtop->molblock)
550 const t_atoms& atoms = mtop->moltype[molb.type].atoms;
551 for (mol = 0; mol < molb.nmol; mol++)
553 for (a = 0; a < atoms.nr; a++)
555 resnr[a_offset + a] = n_res + atoms.atom[a].resind;
558 a_offset += atoms.nr;
563 for (i = 0; (i < n_res); i++)
568 for (i = 0; (i < n_res); i++)
570 snew(matrix[i], n_res);
572 nratoms = interaction_function[F_DISRES].nratoms;
573 nra = (idef.il[F_DISRES].size() / (nratoms + 1));
579 for (i = 0; (i < idef.il[F_DISRES].size()); i += nratoms + 1)
581 tp = idef.il[F_DISRES].iatoms[i];
582 label = idef.iparams[tp].disres.label;
586 /* Set index pointer */
590 gmx_fatal(FARGS, "nlabel is %d, label = %d", nlabel, label);
594 gmx_fatal(FARGS, "ndr = %d, index = %d", ndr, index);
596 /* Update the weight */
597 w_dr[index] = 1.0 / nlabel;
606 printf("nlabel = %d, index = %d, ndr = %d\n", nlabel, index, ndr);
608 for (i = 0; (i < ndr); i++)
610 for (j = ptr[i]; (j < ptr[i + 1]); j += nratoms + 1)
612 tp = idef.il[F_DISRES].iatoms[j];
613 ai = idef.il[F_DISRES].iatoms[j + 1];
614 aj = idef.il[F_DISRES].iatoms[j + 2];
620 rav = gmx::invcbrt(dr->aver_3[i] / nsteps);
624 rav = dr->aver1[i] / nsteps;
628 fprintf(debug, "DR %d, atoms %d, %d, distance %g\n", i, ai, aj, rav);
630 rviol = std::max(0.0_real, rav - idef.iparams[tp].disres.up1);
631 matrix[ri][rj] += w_dr[i] * rviol;
632 matrix[rj][ri] += w_dr[i] * rviol;
633 hi = std::max(hi, matrix[ri][rj]);
634 hi = std::max(hi, matrix[rj][ri]);
644 printf("Warning: the maxdr that you have specified (%g) is smaller than\nthe largest "
645 "value in your simulation (%g)\n",
650 printf("Highest level in the matrix will be %g\n", hi);
651 fp = gmx_ffopen(fn, "w");
652 write_xpm(fp, 0, "Distance Violations", "<V> (nm)", "Residue", "Residue", n_res, n_res, t_res,
653 t_res, matrix, 0, hi, rlo, rhi, &nlevels);
657 int gmx_disre(int argc, char* argv[])
659 const char* desc[] = {
660 "[THISMODULE] computes violations of distance restraints.",
661 "The program always",
662 "computes the instantaneous violations rather than time-averaged,",
663 "because this analysis is done from a trajectory file afterwards",
664 "it does not make sense to use time averaging. However,",
665 "the time averaged values per restraint are given in the log file.[PAR]",
666 "An index file may be used to select specific restraints by index group label for",
668 "When the optional [TT]-q[tt] flag is given a [REF].pdb[ref] file coloured by the",
669 "amount of average violations.[PAR]",
670 "When the [TT]-c[tt] option is given, an index file will be read",
671 "containing the frames in your trajectory corresponding to the clusters",
672 "(defined in another manner) that you want to analyze. For these clusters",
673 "the program will compute average violations using the third power",
674 "averaging algorithm and print them in the log file."
677 static int nlevels = 20;
678 static real max_dr = 0;
679 static gmx_bool bThird = TRUE;
685 "Number of large violations that are stored in the log file every step" },
690 "Maximum distance violation in matrix output. If less than or equal to 0 the "
691 "maximum will be determined by the data." },
692 { "-nlevels", FALSE, etINT, { &nlevels }, "Number of levels in the matrix output" },
697 "Use inverse third power averaging or linear for matrix output" }
700 FILE * out = nullptr, *aver = nullptr, *numv = nullptr, *maxxv = nullptr, *xvg = nullptr;
705 rvec * x, *xav = nullptr;
710 int * index = nullptr, *ind_fit = nullptr;
712 t_cluster_ndx* clust = nullptr;
713 t_dr_result dr, *dr_clust = nullptr;
715 real * vvindex = nullptr, *w_rls = nullptr;
716 t_pbc pbc, *pbc_null;
719 gmx_output_env_t* oenv;
720 gmx_rmpbc_t gpbc = nullptr;
722 t_filenm fnm[] = { { efTPR, nullptr, nullptr, ffREAD }, { efTRX, "-f", nullptr, ffREAD },
723 { efXVG, "-ds", "drsum", ffWRITE }, { efXVG, "-da", "draver", ffWRITE },
724 { efXVG, "-dn", "drnum", ffWRITE }, { efXVG, "-dm", "drmax", ffWRITE },
725 { efXVG, "-dr", "restr", ffWRITE }, { efLOG, "-l", "disres", ffWRITE },
726 { efNDX, nullptr, "viol", ffOPTRD }, { efPDB, "-q", "viol", ffOPTWR },
727 { efNDX, "-c", "clust", ffOPTRD }, { efXPM, "-x", "matrix", ffOPTWR } };
728 #define NFILE asize(fnm)
730 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
731 asize(desc), desc, 0, nullptr, &oenv))
736 fplog = ftp2FILE(efLOG, NFILE, fnm, "w");
743 t_inputrec irInstance;
744 t_inputrec* ir = &irInstance;
746 gmx::TopologyInformation topInfo;
747 topInfo.fillFromInputFile(ftp2fn(efTPR, NFILE, fnm));
748 int ntopatoms = topInfo.mtop()->natoms;
750 bPDB = opt2bSet("-q", NFILE, fnm);
753 snew(xav, ntopatoms);
754 snew(ind_fit, ntopatoms);
755 snew(w_rls, ntopatoms);
756 for (kkk = 0; (kkk < ntopatoms); kkk++)
762 atoms = topInfo.copyAtoms();
764 if (atoms->pdbinfo == nullptr)
766 snew(atoms->pdbinfo, atoms->nr);
768 atoms->havePdbInfo = TRUE;
771 gmx_localtop_t top(topInfo.mtop()->ffparams);
772 gmx_mtop_generate_local_top(*topInfo.mtop(), &top, ir->efep != efepNO);
775 if (ir->pbcType != PbcType::No)
780 if (ftp2bSet(efNDX, NFILE, fnm))
782 /* TODO: Nothing is written to this file if -c is provided, but it is
784 rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &isize, &index, &grpname);
785 xvg = xvgropen(opt2fn("-dr", NFILE, fnm), "Individual Restraints", "Time (ps)", "nm", oenv);
786 snew(vvindex, isize);
788 for (i = 0; (i < isize); i++)
792 sprintf(leg[i], "index %d", index[i]);
794 xvgr_legend(xvg, isize, leg, oenv);
802 init_disres(fplog, topInfo.mtop(), ir, nullptr, nullptr, &fcd, nullptr, FALSE);
804 int natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
807 init_dr_res(&dr, fcd.disres.nres);
808 if (opt2bSet("-c", NFILE, fnm))
810 clust = cluster_index(fplog, opt2fn("-c", NFILE, fnm));
811 snew(dr_clust, clust->clust->nr + 1);
812 for (i = 0; (i <= clust->clust->nr); i++)
814 init_dr_res(&dr_clust[i], fcd.disres.nres);
819 out = xvgropen(opt2fn("-ds", NFILE, fnm), "Sum of Violations", "Time (ps)", "nm", oenv);
820 aver = xvgropen(opt2fn("-da", NFILE, fnm), "Average Violation", "Time (ps)", "nm", oenv);
821 numv = xvgropen(opt2fn("-dn", NFILE, fnm), "# Violations", "Time (ps)", "#", oenv);
822 maxxv = xvgropen(opt2fn("-dm", NFILE, fnm), "Largest Violation", "Time (ps)", "nm", oenv);
825 auto mdAtoms = gmx::makeMDAtoms(fplog, *topInfo.mtop(), *ir, false);
826 atoms2md(topInfo.mtop(), ir, -1, nullptr, ntopatoms, mdAtoms.get());
827 update_mdatoms(mdAtoms->mdatoms(), ir->fepvals->init_lambda);
828 if (ir->pbcType != PbcType::No)
830 gpbc = gmx_rmpbc_init(top.idef, ir->pbcType, natoms);
836 if (ir->pbcType != PbcType::No)
838 if (ir->bPeriodicMols)
840 set_pbc(&pbc, ir->pbcType, box);
844 gmx_rmpbc(gpbc, natoms, box, x);
850 if (j > clust->maxframe)
853 "There are more frames in the trajectory than in the cluster index file. "
857 my_clust = clust->inv_clust[j];
858 range_check(my_clust, 0, clust->clust->nr);
859 check_viol(fplog, top.idef.il[F_DISRES], top.idef.iparams, x, f, pbc_null, dr_clust,
860 my_clust, isize, index, vvindex, &fcd);
864 check_viol(fplog, top.idef.il[F_DISRES], top.idef.iparams, x, f, pbc_null, &dr, 0,
865 isize, index, vvindex, &fcd);
869 reset_x(atoms->nr, ind_fit, atoms->nr, nullptr, x, w_rls);
870 do_fit(atoms->nr, w_rls, x, x);
873 /* Store the first frame of the trajectory as 'characteristic'
874 * for colouring with violations.
876 for (kkk = 0; (kkk < atoms->nr); kkk++)
878 copy_rvec(x[kkk], xav[kkk]);
886 fprintf(xvg, "%10g", t);
887 for (i = 0; (i < isize); i++)
889 fprintf(xvg, " %10g", vvindex[i]);
893 fprintf(out, "%10g %10g\n", t, dr.sumv);
894 fprintf(aver, "%10g %10g\n", t, dr.averv);
895 fprintf(maxxv, "%10g %10g\n", t, dr.maxv);
896 fprintf(numv, "%10g %10d\n", t, dr.nv);
899 } while (read_next_x(oenv, status, &t, x, box));
901 if (ir->pbcType != PbcType::No)
903 gmx_rmpbc_done(gpbc);
908 dump_clust_stats(fplog, fcd.disres, top.idef.il[F_DISRES], top.idef.iparams, clust->clust,
909 dr_clust, clust->grpname, isize, index);
913 dump_stats(fplog, j, fcd.disres, top.idef.il[F_DISRES], top.idef.iparams, &dr, isize, index,
914 bPDB ? atoms.get() : nullptr);
917 write_sto_conf(opt2fn("-q", NFILE, fnm), "Coloured by average violation in Angstrom",
918 atoms.get(), xav, nullptr, ir->pbcType, box);
920 dump_disre_matrix(opt2fn_null("-x", NFILE, fnm), &dr, fcd.disres.nres, j, top.idef,
921 topInfo.mtop(), max_dr, nlevels, bThird);
926 do_view(oenv, opt2fn("-dn", NFILE, fnm), "-nxy");
927 do_view(oenv, opt2fn("-da", NFILE, fnm), "-nxy");
928 do_view(oenv, opt2fn("-ds", NFILE, fnm), "-nxy");
929 do_view(oenv, opt2fn("-dm", NFILE, fnm), "-nxy");
936 do_view(oenv, opt2fn("-dr", NFILE, fnm), "-nxy");