Update energy and trajectory frame types
[gromacs.git] / src / gromacs / gmxana / gmx_enemat.cpp
blobc58c92e4e9fc8b6527aeb8dea0af3c787033f7a2
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,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.
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.
37 #include "gmxpre.h"
39 #include <cmath>
40 #include <cstring>
42 #include "gromacs/commandline/pargs.h"
43 #include "gromacs/fileio/enxio.h"
44 #include "gromacs/fileio/matio.h"
45 #include "gromacs/fileio/trxio.h"
46 #include "gromacs/fileio/xvgr.h"
47 #include "gromacs/gmxana/gmx_ana.h"
48 #include "gromacs/gmxana/gstat.h"
49 #include "gromacs/math/functions.h"
50 #include "gromacs/math/units.h"
51 #include "gromacs/math/vec.h"
52 #include "gromacs/mdtypes/forcerec.h"
53 #include "gromacs/mdtypes/md_enums.h"
54 #include "gromacs/trajectory/energyframe.h"
55 #include "gromacs/utility/arraysize.h"
56 #include "gromacs/utility/cstringutil.h"
57 #include "gromacs/utility/fatalerror.h"
58 #include "gromacs/utility/futil.h"
59 #include "gromacs/utility/smalloc.h"
60 #include "gromacs/utility/strdb.h"
63 static int search_str2(int nstr, char **str, char *key)
65 int i, n;
66 int keylen = std::strlen(key);
67 /* Linear search */
68 n = 0;
69 while ( (n < keylen) && ((key[n] < '0') || (key[n] > '9')) )
71 n++;
73 for (i = 0; (i < nstr); i++)
75 if (gmx_strncasecmp(str[i], key, n) == 0)
77 return i;
81 return -1;
84 int gmx_enemat(int argc, char *argv[])
86 const char *desc[] = {
87 "[THISMODULE] extracts an energy matrix from the energy file ([TT]-f[tt]).",
88 "With [TT]-groups[tt] a file must be supplied with on each",
89 "line a group of atoms to be used. For these groups matrix of",
90 "interaction energies will be extracted from the energy file",
91 "by looking for energy groups with names corresponding to pairs",
92 "of groups of atoms, e.g. if your [TT]-groups[tt] file contains::",
93 "",
94 " 2",
95 " Protein",
96 " SOL",
97 "",
98 "then energy groups with names like 'Coul-SR:Protein-SOL' and ",
99 "'LJ:Protein-SOL' are expected in the energy file (although",
100 "[THISMODULE] is most useful if many groups are analyzed",
101 "simultaneously). Matrices for different energy types are written",
102 "out separately, as controlled by the",
103 "[TT]-[no]coul[tt], [TT]-[no]coulr[tt], [TT]-[no]coul14[tt], ",
104 "[TT]-[no]lj[tt], [TT]-[no]lj14[tt], ",
105 "[TT]-[no]bham[tt] and [TT]-[no]free[tt] options.",
106 "Finally, the total interaction energy energy per group can be ",
107 "calculated ([TT]-etot[tt]).[PAR]",
109 "An approximation of the free energy can be calculated using:",
110 "[MATH]E[SUB]free[sub] = E[SUB]0[sub] + kT [LOG][CHEVRON][EXP](E-E[SUB]0[sub])/kT[exp][chevron][log][math], where '[MATH][CHEVRON][chevron][math]'",
111 "stands for time-average. A file with reference free energies",
112 "can be supplied to calculate the free energy difference",
113 "with some reference state. Group names (e.g. residue names)",
114 "in the reference file should correspond to the group names",
115 "as used in the [TT]-groups[tt] file, but a appended number",
116 "(e.g. residue number) in the [TT]-groups[tt] will be ignored",
117 "in the comparison."
119 static gmx_bool bSum = FALSE;
120 static gmx_bool bMeanEmtx = TRUE;
121 static int skip = 0, nlevels = 20;
122 static real cutmax = 1e20, cutmin = -1e20, reftemp = 300.0;
123 static gmx_bool bCoulSR = TRUE, bCoul14 = FALSE;
124 static gmx_bool bLJSR = TRUE, bLJ14 = FALSE, bBhamSR = FALSE,
125 bFree = TRUE;
126 t_pargs pa[] = {
127 { "-sum", FALSE, etBOOL, {&bSum},
128 "Sum the energy terms selected rather than display them all" },
129 { "-skip", FALSE, etINT, {&skip},
130 "Skip number of frames between data points" },
131 { "-mean", FALSE, etBOOL, {&bMeanEmtx},
132 "with [TT]-groups[tt] extracts matrix of mean energies instead of "
133 "matrix for each timestep" },
134 { "-nlevels", FALSE, etINT, {&nlevels}, "number of levels for matrix colors"},
135 { "-max", FALSE, etREAL, {&cutmax}, "max value for energies"},
136 { "-min", FALSE, etREAL, {&cutmin}, "min value for energies"},
137 { "-coulsr", FALSE, etBOOL, {&bCoulSR}, "extract Coulomb SR energies"},
138 { "-coul14", FALSE, etBOOL, {&bCoul14}, "extract Coulomb 1-4 energies"},
139 { "-ljsr", FALSE, etBOOL, {&bLJSR}, "extract Lennard-Jones SR energies"},
140 { "-lj14", FALSE, etBOOL, {&bLJ14}, "extract Lennard-Jones 1-4 energies"},
141 { "-bhamsr", FALSE, etBOOL, {&bBhamSR}, "extract Buckingham SR energies"},
142 { "-free", FALSE, etBOOL, {&bFree}, "calculate free energy"},
143 { "-temp", FALSE, etREAL, {&reftemp},
144 "reference temperature for free energy calculation"}
146 /* We will define egSP more energy-groups:
147 egTotal (total energy) */
148 #define egTotal egNR
149 #define egSP 1
150 gmx_bool egrp_use[egNR+egSP];
151 ener_file_t in;
152 FILE *out;
153 int timecheck = 0;
154 gmx_enxnm_t *enm = nullptr;
155 t_enxframe *fr;
156 int teller = 0;
157 real sum;
158 gmx_bool bCont, bRef;
159 gmx_bool bCutmax, bCutmin;
160 real **eneset, *time = nullptr;
161 int *set, i, j, k, prevk, m = 0, n, nre, nset, nenergy;
162 char **groups = nullptr;
163 char groupname[255], fn[255];
164 int ngroups;
165 t_rgb rlo, rhi, rmid;
166 real emax, emid, emin;
167 real ***emat, **etot, *groupnr;
168 double beta, expE, **e, *eaver, *efree = nullptr, edum;
169 char label[234];
170 char **ereflines, **erefres = nullptr;
171 real *eref = nullptr, *edif = nullptr;
172 int neref = 0;
173 gmx_output_env_t *oenv;
175 t_filenm fnm[] = {
176 { efEDR, "-f", nullptr, ffOPTRD },
177 { efDAT, "-groups", "groups", ffREAD },
178 { efDAT, "-eref", "eref", ffOPTRD },
179 { efXPM, "-emat", "emat", ffWRITE },
180 { efXVG, "-etot", "energy", ffWRITE }
182 #define NFILE asize(fnm)
184 if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
185 NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
187 return 0;
190 for (i = 0; (i < egNR+egSP); i++)
192 egrp_use[i] = FALSE;
194 egrp_use[egCOULSR] = bCoulSR;
195 egrp_use[egLJSR] = bLJSR;
196 egrp_use[egBHAMSR] = bBhamSR;
197 egrp_use[egCOUL14] = bCoul14;
198 egrp_use[egLJ14] = bLJ14;
199 egrp_use[egTotal] = TRUE;
201 bRef = opt2bSet("-eref", NFILE, fnm);
202 in = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
203 do_enxnms(in, &nre, &enm);
205 if (nre == 0)
207 gmx_fatal(FARGS, "No energies!\n");
210 bCutmax = opt2parg_bSet("-max", asize(pa), pa);
211 bCutmin = opt2parg_bSet("-min", asize(pa), pa);
213 nenergy = 0;
215 /* Read groupnames from input file and construct selection of
216 energy groups from it*/
218 fprintf(stderr, "Will read groupnames from inputfile\n");
219 ngroups = get_lines(opt2fn("-groups", NFILE, fnm), &groups);
220 fprintf(stderr, "Read %d groups\n", ngroups);
221 snew(set, static_cast<size_t>(gmx::square(ngroups)*egNR/2));
222 n = 0;
223 prevk = 0;
224 for (i = 0; (i < ngroups); i++)
226 fprintf(stderr, "\rgroup %d", i);
227 fflush(stderr);
228 for (j = i; (j < ngroups); j++)
230 for (m = 0; (m < egNR); m++)
232 if (egrp_use[m])
234 sprintf(groupname, "%s:%s-%s", egrp_nm[m], groups[i], groups[j]);
235 #ifdef DEBUG
236 fprintf(stderr, "\r%-15s %5d", groupname, n);
237 fflush(stderr);
238 #endif
239 for (k = prevk; (k < prevk+nre); k++)
241 if (std::strcmp(enm[k%nre].name, groupname) == 0)
243 set[n++] = k;
244 break;
247 if (k == prevk+nre)
249 fprintf(stderr, "WARNING! could not find group %s (%d,%d)"
250 "in energy file\n", groupname, i, j);
252 else
254 prevk = k;
260 fprintf(stderr, "\n");
261 nset = n;
262 snew(eneset, nset+1);
263 fprintf(stderr, "Will select half-matrix of energies with %d elements\n", n);
265 /* Start reading energy frames */
266 snew(fr, 1);
271 bCont = do_enx(in, fr);
272 if (bCont)
274 timecheck = check_times(fr->t);
277 while (bCont && (timecheck < 0));
279 if (timecheck == 0)
281 #define DONTSKIP(cnt) (skip) ? ((cnt % skip) == 0) : TRUE
283 if (bCont)
285 fprintf(stderr, "\rRead frame: %d, Time: %.3f", teller, fr->t);
286 fflush(stderr);
288 if ((nenergy % 1000) == 0)
290 srenew(time, nenergy+1000);
291 for (i = 0; (i <= nset); i++)
293 srenew(eneset[i], nenergy+1000);
296 time[nenergy] = fr->t;
297 sum = 0;
298 for (i = 0; (i < nset); i++)
300 eneset[i][nenergy] = fr->ener[set[i]].e;
301 sum += fr->ener[set[i]].e;
303 if (bSum)
305 eneset[nset][nenergy] = sum;
307 nenergy++;
309 teller++;
312 while (bCont && (timecheck == 0));
314 fprintf(stderr, "\n");
316 fprintf(stderr, "Will build energy half-matrix of %d groups, %d elements, "
317 "over %d frames\n", ngroups, nset, nenergy);
319 snew(emat, egNR+egSP);
320 for (j = 0; (j < egNR+egSP); j++)
322 if (egrp_use[m])
324 snew(emat[j], ngroups);
325 for (i = 0; (i < ngroups); i++)
327 snew(emat[j][i], ngroups);
331 snew(groupnr, ngroups);
332 for (i = 0; (i < ngroups); i++)
334 groupnr[i] = i+1;
336 rlo.r = 1.0, rlo.g = 0.0, rlo.b = 0.0;
337 rmid.r = 1.0, rmid.g = 1.0, rmid.b = 1.0;
338 rhi.r = 0.0, rhi.g = 0.0, rhi.b = 1.0;
339 if (bMeanEmtx)
341 snew(e, ngroups);
342 for (i = 0; (i < ngroups); i++)
344 snew(e[i], nenergy);
346 n = 0;
347 for (i = 0; (i < ngroups); i++)
349 for (j = i; (j < ngroups); j++)
351 for (m = 0; (m < egNR); m++)
353 if (egrp_use[m])
355 for (k = 0; (k < nenergy); k++)
357 emat[m][i][j] += eneset[n][k];
358 e[i][k] += eneset[n][k]; /* *0.5; */
359 e[j][k] += eneset[n][k]; /* *0.5; */
361 n++;
362 emat[egTotal][i][j] += emat[m][i][j];
363 emat[m][i][j] /= nenergy;
364 emat[m][j][i] = emat[m][i][j];
367 emat[egTotal][i][j] /= nenergy;
368 emat[egTotal][j][i] = emat[egTotal][i][j];
371 if (bFree)
373 if (bRef)
375 fprintf(stderr, "Will read reference energies from inputfile\n");
376 neref = get_lines(opt2fn("-eref", NFILE, fnm), &ereflines);
377 fprintf(stderr, "Read %d reference energies\n", neref);
378 snew(eref, neref);
379 snew(erefres, neref);
380 for (i = 0; (i < neref); i++)
382 snew(erefres[i], 5);
383 sscanf(ereflines[i], "%s %lf", erefres[i], &edum);
384 eref[i] = edum;
387 snew(eaver, ngroups);
388 for (i = 0; (i < ngroups); i++)
390 for (k = 0; (k < nenergy); k++)
392 eaver[i] += e[i][k];
394 eaver[i] /= nenergy;
396 beta = 1.0/(BOLTZ*reftemp);
397 snew(efree, ngroups);
398 snew(edif, ngroups);
399 for (i = 0; (i < ngroups); i++)
401 expE = 0;
402 for (k = 0; (k < nenergy); k++)
404 expE += std::exp(beta*(e[i][k]-eaver[i]));
406 efree[i] = std::log(expE/nenergy)/beta + eaver[i];
407 if (bRef)
409 n = search_str2(neref, erefres, groups[i]);
410 if (n != -1)
412 edif[i] = efree[i]-eref[n];
414 else
416 edif[i] = efree[i];
417 fprintf(stderr, "WARNING: group %s not found "
418 "in reference energies.\n", groups[i]);
421 else
423 edif[i] = 0;
428 emid = 0.0; /*(emin+emax)*0.5;*/
429 egrp_nm[egTotal] = "total";
430 for (m = 0; (m < egNR+egSP); m++)
432 if (egrp_use[m])
434 emin = 1e10;
435 emax = -1e10;
436 for (i = 0; (i < ngroups); i++)
438 for (j = i; (j < ngroups); j++)
440 if (emat[m][i][j] > emax)
442 emax = emat[m][i][j];
444 else if (emat[m][i][j] < emin)
446 emin = emat[m][i][j];
450 if (emax == emin)
452 fprintf(stderr, "Matrix of %s energy is uniform at %f "
453 "(will not produce output).\n", egrp_nm[m], emax);
455 else
457 fprintf(stderr, "Matrix of %s energy ranges from %f to %f\n",
458 egrp_nm[m], emin, emax);
459 if ((bCutmax) || (emax > cutmax))
461 emax = cutmax;
463 if ((bCutmin) || (emin < cutmin))
465 emin = cutmin;
467 if ((emax == cutmax) || (emin == cutmin))
469 fprintf(stderr, "Energy range adjusted: %f to %f\n", emin, emax);
472 sprintf(fn, "%s%s", egrp_nm[m], ftp2fn(efXPM, NFILE, fnm));
473 sprintf(label, "%s Interaction Energies", egrp_nm[m]);
474 out = gmx_ffopen(fn, "w");
475 if (emin >= emid)
477 write_xpm(out, 0, label, "Energy (kJ/mol)",
478 "Residue Index", "Residue Index",
479 ngroups, ngroups, groupnr, groupnr, emat[m],
480 emid, emax, rmid, rhi, &nlevels);
482 else if (emax <= emid)
484 write_xpm(out, 0, label, "Energy (kJ/mol)",
485 "Residue Index", "Residue Index",
486 ngroups, ngroups, groupnr, groupnr, emat[m],
487 emin, emid, rlo, rmid, &nlevels);
489 else
491 write_xpm3(out, 0, label, "Energy (kJ/mol)",
492 "Residue Index", "Residue Index",
493 ngroups, ngroups, groupnr, groupnr, emat[m],
494 emin, emid, emax, rlo, rmid, rhi, &nlevels);
496 gmx_ffclose(out);
500 snew(etot, egNR+egSP);
501 for (m = 0; (m < egNR+egSP); m++)
503 snew(etot[m], ngroups);
504 for (i = 0; (i < ngroups); i++)
506 for (j = 0; (j < ngroups); j++)
508 etot[m][i] += emat[m][i][j];
513 out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Mean Energy", "Residue", "kJ/mol",
514 oenv);
515 xvgr_legend(out, 0, nullptr, oenv);
516 j = 0;
517 if (output_env_get_print_xvgr_codes(oenv))
519 char str1[STRLEN], str2[STRLEN];
520 if (output_env_get_xvg_format(oenv) == exvgXMGR)
522 sprintf(str1, "@ legend string ");
523 sprintf(str2, " ");
525 else
527 sprintf(str1, "@ s");
528 sprintf(str2, " legend ");
531 for (m = 0; (m < egNR+egSP); m++)
533 if (egrp_use[m])
535 fprintf(out, "%s%d%s \"%s\"\n", str1, j++, str2, egrp_nm[m]);
538 if (bFree)
540 fprintf(out, "%s%d%s \"%s\"\n", str1, j++, str2, "Free");
542 if (bFree)
544 fprintf(out, "%s%d%s \"%s\"\n", str1, j++, str2, "Diff");
546 fprintf(out, "@TYPE xy\n");
547 fprintf(out, "#%3s", "grp");
549 for (m = 0; (m < egNR+egSP); m++)
551 if (egrp_use[m])
553 fprintf(out, " %9s", egrp_nm[m]);
556 if (bFree)
558 fprintf(out, " %9s", "Free");
560 if (bFree)
562 fprintf(out, " %9s", "Diff");
564 fprintf(out, "\n");
566 for (i = 0; (i < ngroups); i++)
568 fprintf(out, "%3.0f", groupnr[i]);
569 for (m = 0; (m < egNR+egSP); m++)
571 if (egrp_use[m])
573 fprintf(out, " %9.5g", etot[m][i]);
576 if (bFree)
578 fprintf(out, " %9.5g", efree[i]);
580 if (bRef)
582 fprintf(out, " %9.5g", edif[i]);
584 fprintf(out, "\n");
586 xvgrclose(out);
588 else
590 fprintf(stderr, "While typing at your keyboard, suddenly...\n"
591 "...nothing happens.\nWARNING: Not Implemented Yet\n");
593 out=ftp2FILE(efMAT,NFILE,fnm,"w");
594 n=0;
595 emin=emax=0.0;
596 for (k=0; (k<nenergy); k++) {
597 for (i=0; (i<ngroups); i++)
598 for (j=i+1; (j<ngroups); j++)
599 emat[i][j]=eneset[n][k];
600 sprintf(label,"t=%.0f ps",time[k]);
601 write_matrix(out,ngroups,1,ngroups,groupnr,emat,label,emin,emax,nlevels);
602 n++;
604 gmx_ffclose(out);
607 close_enx(in);
609 return 0;