示例#1
0
void chk_tps(const char *fn, real vdw_fac, real bon_lo, real bon_hi)
{
    int            natom, i, j, k;
    t_topology     top;
    int            ePBC;
    t_atoms       *atoms;
    rvec          *x, *v;
    rvec           dx;
    matrix         box;
    t_pbc          pbc;
    gmx_bool       bV, bX, bB, bFirst, bOut;
    real           r2, ekin, temp1, temp2, dist2, vdwfac2, bonlo2, bonhi2;
    real          *atom_vdw;
    gmx_atomprop_t aps;

    fprintf(stderr, "Checking coordinate file %s\n", fn);
    read_tps_conf(fn, &top, &ePBC, &x, &v, box, TRUE);
    atoms = &top.atoms;
    natom = atoms->nr;
    fprintf(stderr, "%d atoms in file\n", atoms->nr);

    /* check coordinates and box */
    bV = FALSE;
    bX = FALSE;
    for (i = 0; (i < natom) && !(bV && bX); i++)
    {
        for (j = 0; (j < DIM) && !(bV && bX); j++)
        {
            bV = bV || (v[i][j] != 0);
            bX = bX || (x[i][j] != 0);
        }
    }
    bB = FALSE;
    for (i = 0; (i < DIM) && !bB; i++)
    {
        for (j = 0; (j < DIM) && !bB; j++)
        {
            bB = bB || (box[i][j] != 0);
        }
    }

    fprintf(stderr, "coordinates %s\n", bX ? "found" : "absent");
    fprintf(stderr, "box         %s\n", bB ? "found" : "absent");
    fprintf(stderr, "velocities  %s\n", bV ? "found" : "absent");
    fprintf(stderr, "\n");

    /* check velocities */
    if (bV)
    {
        ekin = 0.0;
        for (i = 0; (i < natom); i++)
        {
            for (j = 0; (j < DIM); j++)
            {
                ekin += 0.5*atoms->atom[i].m*v[i][j]*v[i][j];
            }
        }
        temp1 = (2.0*ekin)/(natom*DIM*BOLTZ);
        temp2 = (2.0*ekin)/(natom*(DIM-1)*BOLTZ);
        fprintf(stderr, "Kinetic energy: %g (kJ/mol)\n", ekin);
        fprintf(stderr, "Assuming the number of degrees of freedom to be "
                "Natoms * %d or Natoms * %d,\n"
                "the velocities correspond to a temperature of the system\n"
                "of %g K or %g K respectively.\n\n", DIM, DIM-1, temp1, temp2);
    }

    /* check coordinates */
    if (bX)
    {
        vdwfac2 = sqr(vdw_fac);
        bonlo2  = sqr(bon_lo);
        bonhi2  = sqr(bon_hi);

        fprintf(stderr,
                "Checking for atoms closer than %g and not between %g and %g,\n"
                "relative to sum of Van der Waals distance:\n",
                vdw_fac, bon_lo, bon_hi);
        snew(atom_vdw, natom);
        aps = gmx_atomprop_init();
        for (i = 0; (i < natom); i++)
        {
            gmx_atomprop_query(aps, epropVDW,
                               *(atoms->resinfo[atoms->atom[i].resind].name),
                               *(atoms->atomname[i]), &(atom_vdw[i]));
            if (debug)
            {
                fprintf(debug, "%5d %4s %4s %7g\n", i+1,
                        *(atoms->resinfo[atoms->atom[i].resind].name),
                        *(atoms->atomname[i]),
                        atom_vdw[i]);
            }
        }
        gmx_atomprop_destroy(aps);
        if (bB)
        {
            set_pbc(&pbc, ePBC, box);
        }

        bFirst = TRUE;
        for (i = 0; (i < natom); i++)
        {
            if (((i+1)%10) == 0)
            {
                fprintf(stderr, "\r%5d", i+1);
            }
            for (j = i+1; (j < natom); j++)
            {
                if (bB)
                {
                    pbc_dx(&pbc, x[i], x[j], dx);
                }
                else
                {
                    rvec_sub(x[i], x[j], dx);
                }
                r2    = iprod(dx, dx);
                dist2 = sqr(atom_vdw[i]+atom_vdw[j]);
                if ( (r2 <= dist2*bonlo2) ||
                     ( (r2 >= dist2*bonhi2) && (r2 <= dist2*vdwfac2) ) )
                {
                    if (bFirst)
                    {
                        fprintf(stderr, "\r%5s %4s %8s %5s  %5s %4s %8s %5s  %6s\n",
                                "atom#", "name", "residue", "r_vdw",
                                "atom#", "name", "residue", "r_vdw", "distance");
                        bFirst = FALSE;
                    }
                    fprintf(stderr,
                            "\r%5d %4s %4s%4d %-5.3g  %5d %4s %4s%4d %-5.3g  %-6.4g\n",
                            i+1, *(atoms->atomname[i]),
                            *(atoms->resinfo[atoms->atom[i].resind].name),
                            atoms->resinfo[atoms->atom[i].resind].nr,
                            atom_vdw[i],
                            j+1, *(atoms->atomname[j]),
                            *(atoms->resinfo[atoms->atom[j].resind].name),
                            atoms->resinfo[atoms->atom[j].resind].nr,
                            atom_vdw[j],
                            std::sqrt(r2) );
                }
            }
        }
        if (bFirst)
        {
            fprintf(stderr, "\rno close atoms found\n");
        }
        fprintf(stderr, "\r      \n");

        if (bB)
        {
            /* check box */
            bFirst = TRUE;
            k      = 0;
            for (i = 0; (i < natom) && (k < 10); i++)
            {
                bOut = FALSE;
                for (j = 0; (j < DIM) && !bOut; j++)
                {
                    bOut = bOut || (x[i][j] < 0) || (x[i][j] > box[j][j]);
                }
                if (bOut)
                {
                    k++;
                    if (bFirst)
                    {
                        fprintf(stderr, "Atoms outside box ( ");
                        for (j = 0; (j < DIM); j++)
                        {
                            fprintf(stderr, "%g ", box[j][j]);
                        }
                        fprintf(stderr, "):\n"
                                "(These may occur often and are normally not a problem)\n"
                                "%5s %4s %8s %5s  %s\n",
                                "atom#", "name", "residue", "r_vdw", "coordinate");
                        bFirst = FALSE;
                    }
                    fprintf(stderr,
                            "%5d %4s %4s%4d %-5.3g",
                            i, *(atoms->atomname[i]),
                            *(atoms->resinfo[atoms->atom[i].resind].name),
                            atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i]);
                    for (j = 0; (j < DIM); j++)
                    {
                        fprintf(stderr, " %6.3g", x[i][j]);
                    }
                    fprintf(stderr, "\n");
                }
            }
            if (k == 10)
            {
                fprintf(stderr, "(maybe more)\n");
            }
            if (bFirst)
            {
                fprintf(stderr, "no atoms found outside box\n");
            }
            fprintf(stderr, "\n");
        }
    }
}
示例#2
0
int gmx_editconf(int argc, char *argv[])
{
    const char
                   *desc[] =
    {
        "[TT]editconf[tt] 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.",
        "Relative to a cubic box with some periodic image distance, the volume of a ",
        "dodecahedron with this same periodic distance is 0.71 times that of the cube, ",
        "and that of a truncated octahedron is 0.77 times.",
        "[PAR]",
        "Option [TT]-box[tt] requires only",
        "one value for a cubic, rhombic dodecahedral, or truncated octahedral box.",
        "[PAR]",
        "With [TT]-d[tt] and a [TT]triclinic[tt] box the size of the system in the [IT]x[it]-, [IT]y[it]-,",
        "and [IT]z[it]-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 cannot 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, with the longest axis aligned with the [IT]x[it]-axis. ",
        "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 [TT].gro[tt]",
        "file is given as input. A special feature of the scaling option is that when the",
        "factor -1 is given in one dimension, one obtains a mirror image,",
        "mirrored in one of the planes. 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 vectors 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 [TT]-mead[tt] a special [TT].pdb[tt] ([TT].pqr[tt])",
        "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 [TT]-grasp[tt] 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], [TT]editconf[tt] can add a chain identifier",
        "to a [TT].pdb[tt] 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[sqrt]/2."
    };
    const char     *bugs[] =
    {
        "For complex molecules, the periodicity removal routine may break down, "
        "in that case you can use [TT]trjconv[tt]."
    };
    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 };
    static int  resnr_start = -1;
    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 [TT]-box[tt] and [TT]-d[tt]" },
        { "-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 [TT]-box[tt] and [TT]-d[tt])" },
        { "-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)" },
        { "-resnr", FALSE, etINT,
          { &resnr_start },
          " Renumber residues starting from resnr" },
        { "-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, etBOOL,
          { &bSig56 },
          "Use rmin/2 (minimum in the Van der Waals potential) rather than [GRK]sigma[grk]/2 " },
        {
            "-vdwread", FALSE, etBOOL,
            { &bReadVDW },
            "Read the Van der Waals radii from the file [TT]vdwradii.dat[tt] 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 [TT].pdb[tt] 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"
               "See the GROMACS manual for a description of the requirements that\n"
               "must be satisfied by descriptions of simulation cells.\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 if (!opt2parg_bSet("-bt", NPA, pa))
        {
            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 (resnr_start >= 0)
        {
            renum_resnr(&atoms, isize, index, resnr_start);
        }

        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 (resnr_start >= 0)
        {
            renum_resnr(&atoms, atoms.nr, NULL, resnr_start);
        }

        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;
}
void sas_plot(int nfile,t_filenm fnm[],real solsize,int ndots,
	      real qcut,gmx_bool bSave,real minarea,gmx_bool bPBC,
	      real dgs_default,gmx_bool bFindex, const output_env_t oenv)
{
  FILE         *fp,*fp2,*fp3=NULL,*vp;
  const char   *flegend[] = { "Hydrophobic", "Hydrophilic", 
			      "Total", "D Gsolv" };
  const char   *vlegend[] = { "Volume (nm\\S3\\N)", "Density (g/l)" };
  const char   *or_and_oa_legend[] = { "Average (nm\\S2\\N)", "Standard deviation (nm\\S2\\N)" };
  const char   *vfile;
  real         t;
  gmx_atomprop_t aps=NULL;
  gmx_rmpbc_t  gpbc=NULL;
  t_trxstatus  *status;
  int          ndefault;
  int          i,j,ii,nfr,natoms,flag,nsurfacedots,res;
  rvec         *xtop,*x;
  matrix       topbox,box;
  t_topology   top;
  char         title[STRLEN];
  int          ePBC;
  gmx_bool         bTop;
  t_atoms      *atoms;
  gmx_bool         *bOut,*bPhobic;
  gmx_bool         bConnelly;
  gmx_bool         bResAt,bITP,bDGsol;
  real         *radius,*dgs_factor=NULL,*area=NULL,*surfacedots=NULL;
  real         at_area,*atom_area=NULL,*atom_area2=NULL;
  real         *res_a=NULL,*res_area=NULL,*res_area2=NULL;
  real         totarea,totvolume,totmass=0,density,harea,tarea,fluc2;
  atom_id      **index,*findex;
  int          *nx,nphobic,npcheck,retval;
  char         **grpname,*fgrpname;
  real         dgsolv;

  bITP   = opt2bSet("-i",nfile,fnm);
  bResAt = opt2bSet("-or",nfile,fnm) || opt2bSet("-oa",nfile,fnm) || bITP;

  bTop = read_tps_conf(ftp2fn(efTPS,nfile,fnm),title,&top,&ePBC,
		       &xtop,NULL,topbox,FALSE);
  atoms = &(top.atoms);
  
  if (!bTop) {
    fprintf(stderr,"No tpr file, will not compute Delta G of solvation\n");
    bDGsol = FALSE;
  } else {
    bDGsol = strcmp(*(atoms->atomtype[0]),"?") != 0;
    if (!bDGsol) {
      fprintf(stderr,"Warning: your tpr file is too old, will not compute "
	      "Delta G of solvation\n");
    } else {
      printf("In case you use free energy of solvation predictions:\n");
      please_cite(stdout,"Eisenberg86a");
    }
  }

  aps = gmx_atomprop_init();
  
  if ((natoms=read_first_x(oenv,&status,ftp2fn(efTRX,nfile,fnm),
			   &t,&x,box))==0)
    gmx_fatal(FARGS,"Could not read coordinates from statusfile\n");

  if ((ePBC != epbcXYZ) || (TRICLINIC(box))) {
    fprintf(stderr,"\n\nWARNING: non-rectangular boxes may give erroneous results or crashes.\n"
	    "Analysis based on vacuum simulations (with the possibility of evaporation)\n" 
	    "will certainly crash the analysis.\n\n");
  }
  snew(nx,2);
  snew(index,2);
  snew(grpname,2);
  fprintf(stderr,"Select a group for calculation of surface and a group for output:\n");
  get_index(atoms,ftp2fn_null(efNDX,nfile,fnm),2,nx,index,grpname);

  if (bFindex) {
    fprintf(stderr,"Select a group of hydrophobic atoms:\n");
    get_index(atoms,ftp2fn_null(efNDX,nfile,fnm),1,&nphobic,&findex,&fgrpname);
  }
  snew(bOut,natoms);
  for(i=0; i<nx[1]; i++)
    bOut[index[1][i]] = TRUE;

  /* Now compute atomic readii including solvent probe size */
  snew(radius,natoms);
  snew(bPhobic,nx[0]);
  if (bResAt) {
    snew(atom_area,nx[0]);
    snew(atom_area2,nx[0]);
    snew(res_a,atoms->nres);
    snew(res_area,atoms->nres);
    snew(res_area2,atoms->nres);
  }
  if (bDGsol)
    snew(dgs_factor,nx[0]);

  /* Get a Van der Waals radius for each atom */
  ndefault = 0;
  for(i=0; (i<natoms); i++) {
    if (!gmx_atomprop_query(aps,epropVDW,
			    *(atoms->resinfo[atoms->atom[i].resind].name),
			    *(atoms->atomname[i]),&radius[i]))
      ndefault++;
    /* radius[i] = calc_radius(*(top->atoms.atomname[i])); */
    radius[i] += solsize;
  }
  if (ndefault > 0)
    fprintf(stderr,"WARNING: could not find a Van der Waals radius for %d atoms\n",ndefault);
  /* Determine which atom is counted as hydrophobic */
  if (bFindex) {
    npcheck = 0;
    for(i=0; (i<nx[0]); i++) {
      ii = index[0][i];
      for(j=0; (j<nphobic); j++) {
	if (findex[j] == ii) {
	  bPhobic[i] = TRUE;
	  if (bOut[ii])
	    npcheck++;
	}
      }
    }
    if (npcheck != nphobic)
      gmx_fatal(FARGS,"Consistency check failed: not all %d atoms in the hydrophobic index\n"
		  "found in the normal index selection (%d atoms)",nphobic,npcheck);
  }
  else
    nphobic = 0;
    
  for(i=0; (i<nx[0]); i++) {
    ii = index[0][i];
    if (!bFindex) {
      bPhobic[i] = fabs(atoms->atom[ii].q) <= qcut;
      if (bPhobic[i] && bOut[ii])
	nphobic++;
    }
    if (bDGsol)
      if (!gmx_atomprop_query(aps,epropDGsol,
			      *(atoms->resinfo[atoms->atom[ii].resind].name),
			      *(atoms->atomtype[ii]),&(dgs_factor[i])))
	dgs_factor[i] = dgs_default;
    if (debug)
      fprintf(debug,"Atom %5d %5s-%5s: q= %6.3f, r= %6.3f, dgsol= %6.3f, hydrophobic= %s\n",
	      ii+1,*(atoms->resinfo[atoms->atom[ii].resind].name),
	      *(atoms->atomname[ii]),
	      atoms->atom[ii].q,radius[ii]-solsize,dgs_factor[i],
	      BOOL(bPhobic[i]));
  }
  fprintf(stderr,"%d out of %d atoms were classified as hydrophobic\n",
	  nphobic,nx[1]);
  
  fp=xvgropen(opt2fn("-o",nfile,fnm),"Solvent Accessible Surface","Time (ps)",
	      "Area (nm\\S2\\N)",oenv);
  xvgr_legend(fp,asize(flegend) - (bDGsol ? 0 : 1),flegend,oenv);
  vfile = opt2fn_null("-tv",nfile,fnm);
  if (vfile) {
    if (!bTop) {
      gmx_fatal(FARGS,"Need a tpr file for option -tv");
    }
    vp=xvgropen(vfile,"Volume and Density","Time (ps)","",oenv);
    xvgr_legend(vp,asize(vlegend),vlegend,oenv);
    totmass  = 0;
    ndefault = 0;
    for(i=0; (i<nx[0]); i++) {
      real mm;
      ii = index[0][i];
      /*
      if (!query_atomprop(atomprop,epropMass,
			  *(top->atoms.resname[top->atoms.atom[ii].resnr]),
			  *(top->atoms.atomname[ii]),&mm))
	ndefault++;
      totmass += mm;
      */
      totmass += atoms->atom[ii].m;
    }
    if (ndefault)
      fprintf(stderr,"WARNING: Using %d default masses for density calculation, which most likely are inaccurate\n",ndefault);
  }
  else
    vp = NULL;
    
  gmx_atomprop_destroy(aps);

  if (bPBC)
    gpbc = gmx_rmpbc_init(&top.idef,ePBC,natoms,box);
  
  nfr=0;
  do {
    if (bPBC)
      gmx_rmpbc(gpbc,natoms,box,x);
    
    bConnelly = (nfr==0 && opt2bSet("-q",nfile,fnm));
    if (bConnelly) {
      if (!bTop)
	gmx_fatal(FARGS,"Need a tpr file for Connelly plot");
      flag = FLAG_ATOM_AREA | FLAG_DOTS;
    } else {
      flag = FLAG_ATOM_AREA;
    }
    if (vp) {
      flag = flag | FLAG_VOLUME;
    }
      
    if (debug)
      write_sto_conf("check.pdb","pbc check",atoms,x,NULL,ePBC,box);

    retval = nsc_dclm_pbc(x,radius,nx[0],ndots,flag,&totarea,
			  &area,&totvolume,&surfacedots,&nsurfacedots,
			  index[0],ePBC,bPBC ? box : NULL);
    if (retval)
      gmx_fatal(FARGS,"Something wrong in nsc_dclm_pbc");
    
    if (bConnelly)
      connelly_plot(ftp2fn(efPDB,nfile,fnm),
		    nsurfacedots,surfacedots,x,atoms,
		    &(top.symtab),ePBC,box,bSave);
    harea  = 0; 
    tarea  = 0;
    dgsolv = 0;
    if (bResAt)
      for(i=0; i<atoms->nres; i++)
	res_a[i] = 0;
    for(i=0; (i<nx[0]); i++) {
      ii = index[0][i];
      if (bOut[ii]) {
	at_area = area[i];
	if (bResAt) {
	  atom_area[i] += at_area;
	  atom_area2[i] += sqr(at_area);
	  res_a[atoms->atom[ii].resind] += at_area;
	}
	tarea += at_area;
	if (bDGsol)
	  dgsolv += at_area*dgs_factor[i];
	if (bPhobic[i])
	  harea += at_area;
      }
    }
    if (bResAt)
      for(i=0; i<atoms->nres; i++) {
	res_area[i] += res_a[i];
	res_area2[i] += sqr(res_a[i]);
      }
    fprintf(fp,"%10g  %10g  %10g  %10g",t,harea,tarea-harea,tarea);
    if (bDGsol)
      fprintf(fp,"  %10g\n",dgsolv);
    else
      fprintf(fp,"\n");
    
    /* Print volume */
    if (vp) {
      density = totmass*AMU/(totvolume*NANO*NANO*NANO);
      fprintf(vp,"%12.5e  %12.5e  %12.5e\n",t,totvolume,density);
    }
    if (area) {
      sfree(area);
      area = NULL;
    }
    if (surfacedots) {
      sfree(surfacedots);
      surfacedots = NULL;
    }
    nfr++;
  } while (read_next_x(oenv,status,&t,natoms,x,box));

  if (bPBC)  
    gmx_rmpbc_done(gpbc);

  fprintf(stderr,"\n");
  close_trj(status);
  ffclose(fp);
  if (vp)
    ffclose(vp);
    
  /* if necessary, print areas per atom to file too: */
  if (bResAt) {
    for(i=0; i<atoms->nres; i++) {
      res_area[i] /= nfr;
      res_area2[i] /= nfr;
    }
    for(i=0; i<nx[0]; i++) {
      atom_area[i] /= nfr;
      atom_area2[i] /= nfr;
    }
    fprintf(stderr,"Printing out areas per atom\n");
    fp  = xvgropen(opt2fn("-or",nfile,fnm),"Area per residue over the trajectory","Residue",
		   "Area (nm\\S2\\N)",oenv);
    xvgr_legend(fp, asize(or_and_oa_legend),or_and_oa_legend,oenv);
    fp2 = xvgropen(opt2fn("-oa",nfile,fnm),"Area per atom over the trajectory","Atom #",
		   "Area (nm\\S2\\N)",oenv);
    xvgr_legend(fp2, asize(or_and_oa_legend),or_and_oa_legend,oenv);
    if (bITP) {
      fp3 = ftp2FILE(efITP,nfile,fnm,"w");
      fprintf(fp3,"[ position_restraints ]\n"
	      "#define FCX 1000\n"
	      "#define FCY 1000\n"
	      "#define FCZ 1000\n"
	      "; Atom  Type  fx   fy   fz\n");
    }
    for(i=0; i<nx[0]; i++) {
      ii = index[0][i];
      res = atoms->atom[ii].resind;
      if (i==nx[0]-1 || res!=atoms->atom[index[0][i+1]].resind) {
	fluc2 = res_area2[res]-sqr(res_area[res]);
	if (fluc2 < 0)
	  fluc2 = 0;
	fprintf(fp,"%10d  %10g %10g\n",
		atoms->resinfo[res].nr,res_area[res],sqrt(fluc2));
      }
      fluc2 = atom_area2[i]-sqr(atom_area[i]);
      if (fluc2 < 0)
	fluc2 = 0;
      fprintf(fp2,"%d %g %g\n",index[0][i]+1,atom_area[i],sqrt(fluc2));
      if (bITP && (atom_area[i] > minarea))
	fprintf(fp3,"%5d   1     FCX  FCX  FCZ\n",ii+1);
    }
    if (bITP)
      ffclose(fp3);
    ffclose(fp);
  }

    /* Be a good citizen, keep our memory free! */
    sfree(x);
    sfree(nx);
    for(i=0;i<2;i++)
    {
        sfree(index[i]);
        sfree(grpname[i]);
    }
    sfree(bOut);
    sfree(radius);
    sfree(bPhobic);
    
    if(bResAt)
    {
        sfree(atom_area);
        sfree(atom_area2);
        sfree(res_a);
        sfree(res_area);
        sfree(res_area2);
    }
    if(bDGsol)
    {
        sfree(dgs_factor);
    }
}
示例#4
0
void set_file(t_x11 *x11,t_manager *man,char *trajectory,char *status)
{
  gmx_atomprop_t aps;
  char         buf[256],quote[256];
  t_tpxheader  sh;
  t_atoms      *at;
  bool         *bB;
  int          i,idum;
  real         rdum;

  read_tpxheader(status,&sh,TRUE,NULL,NULL);
  snew(man->ix,sh.natoms);
  snew(man->zz,sh.natoms);
  snew(man->col,sh.natoms);
  snew(man->size,sh.natoms);
  snew(man->vdw,sh.natoms);
  snew(man->bLabel,sh.natoms);
  snew(man->bVis,sh.natoms);
  for(i=0; (i<sh.natoms); i++)
    man->bVis[i]=FALSE;

  man->bPbc=FALSE;

  snew(man->szLab,sh.natoms);
  snew(man->bHydro,sh.natoms);
  snew(bB,sh.natoms);
  read_tpx_top(status,&(man->step),&(man->time),&rdum,NULL,man->box,
	       &man->natom,NULL,NULL,NULL,&man->top);
  
  man->natom=
    read_first_x(&man->status,trajectory,&(man->time),&(man->x),man->box);
  man->trajfile=strdup(trajectory);
  if (man->natom > man->top.atoms.nr)
    gmx_fatal(FARGS,"Topology %s (%d atoms) and trajectory %s (%d atoms) "
		"do not match",status,man->top.atoms.nr,
		trajectory,man->natom);
 
  cool_quote(quote,255,NULL);
  sprintf(buf,"%s: %s",*man->top.name,quote);
  man->title.text = strdup(buf);
  man->view       = init_view(man->box);
  at  = &(man->top.atoms);
  aps = gmx_atomprop_init();
  for(i=0; (i<man->natom); i++) {
    char *aname=*(at->atomname[i]);
    int  resnr=at->atom[i].resnr;

    man->col[i]=Type2Color(aname);
    snew(man->szLab[i],20);
    sprintf(man->szLab[i],"%s%d, %s",*(at->resname[resnr]),resnr+1,aname);
    man->bHydro[i]=(toupper(aname[0])=='H');
    if ( man->bHydro[i] )
      man->vdw[i]=0;
    else if (!gmx_atomprop_query(aps,epropVDW,
				 *(at->resname[resnr]),aname,
				 &(man->vdw[i])))
      man->vdw[i] = 0;
  }
  gmx_atomprop_destroy(aps);
  add_bpl(man,&(man->top.idef),bB);
  for(i=0; (i<man->natom); i++)
    if (!bB[i]) 
      add_object(man,eOSingle,(atom_id) i,0);
  sfree(bB);

  ExposeWin(x11->disp,man->molw->wd.self);
}
int gmx_genbox(int argc,char *argv[])
{
  const char *desc[] = {
    "[TT]genbox[tt] can do one of 3 things:[PAR]",
    
    "1) Generate a box of solvent. Specify [TT]-cs[tt] and [TT]-box[tt]. Or specify [TT]-cs[tt] and",
    "[TT]-cp[tt] with a structure file with a box, but without atoms.[PAR]",
    
    "2) Solvate a solute configuration, e.g. a protein, in a bath of solvent ",
    "molecules. Specify [TT]-cp[tt] (solute) and [TT]-cs[tt] (solvent). ",
    "The box specified in the solute coordinate file ([TT]-cp[tt]) is used,",
    "unless [TT]-box[tt] is set.",
    "If you want the solute to be centered in the box,",
    "the program [TT]editconf[tt] has sophisticated options",
    "to change the box dimensions and center the solute.",
    "Solvent molecules are removed from the box where the ",
    "distance between any atom of the solute molecule(s) and any atom of ",
    "the solvent molecule is less than the sum of the van der Waals radii of ",
    "both atoms. A database ([TT]vdwradii.dat[tt]) of van der Waals radii is ",
    "read by the program, and atoms not in the database are ",
    "assigned a default distance [TT]-vdwd[tt].",
    "Note that this option will also influence the distances between",
    "solvent molecules if they contain atoms that are not in the database.",
    "[PAR]",
    
    "3) Insert a number ([TT]-nmol[tt]) of extra molecules ([TT]-ci[tt]) ",
    "at random positions.",
    "The program iterates until [TT]nmol[tt] molecules",
    "have been inserted in the box. To test whether an insertion is ",
    "successful the same van der Waals criterium is used as for removal of ",
    "solvent molecules. When no appropriately-sized ",
    "holes (holes that can hold an extra molecule) are available, the ",
    "program tries for [TT]-nmol[tt] * [TT]-try[tt] times before giving up. ",
    "Increase [TT]-try[tt] if you have several small holes to fill.[PAR]",

    "If you need to do more than one of the above operations, it can be",
    "best to call [TT]genbox[tt] separately for each operation, so that",
    "you are sure of the order in which the operations occur.[PAR]",

    "The default solvent is Simple Point Charge water (SPC), with coordinates ",
    "from [TT]$GMXLIB/spc216.gro[tt]. These coordinates can also be used",
    "for other 3-site water models, since a short equibilibration will remove",
    "the small differences between the models.",
    "Other solvents are also supported, as well as mixed solvents. The",
    "only restriction to solvent types is that a solvent molecule consists",
    "of exactly one residue. The residue information in the coordinate",
    "files is used, and should therefore be more or less consistent.",
    "In practice this means that two subsequent solvent molecules in the ",
    "solvent coordinate file should have different residue number.",
    "The box of solute is built by stacking the coordinates read from",
    "the coordinate file. This means that these coordinates should be ",
    "equlibrated in periodic boundary conditions to ensure a good",
    "alignment of molecules on the stacking interfaces.",
    "The [TT]-maxsol[tt] option simply adds only the first [TT]-maxsol[tt]",
    "solvent molecules and leaves out the rest would have fit into the box.",
    "[PAR]",
    
    "The program can optionally rotate the solute molecule to align the",
    "longest molecule axis along a box edge. This way the amount of solvent",
    "molecules necessary is reduced.",
    "It should be kept in mind that this only works for",
    "short simulations, as e.g. an alpha-helical peptide in solution can ",
    "rotate over 90 degrees, within 500 ps. In general it is therefore ",
    "better to make a more or less cubic box.[PAR]",
    
    "Setting [TT]-shell[tt] larger than zero will place a layer of water of",
    "the specified thickness (nm) around the solute. Hint: it is a good",
    "idea to put the protein in the center of a box first (using [TT]editconf[tt]).",
    "[PAR]",
    
    "Finally, [TT]genbox[tt] will optionally remove lines from your topology file in ",
    "which a number of solvent molecules is already added, and adds a ",
    "line with the total number of solvent molecules in your coordinate file."
  };

  const char *bugs[] = {
    "Molecules must be whole in the initial configurations.",
  };
  
  /* parameter data */
  gmx_bool bSol,bProt,bBox;
  const char *conf_prot,*confout;
  int  bInsert;
  real *r;
  char *title_ins;
  gmx_atomprop_t aps;
  
  /* protein configuration data */
  char    *title=NULL;
  t_atoms atoms;
  rvec    *x,*v=NULL;
  int     ePBC=-1;
  matrix  box;
  t_pbc   pbc;
    
  /* other data types */
  int  atoms_added,residues_added;
  
  t_filenm fnm[] = {
    { efSTX, "-cp", "protein", ffOPTRD },
    { efSTX, "-cs", "spc216",  ffLIBOPTRD},
    { efSTX, "-ci", "insert",  ffOPTRD},
    { efSTO, NULL,  NULL,      ffWRITE},
    { efTOP, NULL,  NULL,      ffOPTRW},
  };
#define NFILE asize(fnm)
  
  static int nmol_ins=0,nmol_try=10,seed=1997;
  static real r_distance=0.105,r_shell=0;
  static rvec new_box={0.0,0.0,0.0};
  static gmx_bool bReadV=FALSE;
  static int  max_sol = 0;
  output_env_t oenv;
  t_pargs pa[] = {
    { "-box",    FALSE, etRVEC, {new_box},   
      "box size" },
    { "-nmol",   FALSE, etINT , {&nmol_ins},  
      "no of extra molecules to insert" },
    { "-try",    FALSE, etINT , {&nmol_try},  
      "try inserting [TT]-nmol[tt] times [TT]-try[tt] times" },
    { "-seed",   FALSE, etINT , {&seed},      
      "random generator seed"},
    { "-vdwd",   FALSE, etREAL, {&r_distance},
      "default vdwaals distance"},
    { "-shell",  FALSE, etREAL, {&r_shell},
      "thickness of optional water layer around solute" },
    { "-maxsol", FALSE, etINT,  {&max_sol},
      "maximum number of solvent molecules to add if they fit in the box. If zero (default) this is ignored" },
    { "-vel",    FALSE, etBOOL, {&bReadV},
      "keep velocities from input solute and solvent" }
  };

  CopyRight(stderr,argv[0]);
  parse_common_args(&argc,argv, PCA_BE_NICE,NFILE,fnm,asize(pa),pa,
		    asize(desc),desc,asize(bugs),bugs,&oenv);
  
  bInsert   = opt2bSet("-ci",NFILE,fnm) && (nmol_ins > 0);
  bSol      = opt2bSet("-cs",NFILE,fnm);
  bProt     = opt2bSet("-cp",NFILE,fnm);
  bBox      = opt2parg_bSet("-box",asize(pa),pa);
     
  /* check input */
  if (bInsert && nmol_ins<=0)
    gmx_fatal(FARGS,"When specifying inserted molecules (-ci), "
		"-nmol must be larger than 0");
  if (!bProt && !bBox)
    gmx_fatal(FARGS,"When no solute (-cp) is specified, "
		"a box size (-box) must be specified");

  aps = gmx_atomprop_init();
  
  if (bProt) {
    /*generate a solute configuration */
    conf_prot = opt2fn("-cp",NFILE,fnm);
    title = read_prot(conf_prot,&atoms,&x,bReadV?&v:NULL,&r,&ePBC,box,
		      aps,r_distance);
    if (bReadV && !v)
      fprintf(stderr,"Note: no velocities found\n");
    if (atoms.nr == 0) {
      fprintf(stderr,"Note: no atoms in %s\n",conf_prot);
      bProt = FALSE;
    }
  } 
  if (!bProt) {
    atoms.nr=0;
    atoms.nres=0;
    atoms.resinfo=NULL;
    atoms.atomname=NULL;
    atoms.atom=NULL;
    atoms.pdbinfo=NULL;
    x=NULL;
    r=NULL;
  }
  if (bBox) {
    ePBC = epbcXYZ;
    clear_mat(box);
    box[XX][XX]=new_box[XX];
    box[YY][YY]=new_box[YY];
    box[ZZ][ZZ]=new_box[ZZ];
  }
  if (det(box) == 0) 
    gmx_fatal(FARGS,"Undefined solute box.\nCreate one with editconf "
		"or give explicit -box command line option");
  
  /* add nmol_ins molecules of atoms_ins 
     in random orientation at random place */
  if (bInsert) 
    title_ins = insert_mols(opt2fn("-ci",NFILE,fnm),nmol_ins,nmol_try,seed,
			    &atoms,&x,&r,ePBC,box,aps,r_distance,r_shell,
                            oenv);
  else
    title_ins = strdup("Generated by genbox");
  
  /* add solvent */
  if (bSol)
    add_solv(opt2fn("-cs",NFILE,fnm),&atoms,&x,v?&v:NULL,&r,ePBC,box,
	     aps,r_distance,&atoms_added,&residues_added,r_shell,max_sol,
             oenv);
	     
  /* write new configuration 1 to file confout */
  confout = ftp2fn(efSTO,NFILE,fnm);
  fprintf(stderr,"Writing generated configuration to %s\n",confout);
  if (bProt) {
    write_sto_conf(confout,title,&atoms,x,v,ePBC,box);
    /* print box sizes and box type to stderr */
    fprintf(stderr,"%s\n",title);  
  } else 
    write_sto_conf(confout,title_ins,&atoms,x,v,ePBC,box);
  
  /* print size of generated configuration */
  fprintf(stderr,"\nOutput configuration contains %d atoms in %d residues\n",
	  atoms.nr,atoms.nres);
  update_top(&atoms,box,NFILE,fnm,aps);
	  
  gmx_atomprop_destroy(aps);
  
  thanx(stderr);
  
  return 0;
}
示例#6
0
void set_file(t_x11 *x11, t_manager *man, const char *trajectory,
              const char *status)
{
    gmx_atomprop_t    aps;
    t_tpxheader       sh;
    t_atoms          *at;
    bool             *bB;
    int               i;

    read_tpxheader(status, &sh, true);
    snew(man->ix, sh.natoms);
    snew(man->zz, sh.natoms);
    snew(man->col, sh.natoms);
    snew(man->size, sh.natoms);
    snew(man->vdw, sh.natoms);
    snew(man->bLabel, sh.natoms);
    snew(man->bVis, sh.natoms);
    for (i = 0; (i < sh.natoms); i++)
    {
        man->bVis[i] = false;
    }

    man->bPbc = false;

    snew(man->szLab, sh.natoms);
    snew(man->bHydro, sh.natoms);
    snew(bB, sh.natoms);
    read_tpx_top(status, nullptr, man->box, &man->natom, nullptr, nullptr, &man->top);
    man->gpbc = gmx_rmpbc_init(&man->top.idef, -1, man->natom);

    man->natom =
        read_first_x(man->oenv, &man->status, trajectory, &(man->time), &(man->x),
                     man->box);
    man->trajfile = gmx_strdup(trajectory);
    if (man->natom > man->top.atoms.nr)
    {
        gmx_fatal(FARGS, "Topology %s (%d atoms) and trajectory %s (%d atoms) "
                  "do not match", status, man->top.atoms.nr,
                  trajectory, man->natom);
    }

    man->title.text = gmx_strdup(gmx::formatString("%s: %s", *man->top.name, gmx::getCoolQuote().c_str()).c_str());
    man->view       = init_view(man->box);
    at              = &(man->top.atoms);
    aps             = gmx_atomprop_init();
    for (i = 0; (i < man->natom); i++)
    {
        char      *aname = *(at->atomname[i]);
        t_resinfo *ri    = &at->resinfo[at->atom[i].resind];

        man->col[i] = Type2Color(aname);
        snew(man->szLab[i], 20);
        if (ri->ic != ' ')
        {
            std::sprintf(man->szLab[i], "%s%d%c, %s", *ri->name, ri->nr, ri->ic, aname);
        }
        else
        {
            std::sprintf(man->szLab[i], "%s%d, %s", *ri->name, ri->nr, aname);
        }
        man->bHydro[i] = (toupper(aname[0]) == 'H');
        if (man->bHydro[i])
        {
            man->vdw[i] = 0;
        }
        else if (!gmx_atomprop_query(aps, epropVDW, *ri->name, aname, &(man->vdw[i])))
        {
            man->vdw[i] = 0;
        }
    }
    gmx_atomprop_destroy(aps);
    add_bpl(man, &(man->top.idef), bB);
    for (i = 0; (i < man->natom); i++)
    {
        if (!bB[i])
        {
            add_object(man, eOSingle, (int) i, 0);
        }
    }
    sfree(bB);

    ExposeWin(x11->disp, man->molw->wd.self);
}
示例#7
0
文件: g_x2top.c 项目: hasagar/gromacs
int cmain(int argc, char *argv[])
{
    const char        *desc[] = {
        "[TT]g_x2top[tt] generates a primitive topology from a coordinate file.",
        "The program assumes all hydrogens are present when defining",
        "the hybridization from the atom name and the number of bonds.",
        "The program can also make an [TT].rtp[tt] entry, which you can then add",
        "to the [TT].rtp[tt] database.[PAR]",
        "When [TT]-param[tt] is set, equilibrium distances and angles",
        "and force constants will be printed in the topology for all",
        "interactions. The equilibrium distances and angles are taken",
        "from the input coordinates, the force constant are set with",
        "command line options.",
        "The force fields somewhat supported currently are:[PAR]",
        "G53a5  GROMOS96 53a5 Forcefield (official distribution)[PAR]",
        "oplsaa OPLS-AA/L all-atom force field (2001 aminoacid dihedrals)[PAR]",
        "The corresponding data files can be found in the library directory",
        "with name [TT]atomname2type.n2t[tt]. Check Chapter 5 of the manual for more",
        "information about file formats. By default, the force field selection",
        "is interactive, but you can use the [TT]-ff[tt] option to specify",
        "one of the short names above on the command line instead. In that",
        "case [TT]g_x2top[tt] just looks for the corresponding file.[PAR]",
    };
    const char        *bugs[] = {
        "The atom type selection is primitive. Virtually no chemical knowledge is used",
        "Periodic boundary conditions screw up the bonding",
        "No improper dihedrals are generated",
        "The atoms to atomtype translation table is incomplete ([TT]atomname2type.n2t[tt] file in the data directory). Please extend it and send the results back to the GROMACS crew."
    };
    FILE              *fp;
    t_params           plist[F_NRE];
    t_excls           *excls;
    t_atoms           *atoms; /* list with all atoms */
    gpp_atomtype_t     atype;
    t_nextnb           nnb;
    t_nm2type         *nm2t;
    t_mols             mymol;
    gmx_atomprop_t     aps;
    int                nnm;
    char               title[STRLEN], forcefield[32], ffdir[STRLEN];
    rvec              *x; /* coordinates? */
    int               *nbonds, *cgnr;
    int                bts[] = { 1, 1, 1, 2 };
    matrix             box;    /* box length matrix */
    int                natoms; /* number of atoms in one molecule  */
    int                nres;   /* number of molecules? */
    int                i, j, k, l, m, ndih;
    int                epbc;
    gmx_bool           bRTP, bTOP, bOPLS;
    t_symtab           symtab;
    real               cutoff, qtot, mtot;
    char               n2t[STRLEN];
    output_env_t       oenv;

    t_filenm           fnm[] = {
        { efSTX, "-f", "conf", ffREAD  },
        { efTOP, "-o", "out",  ffOPTWR },
        { efRTP, "-r", "out",  ffOPTWR }
    };
#define NFILE asize(fnm)
    static real        scale = 1.1, kb = 4e5, kt = 400, kp = 5;
    static t_restp     rtp_header_settings;
    static gmx_bool    bRemoveDihedralIfWithImproper = FALSE;
    static gmx_bool    bGenerateHH14Interactions     = TRUE;
    static gmx_bool    bKeepAllGeneratedDihedrals    = FALSE;
    static int         nrexcl                        = 3;
    static gmx_bool    bParam                        = TRUE, bRound = TRUE;
    static gmx_bool    bPairs                        = TRUE, bPBC = TRUE;
    static gmx_bool    bUsePDBcharge                 = FALSE, bVerbose = FALSE;
    static const char *molnm                         = "ICE";
    static const char *ff                            = "oplsaa";
    t_pargs            pa[]                          = {
        { "-ff",     FALSE, etSTR, {&ff},
          "Force field for your simulation. Type \"select\" for interactive selection." },
        { "-v",      FALSE, etBOOL, {&bVerbose},
          "Generate verbose output in the top file." },
        { "-nexcl", FALSE, etINT,  {&nrexcl},
          "Number of exclusions" },
        { "-H14",    FALSE, etBOOL, {&bGenerateHH14Interactions},
          "Use 3rd neighbour interactions for hydrogen atoms" },
        { "-alldih", FALSE, etBOOL, {&bKeepAllGeneratedDihedrals},
          "Generate all proper dihedrals" },
        { "-remdih", FALSE, etBOOL, {&bRemoveDihedralIfWithImproper},
          "Remove dihedrals on the same bond as an improper" },
        { "-pairs",  FALSE, etBOOL, {&bPairs},
          "Output 1-4 interactions (pairs) in topology file" },
        { "-name",   FALSE, etSTR,  {&molnm},
          "Name of your molecule" },
        { "-pbc",    FALSE, etBOOL, {&bPBC},
          "Use periodic boundary conditions." },
        { "-pdbq",  FALSE, etBOOL, {&bUsePDBcharge},
          "Use the B-factor supplied in a [TT].pdb[tt] file for the atomic charges" },
        { "-param", FALSE, etBOOL, {&bParam},
          "Print parameters in the output" },
        { "-round",  FALSE, etBOOL, {&bRound},
          "Round off measured values" },
        { "-kb",    FALSE, etREAL, {&kb},
          "Bonded force constant (kJ/mol/nm^2)" },
        { "-kt",    FALSE, etREAL, {&kt},
          "Angle force constant (kJ/mol/rad^2)" },
        { "-kp",    FALSE, etREAL, {&kp},
          "Dihedral angle force constant (kJ/mol/rad^2)" }
    };

    CopyRight(stderr, argv[0]);

    parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
                      asize(desc), desc, asize(bugs), bugs, &oenv);
    bRTP = opt2bSet("-r", NFILE, fnm);
    bTOP = opt2bSet("-o", NFILE, fnm);
    /* C89 requirements mean that these struct members cannot be used in
     * the declaration of pa. So some temporary variables are needed. */
    rtp_header_settings.bRemoveDihedralIfWithImproper = bRemoveDihedralIfWithImproper;
    rtp_header_settings.bGenerateHH14Interactions     = bGenerateHH14Interactions;
    rtp_header_settings.bKeepAllGeneratedDihedrals    = bKeepAllGeneratedDihedrals;
    rtp_header_settings.nrexcl = nrexcl;

    if (!bRTP && !bTOP)
    {
        gmx_fatal(FARGS, "Specify at least one output file");
    }

    aps = gmx_atomprop_init();

    /* Force field selection, interactive or direct */
    choose_ff(strcmp(ff, "select") == 0 ? NULL : ff,
              forcefield, sizeof(forcefield),
              ffdir, sizeof(ffdir));

    bOPLS = (strcmp(forcefield, "oplsaa") == 0);


    mymol.name = strdup(molnm);
    mymol.nr   = 1;

    /* Init parameter lists */
    init_plist(plist);

    /* Read coordinates */
    get_stx_coordnum(opt2fn("-f", NFILE, fnm), &natoms);
    snew(atoms, 1);

    /* make space for all the atoms */
    init_t_atoms(atoms, natoms, TRUE);
    snew(x, natoms);

    read_stx_conf(opt2fn("-f", NFILE, fnm), title, atoms, x, NULL, &epbc, box);

    sprintf(n2t, "%s", ffdir);
    nm2t = rd_nm2type(n2t, &nnm);
    if (nnm == 0)
    {
        gmx_fatal(FARGS, "No or incorrect atomname2type.n2t file found (looking for %s)",
                  n2t);
    }
    else
    {
        printf("There are %d name to type translations in file %s\n", nnm, n2t);
    }
    if (debug)
    {
        dump_nm2type(debug, nnm, nm2t);
    }
    printf("Generating bonds from distances...\n");
    snew(nbonds, atoms->nr);
    mk_bonds(nnm, nm2t, atoms, x, &(plist[F_BONDS]), nbonds, forcefield,
             bPBC, box, aps);

    open_symtab(&symtab);
    atype = set_atom_type(&symtab, atoms, &(plist[F_BONDS]), nbonds, nnm, nm2t);

    /* Make Angles and Dihedrals */
    snew(excls, atoms->nr);
    printf("Generating angles and dihedrals from bonds...\n");
    init_nnb(&nnb, atoms->nr, 4);
    gen_nnb(&nnb, plist);
    print_nnb(&nnb, "NNB");
    gen_pad(&nnb, atoms, &rtp_header_settings, plist, excls, NULL, TRUE);
    done_nnb(&nnb);

    if (!bPairs)
    {
        plist[F_LJ14].nr = 0;
    }
    fprintf(stderr,
            "There are %4d %s dihedrals, %4d impropers, %4d angles\n"
            "          %4d pairs,     %4d bonds and  %4d atoms\n",
            plist[F_PDIHS].nr,
            bOPLS ? "Ryckaert-Bellemans" : "proper",
            plist[F_IDIHS].nr, plist[F_ANGLES].nr,
            plist[F_LJ14].nr, plist[F_BONDS].nr, atoms->nr);

    calc_angles_dihs(&plist[F_ANGLES], &plist[F_PDIHS], x, bPBC, box);

    set_force_const(plist, kb, kt, kp, bRound, bParam);

    cgnr = set_cgnr(atoms, bUsePDBcharge, &qtot, &mtot);
    printf("Total charge is %g, total mass is %g\n", qtot, mtot);
    if (bOPLS)
    {
        bts[2] = 3;
        bts[3] = 1;
    }

    if (bTOP)
    {
        fp = ftp2FILE(efTOP, NFILE, fnm, "w");
        print_top_header(fp, ftp2fn(efTOP, NFILE, fnm),
                         "Generated by x2top", TRUE, ffdir, 1.0);

        write_top(fp, NULL, mymol.name, atoms, FALSE, bts, plist, excls, atype,
                  cgnr, rtp_header_settings.nrexcl);
        print_top_mols(fp, mymol.name, ffdir, NULL, 0, NULL, 1, &mymol);

        ffclose(fp);
    }
    if (bRTP)
    {
        print_rtp(ftp2fn(efRTP, NFILE, fnm), "Generated by x2top",
                  atoms, plist, atype, cgnr, asize(bts), bts);
    }

    if (debug)
    {
        dump_hybridization(debug, atoms, nbonds);
    }
    close_symtab(&symtab);
    free(mymol.name);

    printf("\nWARNING: topologies generated by %s can not be trusted at face value.\n", Program());
    printf("         Please verify atomtypes and charges by comparison to other\n");
    printf("         topologies.\n");

    thanx(stderr);

    return 0;
}
示例#8
0
gmx_bool read_tps_conf(const char *infile, t_topology *top, int *ePBC,
                       rvec **x, rvec **v, matrix box, gmx_bool bMass)
{
    t_tpxheader      header;
    int              natoms, i;
    gmx_bool         bTop, bXNULL = FALSE;
    gmx_mtop_t      *mtop;
    gmx_atomprop_t   aps;

    bTop  = fn2bTPX(infile);
    if (ePBC != NULL)
    {
        *ePBC = -1;
    }
    if (bTop)
    {
        read_tpxheader(infile, &header, TRUE);
        if (x)
        {
            snew(*x, header.natoms);
        }
        if (v)
        {
            snew(*v, header.natoms);
        }
        snew(mtop, 1);
        int ePBC_tmp
            = read_tpx(infile, NULL, box, &natoms,
                       (x == NULL) ? NULL : *x, (v == NULL) ? NULL : *v, mtop);
        if (ePBC != NULL)
        {
            *ePBC = ePBC_tmp;
        }
        *top = gmx_mtop_t_to_t_topology(mtop);
        /* In this case we need to throw away the group data too */
        done_gmx_groups_t(&mtop->groups);
        sfree(mtop);
        tpx_make_chain_identifiers(&top->atoms, &top->mols);
    }
    else
    {
        open_symtab(&top->symtab);
        get_stx_coordnum(infile, &natoms);
        init_t_atoms(&top->atoms, natoms, (fn2ftp(infile) == efPDB));
        if (x == NULL)
        {
            snew(x, 1);
            bXNULL = TRUE;
        }
        snew(*x, natoms);
        if (v)
        {
            snew(*v, natoms);
        }
        read_stx_conf(infile, top, *x, (v == NULL) ? NULL : *v, ePBC, box);
        if (bXNULL)
        {
            sfree(*x);
            sfree(x);
        }
        if (bMass)
        {
            aps = gmx_atomprop_init();
            for (i = 0; (i < natoms); i++)
            {
                if (!gmx_atomprop_query(aps, epropMass,
                                        *top->atoms.resinfo[top->atoms.atom[i].resind].name,
                                        *top->atoms.atomname[i],
                                        &(top->atoms.atom[i].m)))
                {
                    if (debug)
                    {
                        fprintf(debug, "Can not find mass for atom %s %d %s, setting to 1\n",
                                *top->atoms.resinfo[top->atoms.atom[i].resind].name,
                                top->atoms.resinfo[top->atoms.atom[i].resind].nr,
                                *top->atoms.atomname[i]);
                    }
                }
            }
            gmx_atomprop_destroy(aps);
        }
        top->idef.ntypes = -1;
    }

    return bTop;
}
示例#9
0
int gmx_insert_molecules(int argc, char *argv[])
{
    const char *desc[] = {
        "[THISMODULE] inserts [TT]-nmol[tt] copies of the system specified in",
        "the [TT]-ci[tt] input file. The insertions take place either into",
        "vacant space in the solute conformation given with [TT]-f[tt], or",
        "into an empty box given by [TT]-box[tt]. Specifying both [TT]-f[tt]",
        "and [TT]-box[tt] behaves like [TT]-f[tt], but places a new box",
        "around the solute before insertions. Any velocities present are",
        "discarded.[PAR]",

        "By default, the insertion positions are random (with initial seed",
        "specified by [TT]-seed[tt]). The program iterates until [TT]-nmol[tt]",
        "molecules have been inserted in the box. Molecules are not inserted",
        "where the distance between any existing atom and any atom of the",
        "inserted molecule is less than the sum based on the van der Waals",
        "radii of both atoms. A database ([TT]vdwradii.dat[tt]) of van der",
        "Waals radii is read by the program, and the resulting radii scaled",
        "by [TT]-scale[tt]. If radii are not found in the database, those"
        "atoms are assigned the (pre-scaled) distance [TT]-radius[tt].[PAR]",

        "A total of [TT]-nmol[tt] * [TT]-try[tt] insertion attempts are made",
        "before giving up. Increase [TT]-try[tt] if you have several small",
        "holes to fill. Option [TT]-rot[tt] specifies whether the insertion",
        "molecules are randomly oriented before insertion attempts.[PAR]",

        "Alternatively, the molecules can be inserted only at positions defined in",
        "positions.dat ([TT]-ip[tt]). That file should have 3 columns (x,y,z),",
        "that give the displacements compared to the input molecule position",
        "([TT]-ci[tt]). Hence, if that file should contain the absolute",
        "positions, the molecule must be centered on (0,0,0) before using",
        "[THISMODULE] (e.g. from [gmx-editconf] [TT]-center[tt]).",
        "Comments in that file starting with # are ignored. Option [TT]-dr[tt]",
        "defines the maximally allowed displacements during insertial trials.",
        "[TT]-try[tt] and [TT]-rot[tt] work as in the default mode (see above).",
        "[PAR]",
    };

    /* parameter data */
    real          *exclusionDistances       = NULL;
    real          *exclusionDistances_insrt = NULL;

    /* protein configuration data */
    char          *title = NULL;
    t_atoms       *atoms, *atoms_insrt;
    rvec          *x    = NULL, *x_insrt = NULL;
    int            ePBC = -1;
    matrix         box;

    t_filenm       fnm[] = {
        { efSTX, "-f", "protein", ffOPTRD },
        { efSTX, "-ci", "insert",  ffREAD},
        { efDAT, "-ip", "positions",  ffOPTRD},
        { efSTO, NULL,  NULL,      ffWRITE},
    };
#define NFILE asize(fnm)

    static int      nmol_ins               = 0, nmol_try = 10, seed = 1997;
    static real     defaultDistance        = 0.105, scaleFactor = 0.57;
    static rvec     new_box                = {0.0, 0.0, 0.0}, deltaR = {0.0, 0.0, 0.0};
    output_env_t    oenv;
    const char     *enum_rot_string[] = {NULL, "xyz", "z", "none", NULL};
    t_pargs         pa[]              = {
        { "-box",    FALSE, etRVEC, {new_box},
          "Box size (in nm)" },
        { "-nmol",   FALSE, etINT, {&nmol_ins},
          "Number of extra molecules to insert" },
        { "-try",    FALSE, etINT, {&nmol_try},
          "Try inserting [TT]-nmol[tt] times [TT]-try[tt] times" },
        { "-seed",   FALSE, etINT, {&seed},
          "Random generator seed"},
        { "-radius",   FALSE, etREAL, {&defaultDistance},
          "Default van der Waals distance"},
        { "-scale", FALSE, etREAL, {&scaleFactor},
          "Scale factor to multiply Van der Waals radii from the database in share/gromacs/top/vdwradii.dat. The default value of 0.57 yields density close to 1000 g/l for proteins in water." },
        { "-dr",    FALSE, etRVEC, {deltaR},
          "Allowed displacement in x/y/z from positions in [TT]-ip[tt] file" },
        { "-rot", FALSE,  etENUM, {enum_rot_string},
          "rotate inserted molecules randomly" }
    };

    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
                           asize(desc), desc, 0, NULL, &oenv))
    {
        return 0;
    }

    const bool        bProt    = opt2bSet("-f", NFILE, fnm);
    const bool        bBox     = opt2parg_bSet("-box", asize(pa), pa);
    const char *const posfn    = opt2fn_null("-ip", NFILE, fnm);
    const int         enum_rot = nenum(enum_rot_string);

    /* check input */
    if (nmol_ins <= 0 && !opt2bSet("-ip", NFILE, fnm))
    {
        gmx_fatal(FARGS, "Either -nmol must be larger than 0, "
                  "or positions must be given with -ip");
    }
    if (!bProt && !bBox)
    {
        gmx_fatal(FARGS, "When no solute (-f) is specified, "
                  "a box size (-box) must be specified");
    }

    gmx_atomprop_t aps = gmx_atomprop_init();

    snew(atoms, 1);
    init_t_atoms(atoms, 0, FALSE);
    if (bProt)
    {
        /* Generate a solute configuration */
        const char *conf_prot = opt2fn("-f", NFILE, fnm);
        title                 = readConformation(conf_prot, atoms, &x, NULL,
                                                 &ePBC, box);
        exclusionDistances = makeExclusionDistances(atoms, aps, defaultDistance, scaleFactor);
        if (atoms->nr == 0)
        {
            fprintf(stderr, "Note: no atoms in %s\n", conf_prot);
            sfree(title);
            title = NULL;
        }
    }
    if (bBox)
    {
        ePBC = epbcXYZ;
        clear_mat(box);
        box[XX][XX] = new_box[XX];
        box[YY][YY] = new_box[YY];
        box[ZZ][ZZ] = new_box[ZZ];
    }
    if (det(box) == 0)
    {
        gmx_fatal(FARGS, "Undefined solute box.\nCreate one with gmx editconf "
                  "or give explicit -box command line option");
    }
    snew(atoms_insrt, 1);
    init_t_atoms(atoms_insrt, 0, FALSE);
    {
        int         ePBC_dummy;
        matrix      box_dummy;
        const char *conf_insrt = opt2fn("-ci", NFILE, fnm);
        char       *title_ins
            = readConformation(conf_insrt, atoms_insrt, &x_insrt, NULL,
                               &ePBC_dummy, box_dummy);
        if (atoms_insrt->nr == 0)
        {
            gmx_fatal(FARGS, "No molecule in %s, please check your input", conf_insrt);
        }
        if (title == NULL)
        {
            title = title_ins;
        }
        else
        {
            sfree(title_ins);
        }
        if (posfn == NULL)
        {
            center_molecule(atoms_insrt->nr, x_insrt);
        }
        exclusionDistances_insrt = makeExclusionDistances(atoms_insrt, aps, defaultDistance, scaleFactor);
    }

    gmx_atomprop_destroy(aps);

    /* add nmol_ins molecules of atoms_ins
       in random orientation at random place */
    insert_mols(nmol_ins, nmol_try, seed,
                atoms, &x, &exclusionDistances,
                atoms_insrt, x_insrt, exclusionDistances_insrt,
                ePBC, box, posfn, deltaR, enum_rot);

    /* write new configuration to file confout */
    const char *confout = ftp2fn(efSTO, NFILE, fnm);
    fprintf(stderr, "Writing generated configuration to %s\n", confout);
    write_sto_conf(confout, title, atoms, x, NULL, ePBC, box);

    /* print size of generated configuration */
    fprintf(stderr, "\nOutput configuration contains %d atoms in %d residues\n",
            atoms->nr, atoms->nres);

    sfree(exclusionDistances);
    sfree(exclusionDistances_insrt);
    sfree(x);
    done_atom(atoms);
    done_atom(atoms_insrt);
    sfree(atoms);
    sfree(atoms_insrt);
    sfree(title);

    return 0;
}
static void insert_mols(int nmol_insrt, int ntry, int seed,
                        real defaultDistance, real scaleFactor,
                        t_atoms *atoms, rvec **x,
                        const t_atoms *atoms_insrt, const rvec *x_insrt,
                        int ePBC, matrix box,
                        const std::string &posfn, const rvec deltaR, int enum_rot)
{
    t_pbc            pbc;
    rvec            *x_n;

    fprintf(stderr, "Initialising inter-atomic distances...\n");
    gmx_atomprop_t   aps = gmx_atomprop_init();
    real            *exclusionDistances
        = makeExclusionDistances(atoms, aps, defaultDistance, scaleFactor);
    real            *exclusionDistances_insrt
        = makeExclusionDistances(atoms_insrt, aps, defaultDistance, scaleFactor);
    gmx_atomprop_destroy(aps);

    const real       maxInsertRadius
        = *std::max_element(exclusionDistances_insrt,
                            exclusionDistances_insrt + atoms_insrt->nr);
    real             maxRadius = maxInsertRadius;
    if (atoms->nr > 0)
    {
        const real maxExistingRadius
            = *std::max_element(exclusionDistances,
                                exclusionDistances + atoms->nr);
        maxRadius = std::max(maxInsertRadius, maxExistingRadius);
    }

    // TODO: Make all of this exception-safe.
    gmx::AnalysisNeighborhood nb;
    nb.setCutoff(maxInsertRadius + maxRadius);

    gmx_rng_t        rng = gmx_rng_init(seed);
    set_pbc(&pbc, ePBC, box);

    snew(x_n, atoms_insrt->nr);

    /* With -ip, take nmol_insrt from file posfn */
    double         **rpos = NULL;
    if (!posfn.empty())
    {
        int ncol;
        nmol_insrt = read_xvg(posfn.c_str(), &rpos, &ncol);
        if (ncol != 3)
        {
            gmx_fatal(FARGS, "Expected 3 columns (x/y/z coordinates) in file %s\n",
                      posfn.c_str());
        }
        fprintf(stderr, "Read %d positions from file %s\n\n",
                nmol_insrt, posfn.c_str());
    }

    {
        const int finalAtomCount    = atoms->nr + nmol_insrt * atoms_insrt->nr;
        const int finalResidueCount = atoms->nres + nmol_insrt * atoms_insrt->nres;
        srenew(atoms->resinfo,      finalResidueCount);
        srenew(atoms->atomname,     finalAtomCount);
        srenew(atoms->atom,         finalAtomCount);
        srenew(*x,                  finalAtomCount);
        srenew(exclusionDistances,  finalAtomCount);
    }

    int mol        = 0;
    int trial      = 0;
    int firstTrial = 0;
    int failed     = 0;
    while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt))
    {
        rvec offset_x;
        if (posfn.empty())
        {
            // Insert at random positions.
            offset_x[XX] = box[XX][XX] * gmx_rng_uniform_real(rng);
            offset_x[YY] = box[YY][YY] * gmx_rng_uniform_real(rng);
            offset_x[ZZ] = box[ZZ][ZZ] * gmx_rng_uniform_real(rng);
        }
        else
        {
            // Skip a position if ntry trials were not successful.
            if (trial >= firstTrial + ntry)
            {
                fprintf(stderr, " skipped position (%.3f, %.3f, %.3f)\n",
                        rpos[XX][mol], rpos[YY][mol], rpos[ZZ][mol]);
                ++mol;
                ++failed;
            }
            // Insert at positions taken from option -ip file.
            offset_x[XX] = rpos[XX][mol] + deltaR[XX]*(2 * gmx_rng_uniform_real(rng)-1);
            offset_x[YY] = rpos[YY][mol] + deltaR[YY]*(2 * gmx_rng_uniform_real(rng)-1);
            offset_x[ZZ] = rpos[ZZ][mol] + deltaR[ZZ]*(2 * gmx_rng_uniform_real(rng)-1);
        }
        fprintf(stderr, "\rTry %d", ++trial);
        generate_trial_conf(atoms_insrt->nr, x_insrt, offset_x, enum_rot, rng,
                            x_n);
        gmx::AnalysisNeighborhoodPositions pos(*x, atoms->nr);
        gmx::AnalysisNeighborhoodSearch    search = nb.initSearch(&pbc, pos);
        if (is_insertion_allowed(&search, exclusionDistances, atoms_insrt->nr,
                                 x_n, exclusionDistances_insrt))
        {
            const int firstIndex = atoms->nr;
            for (int i = 0; i < atoms_insrt->nr; ++i)
            {
                copy_rvec(x_n[i], (*x)[firstIndex + i]);
                exclusionDistances[firstIndex + i] = exclusionDistances_insrt[i];
            }
            merge_atoms_noalloc(atoms, atoms_insrt);
            ++mol;
            firstTrial = trial;
            fprintf(stderr, " success (now %d atoms)!\n", atoms->nr);
        }
    }
    gmx_rng_destroy(rng);
    srenew(atoms->resinfo,  atoms->nres);
    srenew(atoms->atomname, atoms->nr);
    srenew(atoms->atom,     atoms->nr);
    srenew(*x,              atoms->nr);

    fprintf(stderr, "\n");
    /* print number of molecules added */
    fprintf(stderr, "Added %d molecules (out of %d requested)\n",
            mol - failed, nmol_insrt);

    sfree(x_n);
    sfree(exclusionDistances);
    sfree(exclusionDistances_insrt);
    if (rpos != NULL)
    {
        for (int i = 0; i < DIM; ++i)
        {
            sfree(rpos[i]);
        }
        sfree(rpos);
    }
}
int gmx_solvate(int argc, char *argv[])
{
    const char *desc[] = {
        "[THISMODULE] can do one of 2 things:[PAR]",

        "1) Generate a box of solvent. Specify [TT]-cs[tt] and [TT]-box[tt].",
        "Or specify [TT]-cs[tt] and [TT]-cp[tt] with a structure file with",
        "a box, but without atoms.[PAR]",

        "2) Solvate a solute configuration, e.g. a protein, in a bath of solvent ",
        "molecules. Specify [TT]-cp[tt] (solute) and [TT]-cs[tt] (solvent). ",
        "The box specified in the solute coordinate file ([TT]-cp[tt]) is used,",
        "unless [TT]-box[tt] is set.",
        "If you want the solute to be centered in the box,",
        "the program [gmx-editconf] has sophisticated options",
        "to change the box dimensions and center the solute.",
        "Solvent molecules are removed from the box where the ",
        "distance between any atom of the solute molecule(s) and any atom of ",
        "the solvent molecule is less than the sum of the scaled van der Waals",
        "radii of both atoms. A database ([TT]vdwradii.dat[tt]) of van der",
        "Waals radii is read by the program, and the resulting radii scaled",
        "by [TT]-scale[tt]. If radii are not found in the database, those"
        "atoms are assigned the (pre-scaled) distance [TT]-radius[tt].[PAR]",

        "The default solvent is Simple Point Charge water (SPC), with coordinates ",
        "from [TT]$GMXLIB/spc216.gro[tt]. These coordinates can also be used",
        "for other 3-site water models, since a short equibilibration will remove",
        "the small differences between the models.",
        "Other solvents are also supported, as well as mixed solvents. The",
        "only restriction to solvent types is that a solvent molecule consists",
        "of exactly one residue. The residue information in the coordinate",
        "files is used, and should therefore be more or less consistent.",
        "In practice this means that two subsequent solvent molecules in the ",
        "solvent coordinate file should have different residue number.",
        "The box of solute is built by stacking the coordinates read from",
        "the coordinate file. This means that these coordinates should be ",
        "equlibrated in periodic boundary conditions to ensure a good",
        "alignment of molecules on the stacking interfaces.",
        "The [TT]-maxsol[tt] option simply adds only the first [TT]-maxsol[tt]",
        "solvent molecules and leaves out the rest that would have fitted",
        "into the box. This can create a void that can cause problems later.",
        "Choose your volume wisely.[PAR]",

        "The program can optionally rotate the solute molecule to align the",
        "longest molecule axis along a box edge. This way the amount of solvent",
        "molecules necessary is reduced.",
        "It should be kept in mind that this only works for",
        "short simulations, as e.g. an alpha-helical peptide in solution can ",
        "rotate over 90 degrees, within 500 ps. In general it is therefore ",
        "better to make a more or less cubic box.[PAR]",

        "Setting [TT]-shell[tt] larger than zero will place a layer of water of",
        "the specified thickness (nm) around the solute. Hint: it is a good",
        "idea to put the protein in the center of a box first (using [gmx-editconf]).",
        "[PAR]",

        "Finally, [THISMODULE] will optionally remove lines from your topology file in ",
        "which a number of solvent molecules is already added, and adds a ",
        "line with the total number of solvent molecules in your coordinate file."
    };

    const char *bugs[] = {
        "Molecules must be whole in the initial configurations.",
    };

    /* parameter data */
    gmx_bool       bProt, bBox;
    const char    *conf_prot, *confout;
    real          *exclusionDistances = NULL;
    gmx_atomprop_t aps;

    /* protein configuration data */
    char    *title = NULL;
    t_atoms *atoms;
    rvec    *x    = NULL, *v = NULL;
    int      ePBC = -1;
    matrix   box;

    /* other data types */
    int      atoms_added, residues_added;

    t_filenm fnm[] = {
        { efSTX, "-cp", "protein", ffOPTRD },
        { efSTX, "-cs", "spc216",  ffLIBRD},
        { efSTO, NULL,  NULL,      ffWRITE},
        { efTOP, NULL,  NULL,      ffOPTRW},
    };
#define NFILE asize(fnm)

    static real     defaultDistance = 0.105, r_shell = 0, scaleFactor = 0.57;
    static rvec     new_box         = {0.0, 0.0, 0.0};
    static gmx_bool bReadV          = FALSE;
    static int      max_sol         = 0;
    output_env_t    oenv;
    t_pargs         pa[]              = {
        { "-box",    FALSE, etRVEC, {new_box},
          "Box size (in nm)" },
        { "-radius",   FALSE, etREAL, {&defaultDistance},
          "Default van der Waals distance"},
        { "-scale", FALSE, etREAL, {&scaleFactor},
          "Scale factor to multiply Van der Waals radii from the database in share/gromacs/top/vdwradii.dat. The default value of 0.57 yields density close to 1000 g/l for proteins in water." },
        { "-shell",  FALSE, etREAL, {&r_shell},
          "Thickness of optional water layer around solute" },
        { "-maxsol", FALSE, etINT,  {&max_sol},
          "Maximum number of solvent molecules to add if they fit in the box. If zero (default) this is ignored" },
        { "-vel",    FALSE, etBOOL, {&bReadV},
          "Keep velocities from input solute and solvent" },
    };

    if (!parse_common_args(&argc, argv, PCA_BE_NICE, NFILE, fnm, asize(pa), pa,
                           asize(desc), desc, asize(bugs), bugs, &oenv))
    {
        return 0;
    }

    const char *solventFileName = opt2fn("-cs", NFILE, fnm);
    bProt     = opt2bSet("-cp", NFILE, fnm);
    bBox      = opt2parg_bSet("-box", asize(pa), pa);

    /* check input */
    if (!bProt && !bBox)
    {
        gmx_fatal(FARGS, "When no solute (-cp) is specified, "
                  "a box size (-box) must be specified");
    }

    aps = gmx_atomprop_init();

    snew(atoms, 1);
    init_t_atoms(atoms, 0, FALSE);
    if (bProt)
    {
        /* Generate a solute configuration */
        conf_prot = opt2fn("-cp", NFILE, fnm);
        title     = readConformation(conf_prot, atoms, &x,
                                     bReadV ? &v : NULL, &ePBC, box);
        exclusionDistances = makeExclusionDistances(atoms, aps, defaultDistance, scaleFactor);

        if (bReadV && !v)
        {
            fprintf(stderr, "Note: no velocities found\n");
        }
        if (atoms->nr == 0)
        {
            fprintf(stderr, "Note: no atoms in %s\n", conf_prot);
            bProt = FALSE;
        }
    }
    if (bBox)
    {
        ePBC = epbcXYZ;
        clear_mat(box);
        box[XX][XX] = new_box[XX];
        box[YY][YY] = new_box[YY];
        box[ZZ][ZZ] = new_box[ZZ];
    }
    if (det(box) == 0)
    {
        gmx_fatal(FARGS, "Undefined solute box.\nCreate one with gmx editconf "
                  "or give explicit -box command line option");
    }

    add_solv(solventFileName, atoms, &x, v ? &v : NULL, &exclusionDistances, ePBC, box,
             aps, defaultDistance, scaleFactor, &atoms_added, &residues_added, r_shell, max_sol,
             oenv);

    /* write new configuration 1 to file confout */
    confout = ftp2fn(efSTO, NFILE, fnm);
    fprintf(stderr, "Writing generated configuration to %s\n", confout);
    if (bProt)
    {
        write_sto_conf(confout, title, atoms, x, v, ePBC, box);
        /* print box sizes and box type to stderr */
        fprintf(stderr, "%s\n", title);
    }
    else
    {
        write_sto_conf(confout, "Generated by gmx solvate", atoms, x, v, ePBC, box);
    }

    /* print size of generated configuration */
    fprintf(stderr, "\nOutput configuration contains %d atoms in %d residues\n",
            atoms->nr, atoms->nres);
    update_top(atoms, box, NFILE, fnm, aps);

    gmx_atomprop_destroy(aps);
    sfree(exclusionDistances);
    sfree(x);
    sfree(v);
    done_atom(atoms);
    sfree(atoms);

    return 0;
}