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.
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
)
66 int keylen
= std::strlen(key
);
69 while ( (n
< keylen
) && ((key
[n
] < '0') || (key
[n
] > '9')) )
73 for (i
= 0; (i
< nstr
); i
++)
75 if (gmx_strncasecmp(str
[i
], key
, n
) == 0)
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::",
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",
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
,
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) */
150 gmx_bool egrp_use
[egNR
+egSP
];
154 gmx_enxnm_t
*enm
= nullptr;
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];
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
;
170 char **ereflines
, **erefres
= nullptr;
171 real
*eref
= nullptr, *edif
= nullptr;
173 gmx_output_env_t
*oenv
;
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
))
190 for (i
= 0; (i
< egNR
+egSP
); i
++)
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
);
207 gmx_fatal(FARGS
, "No energies!\n");
210 bCutmax
= opt2parg_bSet("-max", asize(pa
), pa
);
211 bCutmin
= opt2parg_bSet("-min", asize(pa
), pa
);
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));
224 for (i
= 0; (i
< ngroups
); i
++)
226 fprintf(stderr
, "\rgroup %d", i
);
228 for (j
= i
; (j
< ngroups
); j
++)
230 for (m
= 0; (m
< egNR
); m
++)
234 sprintf(groupname
, "%s:%s-%s", egrp_nm
[m
], groups
[i
], groups
[j
]);
236 fprintf(stderr
, "\r%-15s %5d", groupname
, n
);
239 for (k
= prevk
; (k
< prevk
+nre
); k
++)
241 if (std::strcmp(enm
[k
%nre
].name
, groupname
) == 0)
249 fprintf(stderr
, "WARNING! could not find group %s (%d,%d)"
250 "in energy file\n", groupname
, i
, j
);
260 fprintf(stderr
, "\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 */
271 bCont
= do_enx(in
, fr
);
274 timecheck
= check_times(fr
->t
);
277 while (bCont
&& (timecheck
< 0));
281 #define DONTSKIP(cnt) (skip) ? ((cnt % skip) == 0) : TRUE
285 fprintf(stderr
, "\rRead frame: %d, Time: %.3f", teller
, fr
->t
);
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
;
298 for (i
= 0; (i
< nset
); i
++)
300 eneset
[i
][nenergy
] = fr
->ener
[set
[i
]].e
;
301 sum
+= fr
->ener
[set
[i
]].e
;
305 eneset
[nset
][nenergy
] = sum
;
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
++)
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
++)
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;
342 for (i
= 0; (i
< ngroups
); i
++)
347 for (i
= 0; (i
< ngroups
); i
++)
349 for (j
= i
; (j
< ngroups
); j
++)
351 for (m
= 0; (m
< egNR
); 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; */
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
];
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
);
379 snew(erefres
, neref
);
380 for (i
= 0; (i
< neref
); i
++)
383 sscanf(ereflines
[i
], "%s %lf", erefres
[i
], &edum
);
387 snew(eaver
, ngroups
);
388 for (i
= 0; (i
< ngroups
); i
++)
390 for (k
= 0; (k
< nenergy
); k
++)
396 beta
= 1.0/(BOLTZ
*reftemp
);
397 snew(efree
, ngroups
);
399 for (i
= 0; (i
< ngroups
); i
++)
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
];
409 n
= search_str2(neref
, erefres
, groups
[i
]);
412 edif
[i
] = efree
[i
]-eref
[n
];
417 fprintf(stderr
, "WARNING: group %s not found "
418 "in reference energies.\n", groups
[i
]);
428 emid
= 0.0; /*(emin+emax)*0.5;*/
429 egrp_nm
[egTotal
] = "total";
430 for (m
= 0; (m
< egNR
+egSP
); m
++)
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
];
452 fprintf(stderr
, "Matrix of %s energy is uniform at %f "
453 "(will not produce output).\n", egrp_nm
[m
], emax
);
457 fprintf(stderr
, "Matrix of %s energy ranges from %f to %f\n",
458 egrp_nm
[m
], emin
, emax
);
459 if ((bCutmax
) || (emax
> cutmax
))
463 if ((bCutmin
) || (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");
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
);
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
);
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",
515 xvgr_legend(out
, 0, nullptr, oenv
);
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 ");
527 sprintf(str1
, "@ s");
528 sprintf(str2
, " legend ");
531 for (m
= 0; (m
< egNR
+egSP
); m
++)
535 fprintf(out
, "%s%d%s \"%s\"\n", str1
, j
++, str2
, egrp_nm
[m
]);
540 fprintf(out
, "%s%d%s \"%s\"\n", str1
, j
++, str2
, "Free");
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
++)
553 fprintf(out
, " %9s", egrp_nm
[m
]);
558 fprintf(out
, " %9s", "Free");
562 fprintf(out
, " %9s", "Diff");
566 for (i
= 0; (i
< ngroups
); i
++)
568 fprintf(out
, "%3.0f", groupnr
[i
]);
569 for (m
= 0; (m
< egNR
+egSP
); m
++)
573 fprintf(out
, " %9.5g", etot
[m
][i
]);
578 fprintf(out
, " %9.5g", efree
[i
]);
582 fprintf(out
, " %9.5g", edif
[i
]);
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");
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);