Exemplo n.º 1
0
int gmx_spol(int argc, char *argv[])
{
    t_topology  *top;
    t_inputrec  *ir;
    t_atom      *atom;
    t_trxstatus *status;
    int          nrefat, natoms, nf, ntot;
    real         t;
    rvec        *x, xref, trial, dx = {0}, dip, dir;
    matrix       box;

    FILE        *fp;
    int         *isize, nrefgrp;
    atom_id    **index, *molindex;
    char       **grpname;
    real         rmin2, rmax2, rcut, rcut2, rdx2 = 0, rtry2, qav, q, dip2, invbw;
    int          nbin, i, m, mol, a0, a1, a, d;
    double       sdip, sdip2, sinp, sdinp, nmol;
    int         *hist;
    t_pbc        pbc;
    gmx_rmpbc_t  gpbc = NULL;


    const char     *desc[] = {
        "[THISMODULE] analyzes dipoles around a solute; it is especially useful",
        "for polarizable water. A group of reference atoms, or a center",
        "of mass reference (option [TT]-com[tt]) and a group of solvent",
        "atoms is required. The program splits the group of solvent atoms",
        "into molecules. For each solvent molecule the distance to the",
        "closest atom in reference group or to the COM is determined.",
        "A cumulative distribution of these distances is plotted.",
        "For each distance between [TT]-rmin[tt] and [TT]-rmax[tt]",
        "the inner product of the distance vector",
        "and the dipole of the solvent molecule is determined.",
        "For solvent molecules with net charge (ions), the net charge of the ion",
        "is subtracted evenly from all atoms in the selection of each ion.",
        "The average of these dipole components is printed.",
        "The same is done for the polarization, where the average dipole is",
        "subtracted from the instantaneous dipole. The magnitude of the average",
        "dipole is set with the option [TT]-dip[tt], the direction is defined",
        "by the vector from the first atom in the selected solvent group",
        "to the midpoint between the second and the third atom."
    };

    output_env_t    oenv;
    static gmx_bool bCom   = FALSE;
    static int      srefat = 1;
    static real     rmin   = 0.0, rmax = 0.32, refdip = 0, bw = 0.01;
    t_pargs         pa[]   = {
        { "-com",  FALSE, etBOOL,  {&bCom},
          "Use the center of mass as the reference postion" },
        { "-refat",  FALSE, etINT, {&srefat},
          "The reference atom of the solvent molecule" },
        { "-rmin",  FALSE, etREAL, {&rmin}, "Maximum distance (nm)" },
        { "-rmax",  FALSE, etREAL, {&rmax}, "Maximum distance (nm)" },
        { "-dip",   FALSE, etREAL, {&refdip}, "The average dipole (D)" },
        { "-bw",    FALSE, etREAL, {&bw}, "The bin width" }
    };

    t_filenm        fnm[] = {
        { efTRX, NULL,  NULL,  ffREAD },
        { efTPR, NULL,  NULL,  ffREAD },
        { efNDX, NULL,  NULL,  ffOPTRD },
        { efXVG, NULL,  "scdist",  ffWRITE }
    };
#define NFILE asize(fnm)

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

    snew(top, 1);
    snew(ir, 1);
    read_tpx_top(ftp2fn(efTPR, NFILE, fnm),
                 ir, box, &natoms, NULL, NULL, NULL, top);

    /* get index groups */
    printf("Select a group of reference particles and a solvent group:\n");
    snew(grpname, 2);
    snew(index, 2);
    snew(isize, 2);
    get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm), 2, isize, index, grpname);

    if (bCom)
    {
        nrefgrp = 1;
        nrefat  = isize[0];
    }
    else
    {
        nrefgrp = isize[0];
        nrefat  = 1;
    }

    spol_atom2molindex(&(isize[1]), index[1], &(top->mols));
    srefat--;

    /* initialize reading trajectory:                         */
    natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);

    rcut  = 0.99*std::sqrt(max_cutoff2(ir->ePBC, box));
    if (rcut == 0)
    {
        rcut = 10*rmax;
    }
    rcut2 = sqr(rcut);
    invbw = 1/bw;
    nbin  = static_cast<int>(rcut*invbw)+2;
    snew(hist, nbin);

    rmin2 = sqr(rmin);
    rmax2 = sqr(rmax);

    nf    = 0;
    ntot  = 0;
    sdip  = 0;
    sdip2 = 0;
    sinp  = 0;
    sdinp = 0;

    molindex = top->mols.index;
    atom     = top->atoms.atom;

    gpbc = gmx_rmpbc_init(&top->idef, ir->ePBC, natoms);

    /* start analysis of trajectory */
    do
    {
        /* make molecules whole again */
        gmx_rmpbc(gpbc, natoms, box, x);

        set_pbc(&pbc, ir->ePBC, box);
        if (bCom)
        {
            calc_com_pbc(nrefat, top, x, &pbc, index[0], xref, ir->ePBC);
        }

        for (m = 0; m < isize[1]; m++)
        {
            mol = index[1][m];
            a0  = molindex[mol];
            a1  = molindex[mol+1];
            for (i = 0; i < nrefgrp; i++)
            {
                pbc_dx(&pbc, x[a0+srefat], bCom ? xref : x[index[0][i]], trial);
                rtry2 = norm2(trial);
                if (i == 0 || rtry2 < rdx2)
                {
                    copy_rvec(trial, dx);
                    rdx2 = rtry2;
                }
            }
            if (rdx2 < rcut2)
            {
                hist[static_cast<int>(std::sqrt(rdx2)*invbw)+1]++;
            }
            if (rdx2 >= rmin2 && rdx2 < rmax2)
            {
                unitv(dx, dx);
                clear_rvec(dip);
                qav = 0;
                for (a = a0; a < a1; a++)
                {
                    qav += atom[a].q;
                }
                qav /= (a1 - a0);
                for (a = a0; a < a1; a++)
                {
                    q = atom[a].q - qav;
                    for (d = 0; d < DIM; d++)
                    {
                        dip[d] += q*x[a][d];
                    }
                }
                for (d = 0; d < DIM; d++)
                {
                    dir[d] = -x[a0][d];
                }
                for (a = a0+1; a < a0+3; a++)
                {
                    for (d = 0; d < DIM; d++)
                    {
                        dir[d] += 0.5*x[a][d];
                    }
                }
                unitv(dir, dir);

                svmul(ENM2DEBYE, dip, dip);
                dip2   = norm2(dip);
                sdip  += std::sqrt(dip2);
                sdip2 += dip2;
                for (d = 0; d < DIM; d++)
                {
                    sinp  += dx[d]*dip[d];
                    sdinp += dx[d]*(dip[d] - refdip*dir[d]);
                }

                ntot++;
            }
        }
        nf++;

    }
    while (read_next_x(oenv, status, &t, x, box));

    gmx_rmpbc_done(gpbc);

    /* clean up */
    sfree(x);
    close_trj(status);

    fprintf(stderr, "Average number of molecules within %g nm is %.1f\n",
            rmax, static_cast<real>(ntot)/nf);
    if (ntot > 0)
    {
        sdip  /= ntot;
        sdip2 /= ntot;
        sinp  /= ntot;
        sdinp /= ntot;
        fprintf(stderr, "Average dipole:                               %f (D), std.dev. %f\n",
                sdip, std::sqrt(sdip2-sqr(sdip)));
        fprintf(stderr, "Average radial component of the dipole:       %f (D)\n",
                sinp);
        fprintf(stderr, "Average radial component of the polarization: %f (D)\n",
                sdinp);
    }

    fp = xvgropen(opt2fn("-o", NFILE, fnm),
                  "Cumulative solvent distribution", "r (nm)", "molecules", oenv);
    nmol = 0;
    for (i = 0; i <= nbin; i++)
    {
        nmol += hist[i];
        fprintf(fp, "%g %g\n", i*bw, nmol/nf);
    }
    xvgrclose(fp);

    do_view(oenv, opt2fn("-o", NFILE, fnm), NULL);

    return 0;
}
Exemplo n.º 2
0
int gmx_sorient(int argc, char *argv[])
{
    t_topology        top;
    int               ePBC = -1;
    t_trxstatus      *status;
    int               natoms;
    real              t;
    rvec             *xtop, *x;
    matrix            box;

    FILE             *fp;
    int               i, p, sa0, sa1, sa2, n, ntot, nf, m, *hist1, *hist2, *histn, nbin1, nbin2, nrbin;
    real             *histi1, *histi2, invbw, invrbw;
    double            sum1, sum2;
    int              *isize, nrefgrp, nrefat;
    int             **index;
    char            **grpname;
    real              inp, outp, nav, normfac, rmin2, rmax2, rcut, rcut2, r2, r;
    real              c1, c2;
    char              str[STRLEN];
    gmx_bool          bTPS;
    rvec              xref, dx, dxh1, dxh2, outer;
    gmx_rmpbc_t       gpbc = NULL;
    t_pbc             pbc;
    const char       *legr[] = {
        "<cos(\\8q\\4\\s1\\N)>",
        "<3cos\\S2\\N(\\8q\\4\\s2\\N)-1>"
    };
    const char       *legc[] = {
        "cos(\\8q\\4\\s1\\N)",
        "3cos\\S2\\N(\\8q\\4\\s2\\N)-1"
    };

    const char       *desc[] = {
        "[THISMODULE] analyzes solvent orientation around solutes.",
        "It calculates two angles between the vector from one or more",
        "reference positions to the first atom of each solvent molecule:",
        "",
        " * [GRK]theta[grk][SUB]1[sub]: the angle with the vector from the first atom of the solvent",
        "   molecule to the midpoint between atoms 2 and 3.",
        " * [GRK]theta[grk][SUB]2[sub]: the angle with the normal of the solvent plane, defined by the",
        "   same three atoms, or, when the option [TT]-v23[tt] is set, ",
        "   the angle with the vector between atoms 2 and 3.",
        "",
        "The reference can be a set of atoms or",
        "the center of mass of a set of atoms. The group of solvent atoms should",
        "consist of 3 atoms per solvent molecule.",
        "Only solvent molecules between [TT]-rmin[tt] and [TT]-rmax[tt] are",
        "considered for [TT]-o[tt] and [TT]-no[tt] each frame.[PAR]",
        "[TT]-o[tt]: distribtion of [MATH][COS][GRK]theta[grk][SUB]1[sub][cos][math] for rmin<=r<=rmax.[PAR]",
        "[TT]-no[tt]: distribution of [MATH][COS][GRK]theta[grk][SUB]2[sub][cos][math] for rmin<=r<=rmax.[PAR]",
        "[TT]-ro[tt]: [MATH][CHEVRON][COS][GRK]theta[grk][SUB]1[sub][cos][chevron][math] and [MATH][CHEVRON]3[COS]^2[GRK]theta[grk][SUB]2[sub][cos]-1[chevron][math] as a function of the",
        "distance.[PAR]",
        "[TT]-co[tt]: the sum over all solvent molecules within distance r",
        "of [MATH][COS][GRK]theta[grk][SUB]1[sub][cos][math] and [MATH]3[COS]^2([GRK]theta[grk][SUB]2[sub])-1[cos][math] as a function of r.[PAR]",
        "[TT]-rc[tt]: the distribution of the solvent molecules as a function of r"
    };

    gmx_output_env_t *oenv;
    static gmx_bool   bCom = FALSE, bVec23 = FALSE, bPBC = FALSE;
    static real       rmin = 0.0, rmax = 0.5, binwidth = 0.02, rbinw = 0.02;
    t_pargs           pa[] = {
        {   "-com",  FALSE, etBOOL,  {&bCom},
            "Use the center of mass as the reference postion"
        },
        {   "-v23",  FALSE, etBOOL,  {&bVec23},
            "Use the vector between atoms 2 and 3"
        },
        { "-rmin",  FALSE, etREAL, {&rmin}, "Minimum distance (nm)" },
        { "-rmax",  FALSE, etREAL, {&rmax}, "Maximum distance (nm)" },
        { "-cbin",  FALSE, etREAL, {&binwidth}, "Binwidth for the cosine" },
        { "-rbin",  FALSE, etREAL, {&rbinw}, "Binwidth for r (nm)" },
        { "-pbc",   FALSE, etBOOL, {&bPBC}, "Check PBC for the center of mass calculation. Only necessary when your reference group consists of several molecules." }
    };

    t_filenm          fnm[] = {
        { efTRX, NULL,  NULL,  ffREAD },
        { efTPS, NULL,  NULL,  ffREAD },
        { efNDX, NULL,  NULL,  ffOPTRD },
        { efXVG, NULL,  "sori",   ffWRITE },
        { efXVG, "-no", "snor",   ffWRITE },
        { efXVG, "-ro", "sord",   ffWRITE },
        { efXVG, "-co", "scum",   ffWRITE },
        { efXVG, "-rc", "scount", ffWRITE }
    };
#define NFILE asize(fnm)

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

    bTPS = (opt2bSet("-s", NFILE, fnm) || !opt2bSet("-n", NFILE, fnm) || bCom);
    if (bTPS)
    {
        read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &xtop, NULL, box,
                      bCom);
    }

    /* get index groups */
    printf("Select a group of reference particles and a solvent group:\n");
    snew(grpname, 2);
    snew(index, 2);
    snew(isize, 2);
    if (bTPS)
    {
        get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 2, isize, index, grpname);
    }
    else
    {
        get_index(NULL, ftp2fn(efNDX, NFILE, fnm), 2, isize, index, grpname);
    }

    if (bCom)
    {
        nrefgrp = 1;
        nrefat  = isize[0];
    }
    else
    {
        nrefgrp = isize[0];
        nrefat  = 1;
    }

    if (isize[1] % 3)
    {
        gmx_fatal(FARGS, "The number of solvent atoms (%d) is not a multiple of 3",
                  isize[1]);
    }

    /* initialize reading trajectory:                         */
    natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);

    rmin2 = sqr(rmin);
    rmax2 = sqr(rmax);
    rcut  = 0.99*std::sqrt(max_cutoff2(guess_ePBC(box), box));
    if (rcut == 0)
    {
        rcut = 10*rmax;
    }
    rcut2 = sqr(rcut);

    invbw = 1/binwidth;
    nbin1 = 1+static_cast<int>(2*invbw + 0.5);
    nbin2 = 1+static_cast<int>(invbw + 0.5);

    invrbw = 1/rbinw;

    snew(hist1, nbin1);
    snew(hist2, nbin2);
    nrbin = 1+static_cast<int>(rcut/rbinw);
    if (nrbin == 0)
    {
        nrbin = 1;
    }
    snew(histi1, nrbin);
    snew(histi2, nrbin);
    snew(histn, nrbin);

    ntot = 0;
    nf   = 0;
    sum1 = 0;
    sum2 = 0;

    if (bTPS)
    {
        /* make molecules whole again */
        gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms);
    }
    /* start analysis of trajectory */
    do
    {
        if (bTPS)
        {
            /* make molecules whole again */
            gmx_rmpbc(gpbc, natoms, box, x);
        }

        set_pbc(&pbc, ePBC, box);
        n    = 0;
        inp  = 0;
        for (p = 0; (p < nrefgrp); p++)
        {
            if (bCom)
            {
                calc_com_pbc(nrefat, &top, x, &pbc, index[0], xref, bPBC);
            }
            else
            {
                copy_rvec(x[index[0][p]], xref);
            }

            for (m = 0; m < isize[1]; m += 3)
            {
                sa0 = index[1][m];
                sa1 = index[1][m+1];
                sa2 = index[1][m+2];
                range_check(sa0, 0, natoms);
                range_check(sa1, 0, natoms);
                range_check(sa2, 0, natoms);
                pbc_dx(&pbc, x[sa0], xref, dx);
                r2  = norm2(dx);
                if (r2 < rcut2)
                {
                    r = std::sqrt(r2);
                    if (!bVec23)
                    {
                        /* Determine the normal to the plain */
                        rvec_sub(x[sa1], x[sa0], dxh1);
                        rvec_sub(x[sa2], x[sa0], dxh2);
                        rvec_inc(dxh1, dxh2);
                        svmul(1/r, dx, dx);
                        unitv(dxh1, dxh1);
                        inp = iprod(dx, dxh1);
                        cprod(dxh1, dxh2, outer);
                        unitv(outer, outer);
                        outp = iprod(dx, outer);
                    }
                    else
                    {
                        /* Use the vector between the 2nd and 3rd atom */
                        rvec_sub(x[sa2], x[sa1], dxh2);
                        unitv(dxh2, dxh2);
                        outp = iprod(dx, dxh2)/r;
                    }
                    {
                        int ii = static_cast<int>(invrbw*r);
                        range_check(ii, 0, nrbin);
                        histi1[ii] += inp;
                        histi2[ii] += 3*sqr(outp) - 1;
                        histn[ii]++;
                    }
                    if ((r2 >= rmin2) && (r2 < rmax2))
                    {
                        int ii1 = static_cast<int>(invbw*(inp + 1));
                        int ii2 = static_cast<int>(invbw*std::abs(outp));

                        range_check(ii1, 0, nbin1);
                        range_check(ii2, 0, nbin2);
                        hist1[ii1]++;
                        hist2[ii2]++;
                        sum1 += inp;
                        sum2 += outp;
                        n++;
                    }
                }
            }
        }
        ntot += n;
        nf++;

    }
    while (read_next_x(oenv, status, &t, x, box));

    /* clean up */
    sfree(x);
    close_trj(status);
    gmx_rmpbc_done(gpbc);

    /* Add the bin for the exact maximum to the previous bin */
    hist1[nbin1-1] += hist1[nbin1];
    hist2[nbin2-1] += hist2[nbin2];

    nav     = static_cast<real>(ntot)/(nrefgrp*nf);
    normfac = invbw/ntot;

    fprintf(stderr,  "Average nr of molecules between %g and %g nm: %.1f\n",
            rmin, rmax, nav);
    if (ntot > 0)
    {
        sum1 /= ntot;
        sum2 /= ntot;
        fprintf(stderr, "Average cos(theta1)     between %g and %g nm: %6.3f\n",
                rmin, rmax, sum1);
        fprintf(stderr, "Average 3cos2(theta2)-1 between %g and %g nm: %6.3f\n",
                rmin, rmax, sum2);
    }

    sprintf(str, "Solvent orientation between %g and %g nm", rmin, rmax);
    fp = xvgropen(opt2fn("-o", NFILE, fnm), str, "cos(\\8q\\4\\s1\\N)", "", oenv);
    if (output_env_get_print_xvgr_codes(oenv))
    {
        fprintf(fp, "@ subtitle \"average shell size %.1f molecules\"\n", nav);
    }
    for (i = 0; i < nbin1; i++)
    {
        fprintf(fp, "%g %g\n", (i+0.5)*binwidth-1, 2*normfac*hist1[i]);
    }
    xvgrclose(fp);

    sprintf(str, "Solvent normal orientation between %g and %g nm", rmin, rmax);
    fp = xvgropen(opt2fn("-no", NFILE, fnm), str, "cos(\\8q\\4\\s2\\N)", "", oenv);
    if (output_env_get_print_xvgr_codes(oenv))
    {
        fprintf(fp, "@ subtitle \"average shell size %.1f molecules\"\n", nav);
    }
    for (i = 0; i < nbin2; i++)
    {
        fprintf(fp, "%g %g\n", (i+0.5)*binwidth, normfac*hist2[i]);
    }
    xvgrclose(fp);


    sprintf(str, "Solvent orientation");
    fp = xvgropen(opt2fn("-ro", NFILE, fnm), str, "r (nm)", "", oenv);
    if (output_env_get_print_xvgr_codes(oenv))
    {
        fprintf(fp, "@ subtitle \"as a function of distance\"\n");
    }
    xvgr_legend(fp, 2, legr, oenv);
    for (i = 0; i < nrbin; i++)
    {
        fprintf(fp, "%g %g %g\n", (i+0.5)*rbinw,
                histn[i] ? histi1[i]/histn[i] : 0,
                histn[i] ? histi2[i]/histn[i] : 0);
    }
    xvgrclose(fp);

    sprintf(str, "Cumulative solvent orientation");
    fp = xvgropen(opt2fn("-co", NFILE, fnm), str, "r (nm)", "", oenv);
    if (output_env_get_print_xvgr_codes(oenv))
    {
        fprintf(fp, "@ subtitle \"as a function of distance\"\n");
    }
    xvgr_legend(fp, 2, legc, oenv);
    normfac = 1.0/(nrefgrp*nf);
    c1      = 0;
    c2      = 0;
    fprintf(fp, "%g %g %g\n", 0.0, c1, c2);
    for (i = 0; i < nrbin; i++)
    {
        c1 += histi1[i]*normfac;
        c2 += histi2[i]*normfac;
        fprintf(fp, "%g %g %g\n", (i+1)*rbinw, c1, c2);
    }
    xvgrclose(fp);

    sprintf(str, "Solvent distribution");
    fp = xvgropen(opt2fn("-rc", NFILE, fnm), str, "r (nm)", "molecules/nm", oenv);
    if (output_env_get_print_xvgr_codes(oenv))
    {
        fprintf(fp, "@ subtitle \"as a function of distance\"\n");
    }
    normfac = 1.0/(rbinw*nf);
    for (i = 0; i < nrbin; i++)
    {
        fprintf(fp, "%g %g\n", (i+0.5)*rbinw, histn[i]*normfac);
    }
    xvgrclose(fp);

    do_view(oenv, opt2fn("-o", NFILE, fnm), NULL);
    do_view(oenv, opt2fn("-no", NFILE, fnm), NULL);
    do_view(oenv, opt2fn("-ro", NFILE, fnm), "-nxy");
    do_view(oenv, opt2fn("-co", NFILE, fnm), "-nxy");

    return 0;
}