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,2017,2018 by the GROMACS development team.
7 * Copyright (c) 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.
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/fileio/confio.h"
45 #include "gromacs/fileio/trxio.h"
46 #include "gromacs/fileio/xvgr.h"
47 #include "gromacs/gmxana/gmx_ana.h"
48 #include "gromacs/math/functions.h"
49 #include "gromacs/math/units.h"
50 #include "gromacs/math/vec.h"
51 #include "gromacs/pbcutil/rmpbc.h"
52 #include "gromacs/topology/index.h"
53 #include "gromacs/topology/topology.h"
54 #include "gromacs/trajectory/trajectoryframe.h"
55 #include "gromacs/utility/arraysize.h"
56 #include "gromacs/utility/fatalerror.h"
57 #include "gromacs/utility/futil.h"
58 #include "gromacs/utility/smalloc.h"
72 static void rotate_ends(t_bundle
* bun
, rvec axis
, int c0
, int c1
)
78 for (end
= 0; end
< bun
->nend
; end
++)
80 for (i
= 0; i
< bun
->n
; i
++)
82 copy_rvec(bun
->end
[end
][i
], tmp
);
83 bun
->end
[end
][i
][c0
] = ax
[c1
] * tmp
[c0
] - ax
[c0
] * tmp
[c1
];
84 bun
->end
[end
][i
][c1
] = ax
[c0
] * tmp
[c0
] + ax
[c1
] * tmp
[c1
];
88 axis
[c0
] = ax
[c1
] * tmp
[c0
] - ax
[c0
] * tmp
[c1
];
89 axis
[c1
] = ax
[c0
] * tmp
[c0
] + ax
[c1
] * tmp
[c1
];
92 static void calc_axes(rvec x
[], t_atom atom
[], const int gnx
[], int* index
[], gmx_bool bRot
, t_bundle
* bun
)
96 rvec axis
[MAX_ENDS
], cent
;
103 for (end
= 0; end
< bun
->nend
; end
++)
105 for (i
= 0; i
< bun
->n
; i
++)
107 clear_rvec(bun
->end
[end
][i
]);
110 div
= gnx
[end
] / bun
->n
;
111 for (i
= 0; i
< gnx
[end
]; i
++)
113 m
= atom
[index
[end
][i
]].m
;
114 for (d
= 0; d
< DIM
; d
++)
116 bun
->end
[end
][i
/ div
][d
] += m
* x
[index
[end
][i
]][d
];
120 clear_rvec(axis
[end
]);
121 for (i
= 0; i
< bun
->n
; i
++)
123 svmul(1.0 / mtot
[i
], bun
->end
[end
][i
], bun
->end
[end
][i
]);
124 rvec_inc(axis
[end
], bun
->end
[end
][i
]);
126 svmul(1.0 / bun
->n
, axis
[end
], axis
[end
]);
130 rvec_add(axis
[0], axis
[1], cent
);
131 svmul(0.5, cent
, cent
);
132 /* center the bundle on the origin */
133 for (end
= 0; end
< bun
->nend
; end
++)
135 rvec_dec(axis
[end
], cent
);
136 for (i
= 0; i
< bun
->n
; i
++)
138 rvec_dec(bun
->end
[end
][i
], cent
);
143 /* rotate the axis parallel to the z-axis */
144 rotate_ends(bun
, axis
[0], YY
, ZZ
);
145 rotate_ends(bun
, axis
[0], XX
, ZZ
);
147 for (i
= 0; i
< bun
->n
; i
++)
149 rvec_add(bun
->end
[0][i
], bun
->end
[1][i
], bun
->mid
[i
]);
150 svmul(0.5, bun
->mid
[i
], bun
->mid
[i
]);
151 rvec_sub(bun
->end
[0][i
], bun
->end
[1][i
], bun
->dir
[i
]);
152 bun
->len
[i
] = norm(bun
->dir
[i
]);
153 unitv(bun
->dir
[i
], bun
->dir
[i
]);
157 static void dump_axes(t_trxstatus
* status
, t_trxframe
* fr
, t_atoms
* outat
, t_bundle
* bun
)
160 static rvec
* xout
= nullptr;
163 GMX_ASSERT(outat
->nr
>= bun
->n
, "");
166 snew(xout
, outat
->nr
);
169 for (i
= 0; i
< bun
->n
; i
++)
171 copy_rvec(bun
->end
[0][i
], xout
[3 * i
]);
174 copy_rvec(bun
->end
[2][i
], xout
[3 * i
+ 1]);
178 copy_rvec(bun
->mid
[i
], xout
[3 * i
+ 1]);
180 copy_rvec(bun
->end
[1][i
], xout
[3 * i
+ 2]);
187 frout
.natoms
= outat
->nr
;
190 write_trxframe(status
, &frout
, nullptr);
193 int gmx_bundle(int argc
, char* argv
[])
195 const char* desc
[] = {
196 "[THISMODULE] analyzes bundles of axes. The axes can be for instance",
197 "helix axes. The program reads two index groups and divides both",
198 "of them in [TT]-na[tt] parts. The centers of mass of these parts",
199 "define the tops and bottoms of the axes.",
200 "Several quantities are written to file:",
201 "the axis length, the distance and the z-shift of the axis mid-points",
202 "with respect to the average center of all axes, the total tilt,",
203 "the radial tilt and the lateral tilt with respect to the average axis.",
205 "With options [TT]-ok[tt], [TT]-okr[tt] and [TT]-okl[tt] the total,",
206 "radial and lateral kinks of the axes are plotted. An extra index",
207 "group of kink atoms is required, which is also divided into [TT]-na[tt]",
208 "parts. The kink angle is defined as the angle between the kink-top and",
209 "the bottom-kink vectors.",
211 "With option [TT]-oa[tt] the top, mid (or kink when [TT]-ok[tt] is set)",
212 "and bottom points of each axis",
213 "are written to a [REF].pdb[ref] file each frame. The residue numbers correspond",
214 "to the axis numbers. When viewing this file with Rasmol, use the",
215 "command line option [TT]-nmrpdb[tt], and type [TT]set axis true[tt] to",
216 "display the reference axis."
219 static gmx_bool bZ
= FALSE
;
220 t_pargs pa
[] = { { "-na", FALSE
, etINT
, { &n
}, "Number of axes" },
225 "Use the [IT]z[it]-axis as reference instead of the average axis" } };
226 FILE * flen
, *fdist
, *fz
, *ftilt
, *ftiltr
, *ftiltl
;
227 FILE * fkink
= nullptr, *fkinkr
= nullptr, *fkinkl
= nullptr;
237 char* grpname
[MAX_ENDS
];
238 /* FIXME: The constness should not be cast away */
239 char * anm
= const_cast<char*>("CA"), *rnm
= const_cast<char*>("GLY");
240 int i
, gnx
[MAX_ENDS
];
241 int* index
[MAX_ENDS
];
244 rvec va
, vb
, vc
, vr
, vl
;
245 gmx_output_env_t
* oenv
;
246 gmx_rmpbc_t gpbc
= nullptr;
248 #define NLEG asize(leg)
250 { efTRX
, "-f", nullptr, ffREAD
}, { efTPS
, nullptr, nullptr, ffREAD
},
251 { efNDX
, nullptr, nullptr, ffOPTRD
}, { efXVG
, "-ol", "bun_len", ffWRITE
},
252 { efXVG
, "-od", "bun_dist", ffWRITE
}, { efXVG
, "-oz", "bun_z", ffWRITE
},
253 { efXVG
, "-ot", "bun_tilt", ffWRITE
}, { efXVG
, "-otr", "bun_tiltr", ffWRITE
},
254 { efXVG
, "-otl", "bun_tiltl", ffWRITE
}, { efXVG
, "-ok", "bun_kink", ffOPTWR
},
255 { efXVG
, "-okr", "bun_kinkr", ffOPTWR
}, { efXVG
, "-okl", "bun_kinkl", ffOPTWR
},
256 { efPDB
, "-oa", "axes", ffOPTWR
}
258 #define NFILE asize(fnm)
260 if (!parse_common_args(&argc
, argv
, PCA_CAN_TIME
| PCA_TIME_UNIT
, NFILE
, fnm
, asize(pa
), pa
,
261 asize(desc
), desc
, 0, nullptr, &oenv
))
266 read_tps_conf(ftp2fn(efTPS
, NFILE
, fnm
), &top
, &pbcType
, &xtop
, nullptr, box
, TRUE
);
268 bKink
= opt2bSet("-ok", NFILE
, fnm
) || opt2bSet("-okr", NFILE
, fnm
) || opt2bSet("-okl", NFILE
, fnm
);
278 fprintf(stderr
, "Select a group of top and a group of bottom ");
281 fprintf(stderr
, "and a group of kink ");
283 fprintf(stderr
, "atoms\n");
284 get_index(&top
.atoms
, ftp2fn_null(efNDX
, NFILE
, fnm
), bun
.nend
, gnx
, index
, grpname
);
286 if (n
<= 0 || gnx
[0] % n
|| gnx
[1] % n
|| (bKink
&& gnx
[2] % n
))
288 gmx_fatal(FARGS
, "The size of one of your index groups is not a multiple of n");
301 flen
= xvgropen(opt2fn("-ol", NFILE
, fnm
), "Axis lengths", output_env_get_xvgr_tlabel(oenv
),
303 fdist
= xvgropen(opt2fn("-od", NFILE
, fnm
), "Distance of axis centers",
304 output_env_get_xvgr_tlabel(oenv
), "(nm)", oenv
);
305 fz
= xvgropen(opt2fn("-oz", NFILE
, fnm
), "Z-shift of axis centers",
306 output_env_get_xvgr_tlabel(oenv
), "(nm)", oenv
);
307 ftilt
= xvgropen(opt2fn("-ot", NFILE
, fnm
), "Axis tilts", output_env_get_xvgr_tlabel(oenv
),
309 ftiltr
= xvgropen(opt2fn("-otr", NFILE
, fnm
), "Radial axis tilts",
310 output_env_get_xvgr_tlabel(oenv
), "(degrees)", oenv
);
311 ftiltl
= xvgropen(opt2fn("-otl", NFILE
, fnm
), "Lateral axis tilts",
312 output_env_get_xvgr_tlabel(oenv
), "(degrees)", oenv
);
316 fkink
= xvgropen(opt2fn("-ok", NFILE
, fnm
), "Kink angles", output_env_get_xvgr_tlabel(oenv
),
318 fkinkr
= xvgropen(opt2fn("-okr", NFILE
, fnm
), "Radial kink angles",
319 output_env_get_xvgr_tlabel(oenv
), "(degrees)", oenv
);
320 if (output_env_get_print_xvgr_codes(oenv
))
322 fprintf(fkinkr
, "@ subtitle \"+ = ) ( - = ( )\"\n");
324 fkinkl
= xvgropen(opt2fn("-okl", NFILE
, fnm
), "Lateral kink angles",
325 output_env_get_xvgr_tlabel(oenv
), "(degrees)", oenv
);
328 if (opt2bSet("-oa", NFILE
, fnm
))
330 init_t_atoms(&outatoms
, 3 * n
, FALSE
);
332 for (i
= 0; i
< 3 * n
; i
++)
334 outatoms
.atomname
[i
] = &anm
;
335 outatoms
.atom
[i
].resind
= i
/ 3;
336 outatoms
.resinfo
[i
/ 3].name
= &rnm
;
337 outatoms
.resinfo
[i
/ 3].nr
= i
/ 3 + 1;
338 outatoms
.resinfo
[i
/ 3].ic
= ' ';
340 fpdb
= open_trx(opt2fn("-oa", NFILE
, fnm
), "w");
347 read_first_frame(oenv
, &status
, ftp2fn(efTRX
, NFILE
, fnm
), &fr
, TRX_NEED_X
);
348 gpbc
= gmx_rmpbc_init(&top
.idef
, pbcType
, fr
.natoms
);
352 gmx_rmpbc_trxfr(gpbc
, &fr
);
353 calc_axes(fr
.x
, top
.atoms
.atom
, gnx
, index
, !bZ
, &bun
);
354 t
= output_env_conv_time(oenv
, fr
.time
);
355 fprintf(flen
, " %10g", t
);
356 fprintf(fdist
, " %10g", t
);
357 fprintf(fz
, " %10g", t
);
358 fprintf(ftilt
, " %10g", t
);
359 fprintf(ftiltr
, " %10g", t
);
360 fprintf(ftiltl
, " %10g", t
);
363 fprintf(fkink
, " %10g", t
);
364 fprintf(fkinkr
, " %10g", t
);
365 fprintf(fkinkl
, " %10g", t
);
368 for (i
= 0; i
< bun
.n
; i
++)
370 fprintf(flen
, " %6g", bun
.len
[i
]);
371 fprintf(fdist
, " %6g", norm(bun
.mid
[i
]));
372 fprintf(fz
, " %6g", bun
.mid
[i
][ZZ
]);
373 fprintf(ftilt
, " %6g", RAD2DEG
* acos(bun
.dir
[i
][ZZ
]));
374 comp
= bun
.mid
[i
][XX
] * bun
.dir
[i
][XX
] + bun
.mid
[i
][YY
] * bun
.dir
[i
][YY
];
375 fprintf(ftiltr
, " %6g", RAD2DEG
* std::asin(comp
/ std::hypot(comp
, bun
.dir
[i
][ZZ
])));
376 comp
= bun
.mid
[i
][YY
] * bun
.dir
[i
][XX
] - bun
.mid
[i
][XX
] * bun
.dir
[i
][YY
];
377 fprintf(ftiltl
, " %6g", RAD2DEG
* std::asin(comp
/ std::hypot(comp
, bun
.dir
[i
][ZZ
])));
380 rvec_sub(bun
.end
[0][i
], bun
.end
[2][i
], va
);
381 rvec_sub(bun
.end
[2][i
], bun
.end
[1][i
], vb
);
384 fprintf(fkink
, " %6g", RAD2DEG
* acos(iprod(va
, vb
)));
386 copy_rvec(bun
.mid
[i
], vr
);
389 fprintf(fkinkr
, " %6g", RAD2DEG
* std::asin(iprod(vc
, vr
)));
393 fprintf(fkinkl
, " %6g", RAD2DEG
* std::asin(iprod(vc
, vl
)));
397 fprintf(fdist
, "\n");
399 fprintf(ftilt
, "\n");
400 fprintf(ftiltr
, "\n");
401 fprintf(ftiltl
, "\n");
404 fprintf(fkink
, "\n");
405 fprintf(fkinkr
, "\n");
406 fprintf(fkinkl
, "\n");
410 dump_axes(fpdb
, &fr
, &outatoms
, &bun
);
412 } while (read_next_frame(oenv
, status
, &fr
));
413 gmx_rmpbc_done(gpbc
);