예제 #1
0
int gmx_editconf(int argc, char *argv[])
{
    const char
        *desc[] =
            {
                "editconf converts generic structure format to [TT].gro[tt], [TT].g96[tt]",
                "or [TT].pdb[tt].",
                "[PAR]",
                "The box can be modified with options [TT]-box[tt], [TT]-d[tt] and",
                "[TT]-angles[tt]. Both [TT]-box[tt] and [TT]-d[tt]",
                "will center the system in the box, unless [TT]-noc[tt] is used.",
                "[PAR]",
                "Option [TT]-bt[tt] determines the box type: [TT]triclinic[tt] is a",
                "triclinic box, [TT]cubic[tt] is a rectangular box with all sides equal",
                "[TT]dodecahedron[tt] represents a rhombic dodecahedron and",
                "[TT]octahedron[tt] is a truncated octahedron.",
                "The last two are special cases of a triclinic box.",
                "The length of the three box vectors of the truncated octahedron is the",
                "shortest distance between two opposite hexagons.",
                "The volume of a dodecahedron is 0.71 and that of a truncated octahedron",
                "is 0.77 of that of a cubic box with the same periodic image distance.",
                "[PAR]",
                "Option [TT]-box[tt] requires only",
                "one value for a cubic box, dodecahedron and a truncated octahedron.",
                "[PAR]",
                "With [TT]-d[tt] and a [TT]triclinic[tt] box the size of the system in the x, y",
                "and z directions is used. With [TT]-d[tt] and [TT]cubic[tt],",
                "[TT]dodecahedron[tt] or [TT]octahedron[tt] boxes, the dimensions are set",
                "to the diameter of the system (largest distance between atoms) plus twice",
                "the specified distance.",
                "[PAR]",
                "Option [TT]-angles[tt] is only meaningful with option [TT]-box[tt] and",
                "a triclinic box and can not be used with option [TT]-d[tt].",
                "[PAR]",
                "When [TT]-n[tt] or [TT]-ndef[tt] is set, a group",
                "can be selected for calculating the size and the geometric center,",
                "otherwise the whole system is used.",
                "[PAR]",
                "[TT]-rotate[tt] rotates the coordinates and velocities.",
                "[PAR]",
                "[TT]-princ[tt] aligns the principal axes of the system along the",
                "coordinate axes, this may allow you to decrease the box volume,",
                "but beware that molecules can rotate significantly in a nanosecond.",
                "[PAR]",
                "Scaling is applied before any of the other operations are",
                "performed. Boxes and coordinates can be scaled to give a certain density (option",
                "[TT]-density[tt]). Note that this may be inaccurate in case a gro",
                "file is given as input. A special feature of the scaling option, when the",
                "factor -1 is given in one dimension, one obtains a mirror image,",
                "mirrored in one of the plains, when one uses -1 in three dimensions",
                "a point-mirror image is obtained.[PAR]",
                "Groups are selected after all operations have been applied.[PAR]",
                "Periodicity can be removed in a crude manner.",
                "It is important that the box sizes at the bottom of your input file",
                "are correct when the periodicity is to be removed.",
                "[PAR]",
                "When writing [TT].pdb[tt] files, B-factors can be",
                "added with the [TT]-bf[tt] option. B-factors are read",
                "from a file with with following format: first line states number of",
                "entries in the file, next lines state an index",
                "followed by a B-factor. The B-factors will be attached per residue",
                "unless an index is larger than the number of residues or unless the",
                "[TT]-atom[tt] option is set. Obviously, any type of numeric data can",
                "be added instead of B-factors. [TT]-legend[tt] will produce",
                "a row of CA atoms with B-factors ranging from the minimum to the",
                "maximum value found, effectively making a legend for viewing.",
                "[PAR]",
                "With the option -mead a special pdb (pqr) file for the MEAD electrostatics",
                "program (Poisson-Boltzmann solver) can be made. A further prerequisite",
                "is that the input file is a run input file.",
                "The B-factor field is then filled with the Van der Waals radius",
                "of the atoms while the occupancy field will hold the charge.",
                "[PAR]",
                "The option -grasp is similar, but it puts the charges in the B-factor",
                "and the radius in the occupancy.",
                "[PAR]",
                "Option [TT]-align[tt] allows alignment",
                "of the principal axis of a specified group against the given vector, ",
				"with an optional center of rotation specified by [TT]-aligncenter[tt].",
                "[PAR]",
                "Finally with option [TT]-label[tt] editconf can add a chain identifier",
                "to a pdb file, which can be useful for analysis with e.g. rasmol.",
                    "[PAR]",
                "To convert a truncated octrahedron file produced by a package which uses",
                "a cubic box with the corners cut off (such as Gromos) use:[BR]",
                "[TT]editconf -f <in> -rotate 0 45 35.264 -bt o -box <veclen> -o <out>[tt][BR]",
                "where [TT]veclen[tt] is the size of the cubic box times sqrt(3)/2." };
    const char *bugs[] =
        {
            "For complex molecules, the periodicity removal routine may break down, ",
                "in that case you can use trjconv." };
    static real dist = 0.0, rbox = 0.0, to_diam = 0.0;
    static gmx_bool bNDEF = FALSE, bRMPBC = FALSE, bCenter = FALSE, bReadVDW =
        FALSE, bCONECT = FALSE;
    static gmx_bool peratom = FALSE, bLegend = FALSE, bOrient = FALSE, bMead =
        FALSE, bGrasp = FALSE, bSig56 = FALSE;
    static rvec scale =
        { 1, 1, 1 }, newbox =
        { 0, 0, 0 }, newang =
        { 90, 90, 90 };
    static real rho = 1000.0, rvdw = 0.12;
    static rvec center =
        { 0, 0, 0 }, translation =
        { 0, 0, 0 }, rotangles =
        { 0, 0, 0 }, aligncenter =
		{ 0, 0, 0 }, targetvec =
        { 0, 0, 0 };
    static const char *btype[] =
        { NULL, "triclinic", "cubic", "dodecahedron", "octahedron", NULL },
        *label = "A";
    static rvec visbox =
        { 0, 0, 0 };
    t_pargs
        pa[] =
            {
                    { "-ndef", FALSE, etBOOL,
                        { &bNDEF }, "Choose output from default index groups" },
                    { "-visbox", FALSE, etRVEC,
                        { visbox },
                        "HIDDENVisualize a grid of boxes, -1 visualizes the 14 box images" },
                    { "-bt", FALSE, etENUM,
                        { btype }, "Box type for -box and -d" },
                    { "-box", FALSE, etRVEC,
                        { newbox }, "Box vector lengths (a,b,c)" },
                    { "-angles", FALSE, etRVEC,
                        { newang }, "Angles between the box vectors (bc,ac,ab)" },
                    { "-d", FALSE, etREAL,
                        { &dist }, "Distance between the solute and the box" },
                    { "-c", FALSE, etBOOL,
                        { &bCenter },
                        "Center molecule in box (implied by -box and -d)" },
                    { "-center", FALSE, etRVEC,
                        { center }, "Coordinates of geometrical center" },
                    { "-aligncenter", FALSE, etRVEC,
                        { aligncenter }, "Center of rotation for alignment" },
                    { "-align", FALSE, etRVEC,
                        { targetvec },
                        "Align to target vector" },
                    { "-translate", FALSE, etRVEC,
                        { translation }, "Translation" },
                    { "-rotate", FALSE, etRVEC,
                        { rotangles },
                        "Rotation around the X, Y and Z axes in degrees" },
                    { "-princ", FALSE, etBOOL,
                        { &bOrient },
                        "Orient molecule(s) along their principal axes" },
                    { "-scale", FALSE, etRVEC,
                        { scale }, "Scaling factor" },
                    { "-density", FALSE, etREAL,
                        { &rho },
                        "Density (g/l) of the output box achieved by scaling" },
                    { "-pbc", FALSE, etBOOL,
                        { &bRMPBC },
                        "Remove the periodicity (make molecule whole again)" },
                    { "-grasp", FALSE, etBOOL,
                        { &bGrasp },
                        "Store the charge of the atom in the B-factor field and the radius of the atom in the occupancy field" },
                    {
                        "-rvdw", FALSE, etREAL,
                         { &rvdw },
                        "Default Van der Waals radius (in nm) if one can not be found in the database or if no parameters are present in the topology file" },
                    { "-sig56", FALSE, etREAL,
                        { &bSig56 },
                        "Use rmin/2 (minimum in the Van der Waals potential) rather than sigma/2 " },
                    {
                        "-vdwread", FALSE, etBOOL,
                        { &bReadVDW },
                        "Read the Van der Waals radii from the file vdwradii.dat rather than computing the radii based on the force field" },
                    { "-atom", FALSE, etBOOL,
                        { &peratom }, "Force B-factor attachment per atom" },
                    { "-legend", FALSE, etBOOL,
                        { &bLegend }, "Make B-factor legend" },
                    { "-label", FALSE, etSTR,
                        { &label }, "Add chain label for all residues" },
                    {
                        "-conect", FALSE, etBOOL,
                        { &bCONECT },
                        "Add CONECT records to a pdb file when written. Can only be done when a topology is present" } };
#define NPA asize(pa)

    FILE *out;
    const char *infile, *outfile;
    char title[STRLEN];
    int outftp, inftp, natom, i, j, n_bfac, itype, ntype;
    double *bfac = NULL, c6, c12;
    int *bfac_nr = NULL;
    t_topology *top = NULL;
    t_atoms atoms;
    char *grpname, *sgrpname, *agrpname;
    int isize, ssize, tsize, asize;
    atom_id *index, *sindex, *tindex, *aindex;
    rvec *x, *v, gc, min, max, size;
    int ePBC;
    matrix box,rotmatrix,trans;
	rvec princd,tmpvec;
    gmx_bool bIndex, bSetSize, bSetAng, bCubic, bDist, bSetCenter, bAlign;
    gmx_bool bHaveV, bScale, bRho, bTranslate, bRotate, bCalcGeom, bCalcDiam;
    real xs, ys, zs, xcent, ycent, zcent, diam = 0, mass = 0, d, vdw;
    gmx_atomprop_t aps;
    gmx_conect conect;
    output_env_t oenv;
    t_filenm fnm[] =
        {
            { efSTX, "-f", NULL, ffREAD },
            { efNDX, "-n", NULL, ffOPTRD },
            { efSTO, NULL, NULL, ffOPTWR },
            { efPQR, "-mead", "mead", ffOPTWR },
            { efDAT, "-bf", "bfact", ffOPTRD } };
#define NFILE asize(fnm)

    CopyRight(stderr, argv[0]);
    parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa,
                      asize(desc), desc, asize(bugs), bugs, &oenv);

    bIndex = opt2bSet("-n", NFILE, fnm) || bNDEF;
    bMead = opt2bSet("-mead", NFILE, fnm);
    bSetSize = opt2parg_bSet("-box", NPA, pa);
    bSetAng = opt2parg_bSet("-angles", NPA, pa);
    bSetCenter = opt2parg_bSet("-center", NPA, pa);
    bDist = opt2parg_bSet("-d", NPA, pa);
	bAlign = opt2parg_bSet("-align", NPA, pa);
    /* Only automatically turn on centering without -noc */
    if ((bDist || bSetSize || bSetCenter) && !opt2parg_bSet("-c", NPA, pa))
    {
        bCenter = TRUE;
    }
    bScale = opt2parg_bSet("-scale", NPA, pa);
    bRho = opt2parg_bSet("-density", NPA, pa);
    bTranslate = opt2parg_bSet("-translate", NPA, pa);
    bRotate = opt2parg_bSet("-rotate", NPA, pa);
    if (bScale && bRho)
        fprintf(stderr, "WARNING: setting -density overrides -scale\n");
    bScale = bScale || bRho;
    bCalcGeom = bCenter || bRotate || bOrient || bScale;
    bCalcDiam = btype[0][0] == 'c' || btype[0][0] == 'd' || btype[0][0] == 'o';

    infile = ftp2fn(efSTX, NFILE, fnm);
    if (bMead)
        outfile = ftp2fn(efPQR, NFILE, fnm);
    else
        outfile = ftp2fn(efSTO, NFILE, fnm);
    outftp = fn2ftp(outfile);
    inftp = fn2ftp(infile);

    aps = gmx_atomprop_init();

    if (bMead && bGrasp)
    {
        printf("Incompatible options -mead and -grasp. Turning off -grasp\n");
        bGrasp = FALSE;
    }
    if (bGrasp && (outftp != efPDB))
        gmx_fatal(FARGS, "Output file should be a .pdb file"
        " when using the -grasp option\n");
        if ((bMead || bGrasp) && !((fn2ftp(infile) == efTPR) ||
                (fn2ftp(infile) == efTPA) ||
                (fn2ftp(infile) == efTPB)))
        gmx_fatal(FARGS,"Input file should be a .tp[abr] file"
            " when using the -mead option\n");

        get_stx_coordnum(infile,&natom);
        init_t_atoms(&atoms,natom,TRUE);
        snew(x,natom);
        snew(v,natom);
        read_stx_conf(infile,title,&atoms,x,v,&ePBC,box);
        if (fn2ftp(infile) == efPDB)
        {
            get_pdb_atomnumber(&atoms,aps);
        }
        printf("Read %d atoms\n",atoms.nr);

        /* Get the element numbers if available in a pdb file */
        if (fn2ftp(infile) == efPDB)
        get_pdb_atomnumber(&atoms,aps);

        if (ePBC != epbcNONE)
        {
            real vol = det(box);
            printf("Volume: %g nm^3, corresponds to roughly %d electrons\n",
                vol,100*((int)(vol*4.5)));
        }

        if (bMead || bGrasp || bCONECT)
        top = read_top(infile,NULL);

        if (bMead || bGrasp)
        {
            if (atoms.nr != top->atoms.nr)
            gmx_fatal(FARGS,"Atom numbers don't match (%d vs. %d)",atoms.nr,top->atoms.nr);
        snew(atoms.pdbinfo,top->atoms.nr); 
        ntype = top->idef.atnr;
        for(i=0; (i<atoms.nr); i++) {
            /* Determine the Van der Waals radius from the force field */
            if (bReadVDW) {
                if (!gmx_atomprop_query(aps,epropVDW,
                                        *top->atoms.resinfo[top->atoms.atom[i].resind].name,
                                        *top->atoms.atomname[i],&vdw))
                    vdw = rvdw;
            }
            else {
                itype = top->atoms.atom[i].type;
                c12   = top->idef.iparams[itype*ntype+itype].lj.c12;
                c6    = top->idef.iparams[itype*ntype+itype].lj.c6;
                if ((c6 != 0) && (c12 != 0)) {
                    real sig6; 
                    if (bSig56)
                        sig6 = 2*c12/c6;
                    else
                        sig6 = c12/c6;
                    vdw   = 0.5*pow(sig6,1.0/6.0);
                }
                else
                    vdw = rvdw;
            }
            /* Factor of 10 for nm -> Angstroms */
            vdw *= 10;

            if (bMead) {
                atoms.pdbinfo[i].occup = top->atoms.atom[i].q;
                atoms.pdbinfo[i].bfac  = vdw;
            }
            else {
                atoms.pdbinfo[i].occup = vdw;
                atoms.pdbinfo[i].bfac  = top->atoms.atom[i].q;
            }
        }
    }
    bHaveV=FALSE;
    for (i=0; (i<natom) && !bHaveV; i++)
        for (j=0; (j<DIM) && !bHaveV; j++)
            bHaveV=bHaveV || (v[i][j]!=0);
    printf("%selocities found\n",bHaveV?"V":"No v");

    if (visbox[0] > 0) {
        if (bIndex)
            gmx_fatal(FARGS,"Sorry, can not visualize box with index groups");
        if (outftp != efPDB)
            gmx_fatal(FARGS,"Sorry, can only visualize box with a pdb file");
    } else if (visbox[0] == -1)
        visualize_images("images.pdb",ePBC,box);

    /* remove pbc */
    if (bRMPBC) 
        rm_gropbc(&atoms,x,box);

    if (bCalcGeom) {
        if (bIndex) {
            fprintf(stderr,"\nSelect a group for determining the system size:\n");
            get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),
                      1,&ssize,&sindex,&sgrpname);
        } else {
            ssize = atoms.nr;
            sindex = NULL;
        }
        diam=calc_geom(ssize,sindex,x,gc,min,max,bCalcDiam);
        rvec_sub(max, min, size);
        printf("    system size :%7.3f%7.3f%7.3f (nm)\n",
               size[XX], size[YY], size[ZZ]);
        if (bCalcDiam)
            printf("    diameter    :%7.3f               (nm)\n",diam);
        printf("    center      :%7.3f%7.3f%7.3f (nm)\n", gc[XX], gc[YY], gc[ZZ]);
        printf("    box vectors :%7.3f%7.3f%7.3f (nm)\n", 
               norm(box[XX]), norm(box[YY]), norm(box[ZZ]));
        printf("    box angles  :%7.2f%7.2f%7.2f (degrees)\n",
               norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])),
        norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])),
        norm2(box[YY])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY])));
        printf("    box volume  :%7.2f               (nm^3)\n",det(box));
    }

    if (bRho || bOrient || bAlign)
        mass = calc_mass(&atoms,!fn2bTPX(infile),aps);

    if (bOrient) {
        atom_id *index;
        char    *grpnames;

        /* Get a group for principal component analysis */
        fprintf(stderr,"\nSelect group for the determining the orientation\n");
        get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpnames);

        /* Orient the principal axes along the coordinate axes */
        orient_princ(&atoms,isize,index,natom,x,bHaveV ? v : NULL, NULL);
        sfree(index);
        sfree(grpnames);
    }

    if ( bScale ) {
        /* scale coordinates and box */
        if (bRho) {
            /* Compute scaling constant */
            real vol,dens;

            vol = det(box);
            dens = (mass*AMU)/(vol*NANO*NANO*NANO);
            fprintf(stderr,"Volume  of input %g (nm^3)\n",vol);
            fprintf(stderr,"Mass    of input %g (a.m.u.)\n",mass);
            fprintf(stderr,"Density of input %g (g/l)\n",dens);
            if (vol==0 || mass==0)
                gmx_fatal(FARGS,"Cannot scale density with "
                          "zero mass (%g) or volume (%g)\n",mass,vol);

            scale[XX] = scale[YY] = scale[ZZ] = pow(dens/rho,1.0/3.0);
            fprintf(stderr,"Scaling all box vectors by %g\n",scale[XX]);
        }
        scale_conf(atoms.nr,x,box,scale);
    }

	if (bAlign) {
		if (bIndex) {
            fprintf(stderr,"\nSelect a group that you want to align:\n");
            get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),
                      1,&asize,&aindex,&agrpname);
        } else {
            asize = atoms.nr;
            snew(aindex,asize);
			for (i=0;i<asize;i++)
				aindex[i]=i;
        }
		printf("Aligning %d atoms (out of %d) to %g %g %g, center of rotation %g %g %g\n",asize,natom,
			targetvec[XX],targetvec[YY],targetvec[ZZ],
			aligncenter[XX],aligncenter[YY],aligncenter[ZZ]);
		/*subtract out pivot point*/
		for(i=0; i<asize; i++)
			rvec_dec(x[aindex[i]],aligncenter);
		/*now determine transform and rotate*/
		/*will this work?*/
		principal_comp(asize,aindex,atoms.atom,x, trans,princd);

		unitv(targetvec,targetvec);
		printf("Using %g %g %g as principal axis\n", trans[0][2],trans[1][2],trans[2][2]);
		tmpvec[XX]=trans[0][2]; tmpvec[YY]=trans[1][2]; tmpvec[ZZ]=trans[2][2];
		calc_rotmatrix(tmpvec, targetvec, rotmatrix);
		/* rotmatrix finished */

		for (i=0;i<asize;++i)
		{
			mvmul(rotmatrix,x[aindex[i]],tmpvec);
			copy_rvec(tmpvec,x[aindex[i]]);
		}

		/*add pivot point back*/
		for(i=0; i<asize; i++)
			rvec_inc(x[aindex[i]],aligncenter);
		if (!bIndex)
			sfree(aindex);
	}

    if (bTranslate) {
        if (bIndex) {
            fprintf(stderr,"\nSelect a group that you want to translate:\n");
            get_index(&atoms,ftp2fn_null(efNDX,NFILE,fnm),
                      1,&ssize,&sindex,&sgrpname);
        } else {
            ssize = atoms.nr;
            sindex = NULL;
        }
        printf("Translating %d atoms (out of %d) by %g %g %g nm\n",ssize,natom,
               translation[XX],translation[YY],translation[ZZ]);
        if (sindex) {
            for(i=0; i<ssize; i++)
                rvec_inc(x[sindex[i]],translation);
        }
        else {
            for(i=0; i<natom; i++)
                rvec_inc(x[i],translation);
        }
    }
    if (bRotate) {
        /* Rotate */
        printf("Rotating %g, %g, %g degrees around the X, Y and Z axis respectively\n",rotangles[XX],rotangles[YY],rotangles[ZZ]);
        for(i=0; i<DIM; i++)
            rotangles[i] *= DEG2RAD;
        rotate_conf(natom,x,v,rotangles[XX],rotangles[YY],rotangles[ZZ]);
    }

    if (bCalcGeom) {
        /* recalc geometrical center and max and min coordinates and size */
        calc_geom(ssize,sindex,x,gc,min,max,FALSE);
        rvec_sub(max, min, size);
        if (bScale || bOrient || bRotate)
            printf("new system size : %6.3f %6.3f %6.3f\n",
                   size[XX],size[YY],size[ZZ]);
    }

    if (bSetSize || bDist || (btype[0][0]=='t' && bSetAng)) {
        ePBC = epbcXYZ;
        if (!(bSetSize || bDist))
            for (i=0; i<DIM; i++)
                newbox[i] = norm(box[i]);
        clear_mat(box);
        /* calculate new boxsize */
        switch(btype[0][0]){
        case 't':
            if (bDist)
                for(i=0; i<DIM; i++)
                    newbox[i] = size[i]+2*dist;
            if (!bSetAng) {
                box[XX][XX] = newbox[XX];
                box[YY][YY] = newbox[YY];
                box[ZZ][ZZ] = newbox[ZZ];
            } else {
                matrix_convert(box,newbox,newang);
            }
            break;
        case 'c':
        case 'd':
        case 'o':
            if (bSetSize)
                d = newbox[0];
            else
                d = diam+2*dist;
            if (btype[0][0] == 'c')
                for(i=0; i<DIM; i++)
                    box[i][i] = d;
            else if (btype[0][0] == 'd') {
                box[XX][XX] = d;
                box[YY][YY] = d;
                box[ZZ][XX] = d/2;
                box[ZZ][YY] = d/2;
                box[ZZ][ZZ] = d*sqrt(2)/2;
            } else {
                box[XX][XX] = d;
                box[YY][XX] = d/3;
                box[YY][YY] = d*sqrt(2)*2/3;
                box[ZZ][XX] = -d/3;
                box[ZZ][YY] = d*sqrt(2)/3;
                box[ZZ][ZZ] = d*sqrt(6)/3;
            }
            break;
        } 
    }

    /* calculate new coords for geometrical center */
    if (!bSetCenter)
        calc_box_center(ecenterDEF,box,center);

    /* center molecule on 'center' */
    if (bCenter)
        center_conf(natom,x,center,gc);

    /* print some */
    if (bCalcGeom) {
        calc_geom(ssize,sindex,x, gc, min, max, FALSE);
        printf("new center      :%7.3f%7.3f%7.3f (nm)\n",gc[XX],gc[YY],gc[ZZ]);
    }
    if (bOrient || bScale || bDist || bSetSize) {
        printf("new box vectors :%7.3f%7.3f%7.3f (nm)\n", 
               norm(box[XX]), norm(box[YY]), norm(box[ZZ]));
        printf("new box angles  :%7.2f%7.2f%7.2f (degrees)\n",
               norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ])),
        norm2(box[ZZ])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ])),
        norm2(box[YY])==0 ? 0 :
        RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY])));
        printf("new box volume  :%7.2f               (nm^3)\n",det(box));
    }  

    if (check_box(epbcXYZ,box))
        printf("\nWARNING: %s\n",check_box(epbcXYZ,box));

    if (bDist && btype[0][0]=='t')
    {
        if(TRICLINIC(box))
        {
            printf("\nWARNING: Your box is triclinic with non-orthogonal axes. In this case, the\n"
                "distance from the solute to a box surface along the corresponding normal\n"
                "vector might be somewhat smaller than your specified value %f.\n"
                "You can check the actual value with g_mindist -pi\n",dist);
        }
        else
        {
            printf("\nWARNING: No boxtype specified - distance condition applied in each dimension.\n"
                "If the molecule rotates the actual distance will be smaller. You might want\n"
                "to use a cubic box instead, or why not try a dodecahedron today?\n");
        }
    }
    if (bCONECT && (outftp == efPDB) && (inftp == efTPR)) 
        conect = gmx_conect_generate(top);
    else
        conect = NULL;

    if (bIndex) {
        fprintf(stderr,"\nSelect a group for output:\n");
        get_index(&atoms,opt2fn_null("-n",NFILE,fnm),
                  1,&isize,&index,&grpname);
        if (opt2parg_bSet("-label",NPA,pa)) {
            for(i=0; (i<atoms.nr); i++) 
                atoms.resinfo[atoms.atom[i].resind].chainid=label[0];
        }
                
        if (opt2bSet("-bf",NFILE,fnm) || bLegend)
        {
            gmx_fatal(FARGS,"Sorry, cannot do bfactors with an index group.");
        }

        if (outftp == efPDB) 
        {
            out=ffopen(outfile,"w");
            write_pdbfile_indexed(out,title,&atoms,x,ePBC,box,' ',1,isize,index,conect,TRUE);
            ffclose(out);
        }
        else
        {
            write_sto_conf_indexed(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box,isize,index); 
        }
    }
    else {
        if ((outftp == efPDB) || (outftp == efPQR)) {
            out=ffopen(outfile,"w");
            if (bMead) {
                set_pdb_wide_format(TRUE);
                fprintf(out,"REMARK    "
                        "The B-factors in this file hold atomic radii\n");
                fprintf(out,"REMARK    "
                        "The occupancy in this file hold atomic charges\n");
            }
            else if (bGrasp) {
                fprintf(out,"GRASP PDB FILE\nFORMAT NUMBER=1\n");
                fprintf(out,"REMARK    "
                        "The B-factors in this file hold atomic charges\n");
                fprintf(out,"REMARK    "
                        "The occupancy in this file hold atomic radii\n");
            }
            else if (opt2bSet("-bf",NFILE,fnm)) {
                read_bfac(opt2fn("-bf",NFILE,fnm),&n_bfac,&bfac,&bfac_nr);
                set_pdb_conf_bfac(atoms.nr,atoms.nres,&atoms,
                                  n_bfac,bfac,bfac_nr,peratom);
            }
            if (opt2parg_bSet("-label",NPA,pa)) {
                for(i=0; (i<atoms.nr); i++) 
                    atoms.resinfo[atoms.atom[i].resind].chainid=label[0];
            }
            write_pdbfile(out,title,&atoms,x,ePBC,box,' ',-1,conect,TRUE);
            if (bLegend)
                pdb_legend(out,atoms.nr,atoms.nres,&atoms,x);
            if (visbox[0] > 0)
                visualize_box(out,bLegend ? atoms.nr+12 : atoms.nr,
                    bLegend? atoms.nres=12 : atoms.nres,box,visbox);
            ffclose(out);
        }
        else
            write_sto_conf(outfile,title,&atoms,x,bHaveV?v:NULL,ePBC,box); 
    }
    gmx_atomprop_destroy(aps);

    do_view(oenv,outfile,NULL);

    thanx(stderr);

    return 0;
}
예제 #2
0
int gmx_confrms(int argc, char *argv[])
{
    const char     *desc[] = {
        "[TT]g_confrms[tt] computes the root mean square deviation (RMSD) of two",
        "structures after least-squares fitting the second structure on the first one.",
        "The two structures do NOT need to have the same number of atoms,",
        "only the two index groups used for the fit need to be identical.",
        "With [TT]-name[tt] only matching atom names from the selected groups",
        "will be used for the fit and RMSD calculation. This can be useful ",
        "when comparing mutants of a protein.",
        "[PAR]",
        "The superimposed structures are written to file. In a [TT].pdb[tt] file",
        "the two structures will be written as separate models",
        "(use [TT]rasmol -nmrpdb[tt]). Also in a [TT].pdb[tt] file, B-factors",
        "calculated from the atomic MSD values can be written with [TT]-bfac[tt].",
    };
    static gmx_bool bOne  = FALSE, bRmpbc = FALSE, bMW = TRUE, bName = FALSE,
                    bBfac = FALSE, bFit = TRUE, bLabel = FALSE;

    t_pargs  pa[] = {
        { "-one", FALSE, etBOOL, {&bOne},   "Only write the fitted structure to file" },
        { "-mw",  FALSE, etBOOL, {&bMW},    "Mass-weighted fitting and RMSD" },
        { "-pbc", FALSE, etBOOL, {&bRmpbc}, "Try to make molecules whole again" },
        { "-fit", FALSE, etBOOL, {&bFit},
          "Do least squares superposition of the target structure to the reference" },
        { "-name", FALSE, etBOOL, {&bName},
          "Only compare matching atom names" },
        { "-label", FALSE, etBOOL, {&bLabel},
          "Added chain labels A for first and B for second structure"},
        { "-bfac", FALSE, etBOOL, {&bBfac},
          "Output B-factors from atomic MSD values" }
    };
    t_filenm fnm[] = {
        { efTPS, "-f1",  "conf1.gro", ffREAD  },
        { efSTX, "-f2",  "conf2",     ffREAD  },
        { efSTO, "-o",   "fit.pdb",   ffWRITE },
        { efNDX, "-n1", "fit1.ndx",  ffOPTRD },
        { efNDX, "-n2", "fit2.ndx",  ffOPTRD },
        { efNDX, "-no", "match.ndx", ffOPTWR }
    };
#define NFILE asize(fnm)

    /* the two structure files */
    const char  *conf1file, *conf2file, *matchndxfile, *outfile;
    FILE        *fp;
    char         title1[STRLEN], title2[STRLEN], *name1, *name2;
    t_topology  *top1, *top2;
    int          ePBC1, ePBC2;
    t_atoms     *atoms1, *atoms2;
    int          warn = 0;
    atom_id      at;
    real        *w_rls, mass, totmass;
    rvec        *x1, *v1, *x2, *v2, *fit_x;
    matrix       box1, box2;

    output_env_t oenv;

    /* counters */
    int     i, j, m;

    /* center of mass calculation */
    real    tmas1, tmas2;
    rvec    xcm1, xcm2;

    /* variables for fit */
    char    *groupnames1, *groupnames2;
    int      isize1, isize2;
    atom_id *index1, *index2;
    real     rms, msd, minmsd, maxmsd;
    real    *msds;


    parse_common_args(&argc, argv, PCA_BE_NICE | PCA_CAN_VIEW,
                      NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv);
    matchndxfile = opt2fn_null("-no", NFILE, fnm);
    conf1file    = ftp2fn(efTPS, NFILE, fnm);
    conf2file    = ftp2fn(efSTX, NFILE, fnm);

    /* reading reference structure from first structure file */
    fprintf(stderr, "\nReading first structure file\n");
    snew(top1, 1);
    read_tps_conf(conf1file, title1, top1, &ePBC1, &x1, &v1, box1, TRUE);
    atoms1 = &(top1->atoms);
    fprintf(stderr, "%s\nContaining %d atoms in %d residues\n",
            title1, atoms1->nr, atoms1->nres);

    if (bRmpbc)
    {
        rm_gropbc(atoms1, x1, box1);
    }

    fprintf(stderr, "Select group from first structure\n");
    get_index(atoms1, opt2fn_null("-n1", NFILE, fnm),
              1, &isize1, &index1, &groupnames1);
    printf("\n");

    if (bFit && (isize1 < 3))
    {
        gmx_fatal(FARGS, "Need >= 3 points to fit!\n");
    }

    /* reading second structure file */
    fprintf(stderr, "\nReading second structure file\n");
    snew(top2, 1);
    read_tps_conf(conf2file, title2, top2, &ePBC2, &x2, &v2, box2, TRUE);
    atoms2 = &(top2->atoms);
    fprintf(stderr, "%s\nContaining %d atoms in %d residues\n",
            title2, atoms2->nr, atoms2->nres);

    if (bRmpbc)
    {
        rm_gropbc(atoms2, x2, box2);
    }

    fprintf(stderr, "Select group from second structure\n");
    get_index(atoms2, opt2fn_null("-n2", NFILE, fnm),
              1, &isize2, &index2, &groupnames2);

    if (bName)
    {
        find_matching_names(&isize1, index1, atoms1, &isize2, index2, atoms2);
        if (matchndxfile)
        {
            fp = ffopen(matchndxfile, "w");
            fprintf(fp, "; Matching atoms between %s from %s and %s from %s\n",
                    groupnames1, conf1file, groupnames2, conf2file);
            fprintf(fp, "[ Match_%s_%s ]\n", conf1file, groupnames1);
            for (i = 0; i < isize1; i++)
            {
                fprintf(fp, "%4u%s", index1[i]+1, (i%15 == 14 || i == isize1-1) ? "\n" : " ");
            }
            fprintf(fp, "[ Match_%s_%s ]\n", conf2file, groupnames2);
            for (i = 0; i < isize2; i++)
            {
                fprintf(fp, "%4u%s", index2[i]+1, (i%15 == 14 || i == isize2-1) ? "\n" : " ");
            }
        }
    }

    /* check isizes, must be equal */
    if (isize2 != isize1)
    {
        gmx_fatal(FARGS, "You selected groups with differen number of atoms.\n");
    }

    for (i = 0; i < isize1; i++)
    {
        name1 = *atoms1->atomname[index1[i]];
        name2 = *atoms2->atomname[index2[i]];
        if (strcmp(name1, name2))
        {
            if (warn < 20)
            {
                fprintf(stderr,
                        "Warning: atomnames at index %d don't match: %u %s, %u %s\n",
                        i+1, index1[i]+1, name1, index2[i]+1, name2);
            }
            warn++;
        }
        if (!bMW)
        {
            atoms1->atom[index1[i]].m = 1;
            atoms2->atom[index2[i]].m = 1;
        }
    }
    if (warn)
    {
        fprintf(stderr, "%d atomname%s did not match\n", warn, (warn == 1) ? "" : "s");
    }

    if (bFit)
    {
        /* calculate and remove center of mass of structures */
        calc_rm_cm(isize1, index1, atoms1, x1, xcm1);
        calc_rm_cm(isize2, index2, atoms2, x2, xcm2);

        snew(w_rls, atoms2->nr);
        snew(fit_x, atoms2->nr);
        for (at = 0; (at < isize1); at++)
        {
            w_rls[index2[at]] = atoms1->atom[index1[at]].m;
            copy_rvec(x1[index1[at]], fit_x[index2[at]]);
        }

        /* do the least squares fit to the reference structure */
        do_fit(atoms2->nr, w_rls, fit_x, x2);

        sfree(fit_x);
        sfree(w_rls);
        w_rls = NULL;
    }
    else
    {
        clear_rvec(xcm1);
        clear_rvec(xcm2);
        w_rls = NULL;
    }

    /* calculate the rms deviation */
    rms     = 0;
    totmass = 0;
    maxmsd  = -1e18;
    minmsd  =  1e18;
    snew(msds, isize1);
    for (at = 0; at < isize1; at++)
    {
        mass = atoms1->atom[index1[at]].m;
        for (m = 0; m < DIM; m++)
        {
            msd       = sqr(x1[index1[at]][m] - x2[index2[at]][m]);
            rms      += msd*mass;
            msds[at] += msd;
        }
        maxmsd   = max(maxmsd, msds[at]);
        minmsd   = min(minmsd, msds[at]);
        totmass += mass;
    }
    rms = sqrt(rms/totmass);

    printf("Root mean square deviation after lsq fit = %g nm\n", rms);
    if (bBfac)
    {
        printf("Atomic MSD's range from %g to %g nm^2\n", minmsd, maxmsd);
    }

    if (bFit)
    {
        /* reset coordinates of reference and fitted structure */
        for (i = 0; i < atoms1->nr; i++)
        {
            for (m = 0; m < DIM; m++)
            {
                x1[i][m] += xcm1[m];
            }
        }
        for (i = 0; i < atoms2->nr; i++)
        {
            for (m = 0; m < DIM; m++)
            {
                x2[i][m] += xcm1[m];
            }
        }
    }

    outfile = ftp2fn(efSTO, NFILE, fnm);
    switch (fn2ftp(outfile))
    {
        case efPDB:
        case efBRK:
        case efENT:
            if (bBfac || bLabel)
            {
                srenew(atoms1->pdbinfo, atoms1->nr);
                srenew(atoms1->atom, atoms1->nr); /* Why renew atom? */

                /* Avoid segfaults when writing the pdb-file */
                for (i = 0; i < atoms1->nr; i++)
                {
                    atoms1->pdbinfo[i].type         = eptAtom;
                    atoms1->pdbinfo[i].occup        = 1.00;
                    atoms1->pdbinfo[i].bAnisotropic = FALSE;
                    if (bBfac)
                    {
                        atoms1->pdbinfo[i].bfac = 0;
                    }
                    if (bLabel)
                    {
                        atoms1->resinfo[atoms1->atom[i].resind].chainid = 'A';
                    }
                }

                for (i = 0; i < isize1; i++)
                {
                    /* atoms1->pdbinfo[index1[i]].type = eptAtom; */
/*  atoms1->pdbinfo[index1[i]].bAnisotropic = FALSE; */
                    if (bBfac)
                    {
                        atoms1->pdbinfo[index1[i]].bfac = (800*M_PI*M_PI/3.0)*msds[i];
                    }
/*  if (bLabel) */
/*    atoms1->resinfo[atoms1->atom[index1[i]].resind].chain = 'A'; */
                }
                srenew(atoms2->pdbinfo, atoms2->nr);
                srenew(atoms2->atom, atoms2->nr); /* Why renew atom? */

                for (i = 0; i < atoms2->nr; i++)
                {
                    atoms2->pdbinfo[i].type         = eptAtom;
                    atoms2->pdbinfo[i].occup        = 1.00;
                    atoms2->pdbinfo[i].bAnisotropic = FALSE;
                    if (bBfac)
                    {
                        atoms2->pdbinfo[i].bfac = 0;
                    }
                    if (bLabel)
                    {
                        atoms2->resinfo[atoms1->atom[i].resind].chainid = 'B';
                    }
                }

                for (i = 0; i < isize2; i++)
                {
                    /* atoms2->pdbinfo[index2[i]].type = eptAtom; */
/*  atoms2->pdbinfo[index2[i]].bAnisotropic = FALSE; */
                    if (bBfac)
                    {
                        atoms2->pdbinfo[index2[i]].bfac = (800*M_PI*M_PI/3.0)*msds[i];
                    }
/*  if (bLabel) */
/*    atoms2->resinfo[atoms2->atom[index2[i]].resind].chain = 'B'; */
                }
            }
            fp = ffopen(outfile, "w");
            if (!bOne)
            {
                write_pdbfile(fp, title1, atoms1, x1, ePBC1, box1, ' ', 1, NULL, TRUE);
            }
            write_pdbfile(fp, title2, atoms2, x2, ePBC2, box2, ' ', bOne ? -1 : 2, NULL, TRUE);
            ffclose(fp);
            break;
        case efGRO:
            if (bBfac)
            {
                fprintf(stderr, "WARNING: cannot write B-factor values to gro file\n");
            }
            fp = ffopen(outfile, "w");
            if (!bOne)
            {
                write_hconf_p(fp, title1, atoms1, 3, x1, v1, box1);
            }
            write_hconf_p(fp, title2, atoms2, 3, x2, v2, box2);
            ffclose(fp);
            break;
        default:
            if (bBfac)
            {
                fprintf(stderr, "WARNING: cannot write B-factor values to %s file\n",
                        ftp2ext(fn2ftp(outfile)));
            }
            if (!bOne)
            {
                fprintf(stderr,
                        "WARNING: cannot write the reference structure to %s file\n",
                        ftp2ext(fn2ftp(outfile)));
            }
            write_sto_conf(outfile, title2, atoms2, x2, v2, ePBC2, box2);
            break;
    }

    view_all(oenv, NFILE, fnm);

    thanx(stderr);

    return 0;
}