bool new_data(t_xrama *xr) { if (!read_next_x(xr->traj,&xr->t,xr->natoms,xr->x,xr->box)) return FALSE; calc_dihs(xr); return TRUE; }
gmx_bool new_data(t_xrama *xr) { if (!read_next_x(xr->oenv, xr->traj, &xr->t, xr->x, xr->box)) { return FALSE; } calc_dihs(xr); return TRUE; }
static bool step_man(t_manager *man, int *nat) { static int ncount = 0; static bool bWarn = false; bool bEof; const char *warn; if (!man->natom) { fprintf(stderr, "Not initiated yet!"); exit(1); } bEof = read_next_x(man->oenv, man->status, &man->time, man->x, man->box); *nat = man->natom; if (ncount == man->nSkip) { switch (man->molw->boxtype) { case esbTri: put_atoms_in_triclinic_unitcell(ecenterDEF, man->box, man->natom, man->x); break; case esbTrunc: warn = put_atoms_in_compact_unitcell(man->molw->ePBC, ecenterDEF, man->box, man->natom, man->x); if (warn && !bWarn) { fprintf(stderr, "\n%s\n", warn); bWarn = true; } break; case esbRect: case esbNone: default: break; } if (man->bPbc) { gmx_rmpbc(man->gpbc, man->natom, man->box, man->x); reset_mols(&(man->top.mols), man->box, man->x); } ncount = 0; } else { if (man->nSkip > 0) { ncount++; return step_man(man, nat); } } return bEof; }
static bool step_man(t_manager *man, int *nat) { static int ncount = 0; bool bEof; if (!man->natom) { std::fprintf(stderr, "Not initiated yet!"); std::exit(1); } bEof = read_next_x(man->oenv, man->status, &man->time, man->x, man->box); *nat = man->natom; if (ncount == man->nSkip) { auto atomsArrayRef = gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec *>(man->x), man->natom); switch (man->molw->boxtype) { case esbTri: put_atoms_in_triclinic_unitcell(ecenterDEF, man->box, atomsArrayRef); break; case esbTrunc: put_atoms_in_compact_unitcell(man->molw->ePBC, ecenterDEF, man->box, atomsArrayRef); break; case esbRect: case esbNone: default: break; } if (man->bPbc) { gmx_rmpbc(man->gpbc, man->natom, man->box, man->x); reset_mols(&(man->top.mols), man->box, man->x); } ncount = 0; } else { if (man->nSkip > 0) { ncount++; return step_man(man, nat); } } return bEof; }
int gmx_rotacf(int argc,char *argv[]) { static char *desc[] = { "g_rotacf calculates the rotational correlation function", "for molecules. Three atoms (i,j,k) must be given in the index", "file, defining two vectors ij and jk. The rotational acf", "is calculated as the autocorrelation function of the vector", "n = ij x jk, i.e. the cross product of the two vectors.", "Since three atoms span a plane, the order of the three atoms", "does not matter. Optionally, controlled by the -d switch, you can", "calculate the rotational correlation function for linear molecules", "by specifying two atoms (i,j) in the index file.", "[PAR]", "EXAMPLES[PAR]", "g_rotacf -P 1 -nparm 2 -fft -n index -o rotacf-x-P1", "-fa expfit-x-P1 -beginfit 2.5 -endfit 20.0[PAR]", "This will calculate the rotational correlation function using a first", "order Legendre polynomial of the angle of a vector defined by the index", "file. The correlation function will be fitted from 2.5 ps till 20.0 ps", "to a two parameter exponential", "" }; static bool bVec = FALSE,bAver=TRUE; t_pargs pa[] = { { "-d", FALSE, etBOOL, {&bVec}, "Use index doublets (vectors) for correlation function instead of triplets (planes)" }, { "-aver",FALSE, etBOOL, {&bAver}, "Average over molecules" } }; int status,isize; atom_id *index; char *grpname; rvec *x,*x_s; matrix box; real **c1; rvec xij,xjk,n; int i,m,teller,n_alloc,natoms,nvec,ai,aj,ak; unsigned long mode; real t,t0,t1,dt; t_topology *top; int ePBC; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPX, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffREAD }, { efXVG, "-o", "rotacf", ffWRITE } }; #define NFILE asize(fnm) int npargs; t_pargs *ppa; CopyRight(stderr,argv[0]); npargs = asize(pa); ppa = add_acf_pargs(&npargs,pa); parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE, NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL); rd_index(ftp2fn(efNDX,NFILE,fnm),1,&isize,&index,&grpname); if (bVec) nvec = isize/2; else nvec = isize/3; if (((isize % 3) != 0) && !bVec) gmx_fatal(FARGS,"number of index elements not multiple of 3, " "these can not be atom triplets\n"); if (((isize % 2) != 0) && bVec) gmx_fatal(FARGS,"number of index elements not multiple of 2, " "these can not be atom doublets\n"); top=read_top(ftp2fn(efTPX,NFILE,fnm),&ePBC); snew(c1,nvec); for (i=0; (i<nvec); i++) c1[i]=NULL; n_alloc=0; natoms=read_first_x(&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); snew(x_s,natoms); /* Start the loop over frames */ t1 = t0 = t; teller = 0; do { if (teller >= n_alloc) { n_alloc+=100; for (i=0; (i<nvec); i++) srenew(c1[i],DIM*n_alloc); } t1 = t; /* Remove periodicity */ rm_pbc(&(top->idef),ePBC,natoms,box,x,x_s); /* Compute crossproducts for all vectors, if triplets. * else, just get the vectors in case of doublets. */ if (bVec == FALSE) { for (i=0; (i<nvec); i++) { ai=index[3*i]; aj=index[3*i+1]; ak=index[3*i+2]; rvec_sub(x_s[ai],x_s[aj],xij); rvec_sub(x_s[aj],x_s[ak],xjk); cprod(xij,xjk,n); for(m=0; (m<DIM); m++) c1[i][DIM*teller+m]=n[m]; } } else { for (i=0; (i<nvec); i++) { ai=index[2*i]; aj=index[2*i+1]; rvec_sub(x_s[ai],x_s[aj],n); for(m=0; (m<DIM); m++) c1[i][DIM*teller+m]=n[m]; } } /* Increment loop counter */ teller++; } while (read_next_x(status,&t,natoms,x,box)); close_trj(status); fprintf(stderr,"\nDone with trajectory\n"); /* Autocorrelation function */ if (teller < 2) fprintf(stderr,"Not enough frames for correlation function\n"); else { dt=(t1 - t0)/(teller-1); mode = eacVector; do_autocorr(ftp2fn(efXVG,NFILE,fnm),"Rotational Correlation Function", teller,nvec,c1,dt,mode,bAver); } do_view(ftp2fn(efXVG,NFILE,fnm),NULL); thanx(stderr); return 0; }
void read_ang_dih(const char *trj_fn, gmx_bool bAngles, gmx_bool bSaveAll, gmx_bool bRb, gmx_bool bPBC, int maxangstat, int angstat[], int *nframes, real **time, int isize, atom_id index[], real **trans_frac, real **aver_angle, real *dih[], const output_env_t oenv) { t_pbc *pbc; t_trxstatus *status; int i, angind, natoms, total, teller; int nangles, n_alloc; real t, fraction, pifac, aa, angle; real *angles[2]; matrix box; rvec *x; int cur = 0; #define prev (1-cur) snew(pbc, 1); natoms = read_first_x(oenv, &status, trj_fn, &t, &x, box); if (bAngles) { nangles = isize/3; pifac = M_PI; } else { nangles = isize/4; pifac = 2.0*M_PI; } snew(angles[cur], nangles); snew(angles[prev], nangles); /* Start the loop over frames */ total = 0; teller = 0; n_alloc = 0; *time = NULL; *trans_frac = NULL; *aver_angle = NULL; do { if (teller >= n_alloc) { n_alloc += 100; if (bSaveAll) { for (i = 0; (i < nangles); i++) { srenew(dih[i], n_alloc); } } srenew(*time, n_alloc); srenew(*trans_frac, n_alloc); srenew(*aver_angle, n_alloc); } (*time)[teller] = t; if (pbc) { set_pbc(pbc, -1, box); } if (bAngles) { calc_angles(pbc, isize, index, angles[cur], x); } else { calc_dihs(pbc, isize, index, angles[cur], x); /* Trans fraction */ fraction = calc_fraction(angles[cur], nangles); (*trans_frac)[teller] = fraction; /* Change Ryckaert-Bellemans dihedrals to polymer convention * Modified 990913 by Erik: * We actually shouldn't change the convention, since it's * calculated from polymer above, but we change the intervall * from [-180,180] to [0,360]. */ if (bRb) { for (i = 0; (i < nangles); i++) { if (angles[cur][i] <= 0.0) { angles[cur][i] += 2*M_PI; } } } /* Periodicity in dihedral space... */ if (bPBC) { for (i = 0; (i < nangles); i++) { real dd = angles[cur][i]; angles[cur][i] = atan2(sin(dd), cos(dd)); } } else { if (teller > 1) { for (i = 0; (i < nangles); i++) { while (angles[cur][i] <= angles[prev][i] - M_PI) { angles[cur][i] += 2*M_PI; } while (angles[cur][i] > angles[prev][i] + M_PI) { angles[cur][i] -= 2*M_PI; } } } } } /* Average angles */ aa = 0; for (i = 0; (i < nangles); i++) { aa = aa+angles[cur][i]; /* angle in rad / 2Pi * max determines bin. bins go from 0 to maxangstat, even though scale goes from -pi to pi (dihedral) or -pi/2 to pi/2 (angle) Basically: translate the x-axis by Pi. Translate it back by -Pi when plotting. */ angle = angles[cur][i]; if (!bAngles) { while (angle < -M_PI) { angle += 2*M_PI; } while (angle >= M_PI) { angle -= 2*M_PI; } angle += M_PI; } /* Update the distribution histogram */ angind = (int) ((angle*maxangstat)/pifac + 0.5); if (angind == maxangstat) { angind = 0; } if ( (angind < 0) || (angind >= maxangstat) ) { /* this will never happen */ gmx_fatal(FARGS, "angle (%f) index out of range (0..%d) : %d\n", angle, maxangstat, angind); } angstat[angind]++; if (angind == maxangstat) { fprintf(stderr, "angle %d fr %d = %g\n", i, cur, angle); } total++; } /* average over all angles */ (*aver_angle)[teller] = (aa/nangles); /* this copies all current dih. angles to dih[i], teller is frame */ if (bSaveAll) { for (i = 0; i < nangles; i++) { dih[i][teller] = angles[cur][i]; } } /* Swap buffers */ cur = prev; /* Increment loop counter */ teller++; } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); sfree(x); sfree(angles[cur]); sfree(angles[prev]); *nframes = teller; }
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; }
/* scan trajectory and accumulate data */ static int dotrj(hist_t *hsrms, bb_t *bb, int rescnt, FILE *fplog, trj_t *trj, const char *fxtc, rvec *xrefbb, int nat, matrix box, double *wtot) { int nfr, match, natoms; int fpxtc = 0; /* gromacs file handle for trj */ rvec *x = NULL, *xbb; double t1, w, rmsd; real t = 0.f; xnew(xbb, rescnt * 3); /* loop over xtc frames */ for (nfr = 0; ; nfr++) { if (nfr == 0) { /* first frame, get the file handle fpxtc, allocate x * and check the number of atoms */ natoms = read_first_x(&fpxtc, fxtc, &t, &x, box); if (natoms != nat) { fprintf(stderr, "natoms mismatch! top %d, xtc %d\n", nat, natoms); return -1; } } else { if (!read_next_x(fpxtc, &t, natoms, x, box)) break; } if (ctmd) { /* each frame has a weight */ w = 1.; } else { /* for each xtc frame, we search a corresponding * frame in trj at the same time */ for (match = 0; trj->pos < trj->n; trj->pos++) { t1 = trj->fr[trj->pos].t; if (fabs(t1 - t) < 0.5) { match = 1; break; } else if (t1 > t + 0.5) { fprintf(stderr, "time difference %g (trace), %g (xtc)\n", t1, t); return -1; } } if (!match) { fprintf(stderr, "cannot find a frame for t = %g\n", t); break; } if (!trj->fr[trj->pos].in) { w = 0.0; } else { w = exp(trj->fr[trj->pos].lnw); } } /* skip trivial frames */ if (fplog == NULL && w < 1e-6) continue; /* extract backbone indices */ xgetbb(xbb, x, bb, rescnt); /* fit x to xref */ rmsd = rv3_rmsd(xbb, NULL, xrefbb, vmass, rescnt*3, 0, NULL, NULL); if (fplog) { fprintf(fplog, "%10.0f %8.4f %g %d\n", t, rmsd, w, trj->fr[trj->pos].dataid); } hs_add(hsrms, &rmsd, w, HIST_VERBOSE); *wtot += w; } free(xbb); 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_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; }
int gmx_gyrate(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the radius of gyration of a molecule", "and the radii of gyration about the [IT]x[it]-, [IT]y[it]- and [IT]z[it]-axes,", "as a function of time. The atoms are explicitly mass weighted.[PAR]", "The axis components corresponds to the mass-weighted root-mean-square", "of the radii components orthogonal to each axis, for example:[PAR]", "Rg(x) = sqrt((sum_i m_i (R_i(y)^2 + R_i(z)^2))/(sum_i m_i)).[PAR]", "With the [TT]-nmol[tt] option the radius of gyration will be calculated", "for multiple molecules by splitting the analysis group in equally", "sized parts.[PAR]", "With the option [TT]-nz[tt] 2D radii of gyration in the [IT]x-y[it] plane", "of slices along the [IT]z[it]-axis are calculated." }; static int nmol = 1, nz = 0; static gmx_bool bQ = FALSE, bRot = FALSE, bMOI = FALSE; t_pargs pa[] = { { "-nmol", FALSE, etINT, {&nmol}, "The number of molecules to analyze" }, { "-q", FALSE, etBOOL, {&bQ}, "Use absolute value of the charge of an atom as weighting factor instead of mass" }, { "-p", FALSE, etBOOL, {&bRot}, "Calculate the radii of gyration about the principal axes." }, { "-moi", FALSE, etBOOL, {&bMOI}, "Calculate the moments of inertia (defined by the principal axes)." }, { "-nz", FALSE, etINT, {&nz}, "Calculate the 2D radii of gyration of this number of slices along the z-axis" }, }; FILE *out; t_trxstatus *status; t_topology top; int ePBC; rvec *x, *x_s; rvec xcm, gvec, gvec1; matrix box, trans; gmx_bool bACF; real **moi_trans = NULL; int max_moi = 0, delta_moi = 100; rvec d, d1; /* eigenvalues of inertia tensor */ real t, t0, tm, gyro; int natoms; char *grpname; int j, m, gnx, nam, mol; atom_id *index; gmx_output_env_t *oenv; gmx_rmpbc_t gpbc = NULL; const char *leg[] = { "Rg", "Rg\\sX\\N", "Rg\\sY\\N", "Rg\\sZ\\N" }; const char *legI[] = { "Itot", "I1", "I2", "I3" }; #define NLEG asize(leg) t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, NULL, "gyrate", ffWRITE }, { efXVG, "-acf", "moi-acf", ffOPTWR }, }; #define NFILE asize(fnm) int npargs; t_pargs *ppa; npargs = asize(pa); ppa = add_acf_pargs(&npargs, pa); if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } bACF = opt2bSet("-acf", NFILE, fnm); if (bACF && nmol != 1) { gmx_fatal(FARGS, "Can only do acf with nmol=1"); } bRot = bRot || bMOI || bACF; /* if (nz > 0) bMOI = TRUE; */ if (bRot) { printf("Will rotate system along principal axes\n"); snew(moi_trans, DIM); } if (bMOI) { printf("Will print moments of inertia\n"); bQ = FALSE; } if (bQ) { printf("Will print radius normalised by charge\n"); } read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &x, NULL, box, TRUE); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); if (nmol > gnx || gnx % nmol != 0) { gmx_fatal(FARGS, "The number of atoms in the group (%d) is not a multiple of nmol (%d)", gnx, nmol); } nam = gnx/nmol; natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); snew(x_s, natoms); j = 0; t0 = t; if (bQ) { out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Radius of Charge (total and around axes)", "Time (ps)", "Rg (nm)", oenv); } else if (bMOI) { out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Moments of inertia (total and around axes)", "Time (ps)", "I (a.m.u. nm\\S2\\N)", oenv); } else { out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Radius of gyration (total and around axes)", "Time (ps)", "Rg (nm)", oenv); } if (bMOI) { xvgr_legend(out, NLEG, legI, oenv); } else { if (bRot) { if (output_env_get_print_xvgr_codes(oenv)) { fprintf(out, "@ subtitle \"Axes are principal component axes\"\n"); } } xvgr_legend(out, NLEG, leg, oenv); } if (nz == 0) { gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms); } do { if (nz == 0) { gmx_rmpbc_copy(gpbc, natoms, box, x, x_s); } gyro = 0; clear_rvec(gvec); clear_rvec(gvec1); clear_rvec(d); clear_rvec(d1); for (mol = 0; mol < nmol; mol++) { tm = sub_xcm(nz == 0 ? x_s : x, nam, index+mol*nam, top.atoms.atom, xcm, bQ); if (nz == 0) { gyro += calc_gyro(x_s, nam, index+mol*nam, top.atoms.atom, tm, gvec1, d1, bQ, bRot, bMOI, trans); } else { calc_gyro_z(x, box, nam, index+mol*nam, top.atoms.atom, nz, t, out); } rvec_inc(gvec, gvec1); rvec_inc(d, d1); } if (nmol > 0) { gyro /= nmol; svmul(1.0/nmol, gvec, gvec); svmul(1.0/nmol, d, d); } if (nz == 0) { if (bRot) { if (j >= max_moi) { max_moi += delta_moi; for (m = 0; (m < DIM); m++) { srenew(moi_trans[m], max_moi*DIM); } } for (m = 0; (m < DIM); m++) { copy_rvec(trans[m], moi_trans[m]+DIM*j); } fprintf(out, "%10g %10g %10g %10g %10g\n", t, gyro, d[XX], d[YY], d[ZZ]); } else { fprintf(out, "%10g %10g %10g %10g %10g\n", t, gyro, gvec[XX], gvec[YY], gvec[ZZ]); } } j++; } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); if (nz == 0) { gmx_rmpbc_done(gpbc); } xvgrclose(out); if (bACF) { int mode = eacVector; do_autocorr(opt2fn("-acf", NFILE, fnm), oenv, "Moment of inertia vector ACF", j, 3, moi_trans, (t-t0)/j, mode, FALSE); do_view(oenv, opt2fn("-acf", NFILE, fnm), "-nxy"); } do_view(oenv, ftp2fn(efXVG, NFILE, fnm), "-nxy"); return 0; }
int gmx_disre(int argc,char *argv[]) { const char *desc[] = { "g_disre computes violations of distance restraints.", "If necessary all protons can be added to a protein molecule ", "using the protonate program.[PAR]", "The program always", "computes the instantaneous violations rather than time-averaged,", "because this analysis is done from a trajectory file afterwards", "it does not make sense to use time averaging. However,", "the time averaged values per restraint are given in the log file.[PAR]", "An index file may be used to select specific restraints for", "printing.[PAR]", "When the optional[TT]-q[tt] flag is given a pdb file coloured by the", "amount of average violations.[PAR]", "When the [TT]-c[tt] option is given, an index file will be read", "containing the frames in your trajectory corresponding to the clusters", "(defined in another manner) that you want to analyze. For these clusters", "the program will compute average violations using the third power", "averaging algorithm and print them in the log file." }; static int ntop = 0; static int nlevels = 20; static real max_dr = 0; static gmx_bool bThird = TRUE; t_pargs pa[] = { { "-ntop", FALSE, etINT, {&ntop}, "Number of large violations that are stored in the log file every step" }, { "-maxdr", FALSE, etREAL, {&max_dr}, "Maximum distance violation in matrix output. If less than or equal to 0 the maximum will be determined by the data." }, { "-nlevels", FALSE, etINT, {&nlevels}, "Number of levels in the matrix output" }, { "-third", FALSE, etBOOL, {&bThird}, "Use inverse third power averaging or linear for matrix output" } }; FILE *out=NULL,*aver=NULL,*numv=NULL,*maxxv=NULL,*xvg=NULL; t_tpxheader header; t_inputrec ir; gmx_mtop_t mtop; rvec *xtop; gmx_localtop_t *top; t_atoms *atoms=NULL; t_forcerec *fr; t_fcdata fcd; t_nrnb nrnb; t_commrec *cr; t_graph *g; int ntopatoms,natoms,i,j,kkk; t_trxstatus *status; real t; rvec *x,*f,*xav=NULL; matrix box; gmx_bool bPDB; int isize; atom_id *index=NULL,*ind_fit=NULL; char *grpname; t_cluster_ndx *clust=NULL; t_dr_result dr,*dr_clust=NULL; char **leg; real *vvindex=NULL,*w_rls=NULL; t_mdatoms *mdatoms; t_pbc pbc,*pbc_null; int my_clust; FILE *fplog; output_env_t oenv; gmx_rmpbc_t gpbc=NULL; t_filenm fnm[] = { { efTPX, NULL, NULL, ffREAD }, { efTRX, "-f", NULL, ffREAD }, { efXVG, "-ds", "drsum", ffWRITE }, { efXVG, "-da", "draver", ffWRITE }, { efXVG, "-dn", "drnum", ffWRITE }, { efXVG, "-dm", "drmax", ffWRITE }, { efXVG, "-dr", "restr", ffWRITE }, { efLOG, "-l", "disres", ffWRITE }, { efNDX, NULL, "viol", ffOPTRD }, { efPDB, "-q", "viol", ffOPTWR }, { efNDX, "-c", "clust", ffOPTRD }, { efXPM, "-x", "matrix", ffOPTWR } }; #define NFILE asize(fnm) cr = init_par(&argc,&argv); CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); gmx_log_open(ftp2fn(efLOG,NFILE,fnm),cr,FALSE,0,&fplog); if (ntop) init5(ntop); read_tpxheader(ftp2fn(efTPX,NFILE,fnm),&header,FALSE,NULL,NULL); snew(xtop,header.natoms); read_tpx(ftp2fn(efTPX,NFILE,fnm),&ir,box,&ntopatoms,xtop,NULL,NULL,&mtop); bPDB = opt2bSet("-q",NFILE,fnm); if (bPDB) { snew(xav,ntopatoms); snew(ind_fit,ntopatoms); snew(w_rls,ntopatoms); for(kkk=0; (kkk<ntopatoms); kkk++) { w_rls[kkk] = 1; ind_fit[kkk] = kkk; } snew(atoms,1); *atoms = gmx_mtop_global_atoms(&mtop); if (atoms->pdbinfo == NULL) { snew(atoms->pdbinfo,atoms->nr); } } top = gmx_mtop_generate_local_top(&mtop,&ir); g = NULL; pbc_null = NULL; if (ir.ePBC != epbcNONE) { if (ir.bPeriodicMols) pbc_null = &pbc; else g = mk_graph(fplog,&top->idef,0,mtop.natoms,FALSE,FALSE); } if (ftp2bSet(efNDX,NFILE,fnm)) { rd_index(ftp2fn(efNDX,NFILE,fnm),1,&isize,&index,&grpname); xvg=xvgropen(opt2fn("-dr",NFILE,fnm),"Inidividual Restraints","Time (ps)", "nm",oenv); snew(vvindex,isize); snew(leg,isize); for(i=0; (i<isize); i++) { index[i]++; snew(leg[i],12); sprintf(leg[i],"index %d",index[i]); } xvgr_legend(xvg,isize,(const char**)leg,oenv); } else isize=0; ir.dr_tau=0.0; init_disres(fplog,&mtop,&ir,NULL,FALSE,&fcd,NULL); natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); snew(f,5*natoms); init_dr_res(&dr,fcd.disres.nres); if (opt2bSet("-c",NFILE,fnm)) { clust = cluster_index(fplog,opt2fn("-c",NFILE,fnm)); snew(dr_clust,clust->clust->nr+1); for(i=0; (i<=clust->clust->nr); i++) init_dr_res(&dr_clust[i],fcd.disres.nres); } else { out =xvgropen(opt2fn("-ds",NFILE,fnm), "Sum of Violations","Time (ps)","nm",oenv); aver=xvgropen(opt2fn("-da",NFILE,fnm), "Average Violation","Time (ps)","nm",oenv); numv=xvgropen(opt2fn("-dn",NFILE,fnm), "# Violations","Time (ps)","#",oenv); maxxv=xvgropen(opt2fn("-dm",NFILE,fnm), "Largest Violation","Time (ps)","nm",oenv); } mdatoms = init_mdatoms(fplog,&mtop,ir.efep!=efepNO); atoms2md(&mtop,&ir,0,NULL,0,mtop.natoms,mdatoms); update_mdatoms(mdatoms,ir.init_lambda); fr = mk_forcerec(); fprintf(fplog,"Made forcerec\n"); init_forcerec(fplog,oenv,fr,NULL,&ir,&mtop,cr,box,FALSE,NULL,NULL,NULL, FALSE,-1); init_nrnb(&nrnb); if (ir.ePBC != epbcNONE) gpbc = gmx_rmpbc_init(&top->idef,ir.ePBC,natoms,box); j=0; do { if (ir.ePBC != epbcNONE) { if (ir.bPeriodicMols) set_pbc(&pbc,ir.ePBC,box); else gmx_rmpbc(gpbc,natoms,box,x); } if (clust) { if (j > clust->maxframe) gmx_fatal(FARGS,"There are more frames in the trajectory than in the cluster index file. t = %8f\n",t); my_clust = clust->inv_clust[j]; range_check(my_clust,0,clust->clust->nr); check_viol(fplog,cr,&(top->idef.il[F_DISRES]), top->idef.iparams,top->idef.functype, x,f,fr,pbc_null,g,dr_clust,my_clust,isize,index,vvindex,&fcd); } else check_viol(fplog,cr,&(top->idef.il[F_DISRES]), top->idef.iparams,top->idef.functype, x,f,fr,pbc_null,g,&dr,0,isize,index,vvindex,&fcd); if (bPDB) { reset_x(atoms->nr,ind_fit,atoms->nr,NULL,x,w_rls); do_fit(atoms->nr,w_rls,x,x); if (j == 0) { /* Store the first frame of the trajectory as 'characteristic' * for colouring with violations. */ for(kkk=0; (kkk<atoms->nr); kkk++) copy_rvec(x[kkk],xav[kkk]); } } if (!clust) { if (isize > 0) { fprintf(xvg,"%10g",t); for(i=0; (i<isize); i++) fprintf(xvg," %10g",vvindex[i]); fprintf(xvg,"\n"); } fprintf(out, "%10g %10g\n",t,dr.sumv); fprintf(aver, "%10g %10g\n",t,dr.averv); fprintf(maxxv,"%10g %10g\n",t,dr.maxv); fprintf(numv, "%10g %10d\n",t,dr.nv); } j++; } while (read_next_x(oenv,status,&t,natoms,x,box)); close_trj(status); if (ir.ePBC != epbcNONE) gmx_rmpbc_done(gpbc); if (clust) { dump_clust_stats(fplog,fcd.disres.nres,&(top->idef.il[F_DISRES]), top->idef.iparams,clust->clust,dr_clust, clust->grpname,isize,index); } else { dump_stats(fplog,j,fcd.disres.nres,&(top->idef.il[F_DISRES]), top->idef.iparams,&dr,isize,index, bPDB ? atoms : NULL); if (bPDB) { write_sto_conf(opt2fn("-q",NFILE,fnm), "Coloured by average violation in Angstrom", atoms,xav,NULL,ir.ePBC,box); } dump_disre_matrix(opt2fn_null("-x",NFILE,fnm),&dr,fcd.disres.nres, j,&top->idef,&mtop,max_dr,nlevels,bThird); ffclose(out); ffclose(aver); ffclose(numv); ffclose(maxxv); if (isize > 0) { ffclose(xvg); do_view(oenv,opt2fn("-dr",NFILE,fnm),"-nxy"); } do_view(oenv,opt2fn("-dn",NFILE,fnm),"-nxy"); do_view(oenv,opt2fn("-da",NFILE,fnm),"-nxy"); do_view(oenv,opt2fn("-ds",NFILE,fnm),"-nxy"); do_view(oenv,opt2fn("-dm",NFILE,fnm),"-nxy"); } thanx(stderr); if (gmx_parallel_env_initialized()) gmx_finalize(); gmx_log_close(fplog); return 0; }
void calc_order(const char *fn, atom_id *index, atom_id *a, rvec **order, real ***slOrder, real *slWidth, int nslices, gmx_bool bSliced, gmx_bool bUnsat, t_topology *top, int ePBC, int ngrps, int axis, gmx_bool permolecule, gmx_bool radial, gmx_bool distcalc, const char *radfn, real ***distvals, const gmx_output_env_t *oenv) { /* if permolecule = TRUE, order parameters will be calculed per molecule * and stored in slOrder with #slices = # molecules */ rvec *x0, /* coordinates with pbc */ *x1, /* coordinates without pbc */ dist; /* vector between two atoms */ matrix box; /* box (3x3) */ t_trxstatus *status; rvec cossum, /* sum of vector angles for three axes */ Sx, Sy, Sz, /* the three molecular axes */ tmp1, tmp2, /* temp. rvecs for calculating dot products */ frameorder; /* order parameters for one frame */ real *slFrameorder; /* order parameter for one frame, per slice */ real length, /* total distance between two atoms */ t, /* time from trajectory */ z_ave, z1, z2; /* average z, used to det. which slice atom is in */ int natoms, /* nr. atoms in trj */ nr_tails, /* nr tails, to check if index file is correct */ size = 0, /* nr. of atoms in group. same as nr_tails */ i, j, m, k, teller = 0, slice, /* current slice number */ nr_frames = 0; int *slCount; /* nr. of atoms in one slice */ real sdbangle = 0; /* sum of these angles */ gmx_bool use_unitvector = FALSE; /* use a specified unit vector instead of axis to specify unit normal*/ rvec direction, com, dref, dvec; int comsize, distsize; atom_id *comidx = NULL, *distidx = NULL; char *grpname = NULL; t_pbc pbc; real arcdist, tmpdist; gmx_rmpbc_t gpbc = NULL; /* PBC added for center-of-mass vector*/ /* Initiate the pbc structure */ std::memset(&pbc, 0, sizeof(pbc)); if ((natoms = read_first_x(oenv, &status, fn, &t, &x0, box)) == 0) { gmx_fatal(FARGS, "Could not read coordinates from statusfile\n"); } nr_tails = index[1] - index[0]; fprintf(stderr, "Number of elements in first group: %d\n", nr_tails); /* take first group as standard. Not rocksolid, but might catch error in index*/ if (permolecule) { nslices = nr_tails; bSliced = FALSE; /*force slices off */ fprintf(stderr, "Calculating order parameters for each of %d molecules\n", nslices); } if (radial) { use_unitvector = TRUE; fprintf(stderr, "Select an index group to calculate the radial membrane normal\n"); get_index(&top->atoms, radfn, 1, &comsize, &comidx, &grpname); } if (distcalc) { if (grpname != NULL) { sfree(grpname); } fprintf(stderr, "Select an index group to use as distance reference\n"); get_index(&top->atoms, radfn, 1, &distsize, &distidx, &grpname); bSliced = FALSE; /*force slices off*/ } if (use_unitvector && bSliced) { fprintf(stderr, "Warning: slicing and specified unit vectors are not currently compatible\n"); } snew(slCount, nslices); snew(*slOrder, nslices); for (i = 0; i < nslices; i++) { snew((*slOrder)[i], ngrps); } if (distcalc) { snew(*distvals, nslices); for (i = 0; i < nslices; i++) { snew((*distvals)[i], ngrps); } } snew(*order, ngrps); snew(slFrameorder, nslices); snew(x1, natoms); if (bSliced) { *slWidth = box[axis][axis]/nslices; fprintf(stderr, "Box divided in %d slices. Initial width of slice: %f\n", nslices, *slWidth); } #if 0 nr_tails = index[1] - index[0]; fprintf(stderr, "Number of elements in first group: %d\n", nr_tails); /* take first group as standard. Not rocksolid, but might catch error in index*/ #endif teller = 0; gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms); /*********** Start processing trajectory ***********/ do { if (bSliced) { *slWidth = box[axis][axis]/nslices; } teller++; set_pbc(&pbc, ePBC, box); gmx_rmpbc_copy(gpbc, natoms, box, x0, x1); /* Now loop over all groups. There are ngrps groups, the order parameter can be calculated for grp 1 to grp ngrps - 1. For each group, loop over all atoms in group, which is index[i] to (index[i+1] - 1) See block.h. Of course, in this case index[i+1] -index[i] has to be the same for all groups, namely the number of tails. i just runs over all atoms in a tail, so for DPPC ngrps = 16 and i runs from 1 to 14, including 14 */ if (radial) { /*center-of-mass determination*/ com[XX] = 0.0; com[YY] = 0.0; com[ZZ] = 0.0; for (j = 0; j < comsize; j++) { rvec_inc(com, x1[comidx[j]]); } svmul(1.0/comsize, com, com); } if (distcalc) { dref[XX] = 0.0; dref[YY] = 0.0; dref[ZZ] = 0.0; for (j = 0; j < distsize; j++) { rvec_inc(dist, x1[distidx[j]]); } svmul(1.0/distsize, dref, dref); if (radial) { pbc_dx(&pbc, dref, com, dvec); unitv(dvec, dvec); } } for (i = 1; i < ngrps - 1; i++) { clear_rvec(frameorder); size = index[i+1] - index[i]; if (size != nr_tails) { gmx_fatal(FARGS, "grp %d does not have same number of" " elements as grp 1\n", i); } for (j = 0; j < size; j++) { if (radial) /*create unit vector*/ { pbc_dx(&pbc, x1[a[index[i]+j]], com, direction); unitv(direction, direction); /*DEBUG*/ /*if (j==0) fprintf(stderr,"X %f %f %f\tcom %f %f %f\tdirection %f %f %f\n",x1[a[index[i]+j]][0],x1[a[index[i]+j]][1],x1[a[index[i]+j]][2],com[0],com[1],com[2], direction[0],direction[1],direction[2]);*/ } if (bUnsat) { /* Using convention for unsaturated carbons */ /* first get Sz, the vector from Cn to Cn+1 */ rvec_sub(x1[a[index[i+1]+j]], x1[a[index[i]+j]], dist); length = norm(dist); check_length(length, a[index[i]+j], a[index[i+1]+j]); svmul(1.0/length, dist, Sz); /* this is actually the cosine of the angle between the double bond and axis, because Sz is normalized and the two other components of the axis on the bilayer are zero */ if (use_unitvector) { sdbangle += gmx_angle(direction, Sz); /*this can probably be optimized*/ } else { sdbangle += std::acos(Sz[axis]); } } else { /* get vector dist(Cn-1,Cn+1) for tail atoms */ rvec_sub(x1[a[index[i+1]+j]], x1[a[index[i-1]+j]], dist); length = norm(dist); /* determine distance between two atoms */ check_length(length, a[index[i-1]+j], a[index[i+1]+j]); svmul(1.0/length, dist, Sz); /* Sz is now the molecular axis Sz, normalized and all that */ } /* now get Sx. Sx is normal to the plane of Cn-1, Cn and Cn+1 so we can use the outer product of Cn-1->Cn and Cn+1->Cn, I hope */ rvec_sub(x1[a[index[i+1]+j]], x1[a[index[i]+j]], tmp1); rvec_sub(x1[a[index[i-1]+j]], x1[a[index[i]+j]], tmp2); cprod(tmp1, tmp2, Sx); svmul(1.0/norm(Sx), Sx, Sx); /* now we can get Sy from the outer product of Sx and Sz */ cprod(Sz, Sx, Sy); svmul(1.0/norm(Sy), Sy, Sy); /* the square of cosine of the angle between dist and the axis. Using the innerproduct, but two of the three elements are zero Determine the sum of the orderparameter of all atoms in group */ if (use_unitvector) { cossum[XX] = sqr(iprod(Sx, direction)); /* this is allowed, since Sa is normalized */ cossum[YY] = sqr(iprod(Sy, direction)); cossum[ZZ] = sqr(iprod(Sz, direction)); } else { cossum[XX] = sqr(Sx[axis]); /* this is allowed, since Sa is normalized */ cossum[YY] = sqr(Sy[axis]); cossum[ZZ] = sqr(Sz[axis]); } for (m = 0; m < DIM; m++) { frameorder[m] += 0.5 * (3.0 * cossum[m] - 1.0); } if (bSliced) { /* get average coordinate in box length for slicing, determine which slice atom is in, increase count for that slice. slFrameorder and slOrder are reals, not rvecs. Only the component [axis] of the order tensor is kept, until I find it necessary to know the others too */ z1 = x1[a[index[i-1]+j]][axis]; z2 = x1[a[index[i+1]+j]][axis]; z_ave = 0.5 * (z1 + z2); if (z_ave < 0) { z_ave += box[axis][axis]; } if (z_ave > box[axis][axis]) { z_ave -= box[axis][axis]; } slice = static_cast<int>((0.5 + (z_ave / (*slWidth))) - 1); slCount[slice]++; /* determine slice, increase count */ slFrameorder[slice] += 0.5 * (3 * cossum[axis] - 1); } else if (permolecule) { /* store per-molecule order parameter * To just track single-axis order: (*slOrder)[j][i] += 0.5 * (3 * iprod(cossum,direction) - 1); * following is for Scd order: */ (*slOrder)[j][i] += -1* (1.0/3.0 * (3 * cossum[XX] - 1) + 1.0/3.0 * 0.5 * (3.0 * cossum[YY] - 1)); } if (distcalc) { if (radial) { /* bin order parameter by arc distance from reference group*/ arcdist = gmx_angle(dvec, direction); (*distvals)[j][i] += arcdist; } else if (i == 1) { /* Want minimum lateral distance to first group calculated */ tmpdist = trace(box); /* should be max value */ for (k = 0; k < distsize; k++) { pbc_dx(&pbc, x1[distidx[k]], x1[a[index[i]+j]], dvec); /* at the moment, just remove dvec[axis] */ dvec[axis] = 0; tmpdist = std::min(tmpdist, norm2(dvec)); } //fprintf(stderr, "Min dist %f; trace %f\n", tmpdist, trace(box)); (*distvals)[j][i] += std::sqrt(tmpdist); } } } /* end loop j, over all atoms in group */ for (m = 0; m < DIM; m++) { (*order)[i][m] += (frameorder[m]/size); } if (!permolecule) { /*Skip following if doing per-molecule*/ for (k = 0; k < nslices; k++) { if (slCount[k]) /* if no elements, nothing has to be added */ { (*slOrder)[k][i] += slFrameorder[k]/slCount[k]; slFrameorder[k] = 0; slCount[k] = 0; } } } /* end loop i, over all groups in indexfile */ } nr_frames++; } while (read_next_x(oenv, status, &t, x0, box)); /*********** done with status file **********/ fprintf(stderr, "\nRead trajectory. Printing parameters to file\n"); gmx_rmpbc_done(gpbc); /* average over frames */ for (i = 1; i < ngrps - 1; i++) { svmul(1.0/nr_frames, (*order)[i], (*order)[i]); fprintf(stderr, "Atom %d Tensor: x=%g , y=%g, z=%g\n", i, (*order)[i][XX], (*order)[i][YY], (*order)[i][ZZ]); if (bSliced || permolecule) { for (k = 0; k < nslices; k++) { (*slOrder)[k][i] /= nr_frames; } } if (distcalc) { for (k = 0; k < nslices; k++) { (*distvals)[k][i] /= nr_frames; } } } if (bUnsat) { fprintf(stderr, "Average angle between double bond and normal: %f\n", 180*sdbangle/(nr_frames * size*M_PI)); } sfree(x0); /* free memory used by coordinate arrays */ sfree(x1); if (comidx != NULL) { sfree(comidx); } if (distidx != NULL) { sfree(distidx); } if (grpname != NULL) { sfree(grpname); } }
static void calc_tetra_order_parm(const char *fnNDX, const char *fnTPS, const char *fnTRX, const char *sgfn, const char *skfn, int nslice, int slice_dim, const char *sgslfn, const char *skslfn, const gmx_output_env_t *oenv) { FILE *fpsg = NULL, *fpsk = NULL; t_topology top; int ePBC; t_trxstatus *status; int natoms; real t; rvec *xtop, *x; matrix box; real sg, sk; atom_id **index; char **grpname; int i, *isize, ng, nframes; real *sg_slice, *sg_slice_tot, *sk_slice, *sk_slice_tot; gmx_rmpbc_t gpbc = NULL; read_tps_conf(fnTPS, &top, &ePBC, &xtop, NULL, box, FALSE); snew(sg_slice, nslice); snew(sk_slice, nslice); snew(sg_slice_tot, nslice); snew(sk_slice_tot, nslice); ng = 1; /* get index groups */ printf("Select the group that contains the atoms you want to use for the tetrahedrality order parameter calculation:\n"); snew(grpname, ng); snew(index, ng); snew(isize, ng); get_index(&top.atoms, fnNDX, ng, isize, index, grpname); /* Analyze trajectory */ natoms = read_first_x(oenv, &status, fnTRX, &t, &x, box); if (natoms > top.atoms.nr) { gmx_fatal(FARGS, "Topology (%d atoms) does not match trajectory (%d atoms)", top.atoms.nr, natoms); } check_index(NULL, ng, index[0], NULL, natoms); fpsg = xvgropen(sgfn, "S\\sg\\N Angle Order Parameter", "Time (ps)", "S\\sg\\N", oenv); fpsk = xvgropen(skfn, "S\\sk\\N Distance Order Parameter", "Time (ps)", "S\\sk\\N", oenv); /* loop over frames */ gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms); nframes = 0; do { find_nearest_neighbours(ePBC, natoms, box, x, isize[0], index[0], &sg, &sk, nslice, slice_dim, sg_slice, sk_slice, gpbc); for (i = 0; (i < nslice); i++) { sg_slice_tot[i] += sg_slice[i]; sk_slice_tot[i] += sk_slice[i]; } fprintf(fpsg, "%f %f\n", t, sg); fprintf(fpsk, "%f %f\n", t, sk); nframes++; } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); gmx_rmpbc_done(gpbc); sfree(grpname); sfree(index); sfree(isize); xvgrclose(fpsg); xvgrclose(fpsk); fpsg = xvgropen(sgslfn, "S\\sg\\N Angle Order Parameter / Slab", "(nm)", "S\\sg\\N", oenv); fpsk = xvgropen(skslfn, "S\\sk\\N Distance Order Parameter / Slab", "(nm)", "S\\sk\\N", oenv); for (i = 0; (i < nslice); i++) { fprintf(fpsg, "%10g %10g\n", (i+0.5)*box[slice_dim][slice_dim]/nslice, sg_slice_tot[i]/nframes); fprintf(fpsk, "%10g %10g\n", (i+0.5)*box[slice_dim][slice_dim]/nslice, sk_slice_tot[i]/nframes); } xvgrclose(fpsg); xvgrclose(fpsk); }
int gmx_vanhove(int argc,char *argv[]) { const char *desc[] = { "g_vanhove computes the Van Hove correlation function.", "The Van Hove G(r,t) is the probability that a particle that is at r0", "at time zero can be found at position r0+r at time t.", "g_vanhove determines G not for a vector r, but for the length of r.", "Thus it gives the probability that a particle moves a distance of r", "in time t.", "Jumps across the periodic boundaries are removed.", "Corrections are made for scaling due to isotropic", "or anisotropic pressure coupling.", "[PAR]", "With option [TT]-om[tt] the whole matrix can be written as a function", "of t and r or as a function of sqrt(t) and r (option [TT]-sqrt[tt]).", "[PAR]", "With option [TT]-or[tt] the Van Hove function is plotted for one", "or more values of t. Option [TT]-nr[tt] sets the number of times,", "option [TT]-fr[tt] the number spacing between the times.", "The binwidth is set with option [TT]-rbin[tt]. The number of bins", "is determined automatically.", "[PAR]", "With option [TT]-ot[tt] the integral up to a certain distance", "(option [TT]-rt[tt]) is plotted as a function of time.", "[PAR]", "For all frames that are read the coordinates of the selected particles", "are stored in memory. Therefore the program may use a lot of memory.", "For options [TT]-om[tt] and [TT]-ot[tt] the program may be slow.", "This is because the calculation scales as the number of frames times", "[TT]-fm[tt] or [TT]-ft[tt].", "Note that with the [TT]-dt[tt] option the memory usage and calculation", "time can be reduced." }; static int fmmax=0,ftmax=0,nlev=81,nr=1,fshift=0; static real sbin=0,rmax=2,rbin=0.01,mmax=0,rint=0; t_pargs pa[] = { { "-sqrt", FALSE, etREAL,{&sbin}, "Use sqrt(t) on the matrix axis which binspacing # in sqrt(ps)" }, { "-fm", FALSE, etINT, {&fmmax}, "Number of frames in the matrix, 0 is plot all" }, { "-rmax", FALSE, etREAL, {&rmax}, "Maximum r in the matrix (nm)" }, { "-rbin", FALSE, etREAL, {&rbin}, "Binwidth in the matrix and for -or (nm)" }, { "-mmax", FALSE, etREAL, {&mmax}, "Maximum density in the matrix, 0 is calculate (1/nm)" }, { "-nlevels" ,FALSE, etINT, {&nlev}, "Number of levels in the matrix" }, { "-nr", FALSE, etINT, {&nr}, "Number of curves for the -or output" }, { "-fr", FALSE, etINT, {&fshift}, "Frame spacing for the -or output" }, { "-rt", FALSE, etREAL, {&rint}, "Integration limit for the -ot output (nm)" }, { "-ft", FALSE, etINT, {&ftmax}, "Number of frames in the -ot output, 0 is plot all" } }; #define NPA asize(pa) t_filenm fnm[] = { { efTRX, NULL, NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efXPM, "-om", "vanhove", ffOPTWR }, { efXVG, "-or", "vanhove_r", ffOPTWR }, { efXVG, "-ot", "vanhove_t", ffOPTWR } }; #define NFILE asize(fnm) output_env_t oenv; const char *matfile,*otfile,*orfile; char title[256]; t_topology top; int ePBC; matrix boxtop,box,*sbox,avbox,corr; rvec *xtop,*x,**sx; int isize,nalloc,nallocn,natom; t_trxstatus *status; atom_id *index; char *grpname; int nfr,f,ff,i,m,mat_nx=0,nbin=0,bin,mbin,fbin; real *time,t,invbin=0,rmax2=0,rint2=0,d2; real invsbin=0,matmax,normfac,dt,*tickx,*ticky; char buf[STRLEN],**legend; real **mat=NULL; int *pt=NULL,**pr=NULL,*mcount=NULL,*tcount=NULL,*rcount=NULL; FILE *fp; t_rgb rlo={1,1,1}, rhi={0,0,0}; CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); matfile = opt2fn_null("-om",NFILE,fnm); if (opt2parg_bSet("-fr",NPA,pa)) orfile = opt2fn("-or",NFILE,fnm); else orfile = opt2fn_null("-or",NFILE,fnm); if (opt2parg_bSet("-rt",NPA,pa)) otfile = opt2fn("-ot",NFILE,fnm); else otfile = opt2fn_null("-ot",NFILE,fnm); if (!matfile && !otfile && !orfile) { fprintf(stderr, "For output set one (or more) of the output file options\n"); exit(0); } read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xtop,NULL,boxtop, FALSE); get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpname); nalloc = 0; time = NULL; sbox = NULL; sx = NULL; clear_mat(avbox); natom=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); nfr = 0; do { if (nfr >= nalloc) { nalloc += 100; srenew(time,nalloc); srenew(sbox,nalloc); srenew(sx,nalloc); } time[nfr] = t; copy_mat(box,sbox[nfr]); /* This assumes that the off-diagonal box elements * are not affected by jumps across the periodic boundaries. */ m_add(avbox,box,avbox); snew(sx[nfr],isize); for(i=0; i<isize; i++) copy_rvec(x[index[i]],sx[nfr][i]); nfr++; } while (read_next_x(oenv,status,&t,natom,x,box)); /* clean up */ sfree(x); close_trj(status); fprintf(stderr,"Read %d frames\n",nfr); dt = (time[nfr-1] - time[0])/(nfr - 1); /* Some ugly rounding to get nice nice times in the output */ dt = (int)(10000.0*dt + 0.5)/10000.0; invbin = 1.0/rbin; if (matfile) { if (fmmax <= 0 || fmmax >= nfr) fmmax = nfr - 1; snew(mcount,fmmax); nbin = (int)(rmax*invbin + 0.5); if (sbin == 0) { mat_nx = fmmax + 1; } else { invsbin = 1.0/sbin; mat_nx = sqrt(fmmax*dt)*invsbin + 1; } snew(mat,mat_nx); for(f=0; f<mat_nx; f++) snew(mat[f],nbin); rmax2 = sqr(nbin*rbin); /* Initialize time zero */ mat[0][0] = nfr*isize; mcount[0] += nfr; } else { fmmax = 0; } if (orfile) { snew(pr,nr); nalloc = 0; snew(rcount,nr); } if (otfile) { if (ftmax <= 0) ftmax = nfr - 1; snew(tcount,ftmax); snew(pt,nfr); rint2 = rint*rint; /* Initialize time zero */ pt[0] = nfr*isize; tcount[0] += nfr; } else { ftmax = 0; } msmul(avbox,1.0/nfr,avbox); for(f=0; f<nfr; f++) { if (f % 100 == 0) fprintf(stderr,"\rProcessing frame %d",f); /* Scale all the configuration to the average box */ m_inv_ur0(sbox[f],corr); mmul_ur0(avbox,corr,corr); for(i=0; i<isize; i++) { mvmul_ur0(corr,sx[f][i],sx[f][i]); if (f > 0) { /* Correct for periodic jumps */ for(m=DIM-1; m>=0; m--) { while(sx[f][i][m] - sx[f-1][i][m] > 0.5*avbox[m][m]) rvec_dec(sx[f][i],avbox[m]); while(sx[f][i][m] - sx[f-1][i][m] <= -0.5*avbox[m][m]) rvec_inc(sx[f][i],avbox[m]); } } } for(ff=0; ff<f; ff++) { fbin = f - ff; if (fbin <= fmmax || fbin <= ftmax) { if (sbin == 0) mbin = fbin; else mbin = (int)(sqrt(fbin*dt)*invsbin + 0.5); for(i=0; i<isize; i++) { d2 = distance2(sx[f][i],sx[ff][i]); if (mbin < mat_nx && d2 < rmax2) { bin = (int)(sqrt(d2)*invbin + 0.5); if (bin < nbin) { mat[mbin][bin] += 1; } } if (fbin <= ftmax && d2 <= rint2) pt[fbin]++; } if (matfile) mcount[mbin]++; if (otfile) tcount[fbin]++; } } if (orfile) { for(fbin=0; fbin<nr; fbin++) { ff = f - (fbin + 1)*fshift; if (ff >= 0) { for(i=0; i<isize; i++) { d2 = distance2(sx[f][i],sx[ff][i]); bin = (int)(sqrt(d2)*invbin); if (bin >= nalloc) { nallocn = 10*(bin/10) + 11; for(m=0; m<nr; m++) { srenew(pr[m],nallocn); for(i=nalloc; i<nallocn; i++) pr[m][i] = 0; } nalloc = nallocn; } pr[fbin][bin]++; } rcount[fbin]++; } } } } fprintf(stderr,"\n"); if (matfile) { matmax = 0; for(f=0; f<mat_nx; f++) { normfac = 1.0/(mcount[f]*isize*rbin); for(i=0; i<nbin; i++) { mat[f][i] *= normfac; if (mat[f][i] > matmax && (f!=0 || i!=0)) matmax = mat[f][i]; } } fprintf(stdout,"Value at (0,0): %.3f, maximum of the rest %.3f\n", mat[0][0],matmax); if (mmax > 0) matmax = mmax; snew(tickx,mat_nx); for(f=0; f<mat_nx; f++) { if (sbin == 0) tickx[f] = f*dt; else tickx[f] = f*sbin; } snew(ticky,nbin+1); for(i=0; i<=nbin; i++) ticky[i] = i*rbin; fp = ffopen(matfile,"w"); write_xpm(fp,MAT_SPATIAL_Y,"Van Hove function","G (1/nm)", sbin==0 ? "time (ps)" : "sqrt(time) (ps^1/2)","r (nm)", mat_nx,nbin,tickx,ticky,mat,0,matmax,rlo,rhi,&nlev); ffclose(fp); } if (orfile) { fp = xvgropen(orfile,"Van Hove function","r (nm)","G (nm\\S-1\\N)",oenv); fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname); snew(legend,nr); for(fbin=0; fbin<nr; fbin++) { sprintf(buf,"%g ps",(fbin + 1)*fshift*dt); legend[fbin] = strdup(buf); } xvgr_legend(fp,nr,(const char**)legend,oenv); for(i=0; i<nalloc; i++) { fprintf(fp,"%g",i*rbin); for(fbin=0; fbin<nr; fbin++) fprintf(fp," %g", (real)pr[fbin][i]/(rcount[fbin]*isize*rbin*(i==0 ? 0.5 : 1))); fprintf(fp,"\n"); } ffclose(fp); } if (otfile) { sprintf(buf,"Probability of moving less than %g nm",rint); fp = xvgropen(otfile,buf,"t (ps)","",oenv); fprintf(fp,"@ subtitle \"for particles in group %s\"\n",grpname); for(f=0; f<=ftmax; f++) fprintf(fp,"%g %g\n",f*dt,(real)pt[f]/(tcount[f]*isize)); ffclose(fp); } do_view(oenv, matfile,NULL); do_view(oenv, orfile,NULL); do_view(oenv, otfile,NULL); thanx(stderr); return 0; }
int gmx_sans(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes SANS spectra using Debye formula.", "It currently uses topology file (since it need to assigne element for each atom).", "[PAR]", "Parameters:[PAR]" "[TT]-pr[tt] Computes normalized g(r) function averaged over trajectory[PAR]", "[TT]-prframe[tt] Computes normalized g(r) function for each frame[PAR]", "[TT]-sq[tt] Computes SANS intensity curve averaged over trajectory[PAR]", "[TT]-sqframe[tt] Computes SANS intensity curve for each frame[PAR]", "[TT]-startq[tt] Starting q value in nm[PAR]", "[TT]-endq[tt] Ending q value in nm[PAR]", "[TT]-qstep[tt] Stepping in q space[PAR]", "Note: When using Debye direct method computational cost increases as", "1/2 * N * (N - 1) where N is atom number in group of interest.", "[PAR]", "WARNING: If sq or pr specified this tool can produce large number of files! Up to two times larger than number of frames!" }; static gmx_bool bPBC = TRUE; static gmx_bool bNORM = FALSE; static real binwidth = 0.2, grid = 0.05; /* bins shouldnt be smaller then smallest bond (~0.1nm) length */ static real start_q = 0.0, end_q = 2.0, q_step = 0.01; static real mcover = -1; static unsigned int seed = 0; static int nthreads = -1; static const char *emode[] = { NULL, "direct", "mc", NULL }; static const char *emethod[] = { NULL, "debye", "fft", NULL }; gmx_neutron_atomic_structurefactors_t *gnsf; gmx_sans_t *gsans; #define NPA asize(pa) t_pargs pa[] = { { "-bin", FALSE, etREAL, {&binwidth}, "[HIDDEN]Binwidth (nm)" }, { "-mode", FALSE, etENUM, {emode}, "Mode for sans spectra calculation" }, { "-mcover", FALSE, etREAL, {&mcover}, "Monte-Carlo coverage should be -1(default) or (0,1]"}, { "-method", FALSE, etENUM, {emethod}, "[HIDDEN]Method for sans spectra calculation" }, { "-pbc", FALSE, etBOOL, {&bPBC}, "Use periodic boundary conditions for computing distances" }, { "-grid", FALSE, etREAL, {&grid}, "[HIDDEN]Grid spacing (in nm) for FFTs" }, {"-startq", FALSE, etREAL, {&start_q}, "Starting q (1/nm) "}, {"-endq", FALSE, etREAL, {&end_q}, "Ending q (1/nm)"}, { "-qstep", FALSE, etREAL, {&q_step}, "Stepping in q (1/nm)"}, { "-seed", FALSE, etINT, {&seed}, "Random seed for Monte-Carlo"}, #ifdef GMX_OPENMP { "-nt", FALSE, etINT, {&nthreads}, "Number of threads to start"}, #endif }; FILE *fp; const char *fnTPX, *fnNDX, *fnTRX, *fnDAT = NULL; t_trxstatus *status; t_topology *top = NULL; t_atom *atom = NULL; gmx_rmpbc_t gpbc = NULL; gmx_bool bTPX; gmx_bool bFFT = FALSE, bDEBYE = FALSE; gmx_bool bMC = FALSE; int ePBC = -1; matrix box; char title[STRLEN]; rvec *x; int natoms; real t; char **grpname = NULL; atom_id *index = NULL; int isize; int i, j; char *hdr = NULL; char *suffix = NULL; t_filenm *fnmdup = NULL; gmx_radial_distribution_histogram_t *prframecurrent = NULL, *pr = NULL; gmx_static_structurefactor_t *sqframecurrent = NULL, *sq = NULL; output_env_t oenv; #define NFILE asize(fnm) t_filenm fnm[] = { { efTPX, "-s", NULL, ffREAD }, { efTRX, "-f", NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efDAT, "-d", "nsfactor", ffOPTRD }, { efXVG, "-pr", "pr", ffWRITE }, { efXVG, "-sq", "sq", ffWRITE }, { efXVG, "-prframe", "prframe", ffOPTWR }, { efXVG, "-sqframe", "sqframe", ffOPTWR } }; nthreads = gmx_omp_get_max_threads(); if (!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)) { return 0; } /* check that binwidth not smaller than smallers distance */ check_binwidth(binwidth); check_mcover(mcover); /* setting number of omp threads globaly */ gmx_omp_set_num_threads(nthreads); /* Now try to parse opts for modes */ switch (emethod[0][0]) { case 'd': bDEBYE = TRUE; switch (emode[0][0]) { case 'd': bMC = FALSE; break; case 'm': bMC = TRUE; break; default: break; } break; case 'f': bFFT = TRUE; break; default: break; } if (bDEBYE) { if (bMC) { fprintf(stderr, "Using Monte Carlo Debye method to calculate spectrum\n"); } else { fprintf(stderr, "Using direct Debye method to calculate spectrum\n"); } } else if (bFFT) { gmx_fatal(FARGS, "FFT method not implemented!"); } else { gmx_fatal(FARGS, "Unknown combination for mode and method!"); } /* Try to read files */ fnDAT = ftp2fn(efDAT, NFILE, fnm); fnTPX = ftp2fn(efTPX, NFILE, fnm); fnTRX = ftp2fn(efTRX, NFILE, fnm); gnsf = gmx_neutronstructurefactors_init(fnDAT); fprintf(stderr, "Read %d atom names from %s with neutron scattering parameters\n\n", gnsf->nratoms, fnDAT); snew(top, 1); snew(grpname, 1); snew(index, 1); bTPX = read_tps_conf(fnTPX, title, top, &ePBC, &x, NULL, box, TRUE); printf("\nPlease select group for SANS spectra calculation:\n"); get_index(&(top->atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &isize, &index, grpname); gsans = gmx_sans_init(top, gnsf); /* Prepare reference frame */ if (bPBC) { gpbc = gmx_rmpbc_init(&top->idef, ePBC, top->atoms.nr); gmx_rmpbc(gpbc, top->atoms.nr, box, x); } natoms = read_first_x(oenv, &status, fnTRX, &t, &x, box); if (natoms != top->atoms.nr) { fprintf(stderr, "\nWARNING: number of atoms in tpx (%d) and trajectory (%d) do not match\n", natoms, top->atoms.nr); } do { if (bPBC) { gmx_rmpbc(gpbc, top->atoms.nr, box, x); } /* allocate memory for pr */ if (pr == NULL) { /* in case its first frame to read */ snew(pr, 1); } /* realy calc p(r) */ prframecurrent = calc_radial_distribution_histogram(gsans, x, box, index, isize, binwidth, bMC, bNORM, mcover, seed); /* copy prframecurrent -> pr and summ up pr->gr[i] */ /* allocate and/or resize memory for pr->gr[i] and pr->r[i] */ if (pr->gr == NULL) { /* check if we use pr->gr first time */ snew(pr->gr, prframecurrent->grn); snew(pr->r, prframecurrent->grn); } else { /* resize pr->gr and pr->r if needed to preven overruns */ if (prframecurrent->grn > pr->grn) { srenew(pr->gr, prframecurrent->grn); srenew(pr->r, prframecurrent->grn); } } pr->grn = prframecurrent->grn; pr->binwidth = prframecurrent->binwidth; /* summ up gr and fill r */ for (i = 0; i < prframecurrent->grn; i++) { pr->gr[i] += prframecurrent->gr[i]; pr->r[i] = prframecurrent->r[i]; } /* normalize histo */ normalize_probability(prframecurrent->grn, prframecurrent->gr); /* convert p(r) to sq */ sqframecurrent = convert_histogram_to_intensity_curve(prframecurrent, start_q, end_q, q_step); /* print frame data if needed */ if (opt2fn_null("-prframe", NFILE, fnm)) { snew(hdr, 25); snew(suffix, GMX_PATH_MAX); /* prepare header */ sprintf(hdr, "g(r), t = %f", t); /* prepare output filename */ fnmdup = dup_tfn(NFILE, fnm); sprintf(suffix, "-t%.2f", t); add_suffix_to_output_names(fnmdup, NFILE, suffix); fp = xvgropen(opt2fn_null("-prframe", NFILE, fnmdup), hdr, "Distance (nm)", "Probability", oenv); for (i = 0; i < prframecurrent->grn; i++) { fprintf(fp, "%10.6f%10.6f\n", prframecurrent->r[i], prframecurrent->gr[i]); } done_filenms(NFILE, fnmdup); fclose(fp); sfree(hdr); sfree(suffix); sfree(fnmdup); } if (opt2fn_null("-sqframe", NFILE, fnm)) { snew(hdr, 25); snew(suffix, GMX_PATH_MAX); /* prepare header */ sprintf(hdr, "I(q), t = %f", t); /* prepare output filename */ fnmdup = dup_tfn(NFILE, fnm); sprintf(suffix, "-t%.2f", t); add_suffix_to_output_names(fnmdup, NFILE, suffix); fp = xvgropen(opt2fn_null("-sqframe", NFILE, fnmdup), hdr, "q (nm^-1)", "s(q)/s(0)", oenv); for (i = 0; i < sqframecurrent->qn; i++) { fprintf(fp, "%10.6f%10.6f\n", sqframecurrent->q[i], sqframecurrent->s[i]); } done_filenms(NFILE, fnmdup); fclose(fp); sfree(hdr); sfree(suffix); sfree(fnmdup); } /* free pr structure */ sfree(prframecurrent->gr); sfree(prframecurrent->r); sfree(prframecurrent); /* free sq structure */ sfree(sqframecurrent->q); sfree(sqframecurrent->s); sfree(sqframecurrent); } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); /* normalize histo */ normalize_probability(pr->grn, pr->gr); sq = convert_histogram_to_intensity_curve(pr, start_q, end_q, q_step); /* prepare pr.xvg */ fp = xvgropen(opt2fn_null("-pr", NFILE, fnm), "G(r)", "Distance (nm)", "Probability", oenv); for (i = 0; i < pr->grn; i++) { fprintf(fp, "%10.6f%10.6f\n", pr->r[i], pr->gr[i]); } xvgrclose(fp); /* prepare sq.xvg */ fp = xvgropen(opt2fn_null("-sq", NFILE, fnm), "I(q)", "q (nm^-1)", "s(q)/s(0)", oenv); for (i = 0; i < sq->qn; i++) { fprintf(fp, "%10.6f%10.6f\n", sq->q[i], sq->s[i]); } xvgrclose(fp); /* * Clean up memory */ sfree(pr->gr); sfree(pr->r); sfree(pr); sfree(sq->q); sfree(sq->s); sfree(sq); please_cite(stdout, "Garmay2012"); return 0; }
int gmx_genconf(int argc, char *argv[]) { const char *desc[] = { "[TT]genconf[tt] multiplies a given coordinate file by simply stacking them", "on top of each other, like a small child playing with wooden blocks.", "The program makes a grid of [IT]user-defined[it]", "proportions ([TT]-nbox[tt]), ", "and interspaces the grid point with an extra space [TT]-dist[tt].[PAR]", "When option [TT]-rot[tt] is used the program does not check for overlap", "between molecules on grid points. It is recommended to make the box in", "the input file at least as big as the coordinates + ", "van der Waals radius.[PAR]", "If the optional trajectory file is given, conformations are not", "generated, but read from this file and translated appropriately to", "build the grid." }; const char *bugs[] = { "The program should allow for random displacement of lattice points." }; int vol; t_atoms *atoms; /* list with all atoms */ char title[STRLEN]; rvec *x, *xx, *v; /* coordinates? */ real t; vec4 *xrot, *vrot; int ePBC; matrix box, boxx; /* box length matrix */ rvec shift; int natoms; /* number of atoms in one molecule */ int nres; /* number of molecules? */ int i, j, k, l, m, ndx, nrdx, nx, ny, nz; t_trxstatus *status; gmx_bool bTRX; output_env_t oenv; t_filenm fnm[] = { { efSTX, "-f", "conf", ffREAD }, { efSTO, "-o", "out", ffWRITE }, { efTRX, "-trj", NULL, ffOPTRD } }; #define NFILE asize(fnm) static rvec nrbox = {1, 1, 1}; static int seed = 0; /* seed for random number generator */ static int nmolat = 3; static int nblock = 1; static gmx_bool bShuffle = FALSE; static gmx_bool bSort = FALSE; static gmx_bool bRandom = FALSE; /* False: no random rotations */ static gmx_bool bRenum = TRUE; /* renumber residues */ static rvec dist = {0, 0, 0}; /* space added between molecules ? */ static rvec max_rot = {180, 180, 180}; /* maximum rotation */ t_pargs pa[] = { { "-nbox", FALSE, etRVEC, {nrbox}, "Number of boxes" }, { "-dist", FALSE, etRVEC, {dist}, "Distance between boxes" }, { "-seed", FALSE, etINT, {&seed}, "Random generator seed, if 0 generated from the time" }, { "-rot", FALSE, etBOOL, {&bRandom}, "Randomly rotate conformations" }, { "-shuffle", FALSE, etBOOL, {&bShuffle}, "Random shuffling of molecules" }, { "-sort", FALSE, etBOOL, {&bSort}, "Sort molecules on X coord" }, { "-block", FALSE, etINT, {&nblock}, "Divide the box in blocks on this number of cpus" }, { "-nmolat", FALSE, etINT, {&nmolat}, "Number of atoms per molecule, assumed to start from 0. " "If you set this wrong, it will screw up your system!" }, { "-maxrot", FALSE, etRVEC, {max_rot}, "Maximum random rotation" }, { "-renumber", FALSE, etBOOL, {&bRenum}, "Renumber residues" } }; CopyRight(stderr, argv[0]); parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv); if (bRandom && (seed == 0)) { seed = make_seed(); } bTRX = ftp2bSet(efTRX, NFILE, fnm); nx = (int)(nrbox[XX]+0.5); ny = (int)(nrbox[YY]+0.5); nz = (int)(nrbox[ZZ]+0.5); if ((nx <= 0) || (ny <= 0) || (nz <= 0)) { gmx_fatal(FARGS, "Number of boxes (-nbox) should be larger than zero"); } if ((nmolat <= 0) && bShuffle) { gmx_fatal(FARGS, "Can not shuffle if the molecules only have %d atoms", nmolat); } vol = nx*ny*nz; /* calculate volume in grid points (= nr. molecules) */ get_stx_coordnum(opt2fn("-f", NFILE, fnm), &natoms); snew(atoms, 1); /* make space for all the atoms */ init_t_atoms(atoms, natoms*vol, FALSE); snew(x, natoms*vol); /* get space for coordinates of all atoms */ snew(xrot, natoms); /* get space for rotation matrix? */ snew(v, natoms*vol); /* velocities. not really needed? */ snew(vrot, natoms); /* set atoms->nr to the number in one box * * to avoid complaints in read_stx_conf * */ atoms->nr = natoms; read_stx_conf(opt2fn("-f", NFILE, fnm), title, atoms, x, v, &ePBC, box); nres = atoms->nres; /* nr of residues in one element? */ if (bTRX) { if (!read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &xx, boxx)) { gmx_fatal(FARGS, "No atoms in trajectory %s", ftp2fn(efTRX, NFILE, fnm)); } } else { snew(xx, natoms); for (i = 0; i < natoms; i++) { copy_rvec(x[i], xx[i]); } } for (k = 0; (k < nz); k++) /* loop over all gridpositions */ { shift[ZZ] = k*(dist[ZZ]+box[ZZ][ZZ]); for (j = 0; (j < ny); j++) { shift[YY] = j*(dist[YY]+box[YY][YY])+k*box[ZZ][YY]; for (i = 0; (i < nx); i++) { shift[XX] = i*(dist[XX]+box[XX][XX])+j*box[YY][XX]+k*box[ZZ][XX]; ndx = (i*ny*nz+j*nz+k)*natoms; nrdx = (i*ny*nz+j*nz+k)*nres; /* Random rotation on input coords */ if (bRandom) { rand_rot(natoms, xx, v, xrot, vrot, &seed, max_rot); } for (l = 0; (l < natoms); l++) { for (m = 0; (m < DIM); m++) { if (bRandom) { x[ndx+l][m] = xrot[l][m]; v[ndx+l][m] = vrot[l][m]; } else { x[ndx+l][m] = xx[l][m]; v[ndx+l][m] = v[l][m]; } } if (ePBC == epbcSCREW && i % 2 == 1) { /* Rotate around x axis */ for (m = YY; m <= ZZ; m++) { x[ndx+l][m] = box[YY][m] + box[ZZ][m] - x[ndx+l][m]; v[ndx+l][m] = -v[ndx+l][m]; } } for (m = 0; (m < DIM); m++) { x[ndx+l][m] += shift[m]; } atoms->atom[ndx+l].resind = nrdx + atoms->atom[l].resind; atoms->atomname[ndx+l] = atoms->atomname[l]; } for (l = 0; (l < nres); l++) { atoms->resinfo[nrdx+l] = atoms->resinfo[l]; if (bRenum) { atoms->resinfo[nrdx+l].nr += nrdx; } } if (bTRX) { if (!read_next_x(oenv, status, &t, natoms, xx, boxx) && ((i+1)*(j+1)*(k+1) < vol)) { gmx_fatal(FARGS, "Not enough frames in trajectory"); } } } } } if (bTRX) { close_trj(status); } /* make box bigger */ for (m = 0; (m < DIM); m++) { box[m][m] += dist[m]; } svmul(nx, box[XX], box[XX]); svmul(ny, box[YY], box[YY]); svmul(nz, box[ZZ], box[ZZ]); if (ePBC == epbcSCREW && nx % 2 == 0) { /* With an even number of boxes in x we can forgot about the screw */ ePBC = epbcXYZ; } /* move_x(natoms*vol,x,box); */ /* put atoms in box? */ atoms->nr *= vol; atoms->nres *= vol; /*depending on how you look at it, this is either a nasty hack or the way it should work*/ if (bRenum) { for (i = 0; i < atoms->nres; i++) { atoms->resinfo[i].nr = i+1; } } if (bShuffle) { randwater(0, atoms->nr/nmolat, nmolat, x, v, &seed); } else if (bSort) { sortwater(0, atoms->nr/nmolat, nmolat, x, v); } else if (opt2parg_bSet("-block", asize(pa), pa)) { mkcompact(0, atoms->nr/nmolat, nmolat, x, v, nblock, box); } write_sto_conf(opt2fn("-o", NFILE, fnm), title, atoms, x, v, ePBC, box); thanx(stderr); return 0; }
int gc_traj2uvecs(const char *traj_fname, output_env_t *oenv, real *dt, int atompairs[], int npairs, rvec ***unit_vecs) { rvec *x; t_trxstatus *status = NULL; int natoms = 0; real t = 0.0; matrix box; int nframes = 0; int cur_alloc = GC_FRAME_ALLOC; // allocate memory for unit vectors snew(*unit_vecs, cur_alloc); natoms = read_first_x(*oenv, &status, traj_fname, &t, &x, box); if(natoms > 0) { real cur_dt = 0.0; real last_t = t; if(*dt < 0) { // User didn't provide dt, so use default: // Use trajectory timestep as dt and just store data for all trajectory frames real last_dt = *dt; do { cur_dt = t - last_t; last_t = t; // Check for consistency of trajectory timestep // (this is necessary for proper autocorrelation with default trajectory timestep, // otherwise specify a timestep in dt that is at least as large as the largest timestep // in the trajectory and is a multiple of all other timesteps in the trajectory) if(!GC_TIME_EQ(cur_dt, *dt) && nframes > 1) { gk_log_fatal(FARGS, "Inconsistent time step in frame %d of %s: dt is %f vs. previous dt of %f.\n", nframes, traj_fname, cur_dt, *dt); } else if(nframes == 1) { // Use the dt between the first two frames of the trajectory as the expected dt. *dt = cur_dt; } // Expand memory if needed if(nframes + 1 > cur_alloc) { cur_alloc *= 2; srenew(*unit_vecs, cur_alloc); } // Get unit vectors for the atom pairs in this frame snew((*unit_vecs)[nframes], npairs); for(int p = 0; p < npairs; ++p) { gc_get_unit_vec(x, atompairs[2 * p], atompairs[2 * p + 1], (*unit_vecs)[nframes][p]); } ++nframes; } while(read_next_x(*oenv, status, &t, #ifndef GRO_V5 natoms, #endif x, box)); } // if dt < 0 else { // if provided dt >= 0 // Only store the data in the trajectory intervals matching the given dt last_t = t - *dt; // so that the first trajectory frame will pass dt boundary check int trajframe = 0; do { cur_dt = t - last_t; // if this trajectory frame is not on a dt boundary, skip it if(GC_TIME_EQ(cur_dt, *dt)) { // Expand memory if needed if(nframes + 1 > cur_alloc) { cur_alloc *= 2; srenew(*unit_vecs, cur_alloc); } // Get unit vectors for the atom pairs in this frame snew((*unit_vecs)[nframes], npairs); for(int p = 0; p < npairs; ++p) { gc_get_unit_vec(x, atompairs[2 * p], atompairs[2 * p + 1], (*unit_vecs)[nframes][p]); } // Reset timestep counter last_t = t; ++nframes; } else if(cur_dt > *dt) { gk_log_fatal(FARGS, "Error at frame %d of %s: " "given dt = %f is not a multiple of the trajectory timestep, " "or the trajectory has inconsistent timesteps.\n", trajframe, traj_fname, *dt); } ++trajframe; } while(read_next_x(*oenv, status, &t, #ifndef GRO_V5 natoms, #endif x, box)); } // if provided dt >= 0 } // if natoms > 0 else { gk_log_fatal(FARGS, "No atoms found in %s!\n", traj_fname); } // Done with trajectory close_trx(status); sfree(x); srenew(*unit_vecs, nframes); // free excess memory return nframes; }
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"); }
int gmx_trjorder(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] orders molecules according to the smallest distance", "to atoms in a reference group", "or on z-coordinate (with option [TT]-z[tt]).", "With distance ordering, it will ask for a group of reference", "atoms and a group of molecules. For each frame of the trajectory", "the selected molecules will be reordered according to the shortest", "distance between atom number [TT]-da[tt] in the molecule and all the", "atoms in the reference group. The center of mass of the molecules can", "be used instead of a reference atom by setting [TT]-da[tt] to 0.", "All atoms in the trajectory are written", "to the output trajectory.[PAR]", "[THISMODULE] can be useful for e.g. analyzing the n waters closest to a", "protein.", "In that case the reference group would be the protein and the group", "of molecules would consist of all the water atoms. When an index group", "of the first n waters is made, the ordered trajectory can be used", "with any GROMACS program to analyze the n closest waters.", "[PAR]", "If the output file is a [REF].pdb[ref] file, the distance to the reference target", "will be stored in the B-factor field in order to color with e.g. Rasmol.", "[PAR]", "With option [TT]-nshell[tt] the number of molecules within a shell", "of radius [TT]-r[tt] around the reference group are printed." }; static int na = 3, ref_a = 1; static real rcut = 0; static gmx_bool bCOM = FALSE, bZ = FALSE; t_pargs pa[] = { { "-na", FALSE, etINT, {&na}, "Number of atoms in a molecule" }, { "-da", FALSE, etINT, {&ref_a}, "Atom used for the distance calculation, 0 is COM" }, { "-com", FALSE, etBOOL, {&bCOM}, "Use the distance to the center of mass of the reference group" }, { "-r", FALSE, etREAL, {&rcut}, "Cutoff used for the distance calculation when computing the number of molecules in a shell around e.g. a protein" }, { "-z", FALSE, etBOOL, {&bZ}, "Order molecules on z-coordinate" } }; FILE *fp; t_trxstatus *out; t_trxstatus *status; gmx_bool bNShell, bPDBout; t_topology top; int ePBC; rvec *x, *xsol, xcom, dx; matrix box; t_pbc pbc; gmx_rmpbc_t gpbc; real t, totmass, mass, rcut2 = 0, n2; int natoms, nwat, ncut; char **grpname; int i, j, d, *isize, isize_ref = 0, isize_sol; atom_id sa, sr, *swi, **index, *ind_ref = NULL, *ind_sol; output_env_t oenv; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efTRO, "-o", "ordered", ffOPTWR }, { efXVG, "-nshell", "nshell", ffOPTWR } }; #define NFILE asize(fnm) if (!parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &x, NULL, box, TRUE); sfree(x); /* get index groups */ printf("Select %sa group of molecules to be ordered:\n", bZ ? "" : "a group of reference atoms and "); snew(grpname, 2); snew(index, 2); snew(isize, 2); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), bZ ? 1 : 2, isize, index, grpname); if (!bZ) { isize_ref = isize[0]; isize_sol = isize[1]; ind_ref = index[0]; ind_sol = index[1]; } else { isize_sol = isize[0]; ind_sol = index[0]; } natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); if (natoms > top.atoms.nr) { gmx_fatal(FARGS, "Number of atoms in the run input file is larger than in the trjactory"); } for (i = 0; (i < 2); i++) { for (j = 0; (j < isize[i]); j++) { if (index[i][j] > natoms) { gmx_fatal(FARGS, "An atom number in group %s is larger than the number of atoms in the trajectory"); } } } if ((isize_sol % na) != 0) { gmx_fatal(FARGS, "Number of atoms in the molecule group (%d) is not a multiple of na (%d)", isize[1], na); } nwat = isize_sol/na; if (ref_a > na) { gmx_fatal(FARGS, "The reference atom can not be larger than the number of atoms in a molecule"); } ref_a--; snew(xsol, nwat); snew(order, nwat); snew(swi, natoms); for (i = 0; (i < natoms); i++) { swi[i] = i; } out = NULL; fp = NULL; bNShell = ((opt2bSet("-nshell", NFILE, fnm)) || (opt2parg_bSet("-r", asize(pa), pa))); bPDBout = FALSE; if (bNShell) { rcut2 = rcut*rcut; fp = xvgropen(opt2fn("-nshell", NFILE, fnm), "Number of molecules", "Time (ps)", "N", oenv); printf("Will compute the number of molecules within a radius of %g\n", rcut); } if (!bNShell || opt2bSet("-o", NFILE, fnm)) { bPDBout = (fn2ftp(opt2fn("-o", NFILE, fnm)) == efPDB); if (bPDBout && !top.atoms.pdbinfo) { fprintf(stderr, "Creating pdbfino records\n"); snew(top.atoms.pdbinfo, top.atoms.nr); } out = open_trx(opt2fn("-o", NFILE, fnm), "w"); } gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms); do { gmx_rmpbc(gpbc, natoms, box, x); set_pbc(&pbc, ePBC, box); if (ref_a == -1) { /* Calculate the COM of all solvent molecules */ for (i = 0; i < nwat; i++) { totmass = 0; clear_rvec(xsol[i]); for (j = 0; j < na; j++) { sa = ind_sol[i*na+j]; mass = top.atoms.atom[sa].m; totmass += mass; for (d = 0; d < DIM; d++) { xsol[i][d] += mass*x[sa][d]; } } svmul(1.0/totmass, xsol[i], xsol[i]); } } else { /* Copy the reference atom of all solvent molecules */ for (i = 0; i < nwat; i++) { copy_rvec(x[ind_sol[i*na+ref_a]], xsol[i]); } } if (bZ) { for (i = 0; (i < nwat); i++) { sa = ind_sol[na*i]; order[i].i = sa; order[i].d2 = xsol[i][ZZ]; } } else if (bCOM) { totmass = 0; clear_rvec(xcom); for (i = 0; i < isize_ref; i++) { mass = top.atoms.atom[ind_ref[i]].m; totmass += mass; for (j = 0; j < DIM; j++) { xcom[j] += mass*x[ind_ref[i]][j]; } } svmul(1/totmass, xcom, xcom); for (i = 0; (i < nwat); i++) { sa = ind_sol[na*i]; pbc_dx(&pbc, xcom, xsol[i], dx); order[i].i = sa; order[i].d2 = norm2(dx); } } else { /* Set distance to first atom */ for (i = 0; (i < nwat); i++) { sa = ind_sol[na*i]; pbc_dx(&pbc, x[ind_ref[0]], xsol[i], dx); order[i].i = sa; order[i].d2 = norm2(dx); } for (j = 1; (j < isize_ref); j++) { sr = ind_ref[j]; for (i = 0; (i < nwat); i++) { pbc_dx(&pbc, x[sr], xsol[i], dx); n2 = norm2(dx); if (n2 < order[i].d2) { order[i].d2 = n2; } } } } if (bNShell) { ncut = 0; for (i = 0; (i < nwat); i++) { if (order[i].d2 <= rcut2) { ncut++; } } fprintf(fp, "%10.3f %8d\n", t, ncut); } if (out) { qsort(order, nwat, sizeof(*order), ocomp); for (i = 0; (i < nwat); i++) { for (j = 0; (j < na); j++) { swi[ind_sol[na*i]+j] = order[i].i+j; } } /* Store the distance as the B-factor */ if (bPDBout) { for (i = 0; (i < nwat); i++) { for (j = 0; (j < na); j++) { top.atoms.pdbinfo[order[i].i+j].bfac = std::sqrt(order[i].d2); } } } write_trx(out, natoms, swi, &top.atoms, 0, t, box, x, NULL, NULL); } } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); if (out) { close_trx(out); } if (fp) { xvgrclose(fp); } gmx_rmpbc_done(gpbc); return 0; }
int gmx_principal(int argc,char *argv[]) { const char *desc[] = { "g_principal calculates the three principal axes of inertia for a group", "of atoms.", }; static bool foo = FALSE; t_pargs pa[] = { { "-foo", FALSE, etBOOL, {&foo}, "Dummy option to avoid empty array" } }; int status; t_topology top; int ePBC; real t; rvec * x; int natoms; char *grpname,title[256]; int i,j,m,gnx,nam,mol; atom_id *index; rvec a1,a2,a3,moi; FILE * axis1; FILE * axis2; FILE * axis3; FILE * fmoi; matrix axes,box; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efDAT, "-a1", "axis1", ffWRITE }, { efDAT, "-a2", "axis2", ffWRITE }, { efDAT, "-a3", "axis3", ffWRITE }, { efDAT, "-om", "moi", ffWRITE } }; #define NFILE asize(fnm) CopyRight(stderr,argv[0]); parse_common_args(&argc,argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW | PCA_BE_NICE, NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL); axis1=fopen(opt2fn("-a1",NFILE,fnm),"w"); axis2=fopen(opt2fn("-a2",NFILE,fnm),"w"); axis3=fopen(opt2fn("-a3",NFILE,fnm),"w"); fmoi =fopen(opt2fn("-om",NFILE,fnm),"w"); read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,NULL,NULL,box,TRUE); get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&gnx,&index,&grpname); natoms=read_first_x(&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); do { rm_pbc(&(top.idef),ePBC,natoms,box,x,x); calc_principal_axes(&top,x,index,gnx,axes,moi); fprintf(axis1,"%15.10f %15.10f %15.10f %15.10f\n",t,axes[XX][XX],axes[YY][XX],axes[ZZ][XX]); fprintf(axis2,"%15.10f %15.10f %15.10f %15.10f\n",t,axes[XX][YY],axes[YY][YY],axes[ZZ][YY]); fprintf(axis3,"%15.10f %15.10f %15.10f %15.10f\n",t,axes[XX][ZZ],axes[YY][ZZ],axes[ZZ][ZZ]); fprintf(fmoi, "%15.10f %15.10f %15.10f %15.10f\n",t,moi[XX],moi[YY],moi[ZZ]); } while(read_next_x(status,&t,natoms,x,box)); close_trj(status); fclose(axis1); fclose(axis2); fclose(axis3); fclose(fmoi); thanx(stderr); return 0; }
static void do_sdf(char *fnNDX,char *fnTPS,char *fnTRX, char *fnSDF, char *fnREF, bool bRef, rvec cutoff, real binwidth, int mode, rvec triangle, rvec dtri) { FILE *fp; int status; int ng,natoms,i,j,k,l,X,Y,Z,lc,dest; ivec nbin; int ***count; /* real ***sdf; */ real sdf,min_sdf=1e10,max_sdf=0; char **grpname; int *isize; int isize_cg=0; int isize_ref=3; int ref_resind[3]; int nrefmol=0,refc=0; atom_id **index; atom_id *index_cg=NULL; atom_id *index_ref=NULL; real t,boxmin,hbox,normfac; real invbinw; rvec tri_upper,tri_lower; rvec *x,xcog,dx,*x_i1,xi,*x_refmol; matrix box; matrix rot; /* rotation matrix := unit vectors for the molecule frame */ rvec k_mol,i1_mol,i2_mol,dx_mol; real delta; atom_id ix,jx; t_topology top; int ePBC=-1; t_pbc pbc; bool bTop=FALSE,bRefDone=FALSE,bInGroup=FALSE; char title[STRLEN]; /* Read Topology */ if (fnTPS) { bTop=read_tps_conf(fnTPS,title,&top,&ePBC,&x,NULL,box,TRUE); } if ( !bTop ) { fprintf(stderr,"\nNeed tpr-file to make a reference structure.\n"); fprintf(stderr,"Option -r will be ignored!\n"); bRef = FALSE; } /* Allocate memory for 4 groups, 3 dummy groups and a group for the ref structure if needed */ ng = 4; snew(grpname,ng); /* the dummy groups are used to dynamically store triples of atoms */ /* for molecular coordinate systems */ if ( bRef ) { snew(isize,ng+4); snew(index,ng+4); } else { snew(isize,ng+3); snew(index,ng+3); } /* Read the index groups */ fprintf(stderr,"\nSelect the 3 reference groups and the SDF group:\n"); if (fnTPS) get_index(&top.atoms,fnNDX,ng,isize,index,grpname); else rd_index(fnNDX,ng,isize,index,grpname); isize[NDX_REF1]=isize[G_REF1]; for (i=NDX_REF1; i<=NDX_REF3; i++) snew(index[i],isize[NDX_REF1]); /* Read first frame and check it */ natoms=read_first_x(&status,fnTRX,&t,&x,box); if ( !natoms ) gmx_fatal(FARGS,"Could not read coordinates from statusfile!\n"); /* check with topology */ if (fnTPS) if ( natoms > top.atoms.nr ) gmx_fatal(FARGS,"Trajectory (%d atoms) does not match topology (%d atoms)!\n", natoms,top.atoms.nr); /* check with index groups */ for (i=0; i<ng; i++) for (j=0; j<isize[i]; j++) if ( index[i][j] >= natoms ) gmx_fatal(FARGS,"Atom index (%d) in index group %s (%d atoms) larger " "than number of atoms in trajectory (%d atoms)!\n", index[i][j],grpname[i],isize[i],natoms); /* check reference groups */ if ( mode == 1 ) { if ( isize[G_REF1] != isize[G_REF2] || isize[G_REF1] != isize[G_REF3] || isize[G_REF2] != isize[G_REF3] ) gmx_fatal(FARGS,"For single particle SDF, all reference groups" "must have the same size.\n"); /* for single particle SDF dynamic triples are not needed */ /* so we build them right here */ /* copy all triples from G_REFx to NDX_REFx */ for (i=0; i<isize[G_REF1]; i++) { /* check if all three atoms come from the same molecule */ for (j=G_REF1; j<=G_REF3; j++) ref_resind[j] = top.atoms.atom[index[j][i]].resind; if ( ref_resind[G_REF1] != ref_resind[G_REF2] || ref_resind[G_REF2] != ref_resind[G_REF3] || ref_resind[G_REF3] != ref_resind[G_REF1] ) { fprintf(stderr,"\nWarning: reference triple (%d) will be skipped.\n",i); fprintf(stderr, " resnr[1]: %d, resnr[2]: %d, resnr[3]: %d\n", ref_resind[G_REF1],ref_resind[G_REF2], ref_resind[G_REF3]); isize[NDX_REF1]--; for (j=NDX_REF1; j<=NDX_REF3; j++) srenew(index[j],isize[NDX_REF1]); continue; } else /* check if all entries are unique*/ if ( index[G_REF1][i] == index[G_REF2][i] || index[G_REF2][i] == index[G_REF3][i] || index[G_REF3][i] == index[G_REF1][i] ) { fprintf(stderr,"Warning: reference triple (%d) will be skipped.\n",i); fprintf(stderr, " index[1]: %d, index[2]: %d, index[3]: %d\n", index[G_REF1][i],index[G_REF2][i],index[G_REF3][i]); isize[NDX_REF1]--; for (j=NDX_REF1; j<=NDX_REF3; j++) srenew(index[j],isize[NDX_REF1]); continue; } else /* everythings fine, copy that one */ for (j=G_REF1; j<=G_REF3; j++) index[j+4][i] = index[j][i]; } } else if ( mode == 2 ) { if ( isize[G_REF1] != isize[G_REF2] ) gmx_fatal(FARGS,"For two particle SDF, reference groups 1 and 2" "must have the same size.\n"); for (i=0; i<isize[G_REF1]; i++) { /* check consistency for atoms 1 and 2 */ for (j=G_REF1; j<=G_REF2; j++) ref_resind[j] = top.atoms.atom[index[j][i]].resind; if ( ref_resind[G_REF1] != ref_resind[G_REF2] || index[G_REF1][i] == index[G_REF2][i] ) { if ( ref_resind[G_REF1] != ref_resind[G_REF2] ) { fprintf(stderr,"\nWarning: bond (%d) not from one molecule." "Will not be used for SDF.\n",i); fprintf(stderr, " resnr[1]: %d, resnr[2]: %d\n", ref_resind[G_REF1],ref_resind[G_REF2]); } else { fprintf(stderr,"\nWarning: atom1 and atom2 are identical." "Bond (%d) will not be used for SDF.\n",i); fprintf(stderr, " index[1]: %d, index[2]: %d\n", index[G_REF1][i],index[G_REF2][i]); } for (j=NDX_REF1; j<=NDX_REF2; j++) { for (k=i; k<isize[G_REF1]-1; k++) index[j][k]=index[j][k+1]; isize[j]--; srenew(index[j],isize[j]); } } } } /* Read Atoms for refmol group */ if ( bRef ) { snew(index[G_REFMOL],1); for (i=G_REF1; i<=G_REF3; i++) ref_resind[i] = top.atoms.atom[index[i][0]].resind; for (i=0; i<natoms; i++) { if ( ref_resind[G_REF1] == top.atoms.atom[i].resind || ref_resind[G_REF2] == top.atoms.atom[i].resind || ref_resind[G_REF3] == top.atoms.atom[i].resind ) nrefmol++; } srenew(index[G_REFMOL],nrefmol); isize[G_REFMOL] = nrefmol; nrefmol = 0; for (i=0; i<natoms; i++) { if ( ref_resind[G_REF1] == top.atoms.atom[i].resind || ref_resind[G_REF2] == top.atoms.atom[i].resind || ref_resind[G_REF3] == top.atoms.atom[i].resind ) { index[G_REFMOL][nrefmol] = i; nrefmol++; } } } /* initialize some stuff */ boxmin = min( norm(box[XX]), min( norm(box[YY]), norm(box[ZZ]) ) ); hbox = boxmin / 2.0; for (i=0; i<DIM; i++) { cutoff[i] = cutoff[i] / 2; nbin[i] = (int)(2 * cutoff[i] / binwidth) + 1; invbinw = 1.0 / binwidth; tri_upper[i] = triangle[i] + dtri[i]; tri_upper[i] = sqr(tri_upper[i]); tri_lower[i] = triangle[i] - dtri[i]; tri_lower[i] = sqr(tri_lower[i]); } /* Allocate the array's for sdf */ snew(count,nbin[0]+1); for(i=0; i<nbin[0]+1; i++) { snew(count[i],nbin[1]+1); for (j=0; j<nbin[1]+1; j++) snew(count[i][j],nbin[2]+1); } /* Allocate space for the coordinates */ snew(x_i1,isize[G_SDF]); snew(x_refmol,isize[G_REFMOL]); for (i=0; i<isize[G_REFMOL]; i++) for (j=XX; j<=ZZ; j++) x_refmol[i][j] = 0; normfac = 0; do { /* Must init pbc every step because of pressure coupling */ set_pbc(&pbc,ePBC,box); rm_pbc(&top.idef,ePBC,natoms,box,x,x); /* Dynamically build the ref tripels */ if ( mode == 2 ) { isize[NDX_REF1]=0; for (j=NDX_REF1; j<=NDX_REF3; j++) srenew(index[j],isize[NDX_REF1]+1); /* consistancy of G_REF[1,2] has already been check */ /* hence we can look for the third atom right away */ for (i=0; i<isize[G_REF1]; i++) { for (j=0; j<isize[G_REF3]; j++) { /* Avoid expensive stuff if possible */ if ( top.atoms.atom[index[G_REF1][i]].resind != top.atoms.atom[index[G_REF3][j]].resind && index[G_REF1][i] != index[G_REF3][j] && index[G_REF2][i] != index[G_REF3][j] ) { pbc_dx(&pbc,x[index[G_REF1][i]],x[index[G_REF3][j]],dx); delta = norm2(dx); if ( delta < tri_upper[G_REF1] && delta > tri_lower[G_REF1] ) { pbc_dx(&pbc,x[index[G_REF2][i]],x[index[G_REF3][j]],dx); delta = norm2(dx); if ( delta < tri_upper[G_REF2] && delta > tri_lower[G_REF2] ) { /* found triple */ index[NDX_REF1][isize[NDX_REF1]]=index[G_REF1][i]; index[NDX_REF2][isize[NDX_REF1]]=index[G_REF2][i]; index[NDX_REF3][isize[NDX_REF1]]=index[G_REF3][j]; /* resize groups */ isize[NDX_REF1]++; for (k=NDX_REF1; k<=NDX_REF3; k++) srenew(index[k],isize[NDX_REF1]+1); } } } } } } else if ( mode ==3 ) { isize[NDX_REF1]=0; for (j=NDX_REF1; j<=NDX_REF3; j++) srenew(index[j],isize[NDX_REF1]+1); /* consistancy will be checked while searching */ for (i=0; i<isize[G_REF1]; i++) { for (j=0; j<isize[G_REF2]; j++) { /* Avoid expensive stuff if possible */ if ( top.atoms.atom[index[G_REF1][i]].resind != top.atoms.atom[index[G_REF2][j]].resind && index[G_REF1][i] != index[G_REF2][j] ) { pbc_dx(&pbc,x[index[G_REF1][i]],x[index[G_REF2][j]],dx); delta = norm2(dx); if ( delta < tri_upper[G_REF3] && delta > tri_lower[G_REF3] ) { for (k=0; k<isize[G_REF3]; k++) { if ( top.atoms.atom[index[G_REF1][i]].resind != top.atoms.atom[index[G_REF3][k]].resind && top.atoms.atom[index[G_REF2][j]].resind != top.atoms.atom[index[G_REF3][k]].resind && index[G_REF1][i] != index[G_REF3][k] && index[G_REF2][j] != index[G_REF3][k]) { pbc_dx(&pbc,x[index[G_REF1][i]],x[index[G_REF3][k]],dx); delta = norm2(dx); if ( delta < tri_upper[G_REF1] && delta > tri_lower[G_REF1] ) { pbc_dx(&pbc,x[index[G_REF2][j]],x[index[G_REF3][k]],dx); delta = norm2(dx); if ( delta < tri_upper[G_REF2] && delta > tri_lower[G_REF2] ) { /* found triple */ index[NDX_REF1][isize[NDX_REF1]]=index[G_REF1][i]; index[NDX_REF2][isize[NDX_REF1]]=index[G_REF2][j]; index[NDX_REF3][isize[NDX_REF1]]=index[G_REF3][k]; /* resize groups */ isize[NDX_REF1]++; for (l=NDX_REF1; l<=NDX_REF3; l++) srenew(index[l],isize[NDX_REF1]+1); } } } } } } } } } for (i=0; i<isize[NDX_REF1]; i++) { /* setup the molecular coordinate system (i',j',k') */ /* because the coodinate system of the box forms a unit matrix */ /* (i',j',k') is identical with the rotation matrix */ clear_mat(rot); /* k' = unitv(r(atom0) - r(atom1)) */ pbc_dx(&pbc,x[index[NDX_REF1][i]],x[index[NDX_REF2][i]],k_mol); unitv(k_mol,rot[2]); /* i' = unitv(k' x (r(atom2) - r(atom1))) */ pbc_dx(&pbc,x[index[NDX_REF3][i]],x[index[NDX_REF2][i]],i1_mol); cprod(i1_mol,rot[2],i2_mol); unitv(i2_mol,rot[0]); /* j' = k' x i' */ cprod(rot[2],rot[0],rot[1]); /* set the point of reference */ if ( mode == 2 ) copy_rvec(x[index[NDX_REF3][i]],xi); else copy_rvec(x[index[NDX_REF1][i]],xi); /* make the reference */ if ( bRef ) { for (j=0; j<isize[G_REFMOL]; j++) { pbc_dx(&pbc,xi,x[index[G_REFMOL][j]],dx); mvmul(rot,dx,dx_mol); rvec_inc(x_refmol[j],dx_mol); for(k=XX; k<=ZZ; k++) x_refmol[j][k] = x_refmol[j][k] / 2; } } /* Copy the indexed coordinates to a continuous array */ for(j=0; j<isize[G_SDF]; j++) copy_rvec(x[index[G_SDF][j]],x_i1[j]); /* count the SDF */ for(j=0; j<isize[G_SDF]; j++) { /* Exclude peaks from the reference set */ bInGroup=FALSE; for (k=NDX_REF1; k<=NDX_REF3; k++) if ( index[G_SDF][j] == index[k][i] ) bInGroup=TRUE; if ( !bInGroup ) { pbc_dx(&pbc,xi,x_i1[j],dx); /* transfer dx to the molecular coordinate system */ mvmul(rot,dx,dx_mol); /* check cutoff's and count */ if ( dx_mol[XX] > -cutoff[XX] && dx_mol[XX] < cutoff[XX] ) if ( dx_mol[YY] > -cutoff[YY] && dx_mol[YY] < cutoff[YY] ) if ( dx_mol[ZZ] > -cutoff[ZZ] && dx_mol[ZZ] < cutoff[ZZ] ) { X = (int)(floor(dx_mol[XX]*invbinw)) + (nbin[XX]-1)/2 +1; Y = (int)(floor(dx_mol[YY]*invbinw)) + (nbin[YY]-1)/2 +1; Z = (int)(floor(dx_mol[ZZ]*invbinw)) + (nbin[ZZ]-1)/2 +1; count[X][Y][Z]++; normfac++; } } } } } while (read_next_x(status,&t,natoms,x,box)); fprintf(stderr,"\n"); close_trj(status); sfree(x); /* write the reference strcture*/ if ( bRef ) { fp=ffopen(fnREF,"w"); fprintf(fp,"%s\n",title); fprintf(fp," %d\n",isize[G_REFMOL]); for (i=0; i<isize[G_REFMOL]; i++) fprintf(fp,"%5d%5s%5s%5d%8.3f%8.3f%8.3f\n", top.atoms.resinfo[top.atoms.atom[index[G_REFMOL][i]].resind].nr, *(top.atoms.resinfo[top.atoms.atom[index[G_REFMOL][i]].resind].name), *(top.atoms.atomname[index[G_REFMOL][i]]),i+1, -1*x_refmol[i][XX],-1*x_refmol[i][YY],-1*x_refmol[i][ZZ]); /* Inserted -1* on the line above three times */ fprintf(fp," 10.00000 10.00000 10.00000\n"); ffclose(fp); fprintf(stderr,"\nWrote reference structure. (%d Atoms)\n",isize[G_REFMOL]); } /* Calculate the mean probability density */ fprintf(stderr,"\nNumber of configuations used for SDF: %d\n",(int)normfac); normfac = nbin[0]*nbin[1]*nbin[2] / normfac; fprintf(stderr,"\nMean probability density: %f\n",1/normfac); /* normalize the SDF and write output */ /* see http://www.csc.fi/gopenmol/index.phtml for documentation */ fp=ffopen(fnSDF,"wb"); /* rank */ i_write(fp,3); /* Type of surface */ i_write(fp,42); /* Zdim, Ydim, Xdim */ for (i=ZZ; i>=XX; i--) i_write(fp,nbin[i]); /* [Z,Y,X][min,max] (box corners in Angstroem)*/ for (i=ZZ; i>=XX; i--) { f_write(fp,-cutoff[i]*10); f_write(fp,cutoff[i]*10); } /* Original Code for (i=1; i<nbin[2]+1; i++) for (j=1; j<nbin[1]+1; j++) for (k=1; k<nbin[0]+1; k++) { sdf = normfac * count[k][j][i]; if ( sdf < min_sdf ) min_sdf = sdf; if ( sdf > max_sdf ) max_sdf = sdf; f_write(fp,sdf); }*/ /* Changed Code to Mirror SDF to correct coordinates */ for (i=nbin[2]; i>0; i--) for (j=nbin[1]; j>0; j--) for (k=nbin[0]; k>0; k--) { sdf = normfac * count[k][j][i]; if ( sdf < min_sdf ) min_sdf = sdf; if ( sdf > max_sdf ) max_sdf = sdf; f_write(fp,sdf); } fprintf(stderr,"\nMin: %f Max: %f\n",min_sdf,max_sdf); ffclose(fp); /* Give back the mem */ for(i=0; i<nbin[0]+1; i++) { for (j=0; j<nbin[1]+1; j++) { sfree(count[i][j]); } sfree(count[i]); } sfree(count); }
int main(int argc,char *argv[]) { static char *desc[] = { "The [TT]pmetest[tt] program tests the scaling of the PME code. When only given", "a [TT].tpr[tt] file it will compute PME for one frame. When given a trajectory", "it will do so for all the frames in the trajectory. Before the PME", "routine is called the coordinates are sorted along the X-axis.[PAR]", "As an extra service to the public the program can also compute", "long-range Coulomb energies for components of the system. When the", "[TT]-groups[tt] flag is given to the program the energy groups", "from the [TT].tpr[tt] file will be read, and half an energy matrix computed." }; t_commrec *cr,*mcr; static t_filenm fnm[] = { { efTPX, NULL, NULL, ffREAD }, { efTRN, "-o", NULL, ffWRITE }, { efLOG, "-g", "pme", ffWRITE }, { efTRX, "-f", NULL, ffOPTRD }, { efXVG, "-x", "ener-pme", ffWRITE } }; #define NFILE asize(fnm) /* Command line options ! */ static gmx_bool bVerbose=FALSE; static gmx_bool bOptFFT=FALSE; static gmx_bool bSort=FALSE; static int ewald_geometry=eewg3D; static int nnodes=1; static int pme_order=0; static rvec grid = { -1, -1, -1 }; static real rc = 0.0; static real dtol = 0.0; static gmx_bool bGroups = FALSE; static t_pargs pa[] = { { "-np", FALSE, etINT, {&nnodes}, "Number of nodes, must be the same as used for [TT]grompp[tt]" }, { "-v", FALSE, etBOOL,{&bVerbose}, "Be loud and noisy" }, { "-sort", FALSE, etBOOL,{&bSort}, "Sort coordinates. Crucial for domain decomposition." }, { "-grid", FALSE, etRVEC,{&grid}, "Number of grid cells in X, Y, Z dimension (if -1 use from [TT].tpr[tt])" }, { "-order", FALSE, etINT, {&pme_order}, "Order of the PME spreading algorithm" }, { "-groups", FALSE, etBOOL, {&bGroups}, "Compute half an energy matrix based on the energy groups in your [TT].tpr[tt] file" }, { "-rc", FALSE, etREAL, {&rc}, "Rcoulomb for Ewald summation" }, { "-tol", FALSE, etREAL, {&dtol}, "Tolerance for Ewald summation" } }; FILE *fp; t_inputrec *ir; t_topology top; t_tpxheader tpx; t_nrnb nrnb; t_nsborder *nsb; t_forcerec *fr; t_mdatoms *mdatoms; char title[STRLEN]; int natoms,step,status,i,ncg,root; real t,lambda,ewaldcoeff,qtot; rvec *x,*f,*xbuf; int *index; gmx_bool bCont; real *charge,*qbuf,*qqbuf; matrix box; /* Start the actual parallel code if necessary */ cr = init_par(&argc,&argv); root = 0; if (MASTER(cr)) CopyRight(stderr,argv[0]); /* Parse command line on all processors, arguments are passed on in * init_par (see above) */ parse_common_args(&argc,argv, PCA_KEEP_ARGS | PCA_NOEXIT_ON_ARGS | PCA_BE_NICE | PCA_CAN_SET_DEFFNM | (MASTER(cr) ? 0 : PCA_QUIET), NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL); #ifndef GMX_MPI if (nnodes > 1) gmx_fatal(FARGS,"GROMACS compiled without MPI support - can't do parallel runs"); #endif /* Open log files on all processors */ open_log(ftp2fn(efLOG,NFILE,fnm),cr); snew(ir,1); if (MASTER(cr)) { /* Read tpr file etc. */ read_tpxheader(ftp2fn(efTPX,NFILE,fnm),&tpx,FALSE,NULL,NULL); snew(x,tpx.natoms); read_tpx(ftp2fn(efTPX,NFILE,fnm),&step,&t,&lambda,ir, box,&natoms,x,NULL,NULL,&top); /* Charges */ qtot = 0; snew(charge,natoms); for(i=0; (i<natoms); i++) { charge[i] = top.atoms.atom[i].q; qtot += charge[i]; } /* Grid stuff */ if (opt2parg_bSet("-grid",asize(pa),pa)) { ir->nkx = grid[XX]; ir->nky = grid[YY]; ir->nkz = grid[ZZ]; } /* Check command line parameters for consistency */ if ((ir->nkx <= 0) || (ir->nky <= 0) || (ir->nkz <= 0)) gmx_fatal(FARGS,"PME grid = %d %d %d",ir->nkx,ir->nky,ir->nkz); if (opt2parg_bSet("-rc",asize(pa),pa)) ir->rcoulomb = rc; if (ir->rcoulomb <= 0) gmx_fatal(FARGS,"rcoulomb should be > 0 (not %f)",ir->rcoulomb); if (opt2parg_bSet("-order",asize(pa),pa)) ir->pme_order = pme_order; if (ir->pme_order <= 0) gmx_fatal(FARGS,"pme_order should be > 0 (not %d)",ir->pme_order); if (opt2parg_bSet("-tol",asize(pa),pa)) ir->ewald_rtol = dtol; if (ir->ewald_rtol <= 0) gmx_fatal(FARGS,"ewald_tol should be > 0 (not %f)",ir->ewald_rtol); } else { init_top(&top); } /* Add parallellization code here */ snew(nsb,1); if (MASTER(cr)) { ncg = top.blocks[ebCGS].multinr[0]; for(i=0; (i<cr->nnodes-1); i++) top.blocks[ebCGS].multinr[i] = min(ncg,(ncg*(i+1))/cr->nnodes); for( ; (i<MAXNODES); i++) top.blocks[ebCGS].multinr[i] = ncg; } if (PAR(cr)) { /* Set some variables to zero to avoid core dumps */ ir->opts.ngtc = ir->opts.ngacc = ir->opts.ngfrz = ir->opts.ngener = 0; #ifdef GMX_MPI /* Distribute the data over processors */ MPI_Bcast(&natoms,1,MPI_INT,root,MPI_COMM_WORLD); MPI_Bcast(ir,sizeof(*ir),MPI_BYTE,root,MPI_COMM_WORLD); MPI_Bcast(&qtot,1,GMX_MPI_REAL,root,MPI_COMM_WORLD); #endif /* Call some dedicated communication routines, master sends n-1 times */ if (MASTER(cr)) { for(i=1; (i<cr->nnodes); i++) { mv_block(i,&(top.blocks[ebCGS])); mv_block(i,&(top.atoms.excl)); } } else { ld_block(root,&(top.blocks[ebCGS])); ld_block(root,&(top.atoms.excl)); } if (!MASTER(cr)) { snew(charge,natoms); snew(x,natoms); } #ifdef GMX_MPI MPI_Bcast(charge,natoms,GMX_MPI_REAL,root,MPI_COMM_WORLD); #endif } ewaldcoeff = calc_ewaldcoeff(ir->rcoulomb,ir->ewald_rtol); if (bVerbose) pr_inputrec(stdlog,0,"Inputrec",ir); /* Allocate memory for temp arrays etc. */ snew(xbuf,natoms); snew(f,natoms); snew(qbuf,natoms); snew(qqbuf,natoms); snew(index,natoms); /* Initialize the PME code */ init_pme(stdlog,cr,ir->nkx,ir->nky,ir->nkz,ir->pme_order, natoms,FALSE,bOptFFT,ewald_geometry); /* MFlops accounting */ init_nrnb(&nrnb); /* Initialize the work division */ calc_nsb(stdlog,&(top.blocks[ebCGS]),cr->nnodes,nsb,0); nsb->nodeid = cr->nodeid; print_nsb(stdlog,"pmetest",nsb); /* Initiate forcerec */ mdatoms = atoms2md(stdlog,&top.atoms,ir->opts.nFreeze,ir->eI, ir->delta_t,0,ir->opts.tau_t,FALSE,FALSE); snew(fr,1); init_forcerec(stdlog,fr,ir,&top,cr,mdatoms,nsb,box,FALSE,NULL,NULL,FALSE); /* First do PME based on coordinates in tpr file, send them to * other processors if needed. */ if (MASTER(cr)) fprintf(stdlog,"-----\n" "Results based on tpr file %s\n",ftp2fn(efTPX,NFILE,fnm)); #ifdef GMX_MPI if (PAR(cr)) { MPI_Bcast(x[0],natoms*DIM,GMX_MPI_REAL,root,MPI_COMM_WORLD); MPI_Bcast(box[0],DIM*DIM,GMX_MPI_REAL,root,MPI_COMM_WORLD); MPI_Bcast(&t,1,GMX_MPI_REAL,root,MPI_COMM_WORLD); } #endif do_my_pme(stdlog,0,bVerbose,ir,x,xbuf,f,charge,qbuf,qqbuf,box,bSort, cr,nsb,&nrnb,&(top.atoms.excl),qtot,fr,index,NULL, bGroups ? ir->opts.ngener : 1,mdatoms->cENER); /* If we have a trajectry file, we will read the frames in it and compute * the PME energy. */ if (ftp2bSet(efTRX,NFILE,fnm)) { fprintf(stdlog,"-----\n" "Results based on trx file %s\n",ftp2fn(efTRX,NFILE,fnm)); if (MASTER(cr)) { sfree(x); natoms = read_first_x(&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); if (natoms != top.atoms.nr) gmx_fatal(FARGS,"natoms in trx = %d, in tpr = %d",natoms,top.atoms.nr); fp = xvgropen(ftp2fn(efXVG,NFILE,fnm),"PME Energy","Time (ps)","E (kJ/mol)"); } else fp = NULL; do { /* Send coordinates, box and time to the other nodes */ #ifdef GMX_MPI if (PAR(cr)) { MPI_Bcast(x[0],natoms*DIM,GMX_MPI_REAL,root,MPI_COMM_WORLD); MPI_Bcast(box[0],DIM*DIM,GMX_MPI_REAL,root,MPI_COMM_WORLD); MPI_Bcast(&t,1,GMX_MPI_REAL,root,MPI_COMM_WORLD); } #endif rm_pbc(&top.idef,nsb->natoms,box,x,x); /* Call the PME wrapper function */ do_my_pme(stdlog,t,bVerbose,ir,x,xbuf,f,charge,qbuf,qqbuf,box,bSort,cr, nsb,&nrnb,&(top.atoms.excl),qtot,fr,index,fp, bGroups ? ir->opts.ngener : 1,mdatoms->cENER); /* Only the master processor reads more data */ if (MASTER(cr)) bCont = read_next_x(status,&t,natoms,x,box); /* Check whether we need to continue */ #ifdef GMX_MPI if (PAR(cr)) MPI_Bcast(&bCont,1,MPI_INT,root,MPI_COMM_WORLD); #endif } while (bCont); /* Finish I/O, close files */ if (MASTER(cr)) { close_trx(status); ffclose(fp); } } if (bVerbose) { /* Do some final I/O about performance, might be useful in debugging */ fprintf(stdlog,"-----\n"); print_nrnb(stdlog,&nrnb); } /* Finish the parallel stuff */ if (gmx_parallel_env_initialized()) gmx_finalize(cr); /* Thank the audience, as usual */ if (MASTER(cr)) thanx(stderr); return 0; }
int main(int argc,char *argv[]) { const char *desc[] = { "g_zcoord can output the z(t) coordinates of atoms which are located in a " "cylindrical region. " "This region is defined by its radius R, the axis, and a point on this axis." "It takes an index file with atom, ", "and generates an output file with the ", "z coordinates for each entry in the index file. Coordinates of particles " "that are NOT in the cylinder are set to a special value, which is set " "with the [TT]-nan[TT] option.", "[PAR]For quicker visualisation the [TT]-mat[tt] option is useful. It creates ", "an xpm matrix file. The boundaries of the graph in z are taken from " "z1 and z2; the spacing can be set with the hidden option " "[TT]-matspacing[TT]. Its default is " xstr(XPM_Z_SPACING) " nm.", "[PAR]Due to the huge amount of diskspace that the .dat and .xvg file can " "take up these options have been all made optional. YOU NEED TO SET AT LEAST " "ONE OF [TT]-dat[TT], [TT]-o[TT], or [TT]-mat[TT] to generate any output." }; t_cavity cavity = { /* define volume to count mols in */ {0, 0, 1}, /* axis */ {0, 0, 0}, /* cpoint */ -1, /* radius */ -1, /* z1 < z2 */ -1, 0 /* volume - calculate later */ }; real spacing = XPM_Z_SPACING; /* spacing in nm (!) for conversion to xpm */ int ngroups = 1; /* not used yet >1 */ real invalid = 9999.0; /* mark coordinates of particles not in cylinder */ t_pargs pa[] = { { "-axis", FALSE, etRVEC, {&(cavity.axis)}, "Vector pointing parallel to the pore axis"}, { "-cpoint", FALSE, etRVEC, {&(cavity.cpoint)}, "Point on the pore axis"}, { "-R", FALSE, etREAL, {&(cavity.radius)}, "Radius of the cylindrical pore cavity"}, { "-z1", FALSE, etREAL, {&(cavity.z1)}, "Confine waters to have a z coordinate larger than z1, and"}, { "-z2", FALSE, etREAL, {&(cavity.z2)}, "smaller than z2 (in nm). Also the z-boundaries for the xpm matrix."}, { "-nan", FALSE, etREAL, {&invalid}, "number that is used in output files for coordinates when the particle " "is not in the cylinder"}, { "-matspacing", FALSE, etREAL, {&spacing}, "HIDDENz spacing (in nm) for the xpm matrix"}, { "-ng", FALSE, etINT, {&ngroups}, "HIDDENNumber of groups to consider" }, }; FILE *out = NULL; /* xmgr file with coordinates */ FILE *fData= NULL; /* simple data file: t z */ t_topology top; /* topology */ rvec *xtop; int ePBC; char title[STRLEN]; gmx_bool bTop; rvec *x,*x_s; /* coord, with and without pbc*/ rvec xcm; /* center of mass of molecule */ matrix box; /* box matrix (3x3) */ real t,tm; /* time, total mass molecule */ int natoms; /* number of atoms in system */ t_trxstatus *status; int i,j; /* loopcounters */ int k_frame; /* counts frames */ const char *indexfn; char **grpname; /* groupnames for all groups */ int *isize; atom_id **index; /* molecule numbers in index for each group */ atom_id *atndx = NULL; /* indices from block. */ t_block *mols= NULL; /* all molecules in system */ char *ggrpname; /* name of the FIRST group */ int gnx = 0; /* number of atoms in FIRST group*/ atom_id *gindex = NULL; /* index of FIRST group */ real maxzval = MINZVAL_DEFAULT; /* max z in nm (!) for conversion to xpm */ real minzval = MAXZVAL_DEFAULT; /* min z in nm (!) for conversion to xpm */ int nbins = 0; /* number of bins for conv to xpm */ real **zbins = NULL; /* bins for conversion to xpm */ FILE *xpmOut = NULL; /* xpm matrix file */ t_rgb rlo, rhi; /* low and high colors for matrix */ int nlevels = 2; int max_frames = XPM_INITIAL_FRAMES; /* current max number of frames in xpm matrix */ real *x_axis = NULL;/* x-axis labels */ real *y_axis = NULL;/* y-axis labels */ gmx_bool bXPM = FALSE; /* produce XPM matrix ?*/ gmx_bool bXVG = FALSE; /* no output generated by default */ gmx_bool bDAT = FALSE; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffREAD }, { efXVG, "-o", "zcoord", ffOPTWR }, { efXPM, "-mat", "zcoord", ffOPTWR }, /* this is for xpm output */ { efDAT, "-dat", "zcoord", ffOPTWR }, { efNDX, NULL, NULL, ffOPTRD } }; output_env_t oenv; #define NFILE asize(fnm) #define NPA asize(pa) #define NDFILES 2 FILE *dfiles[NDFILES+1]; /* output files to dump data to terminate with NULL */ const char *bugs[] = { "Even if the cylinder axis is not (0,0,1), the top and bottom of the cylinder are" "still determined by the z-coordinates z1 and z2.", "ATTENTION: no data is generated by default !!!", "xpm graph: If no proper (i.e. |z| < " xstr(Z_SANITY) "nm) z-limits are " "given they are set to " "the arbitrary values z_min=" xstr(MINZVAL_DEFAULT) " and " "z_max=" xstr(MAXZVAL_DEFAULT), }; CopyRight(stderr,argv[0]); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW, NFILE,fnm,asize(pa),pa,asize(desc),desc,asize(bugs),bugs, &oenv); bDAT = (opt2fn_null("-dat", NFILE, fnm)) ? TRUE : FALSE; bXVG = (opt2fn_null("-o", NFILE, fnm)) ? TRUE : FALSE; bXPM = (opt2fn_null("-mat", NFILE, fnm)) ? TRUE : FALSE; if (! (bXPM || bXVG || bDAT)) { /* check if this is a pointless run */ msg("No output selected. I stop here.\n"); return (1); } bTop = read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xtop,NULL,box,TRUE); sfree(xtop); if (!bTop) { gmx_fatal(FARGS, "Need a run input file"); } indexfn = ftp2fn_null(efNDX,NFILE,fnm); if (ngroups != 1) { gmx_fatal(FARGS, "Sorry, only a single group currently allowed."); } snew(grpname,ngroups); snew(isize,ngroups); snew(index,ngroups); get_index(&(top.atoms),indexfn,ngroups,isize,index,grpname); /* ngroups == 1 at moment */ gnx = isize[0]; gindex = index[0]; ggrpname = grpname[0]; mols = &(top.mols); atndx = mols->index; natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); snew(x_s,natoms); /* look at cavity */ if (cavity.z1 >= cavity.z2) { gmx_fatal(FARGS, "z-boundaries have worng values: They must be z1 < z2."); } /* look at cavity set defaults from the simulation box size */ msg("\n"); autoset_cavity(&cavity,box,NPA,pa); cavity.vol = sqr(cavity.radius) * PI * (cavity.z2 - cavity.z1); // not needed, just for completeness if (bXPM) { /* for xpm output: set limits to z1 and z2 */ /* mild sanity check */ minzval = cavity.z1 < -Z_SANITY ? MINZVAL_DEFAULT : cavity.z1; maxzval = cavity.z2 > Z_SANITY ? MAXZVAL_DEFAULT : cavity.z2; /* xpm graphics: initialize bins */ nbins = (int)ceill((maxzval - minzval) / spacing); snew(zbins,max_frames); snew(x_axis,max_frames); msg("Limits for xpm matrix: %g nm < z < %g nm\n", minzval, maxzval); } /* initialize dfiles: use it to dump data to different files simultanously */ for (i = 0; i < NDFILES+1; i++) dfiles[i] = NULL; i = 0; /* use to count how many output files are open */ if (bXVG) { out = xmgropen(opt2fn("-o",NFILE,fnm), "z coordinate", "Coordinate", "Time (ps)","z (nm)"); dfiles[i++] = out; } if (bDAT) { fData = ffopen (opt2fn("-dat", NFILE, fnm), "w"); dfiles[i++] = fData; } k_frame = 0; /*! counts the frames */ do { dump_data (dfiles, "%10g", t); if (bXPM) { // new timeframe // check if we need more memory if (k_frame >= max_frames) { max_frames += XPM_INITIAL_FRAMES; if (!(srenew(zbins,max_frames)) || !(srenew(x_axis,max_frames)) ) { msg("Out of memory for xpm graph: I abort and try to process what " "I have got so far (frame = %g).\n", k_frame); break; } } snew(zbins[k_frame],nbins); x_axis[k_frame]=t/1000; // in ns // initialize bins to zero for (i=0; i<nbins; i++) zbins[k_frame][i] = 0.0; } /* We are not interested in molecules, just in the z-coordinates of atoms */ for(i=0; i<gnx; i++) { if ( bInCavity (x[gindex[i]], &cavity) ) { // only look at cylinder if (bXPM) { if ( (x[gindex[i]][ZZ] >= minzval) && (x[gindex[i]][ZZ] <= maxzval)) zbins[k_frame][(int)floorl((x[gindex[i]][ZZ] - minzval) / spacing)]=1.0; } } else { /* particle OUTSIDE cylinder: mark coordinates as 'invalid' but keep them in the output file */ for(j=0; j<3; j++) { x[gindex[i]][j] = invalid; } } dump_data (dfiles,"\t%10g", x[gindex[i]][ZZ]); } /* some printout for debugging/development - MB for (i=0; i<nbins; i++) for (i=0; i<10; i++) printf("%1d",(int)zbins[k_frame][i]); printf("\n"); */ dump_data (dfiles, "\n"); k_frame++; } while(read_next_x(oenv,status,&t,natoms,x,box)); close_trj(status); if (bXPM) { /* colors for matrix */ rlo.r = 1.0, rlo.g = 1.0, rlo.b = 1.0; // no water color rhi.r = 0.4, rhi.g = 0.4, rhi.b = 1.0; // water color /* create labels */ snew(y_axis,nbins+1); for(i=0; i<=nbins; i++) { // n+1 labels with MAT_SPATIAL_Y y_axis[i]=10 * (minzval + (i * spacing)); // Yes, I WANT Angstroms !!! } /* write xpm matrix */ xpmOut = fopen(opt2fn("-mat", NFILE, fnm),"w"); write_xpm(xpmOut, MAT_SPATIAL_Y, "g_zcoord matrix", // title "existence", // label for the continuous legend "timeframe / ns", // label for the x-axis "z coordinate / A", // label for the y-axis - where the F**k is the // bloody Angstrom k_frame, nbins, // size of the matrix x_axis, // the x-ticklabels // would be nice to have the times here y_axis, // the y-ticklabels // would be nice to have the zcoordinate label in nm or A zbins, // element x,y is matrix[x][y] 0.0, // output lower than lo is set to lo 1.0, // output higher than hi is set to hi rlo, // rgb value for level lo rhi, // rgb value for level hi &nlevels); // number of color levels for the output fclose(xpmOut); }; /* clean up a bit */ fprintf(stderr,"\n"); if (bDAT) fclose(fData); if (bXVG) fclose(out); if (bXPM) { // free memory from xpm matrix data for (i=0; i<k_frame; i++) sfree(zbins[i]); sfree(zbins); sfree(x_axis); } thanx(stdout); 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; }
void sgangle_plot_single(char *fn,char *afile,char *dfile, char *d1file, char *d2file, atom_id index1[], int gnx1, char *grpn1, atom_id index2[], int gnx2, char *grpn2, t_topology *top,int ePBC) { FILE *sg_angle, /* xvgr file with angles */ *sg_distance = NULL, /* xvgr file with distances */ *sg_distance1 = NULL,/* xvgr file with distance between plane and atom */ *sg_distance2 = NULL;/* xvgr file with distance between plane and atom2 */ real t, /* time */ angle, /* cosine of angle between two groups */ distance, /* distance between two groups. */ distance1, /* distance between plane and one of two atoms */ distance2; /* same for second of two atoms */ int status,natoms,teller=0; int i; rvec *x0; /* coordinates, and coordinates corrected for pb */ rvec *xzero; matrix box; char buf[256]; /* for xvgr title */ if ((natoms = read_first_x(&status,fn,&t,&x0,box)) == 0) gmx_fatal(FARGS,"Could not read coordinates from statusfile\n"); sprintf(buf,"Angle between %s and %s",grpn1,grpn2); sg_angle = xvgropen(afile,buf,"Time (ps)","Cos(angle) "); if (dfile) { sprintf(buf,"Distance between %s and %s",grpn1,grpn2); sg_distance = xvgropen(dfile,buf,"Time (ps)","Distance (nm)"); } if (d1file) { sprintf(buf,"Distance between plane and first atom of vector"); sg_distance1 = xvgropen(d1file,buf,"Time (ps)","Distance (nm)"); } if (d2file) { sprintf(buf,"Distance between plane and second atom of vector"); sg_distance2 = xvgropen(d2file,buf,"Time (ps","Distance (nm)"); } snew(xzero,natoms); do { teller++; rm_pbc(&(top->idef),ePBC,natoms,box,x0,x0); if (teller==1) { for(i=0;i<natoms;i++) copy_rvec(x0[i],xzero[i]); } calc_angle_single(ePBC,box, xzero,x0,index1,index2,gnx1,gnx2,&angle, &distance,&distance1,&distance2); fprintf(sg_angle,"%12g %12g %12g\n",t,angle,acos(angle)*180.0/M_PI); if (dfile) fprintf(sg_distance,"%12g %12g\n",t,distance); if (d1file) fprintf(sg_distance1,"%12g %12g\n",t,distance1); if (d2file) fprintf(sg_distance2,"%12g %12g\n",t,distance1); } while (read_next_x(status,&t,natoms,x0,box)); fprintf(stderr,"\n"); close_trj(status); fclose(sg_angle); if (dfile) fclose(sg_distance); if (d1file) fclose(sg_distance1); if (d2file) fclose(sg_distance2); sfree(x0); }
int gmx_densmap(int argc,char *argv[]) { const char *desc[] = { "[TT]g_densmap[tt] computes 2D number-density maps.", "It can make planar and axial-radial density maps.", "The output [TT].xpm[tt] file can be visualized with for instance xv", "and can be converted to postscript with [TT]xpm2ps[tt].", "Optionally, output can be in text form to a [TT].dat[tt] file with [TT]-od[tt], instead of the usual [TT].xpm[tt] file with [TT]-o[tt].", "[PAR]", "The default analysis is a 2-D number-density map for a selected", "group of atoms in the x-y plane.", "The averaging direction can be changed with the option [TT]-aver[tt].", "When [TT]-xmin[tt] and/or [TT]-xmax[tt] are set only atoms that are", "within the limit(s) in the averaging direction are taken into account.", "The grid spacing is set with the option [TT]-bin[tt].", "When [TT]-n1[tt] or [TT]-n2[tt] is non-zero, the grid", "size is set by this option.", "Box size fluctuations are properly taken into account.", "[PAR]", "When options [TT]-amax[tt] and [TT]-rmax[tt] are set, an axial-radial", "number-density map is made. Three groups should be supplied, the centers", "of mass of the first two groups define the axis, the third defines the", "analysis group. The axial direction goes from -amax to +amax, where", "the center is defined as the midpoint between the centers of mass and", "the positive direction goes from the first to the second center of mass.", "The radial direction goes from 0 to rmax or from -rmax to +rmax", "when the [TT]-mirror[tt] option has been set.", "[PAR]", "The normalization of the output is set with the [TT]-unit[tt] option.", "The default produces a true number density. Unit [TT]nm-2[tt] leaves out", "the normalization for the averaging or the angular direction.", "Option [TT]count[tt] produces the count for each grid cell.", "When you do not want the scale in the output to go", "from zero to the maximum density, you can set the maximum", "with the option [TT]-dmax[tt]." }; static int n1=0,n2=0; static real xmin=-1,xmax=-1,bin=0.02,dmin=0,dmax=0,amax=0,rmax=0; static gmx_bool bMirror=FALSE, bSums=FALSE; static const char *eaver[]= { NULL, "z", "y", "x", NULL }; static const char *eunit[]= { NULL, "nm-3", "nm-2", "count", NULL }; t_pargs pa[] = { { "-bin", FALSE, etREAL, {&bin}, "Grid size (nm)" }, { "-aver", FALSE, etENUM, {eaver}, "The direction to average over" }, { "-xmin", FALSE, etREAL, {&xmin}, "Minimum coordinate for averaging" }, { "-xmax", FALSE, etREAL, {&xmax}, "Maximum coordinate for averaging" }, { "-n1", FALSE, etINT, {&n1}, "Number of grid cells in the first direction" }, { "-n2", FALSE, etINT, {&n2}, "Number of grid cells in the second direction" }, { "-amax", FALSE, etREAL, {&amax}, "Maximum axial distance from the center" }, { "-rmax", FALSE, etREAL, {&rmax}, "Maximum radial distance" }, { "-mirror", FALSE, etBOOL, {&bMirror}, "Add the mirror image below the axial axis" }, { "-sums", FALSE, etBOOL, {&bSums}, "Print density sums (1D map) to stdout" }, { "-unit", FALSE, etENUM, {eunit}, "Unit for the output" }, { "-dmin", FALSE, etREAL, {&dmin}, "Minimum density in output" }, { "-dmax", FALSE, etREAL, {&dmax}, "Maximum density in output (0 means calculate it)" }, }; gmx_bool bXmin,bXmax,bRadial; FILE *fp; t_trxstatus *status; t_topology top; int ePBC=-1; rvec *x,xcom[2],direction,center,dx; matrix box; real t,m,mtot; t_pbc pbc; int cav=0,c1=0,c2=0,natoms; char **grpname,title[256],buf[STRLEN]; const char *unit; int i,j,k,l,ngrps,anagrp,*gnx=NULL,nindex,nradial=0,nfr,nmpower; atom_id **ind=NULL,*index; real **grid,maxgrid,m1,m2,box1,box2,*tickx,*tickz,invcellvol; real invspa=0,invspz=0,axial,r,vol_old,vol,rowsum; int nlev=51; t_rgb rlo= {1,1,1}, rhi= {0,0,0}; output_env_t oenv; const char *label[]= { "x (nm)", "y (nm)", "z (nm)" }; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efDAT, "-od", "densmap", ffOPTWR }, { efXPM, "-o", "densmap", ffWRITE } }; #define NFILE asize(fnm) int npargs; CopyRight(stderr,argv[0]); npargs = asize(pa); parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE, NFILE,fnm,npargs,pa,asize(desc),desc,0,NULL,&oenv); bXmin = opt2parg_bSet("-xmin",npargs,pa); bXmax = opt2parg_bSet("-xmax",npargs,pa); bRadial = (amax>0 || rmax>0); if (bRadial) { if (amax<=0 || rmax<=0) gmx_fatal(FARGS,"Both amax and rmax should be larger than zero"); } if (strcmp(eunit[0],"nm-3") == 0) { nmpower = -3; unit = "(nm^-3)"; } else if (strcmp(eunit[0],"nm-2") == 0) { nmpower = -2; unit = "(nm^-2)"; } else { nmpower = 0; unit = "count"; } if (ftp2bSet(efTPS,NFILE,fnm) || !ftp2bSet(efNDX,NFILE,fnm)) read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&x,NULL,box, bRadial); if (!bRadial) { ngrps = 1; fprintf(stderr,"\nSelect an analysis group\n"); } else { ngrps = 3; fprintf(stderr, "\nSelect two groups to define the axis and an analysis group\n"); } snew(gnx,ngrps); snew(grpname,ngrps); snew(ind,ngrps); get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),ngrps,gnx,ind,grpname); anagrp = ngrps - 1; nindex = gnx[anagrp]; index = ind[anagrp]; if (bRadial) { if ((gnx[0]>1 || gnx[1]>1) && !ftp2bSet(efTPS,NFILE,fnm)) gmx_fatal(FARGS,"No run input file was supplied (option -s), this is required for the center of mass calculation"); } switch (eaver[0][0]) { case 'x': cav = XX; c1 = YY; c2 = ZZ; break; case 'y': cav = YY; c1 = XX; c2 = ZZ; break; case 'z': cav = ZZ; c1 = XX; c2 = YY; break; } natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); if (!bRadial) { if (n1 == 0) n1 = (int)(box[c1][c1]/bin + 0.5); if (n2 == 0) n2 = (int)(box[c2][c2]/bin + 0.5); } else { n1 = (int)(2*amax/bin + 0.5); nradial = (int)(rmax/bin + 0.5); invspa = n1/(2*amax); invspz = nradial/rmax; if (bMirror) n2 = 2*nradial; else n2 = nradial; } snew(grid,n1); for(i=0; i<n1; i++) snew(grid[i],n2); box1 = 0; box2 = 0; nfr = 0; do { if (!bRadial) { box1 += box[c1][c1]; box2 += box[c2][c2]; invcellvol = n1*n2; if (nmpower == -3) invcellvol /= det(box); else if (nmpower == -2) invcellvol /= box[c1][c1]*box[c2][c2]; for(i=0; i<nindex; i++) { j = index[i]; if ((!bXmin || x[j][cav] >= xmin) && (!bXmax || x[j][cav] <= xmax)) { m1 = x[j][c1]/box[c1][c1]; if (m1 >= 1) m1 -= 1; if (m1 < 0) m1 += 1; m2 = x[j][c2]/box[c2][c2]; if (m2 >= 1) m2 -= 1; if (m2 < 0) m2 += 1; grid[(int)(m1*n1)][(int)(m2*n2)] += invcellvol; } } } else { set_pbc(&pbc,ePBC,box); for(i=0; i<2; i++) { if (gnx[i] == 1) { /* One atom, just copy the coordinates */ copy_rvec(x[ind[i][0]],xcom[i]); } else { /* Calculate the center of mass */ clear_rvec(xcom[i]); mtot = 0; for(j=0; j<gnx[i]; j++) { k = ind[i][j]; m = top.atoms.atom[k].m; for(l=0; l<DIM; l++) xcom[i][l] += m*x[k][l]; mtot += m; } svmul(1/mtot,xcom[i],xcom[i]); } } pbc_dx(&pbc,xcom[1],xcom[0],direction); for(i=0; i<DIM; i++) center[i] = xcom[0][i] + 0.5*direction[i]; unitv(direction,direction); for(i=0; i<nindex; i++) { j = index[i]; pbc_dx(&pbc,x[j],center,dx); axial = iprod(dx,direction); r = sqrt(norm2(dx) - axial*axial); if (axial>=-amax && axial<amax && r<rmax) { if (bMirror) r += rmax; grid[(int)((axial + amax)*invspa)][(int)(r*invspz)] += 1; } } } nfr++; } while(read_next_x(oenv,status,&t,natoms,x,box)); close_trj(status); /* normalize gridpoints */ maxgrid = 0; if (!bRadial) { for (i=0; i<n1; i++) { for (j=0; j<n2; j++) { grid[i][j] /= nfr; if (grid[i][j] > maxgrid) maxgrid = grid[i][j]; } } } else { for (i=0; i<n1; i++) { vol_old = 0; for (j=0; j<nradial; j++) { switch (nmpower) { case -3: vol = M_PI*(j+1)*(j+1)/(invspz*invspz*invspa); break; case -2: vol = (j+1)/(invspz*invspa); break; default: vol = j+1; break; } if (bMirror) k = j + nradial; else k = j; grid[i][k] /= nfr*(vol - vol_old); if (bMirror) grid[i][nradial-1-j] = grid[i][k]; vol_old = vol; if (grid[i][k] > maxgrid) maxgrid = grid[i][k]; } } } fprintf(stdout,"\n The maximum density is %f %s\n",maxgrid,unit); if (dmax > 0) maxgrid = dmax; snew(tickx,n1+1); snew(tickz,n2+1); if (!bRadial) { /* normalize box-axes */ box1 /= nfr; box2 /= nfr; for (i=0; i<=n1; i++) tickx[i] = i*box1/n1; for (i=0; i<=n2; i++) tickz[i] = i*box2/n2; } else { for (i=0; i<=n1; i++) tickx[i] = i/invspa - amax; if (bMirror) { for (i=0; i<=n2; i++) tickz[i] = i/invspz - rmax; } else { for (i=0; i<=n2; i++) tickz[i] = i/invspz; } } if (bSums) { for (i=0; i<n1; ++i) { fprintf(stdout,"Density sums:\n"); rowsum=0; for (j=0; j<n2; ++j) rowsum+=grid[i][j]; fprintf(stdout,"%g\t",rowsum); } fprintf(stdout,"\n"); } sprintf(buf,"%s number density",grpname[anagrp]); if (!bRadial && (bXmin || bXmax)) { if (!bXmax) sprintf(buf+strlen(buf),", %c > %g nm",eaver[0][0],xmin); else if (!bXmin) sprintf(buf+strlen(buf),", %c < %g nm",eaver[0][0],xmax); else sprintf(buf+strlen(buf),", %c: %g - %g nm",eaver[0][0],xmin,xmax); } if (ftp2bSet(efDAT,NFILE,fnm)) { fp = ffopen(ftp2fn(efDAT,NFILE,fnm),"w"); /*optional text form output: first row is tickz; first col is tickx */ fprintf(fp,"0\t"); for(j=0; j<n2; ++j) fprintf(fp,"%g\t",tickz[j]); fprintf(fp,"\n"); for (i=0; i<n1; ++i) { fprintf(fp,"%g\t",tickx[i]); for (j=0; j<n2; ++j) fprintf(fp,"%g\t",grid[i][j]); fprintf(fp,"\n"); } ffclose(fp); } else { fp = ffopen(ftp2fn(efXPM,NFILE,fnm),"w"); write_xpm(fp,MAT_SPATIAL_X | MAT_SPATIAL_Y,buf,unit, bRadial ? "axial (nm)" : label[c1],bRadial ? "r (nm)" : label[c2], n1,n2,tickx,tickz,grid,dmin,maxgrid,rlo,rhi,&nlev); ffclose(fp); } thanx(stderr); do_view(oenv,opt2fn("-o",NFILE,fnm),NULL); return 0; }
int gmx_rms(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] compares two structures by computing the root mean square", "deviation (RMSD), the size-independent [GRK]rho[grk] similarity parameter", "([TT]rho[tt]) or the scaled [GRK]rho[grk] ([TT]rhosc[tt]), ", "see Maiorov & Crippen, Proteins [BB]22[bb], 273 (1995).", "This is selected by [TT]-what[tt].[PAR]" "Each structure from a trajectory ([TT]-f[tt]) is compared to a", "reference structure. The reference structure", "is taken from the structure file ([TT]-s[tt]).[PAR]", "With option [TT]-mir[tt] also a comparison with the mirror image of", "the reference structure is calculated.", "This is useful as a reference for 'significant' values, see", "Maiorov & Crippen, Proteins [BB]22[bb], 273 (1995).[PAR]", "Option [TT]-prev[tt] produces the comparison with a previous frame", "the specified number of frames ago.[PAR]", "Option [TT]-m[tt] produces a matrix in [TT].xpm[tt] format of", "comparison values of each structure in the trajectory with respect to", "each other structure. This file can be visualized with for instance", "[TT]xv[tt] and can be converted to postscript with [gmx-xpm2ps].[PAR]", "Option [TT]-fit[tt] controls the least-squares fitting of", "the structures on top of each other: complete fit (rotation and", "translation), translation only, or no fitting at all.[PAR]", "Option [TT]-mw[tt] controls whether mass weighting is done or not.", "If you select the option (default) and ", "supply a valid [TT].tpr[tt] file masses will be taken from there, ", "otherwise the masses will be deduced from the [TT]atommass.dat[tt] file in", "[TT]GMXLIB[tt]. This is fine for proteins, but not", "necessarily for other molecules. A default mass of 12.011 amu (carbon)", "is assigned to unknown atoms. You can check whether this happend by", "turning on the [TT]-debug[tt] flag and inspecting the log file.[PAR]", "With [TT]-f2[tt], the 'other structures' are taken from a second", "trajectory, this generates a comparison matrix of one trajectory", "versus the other.[PAR]", "Option [TT]-bin[tt] does a binary dump of the comparison matrix.[PAR]", "Option [TT]-bm[tt] produces a matrix of average bond angle deviations", "analogously to the [TT]-m[tt] option. Only bonds between atoms in the", "comparison group are considered." }; static gmx_bool bPBC = TRUE, bFitAll = TRUE, bSplit = FALSE; static gmx_bool bDeltaLog = FALSE; static int prev = 0, freq = 1, freq2 = 1, nlevels = 80, avl = 0; static real rmsd_user_max = -1, rmsd_user_min = -1, bond_user_max = -1, bond_user_min = -1, delta_maxy = 0.0; /* strings and things for selecting difference method */ enum { ewSel, ewRMSD, ewRho, ewRhoSc, ewNR }; int ewhat; const char *what[ewNR + 1] = { NULL, "rmsd", "rho", "rhosc", NULL }; const char *whatname[ewNR] = { NULL, "RMSD", "Rho", "Rho sc" }; const char *whatlabel[ewNR] = { NULL, "RMSD (nm)", "Rho", "Rho sc" }; const char *whatxvgname[ewNR] = { NULL, "RMSD", "\\8r\\4", "\\8r\\4\\ssc\\N" }; const char *whatxvglabel[ewNR] = { NULL, "RMSD (nm)", "\\8r\\4", "\\8r\\4\\ssc\\N" }; /* strings and things for fitting methods */ enum { efSel, efFit, efReset, efNone, efNR }; int efit; const char *fit[efNR + 1] = { NULL, "rot+trans", "translation", "none", NULL }; const char *fitgraphlabel[efNR + 1] = { NULL, "lsq fit", "translational fit", "no fit" }; static int nrms = 1; static gmx_bool bMassWeighted = TRUE; t_pargs pa[] = { { "-what", FALSE, etENUM, { what }, "Structural difference measure" }, { "-pbc", FALSE, etBOOL, { &bPBC }, "PBC check" }, { "-fit", FALSE, etENUM, { fit }, "Fit to reference structure" }, { "-prev", FALSE, etINT, { &prev }, "Compare with previous frame" }, { "-split", FALSE, etBOOL, { &bSplit }, "Split graph where time is zero" }, { "-fitall", FALSE, etBOOL, { &bFitAll }, "HIDDENFit all pairs of structures in matrix" }, { "-skip", FALSE, etINT, { &freq }, "Only write every nr-th frame to matrix" }, { "-skip2", FALSE, etINT, { &freq2 }, "Only write every nr-th frame to matrix" }, { "-max", FALSE, etREAL, { &rmsd_user_max }, "Maximum level in comparison matrix" }, { "-min", FALSE, etREAL, { &rmsd_user_min }, "Minimum level in comparison matrix" }, { "-bmax", FALSE, etREAL, { &bond_user_max }, "Maximum level in bond angle matrix" }, { "-bmin", FALSE, etREAL, { &bond_user_min }, "Minimum level in bond angle matrix" }, { "-mw", FALSE, etBOOL, { &bMassWeighted }, "Use mass weighting for superposition" }, { "-nlevels", FALSE, etINT, { &nlevels }, "Number of levels in the matrices" }, { "-ng", FALSE, etINT, { &nrms }, "Number of groups to compute RMS between" }, { "-dlog", FALSE, etBOOL, { &bDeltaLog }, "HIDDENUse a log x-axis in the delta t matrix" }, { "-dmax", FALSE, etREAL, { &delta_maxy }, "HIDDENMaximum level in delta matrix" }, { "-aver", FALSE, etINT, { &avl }, "HIDDENAverage over this distance in the RMSD matrix" } }; int natoms_trx, natoms_trx2, natoms; int i, j, k, m, teller, teller2, tel_mat, tel_mat2; #define NFRAME 5000 int maxframe = NFRAME, maxframe2 = NFRAME; real t, *w_rls, *w_rms, *w_rls_m = NULL, *w_rms_m = NULL; gmx_bool bNorm, bAv, bFreq2, bFile2, bMat, bBond, bDelta, bMirror, bMass; gmx_bool bFit, bReset; t_topology top; int ePBC; t_iatom *iatom = NULL; matrix box; rvec *x, *xp, *xm = NULL, **mat_x = NULL, **mat_x2, *mat_x2_j = NULL, vec1, vec2; t_trxstatus *status; char buf[256], buf2[256]; int ncons = 0; FILE *fp; real rlstot = 0, **rls, **rlsm = NULL, *time, *time2, *rlsnorm = NULL, **rmsd_mat = NULL, **bond_mat = NULL, *axis, *axis2, *del_xaxis, *del_yaxis, rmsd_max, rmsd_min, rmsd_avg, bond_max, bond_min, ang; real **rmsdav_mat = NULL, av_tot, weight, weight_tot; real **delta = NULL, delta_max, delta_scalex = 0, delta_scaley = 0, *delta_tot; int delta_xsize = 0, del_lev = 100, mx, my, abs_my; gmx_bool bA1, bA2, bPrev, bTop, *bInMat = NULL; int ifit, *irms, ibond = 0, *ind_bond1 = NULL, *ind_bond2 = NULL, n_ind_m = 0; atom_id *ind_fit, **ind_rms, *ind_m = NULL, *rev_ind_m = NULL, *ind_rms_m = NULL; char *gn_fit, **gn_rms; t_rgb rlo, rhi; output_env_t oenv; gmx_rmpbc_t gpbc = NULL; t_filenm fnm[] = { { efTPS, NULL, NULL, ffREAD }, { efTRX, "-f", NULL, ffREAD }, { efTRX, "-f2", NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, NULL, "rmsd", ffWRITE }, { efXVG, "-mir", "rmsdmir", ffOPTWR }, { efXVG, "-a", "avgrp", ffOPTWR }, { efXVG, "-dist", "rmsd-dist", ffOPTWR }, { efXPM, "-m", "rmsd", ffOPTWR }, { efDAT, "-bin", "rmsd", ffOPTWR }, { efXPM, "-bm", "bond", ffOPTWR } }; #define NFILE asize(fnm) if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } /* parse enumerated options: */ ewhat = nenum(what); if (ewhat == ewRho || ewhat == ewRhoSc) { please_cite(stdout, "Maiorov95"); } efit = nenum(fit); bFit = efit == efFit; bReset = efit == efReset; if (bFit) { bReset = TRUE; /* for fit, reset *must* be set */ } else { bFitAll = FALSE; } /* mark active cmdline options */ bMirror = opt2bSet("-mir", NFILE, fnm); /* calc RMSD vs mirror of ref. */ bFile2 = opt2bSet("-f2", NFILE, fnm); bMat = opt2bSet("-m", NFILE, fnm); bBond = opt2bSet("-bm", NFILE, fnm); bDelta = (delta_maxy > 0); /* calculate rmsd vs delta t matrix from * * your RMSD matrix (hidden option */ bNorm = opt2bSet("-a", NFILE, fnm); bFreq2 = opt2parg_bSet("-skip2", asize(pa), pa); if (freq <= 0) { fprintf(stderr, "The number of frames to skip is <= 0. " "Writing out all frames.\n\n"); freq = 1; } if (!bFreq2) { freq2 = freq; } else if (bFile2 && freq2 <= 0) { fprintf(stderr, "The number of frames to skip in second trajectory is <= 0.\n" " Writing out all frames.\n\n"); freq2 = 1; } bPrev = (prev > 0); if (bPrev) { prev = abs(prev); if (freq != 1) { fprintf(stderr, "WARNING: option -skip also applies to -prev\n"); } } if (bFile2 && !bMat && !bBond) { fprintf( stderr, "WARNING: second trajectory (-f2) useless when not calculating matrix (-m/-bm),\n" " will not read from %s\n", opt2fn("-f2", NFILE, fnm)); bFile2 = FALSE; } if (bDelta) { bMat = TRUE; if (bFile2) { fprintf(stderr, "WARNING: second trajectory (-f2) useless when making delta matrix,\n" " will not read from %s\n", opt2fn("-f2", NFILE, fnm)); bFile2 = FALSE; } } bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), buf, &top, &ePBC, &xp, NULL, box, TRUE); snew(w_rls, top.atoms.nr); snew(w_rms, top.atoms.nr); if (!bTop && bBond) { fprintf(stderr, "WARNING: Need a run input file for bond angle matrix,\n" " will not calculate bond angle matrix.\n"); bBond = FALSE; } if (bReset) { fprintf(stderr, "Select group for %s fit\n", bFit ? "least squares" : "translational"); get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &ifit, &ind_fit, &gn_fit); } else { ifit = 0; } if (bReset) { if (bFit && ifit < 3) { gmx_fatal(FARGS, "Need >= 3 points to fit!\n" ); } bMass = FALSE; for (i = 0; i < ifit; i++) { if (bMassWeighted) { w_rls[ind_fit[i]] = top.atoms.atom[ind_fit[i]].m; } else { w_rls[ind_fit[i]] = 1; } bMass = bMass || (top.atoms.atom[ind_fit[i]].m != 0); } if (!bMass) { fprintf(stderr, "All masses in the fit group are 0, using masses of 1\n"); for (i = 0; i < ifit; i++) { w_rls[ind_fit[i]] = 1; } } } if (bMat || bBond) { nrms = 1; } snew(gn_rms, nrms); snew(ind_rms, nrms); snew(irms, nrms); fprintf(stderr, "Select group%s for %s calculation\n", (nrms > 1) ? "s" : "", whatname[ewhat]); get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), nrms, irms, ind_rms, gn_rms); if (bNorm) { snew(rlsnorm, irms[0]); } snew(rls, nrms); for (j = 0; j < nrms; j++) { snew(rls[j], maxframe); } if (bMirror) { snew(rlsm, nrms); for (j = 0; j < nrms; j++) { snew(rlsm[j], maxframe); } } snew(time, maxframe); for (j = 0; j < nrms; j++) { bMass = FALSE; for (i = 0; i < irms[j]; i++) { if (bMassWeighted) { w_rms[ind_rms[j][i]] = top.atoms.atom[ind_rms[j][i]].m; } else { w_rms[ind_rms[j][i]] = 1.0; } bMass = bMass || (top.atoms.atom[ind_rms[j][i]].m != 0); } if (!bMass) { fprintf(stderr, "All masses in group %d are 0, using masses of 1\n", j); for (i = 0; i < irms[j]; i++) { w_rms[ind_rms[j][i]] = 1; } } } /* Prepare reference frame */ if (bPBC) { gpbc = gmx_rmpbc_init(&top.idef, ePBC, top.atoms.nr); gmx_rmpbc(gpbc, top.atoms.nr, box, xp); } if (bReset) { reset_x(ifit, ind_fit, top.atoms.nr, NULL, xp, w_rls); } if (bMirror) { /* generate reference structure mirror image: */ snew(xm, top.atoms.nr); for (i = 0; i < top.atoms.nr; i++) { copy_rvec(xp[i], xm[i]); xm[i][XX] = -xm[i][XX]; } } if (ewhat == ewRhoSc) { norm_princ(&top.atoms, ifit, ind_fit, top.atoms.nr, xp); } /* read first frame */ natoms_trx = read_first_x(oenv, &status, opt2fn("-f", NFILE, fnm), &t, &x, box); if (natoms_trx != top.atoms.nr) { fprintf(stderr, "\nWARNING: topology has %d atoms, whereas trajectory has %d\n", top.atoms.nr, natoms_trx); } natoms = min(top.atoms.nr, natoms_trx); if (bMat || bBond || bPrev) { snew(mat_x, NFRAME); if (bPrev) { /* With -prev we use all atoms for simplicity */ n_ind_m = natoms; } else { /* Check which atoms we need (fit/rms) */ snew(bInMat, natoms); for (i = 0; i < ifit; i++) { bInMat[ind_fit[i]] = TRUE; } n_ind_m = ifit; for (i = 0; i < irms[0]; i++) { if (!bInMat[ind_rms[0][i]]) { bInMat[ind_rms[0][i]] = TRUE; n_ind_m++; } } } /* Make an index of needed atoms */ snew(ind_m, n_ind_m); snew(rev_ind_m, natoms); j = 0; for (i = 0; i < natoms; i++) { if (bPrev || bInMat[i]) { ind_m[j] = i; rev_ind_m[i] = j; j++; } } snew(w_rls_m, n_ind_m); snew(ind_rms_m, irms[0]); snew(w_rms_m, n_ind_m); for (i = 0; i < ifit; i++) { w_rls_m[rev_ind_m[ind_fit[i]]] = w_rls[ind_fit[i]]; } for (i = 0; i < irms[0]; i++) { ind_rms_m[i] = rev_ind_m[ind_rms[0][i]]; w_rms_m[ind_rms_m[i]] = w_rms[ind_rms[0][i]]; } sfree(bInMat); } if (bBond) { ncons = 0; for (k = 0; k < F_NRE; k++) { if (IS_CHEMBOND(k)) { iatom = top.idef.il[k].iatoms; ncons += top.idef.il[k].nr/3; } } fprintf(stderr, "Found %d bonds in topology\n", ncons); snew(ind_bond1, ncons); snew(ind_bond2, ncons); ibond = 0; for (k = 0; k < F_NRE; k++) { if (IS_CHEMBOND(k)) { iatom = top.idef.il[k].iatoms; ncons = top.idef.il[k].nr/3; for (i = 0; i < ncons; i++) { bA1 = FALSE; bA2 = FALSE; for (j = 0; j < irms[0]; j++) { if (iatom[3*i+1] == ind_rms[0][j]) { bA1 = TRUE; } if (iatom[3*i+2] == ind_rms[0][j]) { bA2 = TRUE; } } if (bA1 && bA2) { ind_bond1[ibond] = rev_ind_m[iatom[3*i+1]]; ind_bond2[ibond] = rev_ind_m[iatom[3*i+2]]; ibond++; } } } } fprintf(stderr, "Using %d bonds for bond angle matrix\n", ibond); if (ibond == 0) { gmx_fatal(FARGS, "0 bonds found"); } } /* start looping over frames: */ tel_mat = 0; teller = 0; do { if (bPBC) { gmx_rmpbc(gpbc, natoms, box, x); } if (bReset) { reset_x(ifit, ind_fit, natoms, NULL, x, w_rls); } if (ewhat == ewRhoSc) { norm_princ(&top.atoms, ifit, ind_fit, natoms, x); } if (bFit) { /*do the least squares fit to original structure*/ do_fit(natoms, w_rls, xp, x); } if (teller % freq == 0) { /* keep frame for matrix calculation */ if (bMat || bBond || bPrev) { if (tel_mat >= NFRAME) { srenew(mat_x, tel_mat+1); } snew(mat_x[tel_mat], n_ind_m); for (i = 0; i < n_ind_m; i++) { copy_rvec(x[ind_m[i]], mat_x[tel_mat][i]); } } tel_mat++; } /*calculate energy of root_least_squares*/ if (bPrev) { j = tel_mat-prev-1; if (j < 0) { j = 0; } for (i = 0; i < n_ind_m; i++) { copy_rvec(mat_x[j][i], xp[ind_m[i]]); } if (bReset) { reset_x(ifit, ind_fit, natoms, NULL, xp, w_rls); } if (bFit) { do_fit(natoms, w_rls, x, xp); } } for (j = 0; (j < nrms); j++) { rls[j][teller] = calc_similar_ind(ewhat != ewRMSD, irms[j], ind_rms[j], w_rms, x, xp); } if (bNorm) { for (j = 0; (j < irms[0]); j++) { rlsnorm[j] += calc_similar_ind(ewhat != ewRMSD, 1, &(ind_rms[0][j]), w_rms, x, xp); } } if (bMirror) { if (bFit) { /*do the least squares fit to mirror of original structure*/ do_fit(natoms, w_rls, xm, x); } for (j = 0; j < nrms; j++) { rlsm[j][teller] = calc_similar_ind(ewhat != ewRMSD, irms[j], ind_rms[j], w_rms, x, xm); } } time[teller] = output_env_conv_time(oenv, t); teller++; if (teller >= maxframe) { maxframe += NFRAME; srenew(time, maxframe); for (j = 0; (j < nrms); j++) { srenew(rls[j], maxframe); } if (bMirror) { for (j = 0; (j < nrms); j++) { srenew(rlsm[j], maxframe); } } } } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); if (bFile2) { snew(time2, maxframe2); fprintf(stderr, "\nWill read second trajectory file\n"); snew(mat_x2, NFRAME); natoms_trx2 = read_first_x(oenv, &status, opt2fn("-f2", NFILE, fnm), &t, &x, box); if (natoms_trx2 != natoms_trx) { gmx_fatal(FARGS, "Second trajectory (%d atoms) does not match the first one" " (%d atoms)", natoms_trx2, natoms_trx); } tel_mat2 = 0; teller2 = 0; do { if (bPBC) { gmx_rmpbc(gpbc, natoms, box, x); } if (bReset) { reset_x(ifit, ind_fit, natoms, NULL, x, w_rls); } if (ewhat == ewRhoSc) { norm_princ(&top.atoms, ifit, ind_fit, natoms, x); } if (bFit) { /*do the least squares fit to original structure*/ do_fit(natoms, w_rls, xp, x); } if (teller2 % freq2 == 0) { /* keep frame for matrix calculation */ if (bMat) { if (tel_mat2 >= NFRAME) { srenew(mat_x2, tel_mat2+1); } snew(mat_x2[tel_mat2], n_ind_m); for (i = 0; i < n_ind_m; i++) { copy_rvec(x[ind_m[i]], mat_x2[tel_mat2][i]); } } tel_mat2++; } time2[teller2] = output_env_conv_time(oenv, t); teller2++; if (teller2 >= maxframe2) { maxframe2 += NFRAME; srenew(time2, maxframe2); } } while (read_next_x(oenv, status, &t, x, box)); close_trj(status); } else { mat_x2 = mat_x; time2 = time; tel_mat2 = tel_mat; freq2 = freq; } gmx_rmpbc_done(gpbc); if (bMat || bBond) { /* calculate RMS matrix */ fprintf(stderr, "\n"); if (bMat) { fprintf(stderr, "Building %s matrix, %dx%d elements\n", whatname[ewhat], tel_mat, tel_mat2); snew(rmsd_mat, tel_mat); } if (bBond) { fprintf(stderr, "Building bond angle matrix, %dx%d elements\n", tel_mat, tel_mat2); snew(bond_mat, tel_mat); } snew(axis, tel_mat); snew(axis2, tel_mat2); rmsd_max = 0; if (bFile2) { rmsd_min = 1e10; } else { rmsd_min = 0; } rmsd_avg = 0; bond_max = 0; bond_min = 1e10; for (j = 0; j < tel_mat2; j++) { axis2[j] = time2[freq2*j]; } if (bDelta) { if (bDeltaLog) { delta_scalex = 8.0/log(2.0); delta_xsize = (int)(log(tel_mat/2)*delta_scalex+0.5)+1; } else { delta_xsize = tel_mat/2; } delta_scaley = 1.0/delta_maxy; snew(delta, delta_xsize); for (j = 0; j < delta_xsize; j++) { snew(delta[j], del_lev+1); } if (avl > 0) { snew(rmsdav_mat, tel_mat); for (j = 0; j < tel_mat; j++) { snew(rmsdav_mat[j], tel_mat); } } } if (bFitAll) { snew(mat_x2_j, natoms); } for (i = 0; i < tel_mat; i++) { axis[i] = time[freq*i]; fprintf(stderr, "\r element %5d; time %5.2f ", i, axis[i]); if (bMat) { snew(rmsd_mat[i], tel_mat2); } if (bBond) { snew(bond_mat[i], tel_mat2); } for (j = 0; j < tel_mat2; j++) { if (bFitAll) { for (k = 0; k < n_ind_m; k++) { copy_rvec(mat_x2[j][k], mat_x2_j[k]); } do_fit(n_ind_m, w_rls_m, mat_x[i], mat_x2_j); } else { mat_x2_j = mat_x2[j]; } if (bMat) { if (bFile2 || (i < j)) { rmsd_mat[i][j] = calc_similar_ind(ewhat != ewRMSD, irms[0], ind_rms_m, w_rms_m, mat_x[i], mat_x2_j); if (rmsd_mat[i][j] > rmsd_max) { rmsd_max = rmsd_mat[i][j]; } if (rmsd_mat[i][j] < rmsd_min) { rmsd_min = rmsd_mat[i][j]; } rmsd_avg += rmsd_mat[i][j]; } else { rmsd_mat[i][j] = rmsd_mat[j][i]; } } if (bBond) { if (bFile2 || (i <= j)) { ang = 0.0; for (m = 0; m < ibond; m++) { rvec_sub(mat_x[i][ind_bond1[m]], mat_x[i][ind_bond2[m]], vec1); rvec_sub(mat_x2_j[ind_bond1[m]], mat_x2_j[ind_bond2[m]], vec2); ang += acos(cos_angle(vec1, vec2)); } bond_mat[i][j] = ang*180.0/(M_PI*ibond); if (bond_mat[i][j] > bond_max) { bond_max = bond_mat[i][j]; } if (bond_mat[i][j] < bond_min) { bond_min = bond_mat[i][j]; } } else { bond_mat[i][j] = bond_mat[j][i]; } } } } if (bFile2) { rmsd_avg /= tel_mat*tel_mat2; } else { rmsd_avg /= tel_mat*(tel_mat - 1)/2; } if (bMat && (avl > 0)) { rmsd_max = 0.0; rmsd_min = 0.0; rmsd_avg = 0.0; for (j = 0; j < tel_mat-1; j++) { for (i = j+1; i < tel_mat; i++) { av_tot = 0; weight_tot = 0; for (my = -avl; my <= avl; my++) { if ((j+my >= 0) && (j+my < tel_mat)) { abs_my = abs(my); for (mx = -avl; mx <= avl; mx++) { if ((i+mx >= 0) && (i+mx < tel_mat)) { weight = (real)(avl+1-max(abs(mx), abs_my)); av_tot += weight*rmsd_mat[i+mx][j+my]; weight_tot += weight; } } } } rmsdav_mat[i][j] = av_tot/weight_tot; rmsdav_mat[j][i] = rmsdav_mat[i][j]; if (rmsdav_mat[i][j] > rmsd_max) { rmsd_max = rmsdav_mat[i][j]; } } } rmsd_mat = rmsdav_mat; } if (bMat) { fprintf(stderr, "\n%s: Min %f, Max %f, Avg %f\n", whatname[ewhat], rmsd_min, rmsd_max, rmsd_avg); rlo.r = 1; rlo.g = 1; rlo.b = 1; rhi.r = 0; rhi.g = 0; rhi.b = 0; if (rmsd_user_max != -1) { rmsd_max = rmsd_user_max; } if (rmsd_user_min != -1) { rmsd_min = rmsd_user_min; } if ((rmsd_user_max != -1) || (rmsd_user_min != -1)) { fprintf(stderr, "Min and Max value set to resp. %f and %f\n", rmsd_min, rmsd_max); } sprintf(buf, "%s %s matrix", gn_rms[0], whatname[ewhat]); write_xpm(opt2FILE("-m", NFILE, fnm, "w"), 0, buf, whatlabel[ewhat], output_env_get_time_label(oenv), output_env_get_time_label(oenv), tel_mat, tel_mat2, axis, axis2, rmsd_mat, rmsd_min, rmsd_max, rlo, rhi, &nlevels); /* Print the distribution of RMSD values */ if (opt2bSet("-dist", NFILE, fnm)) { low_rmsd_dist(opt2fn("-dist", NFILE, fnm), rmsd_max, tel_mat, rmsd_mat, oenv); } if (bDelta) { snew(delta_tot, delta_xsize); for (j = 0; j < tel_mat-1; j++) { for (i = j+1; i < tel_mat; i++) { mx = i-j; if (mx < tel_mat/2) { if (bDeltaLog) { mx = (int)(log(mx)*delta_scalex+0.5); } my = (int)(rmsd_mat[i][j]*delta_scaley*del_lev+0.5); delta_tot[mx] += 1.0; if ((rmsd_mat[i][j] >= 0) && (rmsd_mat[i][j] <= delta_maxy)) { delta[mx][my] += 1.0; } } } } delta_max = 0; for (i = 0; i < delta_xsize; i++) { if (delta_tot[i] > 0.0) { delta_tot[i] = 1.0/delta_tot[i]; for (j = 0; j <= del_lev; j++) { delta[i][j] *= delta_tot[i]; if (delta[i][j] > delta_max) { delta_max = delta[i][j]; } } } } fprintf(stderr, "Maximum in delta matrix: %f\n", delta_max); snew(del_xaxis, delta_xsize); snew(del_yaxis, del_lev+1); for (i = 0; i < delta_xsize; i++) { del_xaxis[i] = axis[i]-axis[0]; } for (i = 0; i < del_lev+1; i++) { del_yaxis[i] = delta_maxy*i/del_lev; } sprintf(buf, "%s %s vs. delta t", gn_rms[0], whatname[ewhat]); fp = gmx_ffopen("delta.xpm", "w"); write_xpm(fp, 0, buf, "density", output_env_get_time_label(oenv), whatlabel[ewhat], delta_xsize, del_lev+1, del_xaxis, del_yaxis, delta, 0.0, delta_max, rlo, rhi, &nlevels); gmx_ffclose(fp); } if (opt2bSet("-bin", NFILE, fnm)) { /* NB: File must be binary if we use fwrite */ fp = ftp2FILE(efDAT, NFILE, fnm, "wb"); for (i = 0; i < tel_mat; i++) { if (fwrite(rmsd_mat[i], sizeof(**rmsd_mat), tel_mat2, fp) != tel_mat2) { gmx_fatal(FARGS, "Error writing to output file"); } } gmx_ffclose(fp); } } if (bBond) { fprintf(stderr, "\nMin. angle: %f, Max. angle: %f\n", bond_min, bond_max); if (bond_user_max != -1) { bond_max = bond_user_max; } if (bond_user_min != -1) { bond_min = bond_user_min; } if ((bond_user_max != -1) || (bond_user_min != -1)) { fprintf(stderr, "Bond angle Min and Max set to:\n" "Min. angle: %f, Max. angle: %f\n", bond_min, bond_max); } rlo.r = 1; rlo.g = 1; rlo.b = 1; rhi.r = 0; rhi.g = 0; rhi.b = 0; sprintf(buf, "%s av. bond angle deviation", gn_rms[0]); write_xpm(opt2FILE("-bm", NFILE, fnm, "w"), 0, buf, "degrees", output_env_get_time_label(oenv), output_env_get_time_label(oenv), tel_mat, tel_mat2, axis, axis2, bond_mat, bond_min, bond_max, rlo, rhi, &nlevels); } } bAv = opt2bSet("-a", NFILE, fnm); /* Write the RMSD's to file */ if (!bPrev) { sprintf(buf, "%s", whatxvgname[ewhat]); } else { sprintf(buf, "%s with frame %g %s ago", whatxvgname[ewhat], time[prev*freq]-time[0], output_env_get_time_label(oenv)); } fp = xvgropen(opt2fn("-o", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv), whatxvglabel[ewhat], oenv); if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"%s%s after %s%s%s\"\n", (nrms == 1) ? "" : "of ", gn_rms[0], fitgraphlabel[efit], bFit ? " to " : "", bFit ? gn_fit : ""); } if (nrms != 1) { xvgr_legend(fp, nrms, (const char**)gn_rms, oenv); } for (i = 0; (i < teller); i++) { if (bSplit && i > 0 && abs(time[bPrev ? freq*i : i]/output_env_get_time_factor(oenv)) < 1e-5) { fprintf(fp, "&\n"); } fprintf(fp, "%12.7f", time[bPrev ? freq*i : i]); for (j = 0; (j < nrms); j++) { fprintf(fp, " %12.7f", rls[j][i]); if (bAv) { rlstot += rls[j][i]; } } fprintf(fp, "\n"); } gmx_ffclose(fp); if (bMirror) { /* Write the mirror RMSD's to file */ sprintf(buf, "%s with Mirror", whatxvgname[ewhat]); sprintf(buf2, "Mirror %s", whatxvglabel[ewhat]); fp = xvgropen(opt2fn("-mir", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv), buf2, oenv); if (nrms == 1) { if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"of %s after lsq fit to mirror of %s\"\n", gn_rms[0], gn_fit); } } else { if (output_env_get_print_xvgr_codes(oenv)) { fprintf(fp, "@ subtitle \"after lsq fit to mirror %s\"\n", gn_fit); } xvgr_legend(fp, nrms, (const char**)gn_rms, oenv); } for (i = 0; (i < teller); i++) { if (bSplit && i > 0 && abs(time[i]) < 1e-5) { fprintf(fp, "&\n"); } fprintf(fp, "%12.7f", time[i]); for (j = 0; (j < nrms); j++) { fprintf(fp, " %12.7f", rlsm[j][i]); } fprintf(fp, "\n"); } gmx_ffclose(fp); } if (bAv) { sprintf(buf, "Average %s", whatxvgname[ewhat]); sprintf(buf2, "Average %s", whatxvglabel[ewhat]); fp = xvgropen(opt2fn("-a", NFILE, fnm), buf, "Residue", buf2, oenv); for (j = 0; (j < nrms); j++) { fprintf(fp, "%10d %10g\n", j, rlstot/teller); } gmx_ffclose(fp); } if (bNorm) { fp = xvgropen("aver.xvg", gn_rms[0], "Residue", whatxvglabel[ewhat], oenv); for (j = 0; (j < irms[0]); j++) { fprintf(fp, "%10d %10g\n", j, rlsnorm[j]/teller); } gmx_ffclose(fp); } do_view(oenv, opt2fn_null("-a", NFILE, fnm), "-graphtype bar"); do_view(oenv, opt2fn("-o", NFILE, fnm), NULL); do_view(oenv, opt2fn_null("-mir", NFILE, fnm), NULL); do_view(oenv, opt2fn_null("-m", NFILE, fnm), NULL); do_view(oenv, opt2fn_null("-bm", NFILE, fnm), NULL); do_view(oenv, opt2fn_null("-dist", NFILE, fnm), NULL); return 0; }
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_saltbr(int argc, char *argv[]) { const char *desc[] = { "[TT]g_saltbr[tt] plots the distance between all combination of charged groups", "as a function of time. The groups are combined in different ways.", "A minimum distance can be given (i.e. a cut-off), such that groups", "that are never closer than that distance will not be plotted.[PAR]", "Output will be in a number of fixed filenames, [TT]min-min.xvg[tt], [TT]plus-min.xvg[tt]", "and [TT]plus-plus.xvg[tt], or files for every individual ion pair if the [TT]-sep[tt]", "option is selected. In this case, files are named as [TT]sb-(Resname)(Resnr)-(Atomnr)[tt].", "There may be [BB]many[bb] such files." }; static gmx_bool bSep = FALSE; static real truncate = 1000.0; t_pargs pa[] = { { "-t", FALSE, etREAL, {&truncate}, "Groups that are never closer than this distance are not plotted" }, { "-sep", FALSE, etBOOL, {&bSep}, "Use separate files for each interaction (may be MANY)" } }; t_filenm fnm[] = { { efTRX, "-f", NULL, ffREAD }, { efTPX, NULL, NULL, ffREAD }, }; #define NFILE asize(fnm) FILE *out[3], *fp; static const char *title[3] = { "Distance between positively charged groups", "Distance between negatively charged groups", "Distance between oppositely charged groups" }; static const char *fn[3] = { "plus-plus.xvg", "min-min.xvg", "plus-min.xvg" }; int nset[3] = {0, 0, 0}; t_topology *top; int ePBC; char *buf; t_trxstatus *status; int i, j, k, m, nnn, teller, ncg, n1, n2, n3, natoms; real t, *time, qi, qj; t_charge *cg; real ***cgdist; int **nWithin; double t0, dt; char label[234]; t_pbc pbc; rvec *x; matrix box; output_env_t oenv; parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv); top = read_top(ftp2fn(efTPX, NFILE, fnm), &ePBC); cg = mk_charge(&top->atoms, &(top->cgs), &ncg); snew(cgdist, ncg); snew(nWithin, ncg); for (i = 0; (i < ncg); i++) { snew(cgdist[i], ncg); snew(nWithin[i], ncg); } natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box); teller = 0; time = NULL; do { srenew(time, teller+1); time[teller] = t; set_pbc(&pbc, ePBC, box); for (i = 0; (i < ncg); i++) { for (j = i+1; (j < ncg); j++) { srenew(cgdist[i][j], teller+1); cgdist[i][j][teller] = calc_dist(&pbc, x, &(top->cgs), cg[i].cg, cg[j].cg); if (cgdist[i][j][teller] < truncate) { nWithin[i][j] = 1; } } } teller++; } while (read_next_x(oenv, status, &t, natoms, x, box)); fprintf(stderr, "\n"); close_trj(status); if (bSep) { snew(buf, 256); for (i = 0; (i < ncg); i++) { for (j = i+1; (j < ncg); j++) { if (nWithin[i][j]) { sprintf(buf, "sb-%s:%s.xvg", cg[i].label, cg[j].label); fp = xvgropen(buf, buf, "Time (ps)", "Distance (nm)", oenv); for (k = 0; (k < teller); k++) { fprintf(fp, "%10g %10g\n", time[k], cgdist[i][j][k]); } ffclose(fp); } } } sfree(buf); } else { for (m = 0; (m < 3); m++) { out[m] = xvgropen(fn[m], title[m], "Time (ps)", "Distance (nm)", oenv); } snew(buf, 256); for (i = 0; (i < ncg); i++) { qi = cg[i].q; for (j = i+1; (j < ncg); j++) { qj = cg[j].q; if (nWithin[i][j]) { sprintf(buf, "%s:%s", cg[i].label, cg[j].label); if (qi*qj < 0) { nnn = 2; } else if (qi+qj > 0) { nnn = 0; } else { nnn = 1; } if (nset[nnn] == 0) { xvgr_legend(out[nnn], 1, (const char**)&buf, oenv); } else { if (output_env_get_xvg_format(oenv) == exvgXMGR) { fprintf(out[nnn], "@ legend string %d \"%s\"\n", nset[nnn], buf); } else if (output_env_get_xvg_format(oenv) == exvgXMGRACE) { fprintf(out[nnn], "@ s%d legend \"%s\"\n", nset[nnn], buf); } } nset[nnn]++; nWithin[i][j] = nnn+1; } } } for (k = 0; (k < teller); k++) { for (m = 0; (m < 3); m++) { fprintf(out[m], "%10g", time[k]); } for (i = 0; (i < ncg); i++) { for (j = i+1; (j < ncg); j++) { nnn = nWithin[i][j]; if (nnn > 0) { fprintf(out[nnn-1], " %10g", cgdist[i][j][k]); } } } for (m = 0; (m < 3); m++) { fprintf(out[m], "\n"); } } for (m = 0; (m < 3); m++) { ffclose(out[m]); if (nset[m] == 0) { remove(fn[m]); } } } thanx(stderr); return 0; }