static void calc_dihs(t_xrama *xr) { int i, t1, t2, t3; rvec r_ij, r_kj, r_kl, m, n; t_dih *dd; gmx_rmpbc_t gpbc = nullptr; gpbc = gmx_rmpbc_init(xr->idef, xr->ePBC, xr->natoms); gmx_rmpbc(gpbc, xr->natoms, xr->box, xr->x); gmx_rmpbc_done(gpbc); for (i = 0; (i < xr->ndih); i++) { dd = &(xr->dih[i]); dd->ang = dih_angle(xr->x[dd->ai[0]], xr->x[dd->ai[1]], xr->x[dd->ai[2]], xr->x[dd->ai[3]], nullptr, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); } }
int gmx_rmsf(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the root mean square fluctuation (RMSF, i.e. standard ", "deviation) of atomic positions in the trajectory (supplied with [TT]-f[tt])", "after (optionally) fitting to a reference frame (supplied with [TT]-s[tt]).[PAR]", "With option [TT]-oq[tt] the RMSF values are converted to B-factor", "values, which are written to a [REF].pdb[ref] file with the coordinates, of the", "structure file, or of a [REF].pdb[ref] file when [TT]-q[tt] is specified.", "Option [TT]-ox[tt] writes the B-factors to a file with the average", "coordinates.[PAR]", "With the option [TT]-od[tt] the root mean square deviation with", "respect to the reference structure is calculated.[PAR]", "With the option [TT]-aniso[tt], [THISMODULE] will compute anisotropic", "temperature factors and then it will also output average coordinates", "and a [REF].pdb[ref] file with ANISOU records (corresonding to the [TT]-oq[tt]", "or [TT]-ox[tt] option). Please note that the U values", "are orientation-dependent, so before comparison with experimental data", "you should verify that you fit to the experimental coordinates.[PAR]", "When a [REF].pdb[ref] input file is passed to the program and the [TT]-aniso[tt]", "flag is set", "a correlation plot of the Uij will be created, if any anisotropic", "temperature factors are present in the [REF].pdb[ref] file.[PAR]", "With option [TT]-dir[tt] the average MSF (3x3) matrix is diagonalized.", "This shows the directions in which the atoms fluctuate the most and", "the least." }; static gmx_bool bRes = FALSE, bAniso = FALSE, bFit = TRUE; t_pargs pargs[] = { { "-res", FALSE, etBOOL, {&bRes}, "Calculate averages for each residue" }, { "-aniso", FALSE, etBOOL, {&bAniso}, "Compute anisotropic termperature factors" }, { "-fit", FALSE, etBOOL, {&bFit}, "Do a least squares superposition before computing RMSF. Without this you must make sure that the reference structure and the trajectory match." } }; int natom; int i, m, teller = 0; real t, *w_rls; t_topology top; int ePBC; t_atoms *pdbatoms, *refatoms; matrix box, pdbbox; rvec *x, *pdbx, *xref; t_trxstatus *status; const char *label; FILE *fp; /* the graphics file */ const char *devfn, *dirfn; int resind; gmx_bool bReadPDB; int *index; int isize; char *grpnames; real bfac, pdb_bfac, *Uaver; double **U, *xav; int aid; rvec *rmsd_x = nullptr; double *rmsf, invcount, totmass; int d; real count = 0; rvec xcm; gmx_rmpbc_t gpbc = nullptr; gmx_output_env_t *oenv; const char *leg[2] = { "MD", "X-Ray" }; t_filenm fnm[] = { { efTRX, "-f", nullptr, ffREAD }, { efTPS, nullptr, nullptr, ffREAD }, { efNDX, nullptr, nullptr, ffOPTRD }, { efPDB, "-q", nullptr, ffOPTRD }, { efPDB, "-oq", "bfac", ffOPTWR }, { efPDB, "-ox", "xaver", ffOPTWR }, { efXVG, "-o", "rmsf", ffWRITE }, { efXVG, "-od", "rmsdev", ffOPTWR }, { efXVG, "-oc", "correl", ffOPTWR }, { efLOG, "-dir", "rmsf", ffOPTWR } }; #define NFILE asize(fnm) if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pargs), pargs, asize(desc), desc, 0, nullptr, &oenv)) { return 0; } bReadPDB = ftp2bSet(efPDB, NFILE, fnm); devfn = opt2fn_null("-od", NFILE, fnm); dirfn = opt2fn_null("-dir", NFILE, fnm); read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &xref, nullptr, box, TRUE); const char *title = *top.name; snew(w_rls, top.atoms.nr); fprintf(stderr, "Select group(s) for root mean square calculation\n"); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &isize, &index, &grpnames); /* Set the weight */ for (i = 0; i < isize; i++) { w_rls[index[i]] = top.atoms.atom[index[i]].m; } /* Malloc the rmsf arrays */ snew(xav, isize*DIM); snew(U, isize); for (i = 0; i < isize; i++) { snew(U[i], DIM*DIM); } snew(rmsf, isize); if (devfn) { snew(rmsd_x, isize); } if (bReadPDB) { t_topology *top_pdb; snew(top_pdb, 1); /* Read coordinates twice */ read_tps_conf(opt2fn("-q", NFILE, fnm), top_pdb, nullptr, nullptr, nullptr, pdbbox, FALSE); snew(pdbatoms, 1); *pdbatoms = top_pdb->atoms; read_tps_conf(opt2fn("-q", NFILE, fnm), top_pdb, nullptr, &pdbx, nullptr, pdbbox, FALSE); /* TODO Should this assert that top_pdb->atoms.nr == top.atoms.nr? * See discussion at https://gerrit.gromacs.org/#/c/6430/1 */ title = *top_pdb->name; snew(refatoms, 1); *refatoms = top_pdb->atoms; sfree(top_pdb); } else { pdbatoms = &top.atoms; refatoms = &top.atoms; pdbx = xref; snew(pdbatoms->pdbinfo, pdbatoms->nr); pdbatoms->havePdbInfo = TRUE; copy_mat(box, pdbbox); } if (bFit) { sub_xcm(xref, isize, index, top.atoms.atom, xcm, FALSE); } natom = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); if (bFit) { gpbc = gmx_rmpbc_init(&top.idef, ePBC, natom); } /* Now read the trj again to compute fluctuations */ teller = 0; do { if (bFit) { /* Remove periodic boundary */ gmx_rmpbc(gpbc, natom, box, x); /* Set center of mass to zero */ sub_xcm(x, isize, index, top.atoms.atom, xcm, FALSE); /* Fit to reference structure */ do_fit(natom, w_rls, xref, x); } /* Calculate Anisotropic U Tensor */ for (i = 0; i < isize; i++) { aid = index[i]; for (d = 0; d < DIM; d++) { xav[i*DIM + d] += x[aid][d]; for (m = 0; m < DIM; m++) { U[i][d*DIM + m] += x[aid][d]*x[aid][m]; } } } if (devfn) { /* Calculate RMS Deviation */ for (i = 0; (i < isize); i++) { aid = index[i]; for (d = 0; (d < DIM); d++) { rmsd_x[i][d] += gmx::square(x[aid][d]-xref[aid][d]); } } } count += 1.0; teller++; } while (read_next_x(oenv, status, &t, x, box)); close_trx(status); if (bFit) { gmx_rmpbc_done(gpbc); } invcount = 1.0/count; snew(Uaver, DIM*DIM); totmass = 0; for (i = 0; i < isize; i++) { for (d = 0; d < DIM; d++) { xav[i*DIM + d] *= invcount; } for (d = 0; d < DIM; d++) { for (m = 0; m < DIM; m++) { U[i][d*DIM + m] = U[i][d*DIM + m]*invcount - xav[i*DIM + d]*xav[i*DIM + m]; Uaver[3*d+m] += top.atoms.atom[index[i]].m*U[i][d*DIM + m]; } } totmass += top.atoms.atom[index[i]].m; } for (d = 0; d < DIM*DIM; d++) { Uaver[d] /= totmass; } if (bRes) { for (d = 0; d < DIM*DIM; d++) { average_residues(nullptr, U, d, isize, index, w_rls, &top.atoms); } } if (bAniso) { for (i = 0; i < isize; i++) { aid = index[i]; pdbatoms->pdbinfo[aid].bAnisotropic = TRUE; pdbatoms->pdbinfo[aid].uij[U11] = static_cast<int>(1e6*U[i][XX*DIM + XX]); pdbatoms->pdbinfo[aid].uij[U22] = static_cast<int>(1e6*U[i][YY*DIM + YY]); pdbatoms->pdbinfo[aid].uij[U33] = static_cast<int>(1e6*U[i][ZZ*DIM + ZZ]); pdbatoms->pdbinfo[aid].uij[U12] = static_cast<int>(1e6*U[i][XX*DIM + YY]); pdbatoms->pdbinfo[aid].uij[U13] = static_cast<int>(1e6*U[i][XX*DIM + ZZ]); pdbatoms->pdbinfo[aid].uij[U23] = static_cast<int>(1e6*U[i][YY*DIM + ZZ]); } } if (bRes) { label = "Residue"; } else { label = "Atom"; } for (i = 0; i < isize; i++) { rmsf[i] = U[i][XX*DIM + XX] + U[i][YY*DIM + YY] + U[i][ZZ*DIM + ZZ]; } if (dirfn) { fprintf(stdout, "\n"); print_dir(stdout, Uaver); fp = gmx_ffopen(dirfn, "w"); print_dir(fp, Uaver); gmx_ffclose(fp); } for (i = 0; i < isize; i++) { sfree(U[i]); } sfree(U); /* Write RMSF output */ if (bReadPDB) { bfac = 8.0*M_PI*M_PI/3.0*100; fp = xvgropen(ftp2fn(efXVG, NFILE, fnm), "B-Factors", label, "(A\\b\\S\\So\\N\\S2\\N)", oenv); xvgr_legend(fp, 2, leg, oenv); for (i = 0; (i < isize); i++) { if (!bRes || i+1 == isize || top.atoms.atom[index[i]].resind != top.atoms.atom[index[i+1]].resind) { resind = top.atoms.atom[index[i]].resind; pdb_bfac = find_pdb_bfac(pdbatoms, &top.atoms.resinfo[resind], *(top.atoms.atomname[index[i]])); fprintf(fp, "%5d %10.5f %10.5f\n", bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : index[i]+1, rmsf[i]*bfac, pdb_bfac); } } xvgrclose(fp); } else { fp = xvgropen(ftp2fn(efXVG, NFILE, fnm), "RMS fluctuation", label, "(nm)", oenv); for (i = 0; i < isize; i++) { if (!bRes || i+1 == isize || top.atoms.atom[index[i]].resind != top.atoms.atom[index[i+1]].resind) { fprintf(fp, "%5d %8.4f\n", bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : index[i]+1, std::sqrt(rmsf[i])); } } xvgrclose(fp); } for (i = 0; i < isize; i++) { pdbatoms->pdbinfo[index[i]].bfac = 800*M_PI*M_PI/3.0*rmsf[i]; } if (devfn) { for (i = 0; i < isize; i++) { rmsf[i] = (rmsd_x[i][XX]+rmsd_x[i][YY]+rmsd_x[i][ZZ])/count; } if (bRes) { average_residues(rmsf, nullptr, 0, isize, index, w_rls, &top.atoms); } /* Write RMSD output */ fp = xvgropen(devfn, "RMS Deviation", label, "(nm)", oenv); for (i = 0; i < isize; i++) { if (!bRes || i+1 == isize || top.atoms.atom[index[i]].resind != top.atoms.atom[index[i+1]].resind) { fprintf(fp, "%5d %8.4f\n", bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : index[i]+1, std::sqrt(rmsf[i])); } } xvgrclose(fp); } if (opt2bSet("-oq", NFILE, fnm)) { /* Write a .pdb file with B-factors and optionally anisou records */ for (i = 0; i < isize; i++) { rvec_inc(pdbx[index[i]], xcm); } write_sto_conf_indexed(opt2fn("-oq", NFILE, fnm), title, pdbatoms, pdbx, nullptr, ePBC, pdbbox, isize, index); } if (opt2bSet("-ox", NFILE, fnm)) { rvec *bFactorX; snew(bFactorX, top.atoms.nr); for (i = 0; i < isize; i++) { for (d = 0; d < DIM; d++) { bFactorX[index[i]][d] = xcm[d] + xav[i*DIM + d]; } } /* Write a .pdb file with B-factors and optionally anisou records */ write_sto_conf_indexed(opt2fn("-ox", NFILE, fnm), title, pdbatoms, bFactorX, nullptr, ePBC, pdbbox, isize, index); sfree(bFactorX); } if (bAniso) { correlate_aniso(opt2fn("-oc", NFILE, fnm), refatoms, pdbatoms, oenv); do_view(oenv, opt2fn("-oc", NFILE, fnm), "-nxy"); } do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); if (devfn) { do_view(oenv, opt2fn("-od", NFILE, fnm), "-nxy"); } return 0; }
int gmx_polystat(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] plots static properties of polymers as a function of time", "and prints the average.[PAR]", "By default it determines the average end-to-end distance and radii", "of gyration of polymers. It asks for an index group and split this", "into molecules. The end-to-end distance is then determined using", "the first and the last atom in the index group for each molecules.", "For the radius of gyration the total and the three principal components", "for the average gyration tensor are written.", "With option [TT]-v[tt] the eigenvectors are written.", "With option [TT]-pc[tt] also the average eigenvalues of the individual", "gyration tensors are written.", "With option [TT]-i[tt] the mean square internal distances are", "written.[PAR]", "With option [TT]-p[tt] the persistence length is determined.", "The chosen index group should consist of atoms that are", "consecutively bonded in the polymer mainchains.", "The persistence length is then determined from the cosine of", "the angles between bonds with an index difference that is even,", "the odd pairs are not used, because straight polymer backbones", "are usually all trans and therefore only every second bond aligns.", "The persistence length is defined as number of bonds where", "the average cos reaches a value of 1/e. This point is determined", "by a linear interpolation of [LOG]<cos>[log]." }; static gmx_bool bMW = TRUE, bPC = FALSE; t_pargs pa[] = { { "-mw", FALSE, etBOOL, {&bMW}, "Use the mass weighting for radii of gyration" }, { "-pc", FALSE, etBOOL, {&bPC}, "Plot average eigenvalues" } }; t_filenm fnm[] = { { efTPR, nullptr, nullptr, ffREAD }, { efTRX, "-f", nullptr, ffREAD }, { efNDX, nullptr, nullptr, ffOPTRD }, { efXVG, "-o", "polystat", ffWRITE }, { efXVG, "-v", "polyvec", ffOPTWR }, { efXVG, "-p", "persist", ffOPTWR }, { efXVG, "-i", "intdist", ffOPTWR } }; #define NFILE asize(fnm) t_topology *top; gmx_output_env_t *oenv; int ePBC; int isize, *index, nmol, *molind, mol, nat_min = 0, nat_max = 0; char *grpname; t_trxstatus *status; real t; rvec *x, *bond = nullptr; matrix box; int natoms, i, j, frame, ind0, ind1, a, d, d2, ord[DIM] = {0}; dvec cm, sum_eig = {0, 0, 0}; double **gyr, **gyr_all, eig[DIM], **eigv; double sum_eed2, sum_eed2_tot, sum_gyro, sum_gyro_tot, sum_pers_tot; int *ninp = nullptr; double *sum_inp = nullptr, pers; double *intd, ymax, ymin; double mmol, m; char title[STRLEN]; FILE *out, *outv, *outp, *outi; const char *leg[8] = { "end to end", "<R\\sg\\N>", "<R\\sg\\N> eig1", "<R\\sg\\N> eig2", "<R\\sg\\N> eig3", "<R\\sg\\N eig1>", "<R\\sg\\N eig2>", "<R\\sg\\N eig3>" }; char **legp, buf[STRLEN]; gmx_rmpbc_t gpbc = nullptr; if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv)) { return 0; } snew(top, 1); ePBC = read_tpx_top(ftp2fn(efTPR, NFILE, fnm), nullptr, box, &natoms, nullptr, nullptr, top); fprintf(stderr, "Select a group of polymer mainchain atoms:\n"); get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &isize, &index, &grpname); snew(molind, top->mols.nr+1); nmol = 0; mol = -1; for (i = 0; i < isize; i++) { if (i == 0 || index[i] >= top->mols.index[mol+1]) { molind[nmol++] = i; do { mol++; } while (index[i] >= top->mols.index[mol+1]); } } molind[nmol] = i; nat_min = top->atoms.nr; nat_max = 0; for (mol = 0; mol < nmol; mol++) { nat_min = std::min(nat_min, molind[mol+1]-molind[mol]); nat_max = std::max(nat_max, molind[mol+1]-molind[mol]); } fprintf(stderr, "Group %s consists of %d molecules\n", grpname, nmol); fprintf(stderr, "Group size per molecule, min: %d atoms, max %d atoms\n", nat_min, nat_max); sprintf(title, "Size of %d polymers", nmol); out = xvgropen(opt2fn("-o", NFILE, fnm), title, output_env_get_xvgr_tlabel(oenv), "(nm)", oenv); xvgr_legend(out, bPC ? 8 : 5, leg, oenv); if (opt2bSet("-v", NFILE, fnm)) { outv = xvgropen(opt2fn("-v", NFILE, fnm), "Principal components", output_env_get_xvgr_tlabel(oenv), "(nm)", oenv); snew(legp, DIM*DIM); for (d = 0; d < DIM; d++) { for (d2 = 0; d2 < DIM; d2++) { sprintf(buf, "eig%d %c", d+1, 'x'+d2); legp[d*DIM+d2] = gmx_strdup(buf); } } xvgr_legend(outv, DIM*DIM, (const char**)legp, oenv); } else { outv = nullptr; } if (opt2bSet("-p", NFILE, fnm)) { outp = xvgropen(opt2fn("-p", NFILE, fnm), "Persistence length", output_env_get_xvgr_tlabel(oenv), "bonds", oenv); snew(bond, nat_max-1); snew(sum_inp, nat_min/2); snew(ninp, nat_min/2); } else { outp = nullptr; } if (opt2bSet("-i", NFILE, fnm)) { outi = xvgropen(opt2fn("-i", NFILE, fnm), "Internal distances", "n", "<R\\S2\\N(n)>/n (nm\\S2\\N)", oenv); i = index[molind[1]-1] - index[molind[0]]; /* Length of polymer -1 */ snew(intd, i); } else { intd = nullptr; outi = nullptr; } natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); snew(gyr, DIM); snew(gyr_all, DIM); snew(eigv, DIM); for (d = 0; d < DIM; d++) { snew(gyr[d], DIM); snew(gyr_all[d], DIM); snew(eigv[d], DIM); } frame = 0; sum_eed2_tot = 0; sum_gyro_tot = 0; sum_pers_tot = 0; gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms); do { gmx_rmpbc(gpbc, natoms, box, x); sum_eed2 = 0; for (d = 0; d < DIM; d++) { clear_dvec(gyr_all[d]); } if (bPC) { clear_dvec(sum_eig); } if (outp) { for (i = 0; i < nat_min/2; i++) { sum_inp[i] = 0; ninp[i] = 0; } } for (mol = 0; mol < nmol; mol++) { ind0 = molind[mol]; ind1 = molind[mol+1]; /* Determine end to end distance */ sum_eed2 += distance2(x[index[ind0]], x[index[ind1-1]]); /* Determine internal distances */ if (outi) { calc_int_dist(intd, x, index[ind0], index[ind1-1]); } /* Determine the radius of gyration */ clear_dvec(cm); for (d = 0; d < DIM; d++) { clear_dvec(gyr[d]); } mmol = 0; for (i = ind0; i < ind1; i++) { a = index[i]; if (bMW) { m = top->atoms.atom[a].m; } else { m = 1; } mmol += m; for (d = 0; d < DIM; d++) { cm[d] += m*x[a][d]; for (d2 = 0; d2 < DIM; d2++) { gyr[d][d2] += m*x[a][d]*x[a][d2]; } } } dsvmul(1/mmol, cm, cm); for (d = 0; d < DIM; d++) { for (d2 = 0; d2 < DIM; d2++) { gyr[d][d2] = gyr[d][d2]/mmol - cm[d]*cm[d2]; gyr_all[d][d2] += gyr[d][d2]; } } if (bPC) { gyro_eigen(gyr, eig, eigv, ord); for (d = 0; d < DIM; d++) { sum_eig[d] += eig[ord[d]]; } } if (outp) { for (i = ind0; i < ind1-1; i++) { rvec_sub(x[index[i+1]], x[index[i]], bond[i-ind0]); unitv(bond[i-ind0], bond[i-ind0]); } for (i = ind0; i < ind1-1; i++) { for (j = 0; (i+j < ind1-1 && j < nat_min/2); j += 2) { sum_inp[j] += iprod(bond[i-ind0], bond[i-ind0+j]); ninp[j]++; } } } } sum_eed2 /= nmol; sum_gyro = 0; for (d = 0; d < DIM; d++) { for (d2 = 0; d2 < DIM; d2++) { gyr_all[d][d2] /= nmol; } sum_gyro += gyr_all[d][d]; } gyro_eigen(gyr_all, eig, eigv, ord); fprintf(out, "%10.3f %8.4f %8.4f %8.4f %8.4f %8.4f", t*output_env_get_time_factor(oenv), std::sqrt(sum_eed2), sqrt(sum_gyro), std::sqrt(eig[ord[0]]), std::sqrt(eig[ord[1]]), std::sqrt(eig[ord[2]])); if (bPC) { for (d = 0; d < DIM; d++) { fprintf(out, " %8.4f", std::sqrt(sum_eig[d]/nmol)); } } fprintf(out, "\n"); if (outv) { fprintf(outv, "%10.3f", t*output_env_get_time_factor(oenv)); for (d = 0; d < DIM; d++) { for (d2 = 0; d2 < DIM; d2++) { fprintf(outv, " %6.3f", eigv[ord[d]][d2]); } } fprintf(outv, "\n"); } sum_eed2_tot += sum_eed2; sum_gyro_tot += sum_gyro; if (outp) { i = -1; for (j = 0; j < nat_min/2; j += 2) { sum_inp[j] /= ninp[j]; if (i == -1 && sum_inp[j] <= std::exp(-1.0)) { i = j; } } if (i == -1) { pers = j; } else { /* Do linear interpolation on a log scale */ pers = i - 2.0 + 2.0*(std::log(sum_inp[i-2]) + 1.0)/(std::log(sum_inp[i-2]) - std::log(sum_inp[i])); } fprintf(outp, "%10.3f %8.4f\n", t*output_env_get_time_factor(oenv), pers); sum_pers_tot += pers; } frame++; } while (read_next_x(oenv, status, &t, x, box)); gmx_rmpbc_done(gpbc); close_trx(status); xvgrclose(out); if (outv) { xvgrclose(outv); } if (outp) { xvgrclose(outp); } sum_eed2_tot /= frame; sum_gyro_tot /= frame; sum_pers_tot /= frame; fprintf(stdout, "\nAverage end to end distance: %.3f (nm)\n", std::sqrt(sum_eed2_tot)); fprintf(stdout, "\nAverage radius of gyration: %.3f (nm)\n", std::sqrt(sum_gyro_tot)); if (opt2bSet("-p", NFILE, fnm)) { fprintf(stdout, "\nAverage persistence length: %.2f bonds\n", sum_pers_tot); } /* Handle printing of internal distances. */ if (outi) { if (output_env_get_print_xvgr_codes(oenv)) { fprintf(outi, "@ xaxes scale Logarithmic\n"); } ymax = -1; ymin = 1e300; j = index[molind[1]-1] - index[molind[0]]; /* Polymer length -1. */ for (i = 0; i < j; i++) { intd[i] /= (i + 1) * frame * nmol; if (intd[i] > ymax) { ymax = intd[i]; } if (intd[i] < ymin) { ymin = intd[i]; } } xvgr_world(outi, 1, ymin, j, ymax, oenv); for (i = 0; i < j; i++) { fprintf(outi, "%d %8.4f\n", i+1, intd[i]); } xvgrclose(outi); } do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); if (opt2bSet("-v", NFILE, fnm)) { do_view(oenv, opt2fn("-v", NFILE, fnm), "-nxy"); } if (opt2bSet("-p", NFILE, fnm)) { do_view(oenv, opt2fn("-p", NFILE, fnm), "-nxy"); } return 0; }
int gmx_mdmat(int argc, char *argv[]) { const char *desc[] = { "[TT]g_mdmat[tt] makes distance matrices consisting of the smallest distance", "between residue pairs. With [TT]-frames[tt], these distance matrices can be", "stored in order to see differences in tertiary structure as a", "function of time. If you choose your options unwisely, this may generate", "a large output file. By default, only an averaged matrix over the whole", "trajectory is output.", "Also a count of the number of different atomic contacts between", "residues over the whole trajectory can be made.", "The output can be processed with [TT]xpm2ps[tt] to make a PostScript (tm) plot." }; static real truncate = 1.5; static gmx_bool bAtom = FALSE; static int nlevels = 40; t_pargs pa[] = { { "-t", FALSE, etREAL, {&truncate}, "trunc distance" }, { "-nlevels", FALSE, etINT, {&nlevels}, "Discretize distance in this number of levels" } }; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXPM, "-mean", "dm", ffWRITE }, { efXPM, "-frames", "dmf", ffOPTWR }, { efXVG, "-no", "num", ffOPTWR }, }; #define NFILE asize(fnm) FILE *out = NULL, *fp; t_topology top; int ePBC; t_atoms useatoms; int isize; atom_id *index; char *grpname; int *rndx, *natm, prevres, newres; int i, j, nres, natoms, nframes, it, trxnat; t_trxstatus *status; int nr0; gmx_bool bCalcN, bFrames; real t, ratio; char title[256], label[234]; t_rgb rlo, rhi; rvec *x; real **mdmat, *resnr, **totmdmat; int **nmat, **totnmat; real *mean_n; int *tot_n; matrix box; output_env_t oenv; gmx_rmpbc_t gpbc = NULL; CopyRight(stderr, argv[0]); parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv); fprintf(stderr, "Will truncate at %f nm\n", truncate); bCalcN = opt2bSet("-no", NFILE, fnm); bFrames = opt2bSet("-frames", NFILE, fnm); if (bCalcN) { fprintf(stderr, "Will calculate number of different contacts\n"); } read_tps_conf(ftp2fn(efTPS, NFILE, fnm), title, &top, &ePBC, &x, NULL, box, FALSE); fprintf(stderr, "Select group for analysis\n"); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &isize, &index, &grpname); natoms = isize; snew(useatoms.atom, natoms); snew(useatoms.atomname, natoms); useatoms.nres = 0; snew(useatoms.resinfo, natoms); prevres = top.atoms.atom[index[0]].resind; newres = 0; for (i = 0; (i < isize); i++) { int ii = index[i]; useatoms.atomname[i] = top.atoms.atomname[ii]; if (top.atoms.atom[ii].resind != prevres) { prevres = top.atoms.atom[ii].resind; newres++; useatoms.resinfo[i] = top.atoms.resinfo[prevres]; if (debug) { fprintf(debug, "New residue: atom %5s %5s %6d, index entry %5d, newres %5d\n", *(top.atoms.resinfo[top.atoms.atom[ii].resind].name), *(top.atoms.atomname[ii]), ii, i, newres); } } useatoms.atom[i].resind = newres; } useatoms.nres = newres+1; useatoms.nr = isize; rndx = res_ndx(&(useatoms)); natm = res_natm(&(useatoms)); nres = useatoms.nres; fprintf(stderr, "There are %d residues with %d atoms\n", nres, natoms); snew(resnr, nres); snew(mdmat, nres); snew(nmat, nres); snew(totnmat, nres); snew(mean_n, nres); snew(tot_n, nres); for (i = 0; (i < nres); i++) { snew(mdmat[i], nres); snew(nmat[i], natoms); snew(totnmat[i], natoms); resnr[i] = i+1; } snew(totmdmat, nres); for (i = 0; (i < nres); i++) { snew(totmdmat[i], nres); } trxnat = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); nframes = 0; rlo.r = 1.0, rlo.g = 1.0, rlo.b = 1.0; rhi.r = 0.0, rhi.g = 0.0, rhi.b = 0.0; gpbc = gmx_rmpbc_init(&top.idef, ePBC, trxnat, box); if (bFrames) { out = opt2FILE("-frames", NFILE, fnm, "w"); } do { gmx_rmpbc(gpbc, trxnat, box, x); nframes++; calc_mat(nres, natoms, rndx, x, index, truncate, mdmat, nmat, ePBC, box); for (i = 0; (i < nres); i++) { for (j = 0; (j < natoms); j++) { if (nmat[i][j]) { totnmat[i][j]++; } } } for (i = 0; (i < nres); i++) { for (j = 0; (j < nres); j++) { totmdmat[i][j] += mdmat[i][j]; } } if (bFrames) { sprintf(label, "t=%.0f ps", t); write_xpm(out, 0, label, "Distance (nm)", "Residue Index", "Residue Index", nres, nres, resnr, resnr, mdmat, 0, truncate, rlo, rhi, &nlevels); } } while (read_next_x(oenv, status, &t, trxnat, x, box)); fprintf(stderr, "\n"); close_trj(status); gmx_rmpbc_done(gpbc); if (bFrames) { ffclose(out); } fprintf(stderr, "Processed %d frames\n", nframes); for (i = 0; (i < nres); i++) { for (j = 0; (j < nres); j++) { totmdmat[i][j] /= nframes; } } write_xpm(opt2FILE("-mean", NFILE, fnm, "w"), 0, "Mean smallest distance", "Distance (nm)", "Residue Index", "Residue Index", nres, nres, resnr, resnr, totmdmat, 0, truncate, rlo, rhi, &nlevels); if (bCalcN) { tot_nmat(nres, natoms, nframes, totnmat, tot_n, mean_n); fp = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Increase in number of contacts", "Residue", "Ratio", oenv); fprintf(fp, "@ legend on\n"); fprintf(fp, "@ legend box on\n"); fprintf(fp, "@ legend loctype view\n"); fprintf(fp, "@ legend 0.75, 0.8\n"); fprintf(fp, "@ legend string 0 \"Total/mean\"\n"); fprintf(fp, "@ legend string 1 \"Total\"\n"); fprintf(fp, "@ legend string 2 \"Mean\"\n"); fprintf(fp, "@ legend string 3 \"# atoms\"\n"); fprintf(fp, "@ legend string 4 \"Mean/# atoms\"\n"); fprintf(fp, "#%3s %8s %3s %8s %3s %8s\n", "res", "ratio", "tot", "mean", "natm", "mean/atm"); for (i = 0; (i < nres); i++) { if (mean_n[i] == 0) { ratio = 1; } else { ratio = tot_n[i]/mean_n[i]; } fprintf(fp, "%3d %8.3f %3d %8.3f %3d %8.3f\n", i+1, ratio, tot_n[i], mean_n[i], natm[i], mean_n[i]/natm[i]); } ffclose(fp); } thanx(stderr); return 0; }
int main(int argc,char *argv[]) { const char *desc[] = { "[TT]do_multiprot[tt] ", "reads a trajectory file and aligns it to a reference structure ", "each time frame", "calling the multiprot program. This allows you to use a reference", "structure whose sequence is different than that of the protein in the ", "trajectory, since the alignment is based on the geometry, not sequence.", "The output of [TT]do_multiprot[tt] includes the rmsd and the number of residues", "on which it was calculated.", "[PAR]", "An aligned trajectory file is generated with the [TT]-ox[tt] option.[PAR]", "With the [TT]-cr[tt] option, the number of hits in the alignment is given", "per residue. This number can be between 0 and the number of frames, and", "indicates the structural conservation of this residue.[PAR]", "If you do not have the [TT]multiprot[tt] program, get it. [TT]do_multiprot[tt] assumes", "that the [TT]multiprot[tt] executable is [TT]/usr/local/bin/multiprot[tt]. If this is ", "not the case, then you should set an environment variable [BB]MULTIPROT[bb]", "pointing to the [TT]multiprot[tt] executable, e.g.: [PAR]", "[TT]setenv MULTIPROT /usr/MultiProtInstall/multiprot.Linux[tt][PAR]", "Note that at the current implementation only binary alignment (your", "molecule to a reference) is supported. In addition, note that the ", "by default [TT]multiprot[tt] aligns the two proteins on their C-alpha carbons.", "and that this depends on the [TT]multiprot[tt] parameters which are not dealt ", "with here. Thus, the C-alpha carbons is expected to give the same " "results as choosing the whole protein and will be slightly faster.[PAR]", "For information about [TT]multiprot[tt], see:", "http://bioinfo3d.cs.tau.ac.il/MultiProt/.[PAR]" }; static bool bVerbose; t_pargs pa[] = { { "-v", FALSE, etBOOL, {&bVerbose}, "HIDDENGenerate miles of useless information" } }; const char *bugs[] = { "The program is very slow, since multiprot is run externally" }; t_trxstatus *status; t_trxstatus *trxout=NULL; FILE *tapein,*fo,*frc,*tmpf,*out=NULL,*fres=NULL; const char *fnRef; const char *fn="2_sol.res"; t_topology top; int ePBC; t_atoms *atoms,ratoms,useatoms; t_trxframe fr; t_pdbinfo p; int nres,nres2,nr0; real t; int i,j,natoms,nratoms,nframe=0,model_nr=-1; int cur_res,prev_res; int nout; t_countres *countres=NULL; matrix box,rbox; int gnx; char *grpnm,*ss_str; atom_id *index; rvec *xp,*x,*xr; char pdbfile[32],refpdb[256],title[256],rtitle[256],filemode[5]; char out_title[256]; char multiprot[256],*mptr; int ftp; int outftp=-1; real rmsd; bool bTrjout,bCountres; const char *TrjoutFile=NULL; output_env_t oenv; static rvec translation={0,0,0},rotangles={0,0,0}; gmx_rmpbc_t gpbc=NULL; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efSTX, "-r", NULL , ffREAD }, { efXVG, "-o", "rmss", ffWRITE }, { efXVG, "-rc", "rescount", ffWRITE}, { efXVG, "-cr", "countres", ffOPTWR}, { efTRX, "-ox", "aligned", ffOPTWR } }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_TIME_UNIT, NFILE,fnm, asize(pa),pa, asize(desc),desc, asize(bugs),bugs,&oenv ); fnRef=opt2fn("-r",NFILE,fnm); bTrjout = opt2bSet("-ox",NFILE,fnm); bCountres= opt2bSet("-cr",NFILE,fnm); if (bTrjout) { TrjoutFile = opt2fn_null("-ox",NFILE,fnm); } read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xp,NULL,box,FALSE); gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,box); atoms=&(top.atoms); ftp=fn2ftp(fnRef); get_stx_coordnum(fnRef,&nratoms); init_t_atoms(&ratoms,nratoms,TRUE); snew(xr,nratoms); read_stx_conf(fnRef,rtitle,&ratoms,xr,NULL,&ePBC,rbox); if (bVerbose) { fprintf(stderr,"Read %d atoms\n",atoms->nr); fprintf(stderr,"Read %d reference atoms\n",ratoms.nr); } if (bCountres) { snew(countres,ratoms.nres); j=0; cur_res=0; for (i=0;i<ratoms.nr;i++) { prev_res=cur_res; cur_res=ratoms.atom[i].resind; if (cur_res != prev_res) { countres[j].resnr=cur_res; countres[j].count=0; j++; } } } get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&gnx,&index,&grpnm); nres=0; nr0=-1; for(i=0; (i<gnx); i++) { if (atoms->atom[index[i]].resind != nr0) { nr0=atoms->atom[index[i]].resind; nres++; } } fprintf(stderr,"There are %d residues in your selected group\n",nres); strcpy(pdbfile,"ddXXXXXX"); gmx_tmpnam(pdbfile); if ((tmpf = fopen(pdbfile,"w")) == NULL) { sprintf(pdbfile,"%ctmp%cfilterXXXXXX",DIR_SEPARATOR,DIR_SEPARATOR); gmx_tmpnam(pdbfile); if ((tmpf = fopen(pdbfile,"w")) == NULL) { gmx_fatal(FARGS,"Can not open tmp file %s",pdbfile); } } else { gmx_ffclose(tmpf); } if (ftp != efPDB) { strcpy(refpdb,"ddXXXXXX"); gmx_tmpnam(refpdb); strcat(refpdb,".pdb"); write_sto_conf(refpdb,rtitle,&ratoms,xr,NULL,ePBC,rbox); } else { strcpy(refpdb,fnRef); } if ((mptr=getenv("MULTIPROT")) == NULL) { mptr="/usr/local/bin/multiprot"; } if (!gmx_fexist(mptr)) { gmx_fatal(FARGS,"MULTIPROT executable (%s) does not exist (use setenv MULTIPROT)", mptr); } sprintf (multiprot,"%s %s %s > /dev/null %s", mptr, refpdb, pdbfile, "2> /dev/null"); if (bVerbose) fprintf(stderr,"multiprot cmd='%s'\n",multiprot); if (!read_first_frame(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&fr,TRX_READ_X)) gmx_fatal(FARGS,"Could not read a frame from %s",ftp2fn(efTRX,NFILE,fnm)); natoms = fr.natoms; if (bTrjout) { nout=natoms; /* open file now */ outftp=fn2ftp(TrjoutFile); if (bVerbose) fprintf(stderr,"Will write %s: %s\n",ftp2ext(ftp),ftp2desc(outftp)); strcpy(filemode,"w"); switch (outftp) { case efXTC: case efG87: case efTRR: case efTRJ: out=NULL; trxout = open_trx(TrjoutFile,filemode); break; case efGRO: case efG96: case efPDB: /* Make atoms struct for output in GRO or PDB files */ /* get memory for stuff to go in pdb file */ init_t_atoms(&useatoms,nout,FALSE); sfree(useatoms.resinfo); useatoms.resinfo=atoms->resinfo; for(i=0;(i<nout);i++) { useatoms.atomname[i]=atoms->atomname[i]; useatoms.atom[i]=atoms->atom[i]; useatoms.nres=max(useatoms.nres,useatoms.atom[i].resind+1); } useatoms.nr=nout; out=gmx_ffopen(TrjoutFile,filemode); break; } } if (natoms > atoms->nr) { gmx_fatal(FARGS,"\nTrajectory does not match topology!"); } if (gnx > natoms) { gmx_fatal(FARGS,"\nTrajectory does not match selected group!"); } fo = xvgropen(opt2fn("-o",NFILE,fnm),"RMSD","Time (ps)","RMSD (nm)",oenv); frc = xvgropen(opt2fn("-rc",NFILE,fnm),"Number of Residues in the alignment","Time (ps)","Residues",oenv); do { t = output_env_conv_time(oenv,fr.time); gmx_rmpbc(gpbc,natoms,fr.box,fr.x); tapein=gmx_ffopen(pdbfile,"w"); write_pdbfile_indexed(tapein,NULL,atoms,fr.x,ePBC,fr.box,' ',-1,gnx,index,NULL,TRUE); gmx_ffclose(tapein); system(multiprot); remove(pdbfile); process_multiprot_output(fn, &rmsd, &nres2,rotangles,translation,bCountres,countres); fprintf(fo,"%12.7f",t); fprintf(fo," %12.7f\n",rmsd); fprintf(frc,"%12.7f",t); fprintf(frc,"%12d\n",nres2); if (bTrjout) { rotate_conf(natoms,fr.x,NULL,rotangles[XX],rotangles[YY],rotangles[ZZ]); for(i=0; i<natoms; i++) { rvec_inc(fr.x[i],translation); } switch(outftp) { case efTRJ: case efTRR: case efG87: case efXTC: write_trxframe(trxout,&fr,NULL); break; case efGRO: case efG96: case efPDB: sprintf(out_title,"Generated by do_multiprot : %s t= %g %s", title,output_env_conv_time(oenv,fr.time),output_env_get_time_unit(oenv)); switch(outftp) { case efGRO: write_hconf_p(out,out_title,&useatoms,prec2ndec(fr.prec), fr.x,NULL,fr.box); break; case efPDB: fprintf(out,"REMARK GENERATED BY DO_MULTIPROT\n"); sprintf(out_title,"%s t= %g %s",title,output_env_conv_time(oenv,fr.time),output_env_get_time_unit(oenv)); /* if reading from pdb, we want to keep the original model numbering else we write the output frame number plus one, because model 0 is not allowed in pdb */ if (ftp==efPDB && fr.step > model_nr) { model_nr = fr.step; } else { model_nr++; } write_pdbfile(out,out_title,&useatoms,fr.x,ePBC,fr.box,' ',model_nr,NULL,TRUE); break; case efG96: fr.title = out_title; fr.bTitle = (nframe == 0); fr.bAtoms = FALSE; fr.bStep = TRUE; fr.bTime = TRUE; write_g96_conf(out,&fr,-1,NULL); } break; } } nframe++; } while(read_next_frame(oenv,status,&fr)); if (bCountres) { fres= xvgropen(opt2fn("-cr",NFILE,fnm),"Number of frames in which the residues are aligned to","Residue","Number",oenv); for (i=0;i<ratoms.nres;i++) { fprintf(fres,"%10d %12d\n",countres[i].resnr,countres[i].count); } gmx_ffclose(fres); } gmx_ffclose(fo); gmx_ffclose(frc); fprintf(stderr,"\n"); close_trj(status); if (trxout != NULL) { close_trx(trxout); } else if (out != NULL) { gmx_ffclose(out); } view_all(oenv,NFILE, fnm); sfree(xr); if (bCountres) { sfree(countres); } free_t_atoms(&ratoms,TRUE); if (bTrjout) { if (outftp==efPDB || outftp==efGRO || outftp==efG96) { free_t_atoms(&useatoms,TRUE); } } gmx_thanx(stderr); return 0; }
int gmx_spatial(int argc,char *argv[]) { const char *desc[] = { "g_spatial calculates the spatial distribution function and ", "outputs it in a form that can be read by VMD as Gaussian98 cube format. ", "This was developed from template.c (gromacs-3.3). ", "For a system of 32K atoms and a 50ns trajectory, the SDF can be generated ", "in about 30 minutes, with most of the time dedicated to the two runs through ", "trjconv that are required to center everything properly. ", "This also takes a whole bunch of space (3 copies of the xtc file). ", "Still, the pictures are pretty and very informative when the fitted selection is properly made. ", "3-4 atoms in a widely mobile group like a free amino acid in solution works ", "well, or select the protein backbone in a stable folded structure to get the SDF ", "of solvent and look at the time-averaged solvation shell. ", "It is also possible using this program to generate the SDF based on some arbitrarty ", "Cartesian coordinate. To do that, simply omit the preliminary trjconv steps. \n", "USAGE: \n", "1. Use make_ndx to create a group containing the atoms around which you want the SDF \n", "2. trjconv -s a.tpr -f a.xtc -o b.xtc -center tric -ur compact -pbc none \n", "3. trjconv -s a.tpr -f b.xtc -o c.xtc -fit rot+trans \n", "4. run g_spatial on the xtc output of step #3. \n", "5. Load grid.cube into VMD and view as an isosurface. \n", "*** Systems such as micelles will require trjconv -pbc cluster between steps 1 and 2\n", "WARNINGS: \n", "The SDF will be generated for a cube that contains all bins that have some non-zero occupancy. ", "However, the preparatory -fit rot+trans option to trjconv implies that your system will be rotating ", "and translating in space (in order that the selected group does not). Therefore the values that are ", "returned will only be valid for some region around your central group/coordinate that has full overlap ", "with system volume throughout the entire translated/rotated system over the course of the trajectory. ", "It is up to the user to ensure that this is the case. \n", "BUGS: \n", "When the allocated memory is not large enough, a segmentation fault may occur. This is usually detected ", "and the program is halted prior to the fault while displaying a warning message suggesting the use of the -nab ", "option. However, the program does not detect all such events. If you encounter a segmentation fault, run it again ", "with an increased -nab value. \n", "RISKY OPTIONS: \n", "To reduce the amount of space and time required, you can output only the coords ", "that are going to be used in the first and subsequent run through trjconv. ", "However, be sure to set the -nab option to a sufficiently high value since ", "memory is allocated for cube bins based on the initial coords and the -nab ", "(Number of Additional Bins) option value. \n" }; static gmx_bool bPBC=FALSE; static gmx_bool bSHIFT=FALSE; static int iIGNOREOUTER=-1; /*Positive values may help if the surface is spikey */ static gmx_bool bCUTDOWN=TRUE; static real rBINWIDTH=0.05; /* nm */ static gmx_bool bCALCDIV=TRUE; static int iNAB=4; t_pargs pa[] = { { "-pbc", FALSE, etBOOL, {&bPBC}, "Use periodic boundary conditions for computing distances" }, { "-div", FALSE, etBOOL, {&bCALCDIV}, "Calculate and apply the divisor for bin occupancies based on atoms/minimal cube size. Set as TRUE for visualization and as FALSE (-nodiv) to get accurate counts per frame" }, { "-ign", FALSE, etINT, {&iIGNOREOUTER}, "Do not display this number of outer cubes (positive values may reduce boundary speckles; -1 ensures outer surface is visible)" }, /* { "-cut", bCUTDOWN, etBOOL, {&bCUTDOWN},*/ /* "Display a total cube that is of minimal size" }, */ { "-bin", FALSE, etREAL, {&rBINWIDTH}, "Width of the bins in nm" }, { "-nab", FALSE, etINT, {&iNAB}, "Number of additional bins to ensure proper memory allocation" } }; double MINBIN[3]; double MAXBIN[3]; t_topology top; int ePBC; char title[STRLEN]; t_trxframe fr; rvec *xtop,*shx[26]; matrix box,box_pbc; t_trxstatus *status; int flags = TRX_READ_X; t_pbc pbc; t_atoms *atoms; int natoms; char *grpnm,*grpnmp; atom_id *index,*indexp; int i,nidx,nidxp; int v; int j,k; long ***bin=(long ***)NULL; long nbin[3]; FILE *flp; long x,y,z,minx,miny,minz,maxx,maxy,maxz; long numfr, numcu; long tot,max,min; double norm; output_env_t oenv; gmx_rmpbc_t gpbc=NULL; t_filenm fnm[] = { { efTPS, NULL, NULL, ffREAD }, /* this is for the topology */ { efTRX, "-f", NULL, ffREAD }, /* and this for the trajectory */ { efNDX, NULL, NULL, ffOPTRD } }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); /* This is the routine responsible for adding default options, * calling the X/motif interface, etc. */ parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xtop,NULL,box,TRUE); sfree(xtop); atoms=&(top.atoms); printf("Select group to generate SDF:\n"); get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&nidx,&index,&grpnm); printf("Select group to output coords (e.g. solute):\n"); get_index(atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&nidxp,&indexp,&grpnmp); /* The first time we read data is a little special */ natoms=read_first_frame(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&fr,flags); /* Memory Allocation */ MINBIN[XX]=MAXBIN[XX]=fr.x[0][XX]; MINBIN[YY]=MAXBIN[YY]=fr.x[0][YY]; MINBIN[ZZ]=MAXBIN[ZZ]=fr.x[0][ZZ]; for(i=1; i<top.atoms.nr; ++i) { if(fr.x[i][XX]<MINBIN[XX])MINBIN[XX]=fr.x[i][XX]; if(fr.x[i][XX]>MAXBIN[XX])MAXBIN[XX]=fr.x[i][XX]; if(fr.x[i][YY]<MINBIN[YY])MINBIN[YY]=fr.x[i][YY]; if(fr.x[i][YY]>MAXBIN[YY])MAXBIN[YY]=fr.x[i][YY]; if(fr.x[i][ZZ]<MINBIN[ZZ])MINBIN[ZZ]=fr.x[i][ZZ]; if(fr.x[i][ZZ]>MAXBIN[ZZ])MAXBIN[ZZ]=fr.x[i][ZZ]; } for (i=ZZ; i>=XX; --i){ MAXBIN[i]=(ceil((MAXBIN[i]-MINBIN[i])/rBINWIDTH)+(double)iNAB)*rBINWIDTH+MINBIN[i]; MINBIN[i]-=(double)iNAB*rBINWIDTH; nbin[i]=(long)ceil((MAXBIN[i]-MINBIN[i])/rBINWIDTH); } bin=(long ***)malloc(nbin[XX]*sizeof(long **)); if(!bin)mequit(); for(i=0; i<nbin[XX]; ++i){ bin[i]=(long **)malloc(nbin[YY]*sizeof(long *)); if(!bin[i])mequit(); for(j=0; j<nbin[YY]; ++j){ bin[i][j]=(long *)calloc(nbin[ZZ],sizeof(long)); if(!bin[i][j])mequit(); } } copy_mat(box,box_pbc); numfr=0; minx=miny=minz=999; maxx=maxy=maxz=0; if (bPBC) gpbc = gmx_rmpbc_init(&top.idef,ePBC,natoms,box); /* This is the main loop over frames */ do { /* Must init pbc every step because of pressure coupling */ copy_mat(box,box_pbc); if (bPBC) { gmx_rmpbc_trxfr(gpbc,&fr); set_pbc(&pbc,ePBC,box_pbc); } for(i=0; i<nidx; i++) { if(fr.x[index[i]][XX]<MINBIN[XX]||fr.x[index[i]][XX]>MAXBIN[XX]|| fr.x[index[i]][YY]<MINBIN[YY]||fr.x[index[i]][YY]>MAXBIN[YY]|| fr.x[index[i]][ZZ]<MINBIN[ZZ]||fr.x[index[i]][ZZ]>MAXBIN[ZZ]) { printf("There was an item outside of the allocated memory. Increase the value given with the -nab option.\n"); printf("Memory was allocated for [%f,%f,%f]\tto\t[%f,%f,%f]\n",MINBIN[XX],MINBIN[YY],MINBIN[ZZ],MAXBIN[XX],MAXBIN[YY],MAXBIN[ZZ]); printf("Memory was required for [%f,%f,%f]\n",fr.x[index[i]][XX],fr.x[index[i]][YY],fr.x[index[i]][ZZ]); exit(1); } x=(long)ceil((fr.x[index[i]][XX]-MINBIN[XX])/rBINWIDTH); y=(long)ceil((fr.x[index[i]][YY]-MINBIN[YY])/rBINWIDTH); z=(long)ceil((fr.x[index[i]][ZZ]-MINBIN[ZZ])/rBINWIDTH); ++bin[x][y][z]; if(x<minx)minx=x; if(x>maxx)maxx=x; if(y<miny)miny=y; if(y>maxy)maxy=y; if(z<minz)minz=z; if(z>maxz)maxz=z; } numfr++; /* printf("%f\t%f\t%f\n",box[XX][XX],box[YY][YY],box[ZZ][ZZ]); */ } while(read_next_frame(oenv,status,&fr)); if (bPBC) gmx_rmpbc_done(gpbc); if(!bCUTDOWN){ minx=miny=minz=0; maxx=nbin[XX]; maxy=nbin[YY]; maxz=nbin[ZZ]; } /* OUTPUT */ flp=ffopen("grid.cube","w"); fprintf(flp,"Spatial Distribution Function\n"); fprintf(flp,"test\n"); fprintf(flp,"%5d%12.6f%12.6f%12.6f\n",nidxp,(MINBIN[XX]+(minx+iIGNOREOUTER)*rBINWIDTH)*10./bohr,(MINBIN[YY]+(miny+iIGNOREOUTER)*rBINWIDTH)*10./bohr,(MINBIN[ZZ]+(minz+iIGNOREOUTER)*rBINWIDTH)*10./bohr); fprintf(flp,"%5ld%12.6f%12.6f%12.6f\n",maxx-minx+1-(2*iIGNOREOUTER),rBINWIDTH*10./bohr,0.,0.); fprintf(flp,"%5ld%12.6f%12.6f%12.6f\n",maxy-miny+1-(2*iIGNOREOUTER),0.,rBINWIDTH*10./bohr,0.); fprintf(flp,"%5ld%12.6f%12.6f%12.6f\n",maxz-minz+1-(2*iIGNOREOUTER),0.,0.,rBINWIDTH*10./bohr); for(i=0; i<nidxp; i++){ v=2; if(*(top.atoms.atomname[indexp[i]][0])=='C')v=6; if(*(top.atoms.atomname[indexp[i]][0])=='N')v=7; if(*(top.atoms.atomname[indexp[i]][0])=='O')v=8; if(*(top.atoms.atomname[indexp[i]][0])=='H')v=1; if(*(top.atoms.atomname[indexp[i]][0])=='S')v=16; fprintf(flp,"%5d%12.6f%12.6f%12.6f%12.6f\n",v,0.,(double)fr.x[indexp[i]][XX]*10./bohr,(double)fr.x[indexp[i]][YY]*10./bohr,(double)fr.x[indexp[i]][ZZ]*10./bohr); } tot=0; for(k=0;k<nbin[XX];k++) { if(!(k<minx||k>maxx))continue; for(j=0;j<nbin[YY];j++) { if(!(j<miny||j>maxy))continue; for(i=0;i<nbin[ZZ];i++) { if(!(i<minz||i>maxz))continue; if(bin[k][j][i]!=0){ printf("A bin was not empty when it should have been empty. Programming error.\n"); printf("bin[%d][%d][%d] was = %ld\n",k,j,i,bin[k][j][i]); exit(1); } } } } min=999; max=0; for(k=0;k<nbin[XX];k++) { if(k<minx+iIGNOREOUTER||k>maxx-iIGNOREOUTER)continue; for(j=0;j<nbin[YY];j++) { if(j<miny+iIGNOREOUTER||j>maxy-iIGNOREOUTER)continue; for(i=0;i<nbin[ZZ];i++) { if(i<minz+iIGNOREOUTER||i>maxz-iIGNOREOUTER)continue; tot+=bin[k][j][i]; if(bin[k][j][i]>max)max=bin[k][j][i]; if(bin[k][j][i]<min)min=bin[k][j][i]; } } } numcu=(maxx-minx+1-(2*iIGNOREOUTER))*(maxy-miny+1-(2*iIGNOREOUTER))*(maxz-minz+1-(2*iIGNOREOUTER)); if(bCALCDIV){ norm=((double)numcu*(double)numfr) / (double)tot; }else{ norm=1.0; } for(k=0;k<nbin[XX];k++) { if(k<minx+iIGNOREOUTER||k>maxx-iIGNOREOUTER)continue; for(j=0;j<nbin[YY];j++) { if(j<miny+iIGNOREOUTER||j>maxy-iIGNOREOUTER)continue; for(i=0;i<nbin[ZZ];i++) { if(i<minz+iIGNOREOUTER||i>maxz-iIGNOREOUTER)continue; fprintf(flp,"%12.6f ",norm*(double)bin[k][j][i]/(double)numfr); } fprintf(flp,"\n"); } fprintf(flp,"\n"); } ffclose(flp); /* printf("x=%d to %d\n",minx,maxx); */ /* printf("y=%d to %d\n",miny,maxy); */ /* printf("z=%d to %d\n",minz,maxz); */ if(bCALCDIV){ printf("Counts per frame in all %ld cubes divided by %le\n",numcu,1.0/norm); printf("Normalized data: average %le, min %le, max %le\n",1.0,norm*(double)min/(double)numfr,norm*(double)max/(double)numfr); }else{ printf("grid.cube contains counts per frame in all %ld cubes\n",numcu); printf("Raw data: average %le, min %le, max %le\n",1.0/norm,(double)min/(double)numfr,(double)max/(double)numfr); } thanx(stderr); return 0; }
int gmx_covar(int argc,char *argv[]) { const char *desc[] = { "[TT]g_covar[tt] calculates and diagonalizes the (mass-weighted)", "covariance matrix.", "All structures are fitted to the structure in the structure file.", "When this is not a run input file periodicity will not be taken into", "account. When the fit and analysis groups are identical and the analysis", "is non mass-weighted, the fit will also be non mass-weighted.", "[PAR]", "The eigenvectors are written to a trajectory file ([TT]-v[tt]).", "When the same atoms are used for the fit and the covariance analysis,", "the reference structure for the fit is written first with t=-1.", "The average (or reference when [TT]-ref[tt] is used) structure is", "written with t=0, the eigenvectors", "are written as frames with the eigenvector number as timestamp.", "[PAR]", "The eigenvectors can be analyzed with [TT]g_anaeig[tt].", "[PAR]", "Option [TT]-ascii[tt] writes the whole covariance matrix to", "an ASCII file. The order of the elements is: x1x1, x1y1, x1z1, x1x2, ...", "[PAR]", "Option [TT]-xpm[tt] writes the whole covariance matrix to an [TT].xpm[tt] file.", "[PAR]", "Option [TT]-xpma[tt] writes the atomic covariance matrix to an [TT].xpm[tt] file,", "i.e. for each atom pair the sum of the xx, yy and zz covariances is", "written.", "[PAR]", "Note that the diagonalization of a matrix requires memory and time", "that will increase at least as fast as than the square of the number", "of atoms involved. It is easy to run out of memory, in which", "case this tool will probably exit with a 'Segmentation fault'. You", "should consider carefully whether a reduced set of atoms will meet", "your needs for lower costs." }; static gmx_bool bFit=TRUE,bRef=FALSE,bM=FALSE,bPBC=TRUE; static int end=-1; t_pargs pa[] = { { "-fit", FALSE, etBOOL, {&bFit}, "Fit to a reference structure"}, { "-ref", FALSE, etBOOL, {&bRef}, "Use the deviation from the conformation in the structure file instead of from the average" }, { "-mwa", FALSE, etBOOL, {&bM}, "Mass-weighted covariance analysis"}, { "-last", FALSE, etINT, {&end}, "Last eigenvector to write away (-1 is till the last)" }, { "-pbc", FALSE, etBOOL, {&bPBC}, "Apply corrections for periodic boundary conditions" } }; FILE *out; t_trxstatus *status; t_trxstatus *trjout; t_topology top; int ePBC; t_atoms *atoms; rvec *x,*xread,*xref,*xav,*xproj; matrix box,zerobox; real *sqrtm,*mat,*eigval,sum,trace,inv_nframes; real t,tstart,tend,**mat2; real xj,*w_rls=NULL; real min,max,*axis; int ntopatoms,step; int natoms,nat,count,nframes0,nframes,nlevels; gmx_large_int_t ndim,i,j,k,l; int WriteXref; const char *fitfile,*trxfile,*ndxfile; const char *eigvalfile,*eigvecfile,*averfile,*logfile; const char *asciifile,*xpmfile,*xpmafile; char str[STRLEN],*fitname,*ananame,*pcwd; int d,dj,nfit; atom_id *index,*ifit; gmx_bool bDiffMass1,bDiffMass2; time_t now; char timebuf[STRLEN]; t_rgb rlo,rmi,rhi; real *tmp; output_env_t oenv; gmx_rmpbc_t gpbc=NULL; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, NULL, "eigenval", ffWRITE }, { efTRN, "-v", "eigenvec", ffWRITE }, { efSTO, "-av", "average.pdb", ffWRITE }, { efLOG, NULL, "covar", ffWRITE }, { efDAT, "-ascii","covar", ffOPTWR }, { efXPM, "-xpm","covar", ffOPTWR }, { efXPM, "-xpma","covara", ffOPTWR } }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_TIME_UNIT | PCA_BE_NICE, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); clear_mat(zerobox); fitfile = ftp2fn(efTPS,NFILE,fnm); trxfile = ftp2fn(efTRX,NFILE,fnm); ndxfile = ftp2fn_null(efNDX,NFILE,fnm); eigvalfile = ftp2fn(efXVG,NFILE,fnm); eigvecfile = ftp2fn(efTRN,NFILE,fnm); averfile = ftp2fn(efSTO,NFILE,fnm); logfile = ftp2fn(efLOG,NFILE,fnm); asciifile = opt2fn_null("-ascii",NFILE,fnm); xpmfile = opt2fn_null("-xpm",NFILE,fnm); xpmafile = opt2fn_null("-xpma",NFILE,fnm); read_tps_conf(fitfile,str,&top,&ePBC,&xref,NULL,box,TRUE); atoms=&top.atoms; if (bFit) { printf("\nChoose a group for the least squares fit\n"); get_index(atoms,ndxfile,1,&nfit,&ifit,&fitname); if (nfit < 3) gmx_fatal(FARGS,"Need >= 3 points to fit!\n"); } else nfit=0; printf("\nChoose a group for the covariance analysis\n"); get_index(atoms,ndxfile,1,&natoms,&index,&ananame); bDiffMass1=FALSE; if (bFit) { snew(w_rls,atoms->nr); for(i=0; (i<nfit); i++) { w_rls[ifit[i]]=atoms->atom[ifit[i]].m; if (i) bDiffMass1 = bDiffMass1 || (w_rls[ifit[i]]!=w_rls[ifit[i-1]]); } } bDiffMass2=FALSE; snew(sqrtm,natoms); for(i=0; (i<natoms); i++) if (bM) { sqrtm[i]=sqrt(atoms->atom[index[i]].m); if (i) bDiffMass2 = bDiffMass2 || (sqrtm[i]!=sqrtm[i-1]); } else sqrtm[i]=1.0; if (bFit && bDiffMass1 && !bDiffMass2) { bDiffMass1 = natoms != nfit; i=0; for (i=0; (i<natoms) && !bDiffMass1; i++) bDiffMass1 = index[i] != ifit[i]; if (!bDiffMass1) { fprintf(stderr,"\n" "Note: the fit and analysis group are identical,\n" " while the fit is mass weighted and the analysis is not.\n" " Making the fit non mass weighted.\n\n"); for(i=0; (i<nfit); i++) w_rls[ifit[i]]=1.0; } } /* Prepare reference frame */ if (bPBC) { gpbc = gmx_rmpbc_init(&top.idef,ePBC,atoms->nr,box); gmx_rmpbc(gpbc,atoms->nr,box,xref); } if (bFit) reset_x(nfit,ifit,atoms->nr,NULL,xref,w_rls); snew(x,natoms); snew(xav,natoms); ndim=natoms*DIM; if (sqrt(GMX_LARGE_INT_MAX)<ndim) { gmx_fatal(FARGS,"Number of degrees of freedoms to large for matrix.\n"); } snew(mat,ndim*ndim); fprintf(stderr,"Calculating the average structure ...\n"); nframes0 = 0; nat=read_first_x(oenv,&status,trxfile,&t,&xread,box); if (nat != atoms->nr) fprintf(stderr,"\nWARNING: number of atoms in tpx (%d) and trajectory (%d) do not match\n",natoms,nat); do { nframes0++; /* calculate x: a fitted struture of the selected atoms */ if (bPBC) gmx_rmpbc(gpbc,nat,box,xread); if (bFit) { reset_x(nfit,ifit,nat,NULL,xread,w_rls); do_fit(nat,w_rls,xref,xread); } for (i=0; i<natoms; i++) rvec_inc(xav[i],xread[index[i]]); } while (read_next_x(oenv,status,&t,nat,xread,box)); close_trj(status); inv_nframes = 1.0/nframes0; for(i=0; i<natoms; i++) for(d=0; d<DIM; d++) { xav[i][d] *= inv_nframes; xread[index[i]][d] = xav[i][d]; } write_sto_conf_indexed(opt2fn("-av",NFILE,fnm),"Average structure", atoms,xread,NULL,epbcNONE,zerobox,natoms,index); sfree(xread); fprintf(stderr,"Constructing covariance matrix (%dx%d) ...\n",(int)ndim,(int)ndim); nframes=0; nat=read_first_x(oenv,&status,trxfile,&t,&xread,box); tstart = t; do { nframes++; tend = t; /* calculate x: a (fitted) structure of the selected atoms */ if (bPBC) gmx_rmpbc(gpbc,nat,box,xread); if (bFit) { reset_x(nfit,ifit,nat,NULL,xread,w_rls); do_fit(nat,w_rls,xref,xread); } if (bRef) for (i=0; i<natoms; i++) rvec_sub(xread[index[i]],xref[index[i]],x[i]); else for (i=0; i<natoms; i++) rvec_sub(xread[index[i]],xav[i],x[i]); for (j=0; j<natoms; j++) { for (dj=0; dj<DIM; dj++) { k=ndim*(DIM*j+dj); xj=x[j][dj]; for (i=j; i<natoms; i++) { l=k+DIM*i; for(d=0; d<DIM; d++) mat[l+d] += x[i][d]*xj; } } } } while (read_next_x(oenv,status,&t,nat,xread,box) && (bRef || nframes < nframes0)); close_trj(status); gmx_rmpbc_done(gpbc); fprintf(stderr,"Read %d frames\n",nframes); if (bRef) { /* copy the reference structure to the ouput array x */ snew(xproj,natoms); for (i=0; i<natoms; i++) copy_rvec(xref[index[i]],xproj[i]); } else { xproj = xav; } /* correct the covariance matrix for the mass */ inv_nframes = 1.0/nframes; for (j=0; j<natoms; j++) for (dj=0; dj<DIM; dj++) for (i=j; i<natoms; i++) { k = ndim*(DIM*j+dj)+DIM*i; for (d=0; d<DIM; d++) mat[k+d] = mat[k+d]*inv_nframes*sqrtm[i]*sqrtm[j]; } /* symmetrize the matrix */ for (j=0; j<ndim; j++) for (i=j; i<ndim; i++) mat[ndim*i+j]=mat[ndim*j+i]; trace=0; for(i=0; i<ndim; i++) trace+=mat[i*ndim+i]; fprintf(stderr,"\nTrace of the covariance matrix: %g (%snm^2)\n", trace,bM ? "u " : ""); if (asciifile) { out = ffopen(asciifile,"w"); for (j=0; j<ndim; j++) { for (i=0; i<ndim; i+=3) fprintf(out,"%g %g %g\n", mat[ndim*j+i],mat[ndim*j+i+1],mat[ndim*j+i+2]); } ffclose(out); } if (xpmfile) { min = 0; max = 0; snew(mat2,ndim); for (j=0; j<ndim; j++) { mat2[j] = &(mat[ndim*j]); for (i=0; i<=j; i++) { if (mat2[j][i] < min) min = mat2[j][i]; if (mat2[j][j] > max) max = mat2[j][i]; } } snew(axis,ndim); for(i=0; i<ndim; i++) axis[i] = i+1; rlo.r = 0; rlo.g = 0; rlo.b = 1; rmi.r = 1; rmi.g = 1; rmi.b = 1; rhi.r = 1; rhi.g = 0; rhi.b = 0; out = ffopen(xpmfile,"w"); nlevels = 80; write_xpm3(out,0,"Covariance",bM ? "u nm^2" : "nm^2", "dim","dim",ndim,ndim,axis,axis, mat2,min,0.0,max,rlo,rmi,rhi,&nlevels); ffclose(out); sfree(axis); sfree(mat2); } if (xpmafile) { min = 0; max = 0; snew(mat2,ndim/DIM); for (i=0; i<ndim/DIM; i++) snew(mat2[i],ndim/DIM); for (j=0; j<ndim/DIM; j++) { for (i=0; i<=j; i++) { mat2[j][i] = 0; for(d=0; d<DIM; d++) mat2[j][i] += mat[ndim*(DIM*j+d)+DIM*i+d]; if (mat2[j][i] < min) min = mat2[j][i]; if (mat2[j][j] > max) max = mat2[j][i]; mat2[i][j] = mat2[j][i]; } } snew(axis,ndim/DIM); for(i=0; i<ndim/DIM; i++) axis[i] = i+1; rlo.r = 0; rlo.g = 0; rlo.b = 1; rmi.r = 1; rmi.g = 1; rmi.b = 1; rhi.r = 1; rhi.g = 0; rhi.b = 0; out = ffopen(xpmafile,"w"); nlevels = 80; write_xpm3(out,0,"Covariance",bM ? "u nm^2" : "nm^2", "atom","atom",ndim/DIM,ndim/DIM,axis,axis, mat2,min,0.0,max,rlo,rmi,rhi,&nlevels); ffclose(out); sfree(axis); for (i=0; i<ndim/DIM; i++) sfree(mat2[i]); sfree(mat2); } /* call diagonalization routine */ fprintf(stderr,"\nDiagonalizing ...\n"); fflush(stderr); snew(eigval,ndim); snew(tmp,ndim*ndim); memcpy(tmp,mat,ndim*ndim*sizeof(real)); eigensolver(tmp,ndim,0,ndim,eigval,mat); sfree(tmp); /* now write the output */ sum=0; for(i=0; i<ndim; i++) sum+=eigval[i]; fprintf(stderr,"\nSum of the eigenvalues: %g (%snm^2)\n", sum,bM ? "u " : ""); if (fabs(trace-sum)>0.01*trace) fprintf(stderr,"\nWARNING: eigenvalue sum deviates from the trace of the covariance matrix\n"); fprintf(stderr,"\nWriting eigenvalues to %s\n",eigvalfile); sprintf(str,"(%snm\\S2\\N)",bM ? "u " : ""); out=xvgropen(eigvalfile, "Eigenvalues of the covariance matrix", "Eigenvector index",str,oenv); for (i=0; (i<ndim); i++) fprintf (out,"%10d %g\n",(int)i+1,eigval[ndim-1-i]); ffclose(out); if (end==-1) { if (nframes-1 < ndim) end=nframes-1; else end=ndim; } if (bFit) { /* misuse lambda: 0/1 mass weighted analysis no/yes */ if (nfit==natoms) { WriteXref = eWXR_YES; for(i=0; i<nfit; i++) copy_rvec(xref[ifit[i]],x[i]); } else WriteXref = eWXR_NO; } else { /* misuse lambda: -1 for no fit */ WriteXref = eWXR_NOFIT; } write_eigenvectors(eigvecfile,natoms,mat,TRUE,1,end, WriteXref,x,bDiffMass1,xproj,bM,eigval); out = ffopen(logfile,"w"); time(&now); gmx_ctime_r(&now,timebuf,STRLEN); fprintf(out,"Covariance analysis log, written %s\n",timebuf); fprintf(out,"Program: %s\n",argv[0]); #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__) pcwd=_getcwd(str,STRLEN); #else pcwd=getcwd(str,STRLEN); #endif if(NULL==pcwd) { gmx_fatal(FARGS,"Current working directory is undefined"); } fprintf(out,"Working directory: %s\n\n",str); fprintf(out,"Read %d frames from %s (time %g to %g %s)\n",nframes,trxfile, output_env_conv_time(oenv,tstart),output_env_conv_time(oenv,tend),output_env_get_time_unit(oenv)); if (bFit) fprintf(out,"Read reference structure for fit from %s\n",fitfile); if (ndxfile) fprintf(out,"Read index groups from %s\n",ndxfile); fprintf(out,"\n"); fprintf(out,"Analysis group is '%s' (%d atoms)\n",ananame,natoms); if (bFit) fprintf(out,"Fit group is '%s' (%d atoms)\n",fitname,nfit); else fprintf(out,"No fit was used\n"); fprintf(out,"Analysis is %smass weighted\n", bDiffMass2 ? "":"non-"); if (bFit) fprintf(out,"Fit is %smass weighted\n", bDiffMass1 ? "":"non-"); fprintf(out,"Diagonalized the %dx%d covariance matrix\n",(int)ndim,(int)ndim); fprintf(out,"Trace of the covariance matrix before diagonalizing: %g\n", trace); fprintf(out,"Trace of the covariance matrix after diagonalizing: %g\n\n", sum); fprintf(out,"Wrote %d eigenvalues to %s\n",(int)ndim,eigvalfile); if (WriteXref == eWXR_YES) fprintf(out,"Wrote reference structure to %s\n",eigvecfile); fprintf(out,"Wrote average structure to %s and %s\n",averfile,eigvecfile); fprintf(out,"Wrote eigenvectors %d to %d to %s\n",1,end,eigvecfile); ffclose(out); fprintf(stderr,"Wrote the log to %s\n",logfile); thanx(stderr); return 0; }
int gmx_anaeig(int argc,char *argv[]) { static const char *desc[] = { "[TT]g_anaeig[tt] analyzes eigenvectors. The eigenvectors can be of a", "covariance matrix ([TT]g_covar[tt]) or of a Normal Modes analysis", "([TT]g_nmeig[tt]).[PAR]", "When a trajectory is projected on eigenvectors, all structures are", "fitted to the structure in the eigenvector file, if present, otherwise", "to the structure in the structure file. When no run input file is", "supplied, periodicity will not be taken into account. Most analyses", "are performed on eigenvectors [TT]-first[tt] to [TT]-last[tt], but when", "[TT]-first[tt] is set to -1 you will be prompted for a selection.[PAR]", "[TT]-comp[tt]: plot the vector components per atom of eigenvectors", "[TT]-first[tt] to [TT]-last[tt].[PAR]", "[TT]-rmsf[tt]: plot the RMS fluctuation per atom of eigenvectors", "[TT]-first[tt] to [TT]-last[tt] (requires [TT]-eig[tt]).[PAR]", "[TT]-proj[tt]: calculate projections of a trajectory on eigenvectors", "[TT]-first[tt] to [TT]-last[tt].", "The projections of a trajectory on the eigenvectors of its", "covariance matrix are called principal components (pc's).", "It is often useful to check the cosine content of the pc's,", "since the pc's of random diffusion are cosines with the number", "of periods equal to half the pc index.", "The cosine content of the pc's can be calculated with the program", "[TT]g_analyze[tt].[PAR]", "[TT]-2d[tt]: calculate a 2d projection of a trajectory on eigenvectors", "[TT]-first[tt] and [TT]-last[tt].[PAR]", "[TT]-3d[tt]: calculate a 3d projection of a trajectory on the first", "three selected eigenvectors.[PAR]", "[TT]-filt[tt]: filter the trajectory to show only the motion along", "eigenvectors [TT]-first[tt] to [TT]-last[tt].[PAR]", "[TT]-extr[tt]: calculate the two extreme projections along a trajectory", "on the average structure and interpolate [TT]-nframes[tt] frames", "between them, or set your own extremes with [TT]-max[tt]. The", "eigenvector [TT]-first[tt] will be written unless [TT]-first[tt] and", "[TT]-last[tt] have been set explicitly, in which case all eigenvectors", "will be written to separate files. Chain identifiers will be added", "when writing a [TT].pdb[tt] file with two or three structures (you", "can use [TT]rasmol -nmrpdb[tt] to view such a [TT].pdb[tt] file).[PAR]", " Overlap calculations between covariance analysis:[BR]", " [BB]Note:[bb] the analysis should use the same fitting structure[PAR]", "[TT]-over[tt]: calculate the subspace overlap of the eigenvectors in", "file [TT]-v2[tt] with eigenvectors [TT]-first[tt] to [TT]-last[tt]", "in file [TT]-v[tt].[PAR]", "[TT]-inpr[tt]: calculate a matrix of inner-products between", "eigenvectors in files [TT]-v[tt] and [TT]-v2[tt]. All eigenvectors", "of both files will be used unless [TT]-first[tt] and [TT]-last[tt]", "have been set explicitly.[PAR]", "When [TT]-v[tt], [TT]-eig[tt], [TT]-v2[tt] and [TT]-eig2[tt] are given,", "a single number for the overlap between the covariance matrices is", "generated. The formulas are:[BR]", " difference = sqrt(tr((sqrt(M1) - sqrt(M2))^2))[BR]", "normalized overlap = 1 - difference/sqrt(tr(M1) + tr(M2))[BR]", " shape overlap = 1 - sqrt(tr((sqrt(M1/tr(M1)) - sqrt(M2/tr(M2)))^2))[BR]", "where M1 and M2 are the two covariance matrices and tr is the trace", "of a matrix. The numbers are proportional to the overlap of the square", "root of the fluctuations. The normalized overlap is the most useful", "number, it is 1 for identical matrices and 0 when the sampled", "subspaces are orthogonal.[PAR]", "When the [TT]-entropy[tt] flag is given an entropy estimate will be", "computed based on the Quasiharmonic approach and based on", "Schlitter's formula." }; static int first=1,last=-1,skip=1,nextr=2,nskip=6; static real max=0.0,temp=298.15; static gmx_bool bSplit=FALSE,bEntropy=FALSE; t_pargs pa[] = { { "-first", FALSE, etINT, {&first}, "First eigenvector for analysis (-1 is select)" }, { "-last", FALSE, etINT, {&last}, "Last eigenvector for analysis (-1 is till the last)" }, { "-skip", FALSE, etINT, {&skip}, "Only analyse every nr-th frame" }, { "-max", FALSE, etREAL, {&max}, "Maximum for projection of the eigenvector on the average structure, " "max=0 gives the extremes" }, { "-nframes", FALSE, etINT, {&nextr}, "Number of frames for the extremes output" }, { "-split", FALSE, etBOOL, {&bSplit}, "Split eigenvector projections where time is zero" }, { "-entropy", FALSE, etBOOL, {&bEntropy}, "Compute entropy according to the Quasiharmonic formula or Schlitter's method." }, { "-temp", FALSE, etREAL, {&temp}, "Temperature for entropy calculations" }, { "-nevskip", FALSE, etINT, {&nskip}, "Number of eigenvalues to skip when computing the entropy due to the quasi harmonic approximation. When you do a rotational and/or translational fit prior to the covariance analysis, you get 3 or 6 eigenvalues that are very close to zero, and which should not be taken into account when computing the entropy." } }; #define NPA asize(pa) FILE *out; int status,trjout; t_topology top; int ePBC=-1; t_atoms *atoms=NULL; rvec *xtop,*xref1,*xref2,*xrefp=NULL; gmx_bool bDMR1,bDMA1,bDMR2,bDMA2; int nvec1,nvec2,*eignr1=NULL,*eignr2=NULL; rvec *x,*xread,*xav1,*xav2,**eigvec1=NULL,**eigvec2=NULL; matrix topbox; real xid,totmass,*sqrtm,*w_rls,t,lambda; int natoms,step; char *grpname; const char *indexfile; char title[STRLEN]; int i,j,d; int nout,*iout,noutvec,*outvec,nfit; atom_id *index,*ifit; const char *VecFile,*Vec2File,*topfile; const char *EigFile,*Eig2File; const char *CompFile,*RmsfFile,*ProjOnVecFile; const char *TwoDPlotFile,*ThreeDPlotFile; const char *FilterFile,*ExtremeFile; const char *OverlapFile,*InpMatFile; gmx_bool bFit1,bFit2,bM,bIndex,bTPS,bTop,bVec2,bProj; gmx_bool bFirstToLast,bFirstLastSet,bTraj,bCompare,bPDB3D; real *eigval1=NULL,*eigval2=NULL; int neig1,neig2; double **xvgdata; output_env_t oenv; gmx_rmpbc_t gpbc; t_filenm fnm[] = { { efTRN, "-v", "eigenvec", ffREAD }, { efTRN, "-v2", "eigenvec2", ffOPTRD }, { efTRX, "-f", NULL, ffOPTRD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, "-eig", "eigenval", ffOPTRD }, { efXVG, "-eig2", "eigenval2", ffOPTRD }, { efXVG, "-comp", "eigcomp", ffOPTWR }, { efXVG, "-rmsf", "eigrmsf", ffOPTWR }, { efXVG, "-proj", "proj", ffOPTWR }, { efXVG, "-2d", "2dproj", ffOPTWR }, { efSTO, "-3d", "3dproj.pdb", ffOPTWR }, { efTRX, "-filt", "filtered", ffOPTWR }, { efTRX, "-extr", "extreme.pdb", ffOPTWR }, { efXVG, "-over", "overlap", ffOPTWR }, { efXPM, "-inpr", "inprod", ffOPTWR } }; #define NFILE asize(fnm) parse_common_args(&argc,argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW | PCA_BE_NICE , NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL,&oenv); indexfile=ftp2fn_null(efNDX,NFILE,fnm); VecFile = opt2fn("-v",NFILE,fnm); Vec2File = opt2fn_null("-v2",NFILE,fnm); topfile = ftp2fn(efTPS,NFILE,fnm); EigFile = opt2fn_null("-eig",NFILE,fnm); Eig2File = opt2fn_null("-eig2",NFILE,fnm); CompFile = opt2fn_null("-comp",NFILE,fnm); RmsfFile = opt2fn_null("-rmsf",NFILE,fnm); ProjOnVecFile = opt2fn_null("-proj",NFILE,fnm); TwoDPlotFile = opt2fn_null("-2d",NFILE,fnm); ThreeDPlotFile = opt2fn_null("-3d",NFILE,fnm); FilterFile = opt2fn_null("-filt",NFILE,fnm); ExtremeFile = opt2fn_null("-extr",NFILE,fnm); OverlapFile = opt2fn_null("-over",NFILE,fnm); InpMatFile = ftp2fn_null(efXPM,NFILE,fnm); bTop = fn2bTPX(topfile); bProj = ProjOnVecFile || TwoDPlotFile || ThreeDPlotFile || FilterFile || ExtremeFile; bFirstLastSet = opt2parg_bSet("-first",NPA,pa) && opt2parg_bSet("-last",NPA,pa); bFirstToLast = CompFile || RmsfFile || ProjOnVecFile || FilterFile || OverlapFile || ((ExtremeFile || InpMatFile) && bFirstLastSet); bVec2 = Vec2File || OverlapFile || InpMatFile; bM = RmsfFile || bProj; bTraj = ProjOnVecFile || FilterFile || (ExtremeFile && (max==0)) || TwoDPlotFile || ThreeDPlotFile; bIndex = bM || bProj; bTPS = ftp2bSet(efTPS,NFILE,fnm) || bM || bTraj || FilterFile || (bIndex && indexfile); bCompare = Vec2File || Eig2File; bPDB3D = fn2ftp(ThreeDPlotFile)==efPDB; read_eigenvectors(VecFile,&natoms,&bFit1, &xref1,&bDMR1,&xav1,&bDMA1, &nvec1,&eignr1,&eigvec1,&eigval1); neig1 = DIM*natoms; /* Overwrite eigenvalues from separate files if the user provides them */ if (EigFile != NULL) { int neig_tmp = read_xvg(EigFile,&xvgdata,&i); if (neig_tmp != neig1) fprintf(stderr,"Warning: number of eigenvalues in xvg file (%d) does not mtch trr file (%d)\n",neig1,natoms); neig1 = neig_tmp; srenew(eigval1,neig1); for(j=0;j<neig1;j++) { real tmp = eigval1[j]; eigval1[j]=xvgdata[1][j]; if (debug && (eigval1[j] != tmp)) fprintf(debug,"Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n", j,tmp,eigval1[j]); } for(j=0;j<i;j++) sfree(xvgdata[j]); sfree(xvgdata); fprintf(stderr,"Read %d eigenvalues from %s\n",neig1,EigFile); } if (bEntropy) { if (bDMA1) { gmx_fatal(FARGS,"Can not calculate entropies from mass-weighted eigenvalues, redo the analysis without mass-weighting"); } calc_entropy_qh(stdout,neig1,eigval1,temp,nskip); calc_entropy_schlitter(stdout,neig1,nskip,eigval1,temp); } if (bVec2) { if (!Vec2File) gmx_fatal(FARGS,"Need a second eigenvector file to do this analysis."); read_eigenvectors(Vec2File,&neig2,&bFit2, &xref2,&bDMR2,&xav2,&bDMA2,&nvec2,&eignr2,&eigvec2,&eigval2); neig2 = DIM*neig2; if (neig2 != neig1) gmx_fatal(FARGS,"Dimensions in the eigenvector files don't match"); } if(Eig2File != NULL) { neig2 = read_xvg(Eig2File,&xvgdata,&i); srenew(eigval2,neig2); for(j=0;j<neig2;j++) eigval2[j]=xvgdata[1][j]; for(j=0;j<i;j++) sfree(xvgdata[j]); sfree(xvgdata); fprintf(stderr,"Read %d eigenvalues from %s\n",neig2,Eig2File); } if ((!bFit1 || xref1) && !bDMR1 && !bDMA1) bM=FALSE; if ((xref1==NULL) && (bM || bTraj)) bTPS=TRUE; xtop=NULL; nfit=0; ifit=NULL; w_rls=NULL; if (!bTPS) { bTop=FALSE; } else { bTop=read_tps_conf(ftp2fn(efTPS,NFILE,fnm), title,&top,&ePBC,&xtop,NULL,topbox,bM); atoms=&top.atoms; gpbc = gmx_rmpbc_init(&top.idef,ePBC,atoms->nr,topbox); gmx_rmpbc(gpbc,atoms->nr,topbox,xtop); /* Fitting is only required for the projection */ if (bProj && bFit1) { if (xref1 == NULL) { printf("\nNote: the structure in %s should be the same\n" " as the one used for the fit in g_covar\n",topfile); } printf("\nSelect the index group that was used for the least squares fit in g_covar\n"); get_index(atoms,indexfile,1,&nfit,&ifit,&grpname); snew(w_rls,atoms->nr); for(i=0; (i<nfit); i++) { if (bDMR1) { w_rls[ifit[i]] = atoms->atom[ifit[i]].m; } else { w_rls[ifit[i]] = 1.0; } } snew(xrefp,atoms->nr); if (xref1 != NULL) { for(i=0; (i<nfit); i++) { copy_rvec(xref1[i],xrefp[ifit[i]]); } } else { /* The top coordinates are the fitting reference */ for(i=0; (i<nfit); i++) { copy_rvec(xtop[ifit[i]],xrefp[ifit[i]]); } reset_x(nfit,ifit,atoms->nr,NULL,xrefp,w_rls); } } gmx_rmpbc_done(gpbc); } if (bIndex) { printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n",natoms); get_index(atoms,indexfile,1,&i,&index,&grpname); if (i!=natoms) gmx_fatal(FARGS,"you selected a group with %d elements instead of %d",i,natoms); printf("\n"); } snew(sqrtm,natoms); if (bM && bDMA1) { proj_unit="u\\S1/2\\Nnm"; for(i=0; (i<natoms); i++) sqrtm[i]=sqrt(atoms->atom[index[i]].m); } else { proj_unit="nm"; for(i=0; (i<natoms); i++) sqrtm[i]=1.0; } if (bVec2) { t=0; totmass=0; for(i=0; (i<natoms); i++) for(d=0;(d<DIM);d++) { t+=sqr((xav1[i][d]-xav2[i][d])*sqrtm[i]); totmass+=sqr(sqrtm[i]); } fprintf(stdout,"RMSD (without fit) between the two average structures:" " %.3f (nm)\n\n",sqrt(t/totmass)); } if (last==-1) last=natoms*DIM; if (first>-1) { if (bFirstToLast) { /* make an index from first to last */ nout=last-first+1; snew(iout,nout); for(i=0; i<nout; i++) iout[i]=first-1+i; } else if (ThreeDPlotFile) { /* make an index of first+(0,1,2) and last */ nout = bPDB3D ? 4 : 3; nout = min(last-first+1, nout); snew(iout,nout); iout[0]=first-1; iout[1]=first; if (nout>3) iout[2]=first+1; iout[nout-1]=last-1; } else { /* make an index of first and last */ nout=2; snew(iout,nout); iout[0]=first-1; iout[1]=last-1; } } else { printf("Select eigenvectors for output, end your selection with 0\n"); nout=-1; iout=NULL; do { nout++; srenew(iout,nout+1); if(1 != scanf("%d",&iout[nout])) { gmx_fatal(FARGS,"Error reading user input"); } iout[nout]--; } while (iout[nout]>=0); printf("\n"); } /* make an index of the eigenvectors which are present */ snew(outvec,nout); noutvec=0; for(i=0; i<nout; i++) { j=0; while ((j<nvec1) && (eignr1[j]!=iout[i])) j++; if ((j<nvec1) && (eignr1[j]==iout[i])) { outvec[noutvec]=j; noutvec++; } } fprintf(stderr,"%d eigenvectors selected for output",noutvec); if (noutvec <= 100) { fprintf(stderr,":"); for(j=0; j<noutvec; j++) fprintf(stderr," %d",eignr1[outvec[j]]+1); } fprintf(stderr,"\n"); if (CompFile) components(CompFile,natoms,eignr1,eigvec1,noutvec,outvec,oenv); if (RmsfFile) rmsf(RmsfFile,natoms,sqrtm,eignr1,eigvec1,noutvec,outvec,eigval1, neig1,oenv); if (bProj) project(bTraj ? opt2fn("-f",NFILE,fnm) : NULL, bTop ? &top : NULL,ePBC,topbox, ProjOnVecFile,TwoDPlotFile,ThreeDPlotFile,FilterFile,skip, ExtremeFile,bFirstLastSet,max,nextr,atoms,natoms,index, bFit1,xrefp,nfit,ifit,w_rls, sqrtm,xav1,eignr1,eigvec1,noutvec,outvec,bSplit, oenv); if (OverlapFile) overlap(OverlapFile,natoms, eigvec1,nvec2,eignr2,eigvec2,noutvec,outvec,oenv); if (InpMatFile) inprod_matrix(InpMatFile,natoms, nvec1,eignr1,eigvec1,nvec2,eignr2,eigvec2, bFirstLastSet,noutvec,outvec); if (bCompare) compare(natoms,nvec1,eigvec1,nvec2,eigvec2,eigval1,neig1,eigval2,neig2); if (!CompFile && !bProj && !OverlapFile && !InpMatFile && !bCompare && !bEntropy) { fprintf(stderr,"\nIf you want some output," " set one (or two or ...) of the output file options\n"); } view_all(oenv,NFILE, fnm); thanx(stdout); return 0; }
static void project(const char *trajfile,t_topology *top,int ePBC,matrix topbox, const char *projfile,const char *twodplotfile, const char *threedplotfile, const char *filterfile,int skip, const char *extremefile,gmx_bool bExtrAll,real extreme, int nextr, t_atoms *atoms,int natoms,atom_id *index, gmx_bool bFit,rvec *xref,int nfit,atom_id *ifit,real *w_rls, real *sqrtm,rvec *xav, int *eignr,rvec **eigvec, int noutvec,int *outvec, gmx_bool bSplit, const output_env_t oenv) { FILE *xvgrout=NULL; int nat,i,j,d,v,vec,nfr,nframes=0,snew_size,frame; t_trxstatus *out=NULL; t_trxstatus *status; int noutvec_extr,imin,imax; real *pmin,*pmax; atom_id *all_at; matrix box; rvec *xread,*x; real t,inp,**inprod=NULL,min=0,max=0; char str[STRLEN],str2[STRLEN],**ylabel,*c; real fact; gmx_rmpbc_t gpbc=NULL; snew(x,natoms); if (bExtrAll) noutvec_extr=noutvec; else noutvec_extr=1; if (trajfile) { snew(inprod,noutvec+1); if (filterfile) { fprintf(stderr,"Writing a filtered trajectory to %s using eigenvectors\n", filterfile); for(i=0; i<noutvec; i++) fprintf(stderr,"%d ",outvec[i]+1); fprintf(stderr,"\n"); out=open_trx(filterfile,"w"); } snew_size=0; nfr=0; nframes=0; nat=read_first_x(oenv,&status,trajfile,&t,&xread,box); if (nat>atoms->nr) gmx_fatal(FARGS,"the number of atoms in your trajectory (%d) is larger than the number of atoms in your structure file (%d)",nat,atoms->nr); snew(all_at,nat); if (top) gpbc = gmx_rmpbc_init(&top->idef,ePBC,nat,box); for(i=0; i<nat; i++) all_at[i]=i; do { if (nfr % skip == 0) { if (top) gmx_rmpbc(gpbc,nat,box,xread); if (nframes>=snew_size) { snew_size+=100; for(i=0; i<noutvec+1; i++) srenew(inprod[i],snew_size); } inprod[noutvec][nframes]=t; /* calculate x: a fitted struture of the selected atoms */ if (bFit) { reset_x(nfit,ifit,nat,NULL,xread,w_rls); do_fit(nat,w_rls,xref,xread); } for (i=0; i<natoms; i++) copy_rvec(xread[index[i]],x[i]); for(v=0; v<noutvec; v++) { vec=outvec[v]; /* calculate (mass-weighted) projection */ inp=0; for (i=0; i<natoms; i++) { inp+=(eigvec[vec][i][0]*(x[i][0]-xav[i][0])+ eigvec[vec][i][1]*(x[i][1]-xav[i][1])+ eigvec[vec][i][2]*(x[i][2]-xav[i][2]))*sqrtm[i]; } inprod[v][nframes]=inp; } if (filterfile) { for(i=0; i<natoms; i++) for(d=0; d<DIM; d++) { /* misuse xread for output */ xread[index[i]][d] = xav[i][d]; for(v=0; v<noutvec; v++) xread[index[i]][d] += inprod[v][nframes]*eigvec[outvec[v]][i][d]/sqrtm[i]; } write_trx(out,natoms,index,atoms,0,t,box,xread,NULL,NULL); } nframes++; } nfr++; } while (read_next_x(oenv,status,&t,nat,xread,box)); close_trx(status); sfree(x); if (filterfile) close_trx(out); } else snew(xread,atoms->nr); if (top) gmx_rmpbc_done(gpbc); if (projfile) { snew(ylabel,noutvec); for(v=0; v<noutvec; v++) { sprintf(str,"vec %d",eignr[outvec[v]]+1); ylabel[v]=strdup(str); } sprintf(str,"projection on eigenvectors (%s)",proj_unit); write_xvgr_graphs(projfile, noutvec, 1, str, NULL, output_env_get_xvgr_tlabel(oenv), (const char **)ylabel, nframes, inprod[noutvec], inprod, NULL, output_env_get_time_factor(oenv), FALSE, bSplit,oenv); } if (twodplotfile) { sprintf(str,"projection on eigenvector %d (%s)", eignr[outvec[0]]+1,proj_unit); sprintf(str2,"projection on eigenvector %d (%s)", eignr[outvec[noutvec-1]]+1,proj_unit); xvgrout=xvgropen(twodplotfile,"2D projection of trajectory",str,str2, oenv); for(i=0; i<nframes; i++) { if ( bSplit && i>0 && abs(inprod[noutvec][i])<1e-5 ) fprintf(xvgrout,"&\n"); fprintf(xvgrout,"%10.5f %10.5f\n",inprod[0][i],inprod[noutvec-1][i]); } ffclose(xvgrout); } if (threedplotfile) { t_atoms atoms; rvec *x; real *b=NULL; matrix box; char *resnm,*atnm, pdbform[STRLEN]; gmx_bool bPDB, b4D; FILE *out; if (noutvec < 3) gmx_fatal(FARGS,"You have selected less than 3 eigenvectors"); /* initialize */ bPDB = fn2ftp(threedplotfile)==efPDB; clear_mat(box); box[XX][XX] = box[YY][YY] = box[ZZ][ZZ] = 1; b4D = bPDB && (noutvec >= 4); if (b4D) { fprintf(stderr, "You have selected four or more eigenvectors:\n" "fourth eigenvector will be plotted " "in bfactor field of pdb file\n"); sprintf(str,"4D proj. of traj. on eigenv. %d, %d, %d and %d", eignr[outvec[0]]+1,eignr[outvec[1]]+1, eignr[outvec[2]]+1,eignr[outvec[3]]+1); } else { sprintf(str,"3D proj. of traj. on eigenv. %d, %d and %d", eignr[outvec[0]]+1,eignr[outvec[1]]+1,eignr[outvec[2]]+1); } init_t_atoms(&atoms,nframes,FALSE); snew(x,nframes); snew(b,nframes); atnm=strdup("C"); resnm=strdup("PRJ"); if(nframes>10000) fact=10000.0/nframes; else fact=1.0; for(i=0; i<nframes; i++) { atoms.atomname[i] = &atnm; atoms.atom[i].resind = i; atoms.resinfo[i].name = &resnm; atoms.resinfo[i].nr = ceil(i*fact); atoms.resinfo[i].ic = ' '; x[i][XX]=inprod[0][i]; x[i][YY]=inprod[1][i]; x[i][ZZ]=inprod[2][i]; if (b4D) b[i] =inprod[3][i]; } if ( ( b4D || bSplit ) && bPDB ) { strcpy(pdbform,get_pdbformat()); strcat(pdbform,"%8.4f%8.4f\n"); out=ffopen(threedplotfile,"w"); fprintf(out,"HEADER %s\n",str); if ( b4D ) fprintf(out,"REMARK %s\n","fourth dimension plotted as B-factor"); j=0; for(i=0; i<atoms.nr; i++) { if ( j>0 && bSplit && abs(inprod[noutvec][i])<1e-5 ) { fprintf(out,"TER\n"); j=0; } fprintf(out,pdbform,"ATOM",i+1,"C","PRJ",' ',j+1, PR_VEC(10*x[i]), 1.0, 10*b[i]); if (j>0) fprintf(out,"CONECT%5d%5d\n", i, i+1); j++; } fprintf(out,"TER\n"); ffclose(out); } else write_sto_conf(threedplotfile,str,&atoms,x,NULL,ePBC,box); free_t_atoms(&atoms,FALSE); } if (extremefile) { snew(pmin,noutvec_extr); snew(pmax,noutvec_extr); if (extreme==0) { fprintf(stderr,"%11s %17s %17s\n","eigenvector","Minimum","Maximum"); fprintf(stderr, "%11s %10s %10s %10s %10s\n","","value","frame","value","frame"); imin = 0; imax = 0; for(v=0; v<noutvec_extr; v++) { for(i=0; i<nframes; i++) { if (inprod[v][i]<inprod[v][imin]) imin = i; if (inprod[v][i]>inprod[v][imax]) imax = i; } pmin[v] = inprod[v][imin]; pmax[v] = inprod[v][imax]; fprintf(stderr,"%7d %10.6f %10d %10.6f %10d\n", eignr[outvec[v]]+1, pmin[v],imin,pmax[v],imax); } } else { pmin[0] = -extreme; pmax[0] = extreme; } /* build format string for filename: */ strcpy(str,extremefile);/* copy filename */ c=strrchr(str,'.'); /* find where extention begins */ strcpy(str2,c); /* get extention */ sprintf(c,"%%d%s",str2); /* append '%s' and extention to filename */ for(v=0; v<noutvec_extr; v++) { /* make filename using format string */ if (noutvec_extr==1) strcpy(str2,extremefile); else sprintf(str2,str,eignr[outvec[v]]+1); fprintf(stderr,"Writing %d frames along eigenvector %d to %s\n", nextr,outvec[v]+1,str2); out=open_trx(str2,"w"); for(frame=0; frame<nextr; frame++) { if ((extreme==0) && (nextr<=3)) for(i=0; i<natoms; i++) { atoms->resinfo[atoms->atom[index[i]].resind].chainid = 'A' + frame; } for(i=0; i<natoms; i++) for(d=0; d<DIM; d++) xread[index[i]][d] = (xav[i][d] + (pmin[v]*(nextr-frame-1)+pmax[v]*frame)/(nextr-1) *eigvec[outvec[v]][i][d]/sqrtm[i]); write_trx(out,natoms,index,atoms,0,frame,topbox,xread,NULL,NULL); } close_trx(out); } sfree(pmin); sfree(pmax); } fprintf(stderr,"\n"); }
void TrajectoryAnalysisRunnerCommon::initFirstFrame() { // Return if we have already initialized the trajectory. if (impl_->fr) { return; } time_unit_t time_unit = static_cast<time_unit_t>(impl_->settings_.timeUnit() + 1); output_env_init(&impl_->oenv_, 0, NULL, time_unit, FALSE, exvgNONE, 0, 0); int frflags = impl_->settings_.frflags(); frflags |= TRX_NEED_X; snew(impl_->fr, 1); const TopologyInformation &top = impl_->topInfo_; if (hasTrajectory()) { if (!read_first_frame(impl_->oenv_, &impl_->status_, impl_->trjfile_.c_str(), impl_->fr, frflags)) { GMX_THROW(FileIOError("Could not read coordinates from trajectory")); } impl_->bTrajOpen_ = true; if (top.hasTopology() && impl_->fr->natoms > top.topology()->atoms.nr) { GMX_THROW(InconsistentInputError(formatString( "Trajectory (%d atoms) does not match topology (%d atoms)", impl_->fr->natoms, top.topology()->atoms.nr))); } // Check index groups if they have been initialized based on the topology. /* if (top) { for (int i = 0; i < impl_->sel->nr(); ++i) { gmx_ana_index_check(impl_->sel->sel(i)->indexGroup(), impl_->fr->natoms); } } */ } else { // Prepare a frame from topology information. // TODO: Initialize more of the fields. if (frflags & (TRX_NEED_V)) { GMX_THROW(NotImplementedError("Velocity reading from a topology not implemented")); } if (frflags & (TRX_NEED_F)) { GMX_THROW(InvalidInputError("Forces cannot be read from a topology")); } impl_->fr->flags = frflags; impl_->fr->natoms = top.topology()->atoms.nr; impl_->fr->bX = TRUE; snew(impl_->fr->x, impl_->fr->natoms); memcpy(impl_->fr->x, top.xtop_, sizeof(*impl_->fr->x) * impl_->fr->natoms); impl_->fr->bBox = TRUE; copy_mat(const_cast<rvec *>(top.boxtop_), impl_->fr->box); } set_trxframe_ePBC(impl_->fr, top.ePBC()); if (top.hasTopology() && impl_->settings_.hasRmPBC()) { impl_->gpbc_ = gmx_rmpbc_init(&top.topology()->idef, top.ePBC(), impl_->fr->natoms, impl_->fr->box); } }
int gmx_dist(int argc,char *argv[]) { const char *desc[] = { "[TT]g_dist[tt] can calculate the distance between the centers of mass of two", "groups of atoms as a function of time. The total distance and its", "[IT]x[it]-, [IT]y[it]-, and [IT]z[it]-components are plotted.[PAR]", "Or when [TT]-dist[tt] is set, print all the atoms in group 2 that are", "closer than a certain distance to the center of mass of group 1.[PAR]", "With options [TT]-lt[tt] and [TT]-dist[tt] the number of contacts", "of all atoms in group 2 that are closer than a certain distance", "to the center of mass of group 1 are plotted as a function of the time", "that the contact was continuously present.[PAR]", "Other programs that calculate distances are [TT]g_mindist[tt]", "and [TT]g_bond[tt]." }; t_topology *top=NULL; int ePBC; real t,t0,cut2,dist2; rvec *x=NULL,*v=NULL,dx; matrix box; t_trxstatus *status; int natoms; int g,d,i,j,res,teller=0; atom_id aid; int ngrps; /* the number of index groups */ atom_id **index,max; /* the index for the atom numbers */ int *isize; /* the size of each group */ char **grpname; /* the name of each group */ rvec *com; real *mass; FILE *fp=NULL,*fplt=NULL; gmx_bool bCutoff,bPrintDist,bLifeTime; t_pbc *pbc; int *contact_time=NULL,*ccount=NULL,ccount_nalloc=0,sum; char buf[STRLEN]; output_env_t oenv; gmx_rmpbc_t gpbc=NULL; const char *leg[4] = { "|d|","d\\sx\\N","d\\sy\\N","d\\sz\\N" }; static real cut=0; static t_pargs pa[] = { { "-dist", FALSE, etREAL, {&cut}, "Print all atoms in group 2 closer than dist to the center of mass of group 1" } }; #define NPA asize(pa) t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPX, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, NULL, "dist", ffOPTWR }, { efXVG, "-lt", "lifetime", ffOPTWR }, }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_BE_NICE, NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL,&oenv); bCutoff = opt2parg_bSet("-dist",NPA,pa); cut2 = cut*cut; bLifeTime = opt2bSet("-lt",NFILE,fnm); bPrintDist = (bCutoff && !bLifeTime); top=read_top(ftp2fn(efTPX,NFILE,fnm),&ePBC); /* read index files */ ngrps = 2; snew(com,ngrps); snew(grpname,ngrps); snew(index,ngrps); snew(isize,ngrps); get_index(&top->atoms,ftp2fn(efNDX,NFILE,fnm),ngrps,isize,index,grpname); /* calculate mass */ max=0; snew(mass,ngrps); for(g=0;(g<ngrps);g++) { mass[g]=0; for(i=0;(i<isize[g]);i++) { if (index[g][i]>max) max=index[g][i]; if (index[g][i] >= top->atoms.nr) gmx_fatal(FARGS,"Atom number %d, item %d of group %d, is larger than number of atoms in the topolgy (%d)\n",index[g][i]+1,i+1,g+1,top->atoms.nr+1); mass[g]+=top->atoms.atom[index[g][i]].m; } } natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); t0 = t; if (max>=natoms) gmx_fatal(FARGS,"Atom number %d in an index group is larger than number of atoms in the trajectory (%d)\n",(int)max+1,natoms); if (!bCutoff) { /* open output file */ fp = xvgropen(ftp2fn(efXVG,NFILE,fnm), "Distance","Time (ps)","Distance (nm)",oenv); xvgr_legend(fp,4,leg,oenv); } else { ngrps = 1; if (bLifeTime) snew(contact_time,isize[1]); } if (ePBC != epbcNONE) snew(pbc,1); else pbc = NULL; gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box); do { /* initialisation for correct distance calculations */ if (pbc) { set_pbc(pbc,ePBC,box); /* make molecules whole again */ gmx_rmpbc(gpbc,natoms,box,x); } /* calculate center of masses */ for(g=0;(g<ngrps);g++) { if (isize[g] == 1) { copy_rvec(x[index[g][0]],com[g]); } else { for(d=0;(d<DIM);d++) { com[g][d]=0; for(i=0;(i<isize[g]);i++) { com[g][d] += x[index[g][i]][d] * top->atoms.atom[index[g][i]].m; } com[g][d] /= mass[g]; } } } if (!bCutoff) { /* write to output */ fprintf(fp,"%12.7f ",t); for(g=0;(g<ngrps/2);g++) { if (pbc) pbc_dx(pbc,com[2*g],com[2*g+1],dx); else rvec_sub(com[2*g],com[2*g+1],dx); fprintf(fp,"%12.7f %12.7f %12.7f %12.7f", norm(dx),dx[XX],dx[YY],dx[ZZ]); } fprintf(fp,"\n"); } else { for(i=0;(i<isize[1]);i++) { j=index[1][i]; if (pbc) pbc_dx(pbc,x[j],com[0],dx); else rvec_sub(x[j],com[0],dx); dist2 = norm2(dx); if (dist2<cut2) { if (bPrintDist) { res=top->atoms.atom[j].resind; fprintf(stdout,"\rt: %g %d %s %d %s %g (nm)\n", t,top->atoms.resinfo[res].nr,*top->atoms.resinfo[res].name, j+1,*top->atoms.atomname[j],sqrt(dist2)); } if (bLifeTime) contact_time[i]++; } else { if (bLifeTime) { if (contact_time[i]) { add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1); contact_time[i] = 0; } } } } } teller++; } while (read_next_x(oenv,status,&t,natoms,x,box)); gmx_rmpbc_done(gpbc); if (!bCutoff) ffclose(fp); close_trj(status); if (bCutoff && bLifeTime) { /* Add the contacts still present in the last frame */ for(i=0; i<isize[1]; i++) if (contact_time[i]) add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1); sprintf(buf,"%s - %s within %g nm", grpname[0],grpname[1],cut); fp = xvgropen(opt2fn("-lt",NFILE,fnm), buf,"Time (ps)","Number of contacts",oenv); for(i=0; i<min(ccount_nalloc,teller-1); i++) { /* Account for all subintervals of longer intervals */ sum = 0; for(j=i; j<ccount_nalloc; j++) sum += (j-i+1)*ccount[j]; fprintf(fp,"%10.3f %10.3f\n",i*(t-t0)/(teller-1),sum/(double)(teller-i)); } ffclose(fp); } thanx(stderr); return 0; }