def pdb2gmx_periodic(pdb, watermodel, forcefield):

    # Assume a pdb2gmx wrapper script for periodic molecules is in the same directory as this file.
    periodic_pdb2gmx = os.path.dirname(os.path.realpath(__file__)) + '/gmx-pdb2gmx-wrapper-periodic-dna.sh'

    args=' '.join(['-water', watermodel, '-ff', forcefield, '-f', pdb])
    xsh(' '.join([periodic_pdb2gmx, args]))
def neutralize_box(gro='conf.gro', top='topol.top', tpr='topol.tpr'):
    args = ' '.join(
        ['-neutral', '-pname', 'NA', '-p', 'topol.top', '-o', 'conf.gro'])
    interactive_args = 'SOL'
    cmd = ' '.join(['echo -e', interactive_args, '|', gmx, 'genion', args])

    stdout = xsh(cmd)
def make_box_for_periodic_dna(gro='conf.gro'):
    # Make a box for a DNA molecule that is periodically connected in the z-direction.

    # The box angles (naming as in gmx manual).
    # Here vectors a and b lie in the xy-plane, and are 60 deg apart.
    # vector c is parallel to the z axis
    bc, ac, ab = 90, 90, 60

    # Very simple measure of the diameter along each dimension:
    coords = gmxb.read_gro_coordinates(gro)
    diameter = coords.max(0) - coords.min(0)

    # Dna is roughly circular in x and y. Use the x diameter and add 2 nm
    # to ensure that periodic images are ~ 2 nm apart.

    a = diameter[0] + 2.0
    b = a

    # The z box length should equal the molecule length since we are making a
    # periodic molecule.
    c = diameter[-1]

    # Make the box with editconf
    angles = ' '.join([str(bc), str(ac), str(ab)])
    lengths = ' '.join([str(a), str(b), str(c)])
    out = 'conf.gro'
    args = ' '.join(['-angles', angles, '-box', lengths, '-o', out])
    stdout = xsh(' '.join([gmx, 'editconf', args]))
def solvate_box(gro='conf.gro', top='topol.top', tpr='topol.tpr'):
    args = ' '.join(['-cp', gro, '-p', top, '-cs', '-o', 'conf.gro'])
    stdout = xsh(' '.join([gmx, 'solvate', args]))
def example_build(make_clean=False):

    # External parameters are assumed to be present
    scripts_dir = os.path.dirname(os.path.realpath(__file__))
    external_params_dir = scripts_dir + '/../external-parameters'

    # Note: the pdb files could be generated from a sequence from within here calling some modeling tool like x3dna.
    # Another option is using the pmx python library. However, the current modeling capabilities of pmx for DNA is
    # limited and not optimal for generating the periodic DNA topologies since the phosphates at the end residues are
    # missing in the moddel.
    pdb_dir = external_params_dir + '/pdbs/vary-num-T'
    pdbs = [
        '/'.join([pdb_dir, f]) for f in os.listdir(pdb_dir)
        if f.endswith('.pdb')
    ]

    # Build specifications (model parameters)
    build_list = [{
        'name': 'charmm',
        'ff': 'charmm27',
        'water': 'tip3p',
        'ffdir': None
    }, {
        'name': 'amber',
        'ff': 'amber99bsc1',
        'water': 'spce',
        'ffdir': external_params_dir + '/forcefields/amber99bsc1.ff'
    }]

    def sysname(pdb):
        return pdb.split('.pdb')[0].split('/')[-1]

    startdir = os.getcwd()

    # Here, each pdb is built with each model.
    for pdb, specs in zip(
            len(build_list) * pdbs,
            len(pdbs) * build_list,
    ):
        print 'Building:', sysname(pdb), specs['name']

        # Define the directory hierarchy. Infer system name from pdb file.
        build_dir = '/'.join([startdir, specs['name'], sysname(pdb), 'build'])

        if make_clean:
            xsh('rm -rf ' + build_dir)
        xsh('mkdir -p ' + build_dir)

        # Add external parameters if needed
        if specs['ffdir']:
            xsh('cp -r ' + specs['ffdir'] + ' ' + build_dir)

        # Build the gmx system
        os.chdir(build_dir)
        build_periodic_dna(pdb,
                           forcefield=specs['ff'],
                           watermodel=specs['water'])
        os.chdir(startdir)

        # Add runs.  Here, each run is added to each build.
        run_list = [
            {
                'name': 'em',
                'mdp': mdp_periodic_dna(specs['name'], 'em'),
                'selections': []
            },
            {
                'name': 'npt',
                'mdp': mdp_periodic_dna(specs['name'], 'npt'),
                'selections': []
            },
        ]

        # Add AWH runs, calculate PMF for some base pairs (bp).  The reaction coordinate requires
        # bp-specific atom selections. Here, generate all possible selections, then specify which
        # bp is targeted in the mdp-file (could also generate only the selections needed for the
        # target bp and use one mdp file).
        target_basepairs = get_target_basepair_resids(build_dir + '/conf.gro')

        for resid1, resid2 in target_basepairs:
            name1, name2 = ['resid' + str(resid) for resid in [resid1, resid2]]
            awh_sel = basepair_distance_selections(resid1,
                                                   resid2,
                                                   name1=name1,
                                                   name2=name2)
            awh_mdp = gmxb.merge_mdps([
                mdp_periodic_dna(specs['name'], 'npt'),
                awh_basepair_dist_mdp(name1, name2), {
                    'nsteps': '100000000'
                }
            ])

            # Add the run specs (mdp and selections) for this base pair
            run_list.append({
                'name': '-'.join(['awh', name1, name2]),
                'mdp': awh_mdp,
                'selections': awh_sel
            })

        # Put the run directory on the same level as the build director
        print 'Adding runs:'
        for run in run_list:
            print run['name']
            run_dir = '/'.join(
                [startdir, specs['name'],
                 sysname(pdb), run['name']])
            if make_clean:
                xsh('rm -rf ' + run_dir)
            xsh('mkdir -p ' + run_dir)
            template_dir = run_dir + '/template'

            gmxb.make_run_template(build_dir,
                                   run['mdp'],
                                   template_dir,
                                   selections=run['selections'])