File: | gromacs/gmxana/gmx_nmeig.c |
Location: | line 233, column 33 |
Description: | Access to field 'ndata' results in a dereference of a null pointer (loaded from variable 'sparse_hessian') |
1 | /* | |||
2 | * This file is part of the GROMACS molecular simulation package. | |||
3 | * | |||
4 | * Copyright (c) 1991-2000, University of Groningen, The Netherlands. | |||
5 | * Copyright (c) 2001-2004, The GROMACS development team. | |||
6 | * Copyright (c) 2013,2014, 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. | |||
10 | * | |||
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. | |||
15 | * | |||
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. | |||
20 | * | |||
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. | |||
25 | * | |||
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. | |||
33 | * | |||
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. | |||
36 | */ | |||
37 | #ifdef HAVE_CONFIG_H1 | |||
38 | #include <config.h> | |||
39 | #endif | |||
40 | ||||
41 | #include <math.h> | |||
42 | #include <string.h> | |||
43 | ||||
44 | #include "gromacs/commandline/pargs.h" | |||
45 | #include "typedefs.h" | |||
46 | #include "gromacs/utility/smalloc.h" | |||
47 | #include "macros.h" | |||
48 | #include "gromacs/math/vec.h" | |||
49 | #include "pbc.h" | |||
50 | #include "copyrite.h" | |||
51 | #include "gromacs/utility/futil.h" | |||
52 | #include "index.h" | |||
53 | #include "mshift.h" | |||
54 | #include "gromacs/fileio/xvgr.h" | |||
55 | #include "gstat.h" | |||
56 | #include "txtdump.h" | |||
57 | #include "eigio.h" | |||
58 | #include "mtop_util.h" | |||
59 | #include "physics.h" | |||
60 | #include "gmx_ana.h" | |||
61 | ||||
62 | #include "gromacs/linearalgebra/eigensolver.h" | |||
63 | #include "gromacs/linearalgebra/mtxio.h" | |||
64 | #include "gromacs/linearalgebra/sparsematrix.h" | |||
65 | ||||
66 | static double cv_corr(double nu, double T) | |||
67 | { | |||
68 | double x = PLANCK(6.6262e-34*(6.0221367e23)/((1e-12)*(1e3)))*nu/(BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*T); | |||
69 | double ex = exp(x); | |||
70 | ||||
71 | if (nu <= 0) | |||
72 | { | |||
73 | return BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*KILO(1e3); | |||
74 | } | |||
75 | else | |||
76 | { | |||
77 | return BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*KILO(1e3)*(ex*sqr(x)/sqr(ex-1) - 1); | |||
78 | } | |||
79 | } | |||
80 | ||||
81 | static double u_corr(double nu, double T) | |||
82 | { | |||
83 | double x = PLANCK(6.6262e-34*(6.0221367e23)/((1e-12)*(1e3)))*nu/(BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*T); | |||
84 | double ex = exp(x); | |||
85 | ||||
86 | if (nu <= 0) | |||
87 | { | |||
88 | return BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*T; | |||
89 | } | |||
90 | else | |||
91 | { | |||
92 | return BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*T*(0.5*x - 1 + x/(ex-1)); | |||
93 | } | |||
94 | } | |||
95 | ||||
96 | static int get_nharm_mt(gmx_moltype_t *mt) | |||
97 | { | |||
98 | static int harm_func[] = { F_BONDS }; | |||
99 | int i, ft, nh; | |||
100 | ||||
101 | nh = 0; | |||
102 | for (i = 0; (i < asize(harm_func)((int)(sizeof(harm_func)/sizeof((harm_func)[0])))); i++) | |||
103 | { | |||
104 | ft = harm_func[i]; | |||
105 | nh += mt->ilist[ft].nr/(interaction_function[ft].nratoms+1); | |||
106 | } | |||
107 | return nh; | |||
108 | } | |||
109 | ||||
110 | static int get_nvsite_mt(gmx_moltype_t *mt) | |||
111 | { | |||
112 | static int vs_func[] = { | |||
113 | F_VSITE2, F_VSITE3, F_VSITE3FD, F_VSITE3FAD, | |||
114 | F_VSITE3OUT, F_VSITE4FD, F_VSITE4FDN, F_VSITEN | |||
115 | }; | |||
116 | int i, ft, nh; | |||
117 | ||||
118 | nh = 0; | |||
119 | for (i = 0; (i < asize(vs_func)((int)(sizeof(vs_func)/sizeof((vs_func)[0])))); i++) | |||
120 | { | |||
121 | ft = vs_func[i]; | |||
122 | nh += mt->ilist[ft].nr/(interaction_function[ft].nratoms+1); | |||
123 | } | |||
124 | return nh; | |||
125 | } | |||
126 | ||||
127 | static int get_nharm(gmx_mtop_t *mtop, int *nvsites) | |||
128 | { | |||
129 | int j, mt, nh, nv; | |||
130 | ||||
131 | nh = 0; | |||
132 | nv = 0; | |||
133 | for (j = 0; (j < mtop->nmolblock); j++) | |||
134 | { | |||
135 | mt = mtop->molblock[j].type; | |||
136 | nh += mtop->molblock[j].nmol * get_nharm_mt(&(mtop->moltype[mt])); | |||
137 | nv += mtop->molblock[j].nmol * get_nvsite_mt(&(mtop->moltype[mt])); | |||
138 | } | |||
139 | *nvsites = nv; | |||
140 | return nh; | |||
141 | } | |||
142 | ||||
143 | static void | |||
144 | nma_full_hessian(real * hess, | |||
145 | int ndim, | |||
146 | gmx_bool bM, | |||
147 | t_topology * top, | |||
148 | int begin, | |||
149 | int end, | |||
150 | real * eigenvalues, | |||
151 | real * eigenvectors) | |||
152 | { | |||
153 | int i, j, k, l; | |||
154 | real mass_fac, rdum; | |||
155 | int natoms; | |||
156 | ||||
157 | natoms = top->atoms.nr; | |||
158 | ||||
159 | /* divide elements hess[i][j] by sqrt(mas[i])*sqrt(mas[j]) when required */ | |||
160 | ||||
161 | if (bM) | |||
162 | { | |||
163 | for (i = 0; (i < natoms); i++) | |||
164 | { | |||
165 | for (j = 0; (j < DIM3); j++) | |||
166 | { | |||
167 | for (k = 0; (k < natoms); k++) | |||
168 | { | |||
169 | mass_fac = gmx_invsqrt(top->atoms.atom[i].m*top->atoms.atom[k].m)gmx_software_invsqrt(top->atoms.atom[i].m*top->atoms.atom [k].m); | |||
170 | for (l = 0; (l < DIM3); l++) | |||
171 | { | |||
172 | hess[(i*DIM3+j)*ndim+k*DIM3+l] *= mass_fac; | |||
173 | } | |||
174 | } | |||
175 | } | |||
176 | } | |||
177 | } | |||
178 | ||||
179 | /* call diagonalization routine. */ | |||
180 | ||||
181 | fprintf(stderrstderr, "\nDiagonalizing to find vectors %d through %d...\n", begin, end); | |||
182 | fflush(stderrstderr); | |||
183 | ||||
184 | eigensolver(hess, ndim, begin-1, end-1, eigenvalues, eigenvectors); | |||
185 | ||||
186 | /* And scale the output eigenvectors */ | |||
187 | if (bM && eigenvectors != NULL((void*)0)) | |||
188 | { | |||
189 | for (i = 0; i < (end-begin+1); i++) | |||
190 | { | |||
191 | for (j = 0; j < natoms; j++) | |||
192 | { | |||
193 | mass_fac = gmx_invsqrt(top->atoms.atom[j].m)gmx_software_invsqrt(top->atoms.atom[j].m); | |||
194 | for (k = 0; (k < DIM3); k++) | |||
195 | { | |||
196 | eigenvectors[i*ndim+j*DIM3+k] *= mass_fac; | |||
197 | } | |||
198 | } | |||
199 | } | |||
200 | } | |||
201 | } | |||
202 | ||||
203 | ||||
204 | ||||
205 | static void | |||
206 | nma_sparse_hessian(gmx_sparsematrix_t * sparse_hessian, | |||
207 | gmx_bool bM, | |||
208 | t_topology * top, | |||
209 | int neig, | |||
210 | real * eigenvalues, | |||
211 | real * eigenvectors) | |||
212 | { | |||
213 | int i, j, k; | |||
214 | int row, col; | |||
215 | real mass_fac; | |||
216 | int iatom, katom; | |||
217 | int natoms; | |||
218 | int ndim; | |||
219 | ||||
220 | natoms = top->atoms.nr; | |||
221 | ndim = DIM3*natoms; | |||
222 | ||||
223 | /* Cannot check symmetry since we only store half matrix */ | |||
224 | /* divide elements hess[i][j] by sqrt(mas[i])*sqrt(mas[j]) when required */ | |||
225 | ||||
226 | if (bM) | |||
227 | { | |||
228 | for (iatom = 0; (iatom < natoms); iatom++) | |||
229 | { | |||
230 | for (j = 0; (j < DIM3); j++) | |||
231 | { | |||
232 | row = DIM3*iatom+j; | |||
233 | for (k = 0; k < sparse_hessian->ndata[row]; k++) | |||
| ||||
234 | { | |||
235 | col = sparse_hessian->data[row][k].col; | |||
236 | katom = col/3; | |||
237 | mass_fac = gmx_invsqrt(top->atoms.atom[iatom].m*top->atoms.atom[katom].m)gmx_software_invsqrt(top->atoms.atom[iatom].m*top->atoms .atom[katom].m); | |||
238 | sparse_hessian->data[row][k].value *= mass_fac; | |||
239 | } | |||
240 | } | |||
241 | } | |||
242 | } | |||
243 | fprintf(stderrstderr, "\nDiagonalizing to find eigenvectors 1 through %d...\n", neig); | |||
244 | fflush(stderrstderr); | |||
245 | ||||
246 | sparse_eigensolver(sparse_hessian, neig, eigenvalues, eigenvectors, 10000000); | |||
247 | ||||
248 | /* Scale output eigenvectors */ | |||
249 | if (bM && eigenvectors != NULL((void*)0)) | |||
250 | { | |||
251 | for (i = 0; i < neig; i++) | |||
252 | { | |||
253 | for (j = 0; j < natoms; j++) | |||
254 | { | |||
255 | mass_fac = gmx_invsqrt(top->atoms.atom[j].m)gmx_software_invsqrt(top->atoms.atom[j].m); | |||
256 | for (k = 0; (k < DIM3); k++) | |||
257 | { | |||
258 | eigenvectors[i*ndim+j*DIM3+k] *= mass_fac; | |||
259 | } | |||
260 | } | |||
261 | } | |||
262 | } | |||
263 | } | |||
264 | ||||
265 | ||||
266 | ||||
267 | int gmx_nmeig(int argc, char *argv[]) | |||
268 | { | |||
269 | const char *desc[] = { | |||
270 | "[THISMODULE] calculates the eigenvectors/values of a (Hessian) matrix,", | |||
271 | "which can be calculated with [gmx-mdrun].", | |||
272 | "The eigenvectors are written to a trajectory file ([TT]-v[tt]).", | |||
273 | "The structure is written first with t=0. The eigenvectors", | |||
274 | "are written as frames with the eigenvector number as timestamp.", | |||
275 | "The eigenvectors can be analyzed with [gmx-anaeig].", | |||
276 | "An ensemble of structures can be generated from the eigenvectors with", | |||
277 | "[gmx-nmens]. When mass weighting is used, the generated eigenvectors", | |||
278 | "will be scaled back to plain Cartesian coordinates before generating the", | |||
279 | "output. In this case, they will no longer be exactly orthogonal in the", | |||
280 | "standard Cartesian norm, but in the mass-weighted norm they would be.[PAR]", | |||
281 | "This program can be optionally used to compute quantum corrections to heat capacity", | |||
282 | "and enthalpy by providing an extra file argument [TT]-qcorr[tt]. See the GROMACS", | |||
283 | "manual, Chapter 1, for details. The result includes subtracting a harmonic", | |||
284 | "degree of freedom at the given temperature.", | |||
285 | "The total correction is printed on the terminal screen.", | |||
286 | "The recommended way of getting the corrections out is:[PAR]", | |||
287 | "[TT]gmx nmeig -s topol.tpr -f nm.mtx -first 7 -last 10000 -T 300 -qc [-constr][tt][PAR]", | |||
288 | "The [TT]-constr[tt] option should be used when bond constraints were used during the", | |||
289 | "simulation [BB]for all the covalent bonds[bb]. If this is not the case, ", | |||
290 | "you need to analyze the [TT]quant_corr.xvg[tt] file yourself.[PAR]", | |||
291 | "To make things more flexible, the program can also take virtual sites into account", | |||
292 | "when computing quantum corrections. When selecting [TT]-constr[tt] and", | |||
293 | "[TT]-qc[tt], the [TT]-begin[tt] and [TT]-end[tt] options will be set automatically as well.", | |||
294 | "Again, if you think you know it better, please check the [TT]eigenfreq.xvg[tt]", | |||
295 | "output." | |||
296 | }; | |||
297 | ||||
298 | static gmx_bool bM = TRUE1, bCons = FALSE0; | |||
299 | static int begin = 1, end = 50, maxspec = 4000; | |||
300 | static real T = 298.15, width = 1; | |||
301 | t_pargs pa[] = | |||
302 | { | |||
303 | { "-m", FALSE0, etBOOL, {&bM}, | |||
304 | "Divide elements of Hessian by product of sqrt(mass) of involved " | |||
305 | "atoms prior to diagonalization. This should be used for 'Normal Modes' " | |||
306 | "analysis" }, | |||
307 | { "-first", FALSE0, etINT, {&begin}, | |||
308 | "First eigenvector to write away" }, | |||
309 | { "-last", FALSE0, etINT, {&end}, | |||
310 | "Last eigenvector to write away" }, | |||
311 | { "-maxspec", FALSE0, etINT, {&maxspec}, | |||
312 | "Highest frequency (1/cm) to consider in the spectrum" }, | |||
313 | { "-T", FALSE0, etREAL, {&T}, | |||
314 | "Temperature for computing quantum heat capacity and enthalpy when using normal mode calculations to correct classical simulations" }, | |||
315 | { "-constr", FALSE0, etBOOL, {&bCons}, | |||
316 | "If constraints were used in the simulation but not in the normal mode analysis (this is the recommended way of doing it) you will need to set this for computing the quantum corrections." }, | |||
317 | { "-width", FALSE0, etREAL, {&width}, | |||
318 | "Width (sigma) of the gaussian peaks (1/cm) when generating a spectrum" } | |||
319 | }; | |||
320 | FILE *out, *qc, *spec; | |||
321 | int status, trjout; | |||
322 | t_topology top; | |||
323 | gmx_mtop_t mtop; | |||
324 | int ePBC; | |||
325 | rvec *top_x; | |||
326 | matrix box; | |||
327 | real *eigenvalues; | |||
328 | real *eigenvectors; | |||
329 | real rdum, mass_fac, qcvtot, qutot, qcv, qu; | |||
330 | int natoms, ndim, nrow, ncol, count, nharm, nvsite; | |||
331 | char *grpname; | |||
332 | int i, j, k, l, d, gnx; | |||
333 | gmx_bool bSuck; | |||
334 | atom_id *index; | |||
335 | t_tpxheader tpx; | |||
336 | int version, generation; | |||
337 | real value, omega, nu; | |||
338 | real factor_gmx_to_omega2; | |||
339 | real factor_omega_to_wavenumber; | |||
340 | real *spectrum = NULL((void*)0); | |||
341 | real wfac; | |||
342 | output_env_t oenv; | |||
343 | const char *qcleg[] = { | |||
344 | "Heat Capacity cV (J/mol K)", | |||
345 | "Enthalpy H (kJ/mol)" | |||
346 | }; | |||
347 | real * full_hessian = NULL((void*)0); | |||
348 | gmx_sparsematrix_t * sparse_hessian = NULL((void*)0); | |||
349 | ||||
350 | t_filenm fnm[] = { | |||
351 | { efMTX, "-f", "hessian", ffREAD1<<1 }, | |||
352 | { efTPX, NULL((void*)0), NULL((void*)0), ffREAD1<<1 }, | |||
353 | { efXVG, "-of", "eigenfreq", ffWRITE1<<2 }, | |||
354 | { efXVG, "-ol", "eigenval", ffWRITE1<<2 }, | |||
355 | { efXVG, "-os", "spectrum", ffOPTWR(1<<2| 1<<3) }, | |||
356 | { efXVG, "-qc", "quant_corr", ffOPTWR(1<<2| 1<<3) }, | |||
357 | { efTRN, "-v", "eigenvec", ffWRITE1<<2 } | |||
358 | }; | |||
359 | #define NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))) asize(fnm)((int)(sizeof(fnm)/sizeof((fnm)[0]))) | |||
360 | ||||
361 | if (!parse_common_args(&argc, argv, PCA_BE_NICE(1<<13), | |||
| ||||
362 | NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm, asize(pa)((int)(sizeof(pa)/sizeof((pa)[0]))), pa, asize(desc)((int)(sizeof(desc)/sizeof((desc)[0]))), desc, 0, NULL((void*)0), &oenv)) | |||
363 | { | |||
364 | return 0; | |||
365 | } | |||
366 | ||||
367 | /* Read tpr file for volume and number of harmonic terms */ | |||
368 | read_tpxheader(ftp2fn(efTPX, NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), &tpx, TRUE1, &version, &generation); | |||
369 | snew(top_x, tpx.natoms)(top_x) = save_calloc("top_x", "/home/alexxy/Develop/gromacs/src/gromacs/gmxana/gmx_nmeig.c" , 369, (tpx.natoms), sizeof(*(top_x))); | |||
370 | ||||
371 | read_tpx(ftp2fn(efTPX, NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), NULL((void*)0), box, &natoms, | |||
372 | top_x, NULL((void*)0), NULL((void*)0), &mtop); | |||
373 | if (bCons) | |||
374 | { | |||
375 | nharm = get_nharm(&mtop, &nvsite); | |||
376 | } | |||
377 | else | |||
378 | { | |||
379 | nharm = 0; | |||
380 | nvsite = 0; | |||
381 | } | |||
382 | top = gmx_mtop_t_to_t_topology(&mtop); | |||
383 | ||||
384 | bM = TRUE1; | |||
385 | ndim = DIM3*natoms; | |||
386 | ||||
387 | if (opt2bSet("-qc", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm)) | |||
388 | { | |||
389 | begin = 7+DIM3*nvsite; | |||
390 | end = DIM3*natoms; | |||
391 | } | |||
392 | if (begin < 1) | |||
393 | { | |||
394 | begin = 1; | |||
395 | } | |||
396 | if (end > ndim) | |||
397 | { | |||
398 | end = ndim; | |||
399 | } | |||
400 | printf("Using begin = %d and end = %d\n", begin, end); | |||
401 | ||||
402 | /*open Hessian matrix */ | |||
403 | gmx_mtxio_read(ftp2fn(efMTX, NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), &nrow, &ncol, &full_hessian, &sparse_hessian); | |||
404 | ||||
405 | /* Memory for eigenvalues and eigenvectors (begin..end) */ | |||
406 | snew(eigenvalues, nrow)(eigenvalues) = save_calloc("eigenvalues", "/home/alexxy/Develop/gromacs/src/gromacs/gmxana/gmx_nmeig.c" , 406, (nrow), sizeof(*(eigenvalues))); | |||
407 | snew(eigenvectors, nrow*(end-begin+1))(eigenvectors) = save_calloc("eigenvectors", "/home/alexxy/Develop/gromacs/src/gromacs/gmxana/gmx_nmeig.c" , 407, (nrow*(end-begin+1)), sizeof(*(eigenvectors))); | |||
408 | ||||
409 | /* If the Hessian is in sparse format we can calculate max (ndim-1) eigenvectors, | |||
410 | * and they must start at the first one. If this is not valid we convert to full matrix | |||
411 | * storage, but warn the user that we might run out of memory... | |||
412 | */ | |||
413 | if ((sparse_hessian != NULL((void*)0)) && (begin != 1 || end == ndim)) | |||
414 | { | |||
415 | if (begin != 1) | |||
416 | { | |||
417 | fprintf(stderrstderr, "Cannot use sparse Hessian with first eigenvector != 1.\n"); | |||
418 | } | |||
419 | else if (end == ndim) | |||
420 | { | |||
421 | fprintf(stderrstderr, "Cannot use sparse Hessian to calculate all eigenvectors.\n"); | |||
422 | } | |||
423 | ||||
424 | fprintf(stderrstderr, "Will try to allocate memory and convert to full matrix representation...\n"); | |||
425 | ||||
426 | snew(full_hessian, nrow*ncol)(full_hessian) = save_calloc("full_hessian", "/home/alexxy/Develop/gromacs/src/gromacs/gmxana/gmx_nmeig.c" , 426, (nrow*ncol), sizeof(*(full_hessian))); | |||
427 | for (i = 0; i < nrow*ncol; i++) | |||
428 | { | |||
429 | full_hessian[i] = 0; | |||
430 | } | |||
431 | ||||
432 | for (i = 0; i < sparse_hessian->nrow; i++) | |||
433 | { | |||
434 | for (j = 0; j < sparse_hessian->ndata[i]; j++) | |||
435 | { | |||
436 | k = sparse_hessian->data[i][j].col; | |||
437 | value = sparse_hessian->data[i][j].value; | |||
438 | full_hessian[i*ndim+k] = value; | |||
439 | full_hessian[k*ndim+i] = value; | |||
440 | } | |||
441 | } | |||
442 | gmx_sparsematrix_destroy(sparse_hessian); | |||
443 | sparse_hessian = NULL((void*)0); | |||
444 | fprintf(stderrstderr, "Converted sparse to full matrix storage.\n"); | |||
445 | } | |||
446 | ||||
447 | if (full_hessian != NULL((void*)0)) | |||
448 | { | |||
449 | /* Using full matrix storage */ | |||
450 | nma_full_hessian(full_hessian, nrow, bM, &top, begin, end, | |||
451 | eigenvalues, eigenvectors); | |||
452 | } | |||
453 | else | |||
454 | { | |||
455 | /* Sparse memory storage, allocate memory for eigenvectors */ | |||
456 | snew(eigenvectors, ncol*end)(eigenvectors) = save_calloc("eigenvectors", "/home/alexxy/Develop/gromacs/src/gromacs/gmxana/gmx_nmeig.c" , 456, (ncol*end), sizeof(*(eigenvectors))); | |||
457 | nma_sparse_hessian(sparse_hessian, bM, &top, end, eigenvalues, eigenvectors); | |||
458 | } | |||
459 | ||||
460 | /* check the output, first 6 eigenvalues should be reasonably small */ | |||
461 | bSuck = FALSE0; | |||
462 | for (i = begin-1; (i < 6); i++) | |||
463 | { | |||
464 | if (fabs(eigenvalues[i]) > 1.0e-3) | |||
465 | { | |||
466 | bSuck = TRUE1; | |||
467 | } | |||
468 | } | |||
469 | if (bSuck) | |||
470 | { | |||
471 | fprintf(stderrstderr, "\nOne of the lowest 6 eigenvalues has a non-zero value.\n"); | |||
472 | fprintf(stderrstderr, "This could mean that the reference structure was not\n"); | |||
473 | fprintf(stderrstderr, "properly energy minimized.\n"); | |||
474 | } | |||
475 | ||||
476 | /* now write the output */ | |||
477 | fprintf (stderrstderr, "Writing eigenvalues...\n"); | |||
478 | out = xvgropen(opt2fn("-ol", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), | |||
479 | "Eigenvalues", "Eigenvalue index", "Eigenvalue [Gromacs units]", | |||
480 | oenv); | |||
481 | if (output_env_get_print_xvgr_codes(oenv)) | |||
482 | { | |||
483 | if (bM) | |||
484 | { | |||
485 | fprintf(out, "@ subtitle \"mass weighted\"\n"); | |||
486 | } | |||
487 | else | |||
488 | { | |||
489 | fprintf(out, "@ subtitle \"not mass weighted\"\n"); | |||
490 | } | |||
491 | } | |||
492 | ||||
493 | for (i = 0; i <= (end-begin); i++) | |||
494 | { | |||
495 | fprintf (out, "%6d %15g\n", begin+i, eigenvalues[i]); | |||
496 | } | |||
497 | gmx_ffclose(out); | |||
498 | ||||
499 | ||||
500 | if (opt2bSet("-qc", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm)) | |||
501 | { | |||
502 | qc = xvgropen(opt2fn("-qc", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), "Quantum Corrections", "Eigenvector index", "", oenv); | |||
503 | xvgr_legend(qc, asize(qcleg)((int)(sizeof(qcleg)/sizeof((qcleg)[0]))), qcleg, oenv); | |||
504 | qcvtot = qutot = 0; | |||
505 | } | |||
506 | else | |||
507 | { | |||
508 | qc = NULL((void*)0); | |||
509 | } | |||
510 | printf("Writing eigenfrequencies - negative eigenvalues will be set to zero.\n"); | |||
511 | ||||
512 | out = xvgropen(opt2fn("-of", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), | |||
513 | "Eigenfrequencies", "Eigenvector index", "Wavenumber [cm\\S-1\\N]", | |||
514 | oenv); | |||
515 | if (output_env_get_print_xvgr_codes(oenv)) | |||
516 | { | |||
517 | if (bM) | |||
518 | { | |||
519 | fprintf(out, "@ subtitle \"mass weighted\"\n"); | |||
520 | } | |||
521 | else | |||
522 | { | |||
523 | fprintf(out, "@ subtitle \"not mass weighted\"\n"); | |||
524 | } | |||
525 | } | |||
526 | /* Spectrum ? */ | |||
527 | spec = NULL((void*)0); | |||
528 | if (opt2bSet("-os", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm) && (maxspec > 0)) | |||
529 | { | |||
530 | snew(spectrum, maxspec)(spectrum) = save_calloc("spectrum", "/home/alexxy/Develop/gromacs/src/gromacs/gmxana/gmx_nmeig.c" , 530, (maxspec), sizeof(*(spectrum))); | |||
531 | spec = xvgropen(opt2fn("-os", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), | |||
532 | "Vibrational spectrum based on harmonic approximation", | |||
533 | "\\f{12}w\\f{4} (cm\\S-1\\N)", | |||
534 | "Intensity [Gromacs units]", | |||
535 | oenv); | |||
536 | for (i = 0; (i < maxspec); i++) | |||
537 | { | |||
538 | spectrum[i] = 0; | |||
539 | } | |||
540 | } | |||
541 | ||||
542 | /* Gromacs units are kJ/(mol*nm*nm*amu), | |||
543 | * where amu is the atomic mass unit. | |||
544 | * | |||
545 | * For the eigenfrequencies we want to convert this to spectroscopic absorption | |||
546 | * wavenumbers given in cm^(-1), which is the frequency divided by the speed of | |||
547 | * light. Do this by first converting to omega^2 (units 1/s), take the square | |||
548 | * root, and finally divide by the speed of light (nm/ps in gromacs). | |||
549 | */ | |||
550 | factor_gmx_to_omega2 = 1.0E21/(AVOGADRO(6.0221367e23)*AMU(1.6605402e-27)); | |||
551 | factor_omega_to_wavenumber = 1.0E-5/(2.0*M_PI3.14159265358979323846*SPEED_OF_LIGHT(2.9979245800E05)); | |||
552 | ||||
553 | for (i = begin; (i <= end); i++) | |||
554 | { | |||
555 | value = eigenvalues[i-begin]; | |||
556 | if (value < 0) | |||
557 | { | |||
558 | value = 0; | |||
559 | } | |||
560 | omega = sqrt(value*factor_gmx_to_omega2); | |||
561 | nu = 1e-12*omega/(2*M_PI3.14159265358979323846); | |||
562 | value = omega*factor_omega_to_wavenumber; | |||
563 | fprintf (out, "%6d %15g\n", i, value); | |||
564 | if (NULL((void*)0) != spec) | |||
565 | { | |||
566 | wfac = eigenvalues[i-begin]/(width*sqrt(2*M_PI3.14159265358979323846)); | |||
567 | for (j = 0; (j < maxspec); j++) | |||
568 | { | |||
569 | spectrum[j] += wfac*exp(-sqr(j-value)/(2*sqr(width))); | |||
570 | } | |||
571 | } | |||
572 | if (NULL((void*)0) != qc) | |||
573 | { | |||
574 | qcv = cv_corr(nu, T); | |||
575 | qu = u_corr(nu, T); | |||
576 | if (i > end-nharm) | |||
577 | { | |||
578 | qcv += BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*KILO(1e3); | |||
579 | qu += BOLTZ(((1.380658e-23)*(6.0221367e23))/(1e3))*T; | |||
580 | } | |||
581 | fprintf (qc, "%6d %15g %15g\n", i, qcv, qu); | |||
582 | qcvtot += qcv; | |||
583 | qutot += qu; | |||
584 | } | |||
585 | } | |||
586 | gmx_ffclose(out); | |||
587 | if (NULL((void*)0) != spec) | |||
588 | { | |||
589 | for (j = 0; (j < maxspec); j++) | |||
590 | { | |||
591 | fprintf(spec, "%10g %10g\n", 1.0*j, spectrum[j]); | |||
592 | } | |||
593 | gmx_ffclose(spec); | |||
594 | } | |||
595 | if (NULL((void*)0) != qc) | |||
596 | { | |||
597 | printf("Quantum corrections for harmonic degrees of freedom\n"); | |||
598 | printf("Use appropriate -first and -last options to get reliable results.\n"); | |||
599 | printf("There were %d constraints and %d vsites in the simulation\n", | |||
600 | nharm, nvsite); | |||
601 | printf("Total correction to cV = %g J/mol K\n", qcvtot); | |||
602 | printf("Total correction to H = %g kJ/mol\n", qutot); | |||
603 | gmx_ffclose(qc); | |||
604 | please_cite(stdoutstdout, "Caleman2011b"); | |||
605 | } | |||
606 | /* Writing eigenvectors. Note that if mass scaling was used, the eigenvectors | |||
607 | * were scaled back from mass weighted cartesian to plain cartesian in the | |||
608 | * nma_full_hessian() or nma_sparse_hessian() routines. Mass scaled vectors | |||
609 | * will not be strictly orthogonal in plain cartesian scalar products. | |||
610 | */ | |||
611 | write_eigenvectors(opt2fn("-v", NFILE((int)(sizeof(fnm)/sizeof((fnm)[0]))), fnm), natoms, eigenvectors, FALSE0, begin, end, | |||
612 | eWXR_NO, NULL((void*)0), FALSE0, top_x, bM, eigenvalues); | |||
613 | ||||
614 | return 0; | |||
615 | } |