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_rmsf(int argc,char *argv[]) { static char *desc[] = { "g_rmsf computes the root mean square fluctuation (RMSF, i.e. standard ", "deviation) of atomic positions ", "after (optionally) fitting to a reference frame.[PAR]", "With option [TT]-oq[tt] the RMSF values are converted to B-factor", "values, which are written to a pdb file with the coordinates, of the", "structure file, or of a pdb 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] g_rmsf will compute anisotropic", "temperature factors and then it will also output average coordinates", "and a pdb 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 pdb 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 pdb 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 bool bRes=FALSE,bAniso=FALSE,bdevX=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 step,nre,natom,natoms,i,g,m,teller=0; real t,lambda,*w_rls,*w_rms; t_tpxheader header; t_inputrec ir; t_topology top; int ePBC; t_atoms *pdbatoms,*refatoms; bool bCont; matrix box,pdbbox; rvec *x,*pdbx,*xref; int status,npdbatoms,res0; char buf[256],*label; char title[STRLEN]; FILE *fp; /* the graphics file */ char *devfn,*dirfn; int resnr; bool bReadPDB; atom_id *index; int isize; char *grpnames; real bfac,pdb_bfac,*Uaver; double **U,*xav; atom_id aid; rvec *rmsd_x=NULL; real *rmsf,invcount,totmass; int d; real count=0; rvec xcm; char *leg[2] = { "MD", "X-Ray" }; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efPDB, "-q", NULL, 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) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE , NFILE,fnm,asize(pargs),pargs,asize(desc),desc,0,NULL); bReadPDB = ftp2bSet(efPDB,NFILE,fnm); devfn = opt2fn_null("-od",NFILE,fnm); dirfn = opt2fn_null("-dir",NFILE,fnm); read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xref,NULL,box,TRUE); 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) { get_stx_coordnum(opt2fn("-q",NFILE,fnm),&npdbatoms); snew(pdbatoms,1); snew(refatoms,1); init_t_atoms(pdbatoms,npdbatoms,TRUE); init_t_atoms(refatoms,npdbatoms,TRUE); snew(pdbx,npdbatoms); /* Read coordinates twice */ read_stx_conf(opt2fn("-q",NFILE,fnm),title,pdbatoms,pdbx,NULL,NULL,pdbbox); read_stx_conf(opt2fn("-q",NFILE,fnm),title,refatoms,pdbx,NULL,NULL,pdbbox); } else { pdbatoms = &top.atoms; refatoms = &top.atoms; pdbx = xref; npdbatoms = pdbatoms->nr; snew(pdbatoms->pdbinfo,npdbatoms); copy_mat(box,pdbbox); } if (bFit) sub_xcm(xref,isize,index,top.atoms.atom,xcm,FALSE); natom = read_first_x(&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); /* Now read the trj again to compute fluctuations */ teller = 0; do { if (bFit) { /* Remove periodic boundary */ rm_pbc(&(top.idef),ePBC,natom,box,x,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] += sqr(x[aid][d]-xref[aid][d]); } } } count += 1.0; teller++; } while(read_next_x(status,&t,natom,x,box)); close_trj(status); 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 (bAniso) { for(i=0; i<isize; i++) { aid = index[i]; pdbatoms->pdbinfo[aid].bAnisotropic = TRUE; pdbatoms->pdbinfo[aid].uij[U11] = 1e6*U[i][XX*DIM + XX]; pdbatoms->pdbinfo[aid].uij[U22] = 1e6*U[i][YY*DIM + YY]; pdbatoms->pdbinfo[aid].uij[U33] = 1e6*U[i][ZZ*DIM + ZZ]; pdbatoms->pdbinfo[aid].uij[U12] = 1e6*U[i][XX*DIM + YY]; pdbatoms->pdbinfo[aid].uij[U13] = 1e6*U[i][XX*DIM + ZZ]; pdbatoms->pdbinfo[aid].uij[U23] = 1e6*U[i][YY*DIM + ZZ]; } } if (bRes) { average_residues(rmsf,isize,index,w_rls,&top.atoms); 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 = ffopen(dirfn,"w"); print_dir(fp,Uaver); fclose(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)"); xvgr_legend(fp,2,leg); for(i=0;(i<isize);i++) { if (!bRes || i+1==isize || top.atoms.atom[index[i]].resnr!=top.atoms.atom[index[i+1]].resnr) { resnr = top.atoms.atom[index[i]].resnr; pdb_bfac = find_pdb_bfac(pdbatoms,*(top.atoms.resname[resnr]),resnr, *(top.atoms.atomname[index[i]])); fprintf(fp,"%5d %10.5f %10.5f\n", bRes ? top.atoms.atom[index[i]].resnr+1 : i+1,rmsf[i]*bfac, pdb_bfac); } } fclose(fp); } else { fp = xvgropen(ftp2fn(efXVG,NFILE,fnm),"RMS fluctuation",label,"(nm)"); for(i=0; i<isize; i++) if (!bRes || i+1==isize || top.atoms.atom[index[i]].resnr!=top.atoms.atom[index[i+1]].resnr) fprintf(fp,"%5d %8.4f\n", bRes ? top.atoms.atom[index[i]].resnr+1 : i+1,sqrt(rmsf[i])); fclose(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,isize,index,w_rls,&top.atoms); /* Write RMSD output */ fp = xvgropen(devfn,"RMS Deviation",label,"(nm)"); for(i=0; i<isize; i++) if (!bRes || i+1==isize || top.atoms.atom[index[i]].resnr!=top.atoms.atom[index[i+1]].resnr) fprintf(fp,"%5d %8.4f\n", bRes ? top.atoms.atom[index[i]].resnr+1 : i+1,sqrt(rmsf[i])); fclose(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(xref[index[i]],xcm); write_sto_conf_indexed(opt2fn("-oq",NFILE,fnm),title,pdbatoms,pdbx, NULL,ePBC,pdbbox,isize,index); } if (opt2bSet("-ox",NFILE,fnm)) { /* Misuse xref as a temporary array */ for(i=0; i<isize; i++) for(d=0; d<DIM; d++) xref[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,xref,NULL, ePBC,pdbbox,isize,index); } if (bAniso) { correlate_aniso(opt2fn("-oc",NFILE,fnm),refatoms,pdbatoms); do_view(opt2fn("-oc",NFILE,fnm),"-nxy"); } do_view(opt2fn("-o",NFILE,fnm),"-nxy"); if (devfn) do_view(opt2fn("-od",NFILE,fnm),"-nxy"); thanx(stderr); return 0; }