def mdp_periodic_dna(ff_name, run_type):

    if run_type == 'npt':
        base = npt_mdp
    elif run_type == 'em':
        base = em_mdp
    else:
        valid = {'npt', 'em'}
        raise ValueError("results: status must be one of %r." % valid)

    # Force field specific settings
    electrostatics_vdw = electrostatics_vdw_mdp(ff_name)

    # Extra definitions to add because of the molecule being periodi
    periodic_mol = {
        'periodic-molecules': 'yes',
        'pcoupl-type': 'semiisotropic',
        'ref-p': '1.0 1.0',
        'compressibility': '4.5e-5 4.5e-5',
    }

    # The merge order matters. Later mdps have precedence.
    mdp = gmxb.merge_mdps([base, electrostatics_vdw, periodic_mol])

    return mdp
def awh_basepair_dist_mdp(name1, name2):

    pull_mdp = pull_basepair_distance_mdp(name1, name2)

    awh_mdp = {
        'pull-coord1-potential-provider': 'awh',
        'pull-coord1-type        ': 'external-potential',
        'awh                      ': 'yes',
        'awh-nbias                ': '1',
        'awh-nstout               ': '50000',
        'awh-share-multisim       ': 'yes',
        'awh1-share-group         ': '1',
        'awh1-ndim                ': '1',
        'awh1-error-init          ': '5',
        'awh1-dim1-coord-index    ': '1',
        'awh1-dim1-diffusion      ': '5e-5',
        'awh1-dim1-start          ': '0.25',
        'awh1-dim1-end            ': '0.60',
        'awh1-dim1-force-constant ': '128000',
        'awh1-equilibrate-histogram': 'yes'
    }

    return gmxb.merge_mdps([pull_mdp, awh_mdp])
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'])