Пример #1
0
def benchmark_dhfr():

    pdb_path = 'tests/data/5dfr_solv_equil.pdb'
    host_pdb = app.PDBFile(pdb_path)
    protein_ff = app.ForceField('amber99sbildn.xml', 'tip3p.xml')
    host_system = protein_ff.createSystem(
        host_pdb.topology,
        nonbondedMethod=app.NoCutoff,
        constraints=None,
        rigidWater=False
    )
    host_coords = host_pdb.positions
    box = host_pdb.topology.getPeriodicBoxVectors()
    box = np.asarray(box/box.unit)

    host_fns, host_masses = openmm_deserializer.deserialize_system(
        host_system,
        cutoff=1.0
    )

    host_conf = []
    for x,y,z in host_coords:
        host_conf.append([to_md_units(x),to_md_units(y),to_md_units(z)])
    host_conf = np.array(host_conf)

    seed = 1234
    dt = 1.5e-3

    intg = LangevinIntegrator(
        300,
        dt,
        1.0,
        np.array(host_masses),
        seed
    ).impl()

    bps = []

    for potential in host_fns:
        bps.append(potential.bound_impl(precision=np.float32)) # get the bound implementation

    x0 = host_conf
    v0 = np.zeros_like(host_conf)

    ctxt = custom_ops.Context(
        x0,
        v0,
        box,
        intg,
        bps
    )

    # initialize observables
    obs = []
    for bp in bps:
        du_dp_obs = custom_ops.AvgPartialUPartialParam(bp, 100)
        ctxt.add_observable(du_dp_obs)
        obs.append(du_dp_obs)

    lamb = 0.0

    start = time.time()
    # num_steps = 50000
    num_steps = 50000
    # num_steps = 10

    writer = PDBWriter([host_pdb.topology], "dhfr.pdb")

    for step in range(num_steps):
        ctxt.step(lamb)
        if step % 1000 == 0:

            delta = time.time()-start
            steps_per_second = step/delta
            seconds_per_day = 86400
            steps_per_day = steps_per_second*seconds_per_day
            ps_per_day = dt*steps_per_day
            ns_per_day = ps_per_day*1e-3

            print(step, "ns/day", ns_per_day)
            # coords = recenter(ctxt.get_x_t(), box)
            # writer.write_frame(coords*10)

    print("total time", time.time() - start)

    writer.close()


    # bond angle torsions nonbonded
    for potential, du_dp_obs in zip(host_fns, obs):
        dp = du_dp_obs.avg_du_dp()
        print(potential, dp.shape)
        print(dp)
Пример #2
0
    def test_benchmark(self):

        pdb_path = 'tests/data/5dfr_solv_equil.pdb'
        host_pdb = app.PDBFile(pdb_path)
        protein_ff = app.ForceField('amber99sbildn.xml', 'tip3p.xml')

        host_system = protein_ff.createSystem(host_pdb.topology,
                                              nonbondedMethod=app.NoCutoff,
                                              constraints=None,
                                              rigidWater=False)

        host_coords = host_pdb.positions
        box = host_pdb.topology.getPeriodicBoxVectors()
        box = np.asarray(box / box.unit)

        host_fns, host_masses = openmm_deserializer.deserialize_system(
            host_system, cutoff=1.0)

        for f in host_fns:
            if isinstance(f, potentials.Nonbonded):
                nonbonded_fn = f

        host_conf = []
        for x, y, z in host_coords:
            host_conf.append([to_md_units(x), to_md_units(y), to_md_units(z)])
        host_conf = np.array(host_conf)

        beta = 2.0
        cutoff = 1.1
        lamb = 0.0

        N = host_conf.shape[0]

        test_conf = host_conf[:N]

        # process exclusions
        test_exclusions = []
        test_scales = []
        for (i, j), (sa, sb) in zip(nonbonded_fn.get_exclusion_idxs(),
                                    nonbonded_fn.get_scale_factors()):
            if i < N and j < N:
                test_exclusions.append((i, j))
                test_scales.append((sa, sb))
        test_exclusions = np.array(test_exclusions, dtype=np.int32)
        test_scales = np.array(test_scales, dtype=np.float64)
        test_params = nonbonded_fn.params[:N, :]

        test_lambda_plane_idxs = np.zeros(N, dtype=np.int32)
        test_lambda_offset_idxs = np.zeros(N, dtype=np.int32)

        test_nonbonded_fn = potentials.Nonbonded(test_exclusions, test_scales,
                                                 test_lambda_plane_idxs,
                                                 test_lambda_offset_idxs, beta,
                                                 cutoff)

        precision = np.float32

        impl = test_nonbonded_fn.unbound_impl(precision)

        for _ in range(100):

            impl.execute_du_dx(test_conf, test_params, box, lamb)
Пример #3
0
def run_simulation(mol_name, mol, smirnoff_params, pdb, inference):
    omm_forcefield = app.ForceField('amber99sb.xml', 'tip3p.xml')
    system = omm_forcefield.createSystem(
        pdb.topology,
        nonbondedMethod=app.NoCutoff,
        constraints=None,
        rigidWater=False)
    
    coords = []
    for x,y,z in pdb.positions:
        coords.append([to_md_units(x),to_md_units(y),to_md_units(z)])
    coords = np.array(coords)
    host_conf = coords

    host_potentials, (host_params, host_param_groups), host_masses = serialize.deserialize_system(system)
    smirnoff = ForceField("test_forcefields/smirnoff99Frosst.offxml")

    # CAREFUL THIS SHOULD BE THE SINGLE SET OF CONSISTENT FORCEFIELDS
    am1 = True
    if am1:
        guest_potentials, smirnoff_params, smirnoff_param_groups, guest_conf, guest_masses = forcefield.parameterize(mol, smirnoff, am1)
    else:
        guest_potentials, _, smirnoff_param_groups, guest_conf, guest_masses = forcefield.parameterize(mol, smirnoff, am1)

    # guest_conf = rescale_and_center(guest_conf, scale_factor=3.0)

    combined_potentials, combined_params, combined_param_groups, combined_conf, combined_masses = forcefield.combiner(
        host_potentials, guest_potentials, 
        host_params, smirnoff_params, 
        host_param_groups, smirnoff_param_groups, 
        host_conf, guest_conf, 
        host_masses, guest_masses)

    num_host_atoms = host_conf.shape[0]

    def filter_groups(param_groups, groups):
        roll = np.zeros_like(param_groups)
        for g in groups:
            roll = np.logical_or(roll, param_groups == g)
        return roll

    # host_dp_idxs = np.argwhere(filter_groups(host_param_groups, [7])).reshape(-1)
    # guest_dp_idxs = np.argwhere(filter_groups(smirnoff_param_groups, [7])).reshape(-1)

    # 1. host bond lengths
    # 7. host charges
    # 8. host vdw sigma
    # 9. host vdw epsilon

    # 17. charge

    combined_dp_idxs = np.argwhere(filter_groups(combined_param_groups, [17])).reshape(-1)
    if inference:
        combined_dp_idxs = []

    outfile = open("frames/"+mol_name+".pdb", "w")

    combined_pdb = Chem.CombineMols(Chem.MolFromPDBFile(pdb.filepath, removeHs=False), mol)
    combined_pdb_str = StringIO(Chem.MolToPDBBlock(combined_pdb))

    cpdb = app.PDBFile(combined_pdb_str)
    PDBFile.writeHeader(cpdb.topology, outfile)

    def write_fn(x, frame_idx):
        PDBFile.writeModel(cpdb.topology, x, outfile, frame_idx)

    dG, dG_grads, all_xis = minimize(
        mol_name,
        num_host_atoms,
        combined_potentials,
        combined_params,
        combined_conf,
        combined_masses,
        combined_dp_idxs,
        writer_fn=write_fn
    )

    PDBFile.writeFooter(cpdb.topology, outfile)
    outfile.flush()

    # print("CDPI", combined_dp_idxs)
    # (ytz): we need to offset this by number of host params to compute the indices
    # of the original ligand parameters.
    if not inference:
        ligand_dp_idxs = combined_dp_idxs - len(host_params)
    else:
        ligand_dp_idxs = None

    return dG, dG_grads, ligand_dp_idxs
Пример #4
0
    def test_dhfr(self):

        pdb_path = 'tests/data/5dfr_solv_equil.pdb'
        host_pdb = app.PDBFile(pdb_path)
        protein_ff = app.ForceField('amber99sbildn.xml', 'tip3p.xml')

        host_system = protein_ff.createSystem(host_pdb.topology,
                                              nonbondedMethod=app.NoCutoff,
                                              constraints=None,
                                              rigidWater=False)

        host_coords = host_pdb.positions
        box = host_pdb.topology.getPeriodicBoxVectors()
        box = np.asarray(box / box.unit)

        host_fns, host_masses = openmm_deserializer.deserialize_system(
            host_system, cutoff=1.0)

        for f in host_fns:
            if isinstance(f, potentials.Nonbonded):
                nonbonded_fn = f

        host_conf = []
        for x, y, z in host_coords:
            host_conf.append([to_md_units(x), to_md_units(y), to_md_units(z)])
        host_conf = np.array(host_conf)

        beta = 2.0
        cutoff = 1.1
        lamb = 0.1

        max_N = host_conf.shape[0]

        for N in [33, 65, 231, 1050, 4080]:

            print("N", N)

            test_conf = host_conf[:N]

            # process exclusions
            test_exclusions = []
            test_scales = []
            for (i, j), (sa, sb) in zip(nonbonded_fn.get_exclusion_idxs(),
                                        nonbonded_fn.get_scale_factors()):
                if i < N and j < N:
                    test_exclusions.append((i, j))
                    test_scales.append((sa, sb))
            test_exclusions = np.array(test_exclusions, dtype=np.int32)
            test_scales = np.array(test_scales, dtype=np.float64)
            test_params = nonbonded_fn.params[:N, :]

            test_lambda_plane_idxs = np.random.randint(low=-2,
                                                       high=2,
                                                       size=N,
                                                       dtype=np.int32)
            test_lambda_offset_idxs = np.random.randint(low=-2,
                                                        high=2,
                                                        size=N,
                                                        dtype=np.int32)

            test_nonbonded_fn = potentials.Nonbonded(test_exclusions,
                                                     test_scales,
                                                     test_lambda_plane_idxs,
                                                     test_lambda_offset_idxs,
                                                     beta, cutoff)

            ref_nonbonded_fn = prepare_reference_nonbonded(
                test_params, test_exclusions, test_scales,
                test_lambda_plane_idxs, test_lambda_offset_idxs, beta, cutoff)

            for precision, rtol in [(np.float64, 1e-8), (np.float32, 1e-4)]:

                self.compare_forces(test_conf,
                                    test_params,
                                    box,
                                    lamb,
                                    ref_nonbonded_fn,
                                    test_nonbonded_fn,
                                    rtol,
                                    precision=precision)
Пример #5
0
def pose_dock(
    guests_sdfile,
    host_pdbfile,
    transition_type,
    n_steps,
    transition_steps,
    max_lambda,
    outdir,
    random_rotation=False,
    constant_atoms=[],
):
    """Runs short simulations in which the guests phase in or out over time

    Parameters
    ----------

    guests_sdfile: path to input sdf with guests to pose/dock
    host_pdbfile: path to host pdb file to dock into
    transition_type: "insertion" or "deletion"
    n_steps: how many total steps of simulation to do (recommended: <= 1000)
    transition_steps: how many steps to insert/delete the guest over (recommended: <= 500)
        (must be <= n_steps)
    max_lambda: lambda value the guest should insert from or delete to
        (recommended: 1.0 for work calulation, 0.25 to stay close to original pose)
        (must be =1 for work calculation to be applicable)
    outdir: where to write output (will be created if it does not already exist)
    random_rotation: whether to apply a random rotation to each guest before inserting
    constant_atoms: atom numbers from the host_pdbfile to hold mostly fixed across the simulation
        (1-indexed, like PDB files)

    Output
    ------

    A pdb & sdf file every 100 steps (outdir/<guest_name>_<step>.pdb)
    stdout every 100 steps noting the step number, lambda value, and energy
    stdout for each guest noting the work of transition
    stdout for each guest noting how long it took to run

    Note
    ----
    If any norm of force per atom exceeds 20000 kJ/(mol*nm) [MAX_NORM_FORCE defined in docking/report.py],
    the simulation for that guest will stop and the work will not be calculated.
    """
    assert transition_steps <= n_steps
    assert transition_type in ("insertion", "deletion")
    if random_rotation:
        assert transition_type == "insertion"

    if not os.path.exists(outdir):
        os.makedirs(outdir)

    host_mol = Chem.MolFromPDBFile(host_pdbfile, removeHs=False)
    amber_ff = app.ForceField("amber99sbildn.xml", "tip3p.xml")
    host_file = PDBFile(host_pdbfile)
    host_system = amber_ff.createSystem(
        host_file.topology,
        nonbondedMethod=app.NoCutoff,
        constraints=None,
        rigidWater=False,
    )
    host_conf = []
    for x, y, z in host_file.positions:
        host_conf.append([to_md_units(x), to_md_units(y), to_md_units(z)])
    host_conf = np.array(host_conf)

    final_potentials = []
    host_potentials, host_masses = openmm_deserializer.deserialize_system(
        host_system, cutoff=1.2)
    host_nb_bp = None
    for bp in host_potentials:
        if isinstance(bp, potentials.Nonbonded):
            # (ytz): hack to ensure we only have one nonbonded term
            assert host_nb_bp is None
            host_nb_bp = bp
        else:
            final_potentials.append(bp)

    # TODO (ytz): we should really fix this later on. This padding was done to
    # address the particles that are too close to the boundary.
    padding = 0.1
    box_lengths = np.amax(host_conf, axis=0) - np.amin(host_conf, axis=0)
    box_lengths = box_lengths + padding
    box = np.eye(3, dtype=np.float64) * box_lengths

    suppl = Chem.SDMolSupplier(guests_sdfile, removeHs=False)
    for guest_mol in suppl:
        start_time = time.time()
        guest_name = guest_mol.GetProp("_Name")
        guest_ff_handlers = deserialize_handlers(
            open(
                os.path.join(
                    os.path.dirname(os.path.abspath(__file__)),
                    "..",
                    "ff/params/smirnoff_1_1_0_ccc.py",
                )).read())
        ff = Forcefield(guest_ff_handlers)
        guest_base_topology = topology.BaseTopology(guest_mol, ff)

        # combine
        hgt = topology.HostGuestTopology(host_nb_bp, guest_base_topology)
        # setup the parameter handlers for the ligand
        bonded_tuples = [[hgt.parameterize_harmonic_bond, ff.hb_handle],
                         [hgt.parameterize_harmonic_angle, ff.ha_handle],
                         [hgt.parameterize_proper_torsion, ff.pt_handle],
                         [hgt.parameterize_improper_torsion, ff.it_handle]]
        these_potentials = list(final_potentials)
        # instantiate the vjps while parameterizing (forward pass)
        for fn, handle in bonded_tuples:
            params, potential = fn(handle.params)
            these_potentials.append(potential.bind(params))
        nb_params, nb_potential = hgt.parameterize_nonbonded(
            ff.q_handle.params, ff.lj_handle.params)
        these_potentials.append(nb_potential.bind(nb_params))
        bps = these_potentials

        guest_masses = [a.GetMass() for a in guest_mol.GetAtoms()]
        masses = np.concatenate([host_masses, guest_masses])

        for atom_num in constant_atoms:
            masses[atom_num - 1] += 50000

        conformer = guest_mol.GetConformer(0)
        mol_conf = np.array(conformer.GetPositions(), dtype=np.float64)
        mol_conf = mol_conf / 10  # convert to md_units

        if random_rotation:
            center = np.mean(mol_conf, axis=0)
            mol_conf -= center
            from scipy.stats import special_ortho_group

            mol_conf = np.matmul(mol_conf, special_ortho_group.rvs(3))
            mol_conf += center

        x0 = np.concatenate([host_conf, mol_conf])  # combined geometry
        v0 = np.zeros_like(x0)

        seed = 2021
        intg = LangevinIntegrator(300, 1.5e-3, 1.0, masses, seed).impl()

        impls = []
        precision = np.float32
        for b in bps:
            p_impl = b.bound_impl(precision)
            impls.append(p_impl)

        ctxt = custom_ops.Context(x0, v0, box, intg, impls)

        # collect a du_dl calculation once every other step
        subsample_freq = 2
        du_dl_obs = custom_ops.FullPartialUPartialLambda(impls, subsample_freq)
        ctxt.add_observable(du_dl_obs)

        if transition_type == "insertion":
            new_lambda_schedule = np.concatenate([
                np.linspace(max_lambda, 0.0, transition_steps),
                np.zeros(n_steps - transition_steps),
            ])
        elif transition_type == "deletion":
            new_lambda_schedule = np.concatenate([
                np.linspace(0.0, max_lambda, transition_steps),
                np.ones(n_steps - transition_steps) * max_lambda,
            ])
        else:
            raise (RuntimeError(
                'invalid `transition_type` (must be one of ["insertion", "deletion"])'
            ))

        calc_work = True
        for step, lamb in enumerate(new_lambda_schedule):
            ctxt.step(lamb)
            if step % 100 == 0:
                report.report_step(ctxt, step, lamb, box, bps, impls,
                                   guest_name, n_steps, 'pose_dock')
                host_coords = ctxt.get_x_t()[:len(host_conf)] * 10
                guest_coords = ctxt.get_x_t()[len(host_conf):] * 10
                report.write_frame(host_coords, host_mol, guest_coords,
                                   guest_mol, guest_name, outdir, step, 'pd')
            if step in (0, int(n_steps / 2), n_steps - 1):
                if report.too_much_force(ctxt, lamb, box, bps, impls):
                    calc_work = False
                    break

        # Note: this condition only applies for ABFE, not RBFE
        if (abs(du_dl_obs.full_du_dl()[0]) > 0.001
                or abs(du_dl_obs.full_du_dl()[-1]) > 0.001):
            print("Error: du_dl endpoints are not ~0")
            calc_work = False

        if calc_work:
            work = np.trapz(du_dl_obs.full_du_dl(),
                            new_lambda_schedule[::subsample_freq])
            print(f"guest_name: {guest_name}\twork: {work:.2f}")
        end_time = time.time()
        print(f"{guest_name} took {(end_time - start_time):.2f} seconds")
Пример #6
0
def create_system(guest_mol, host_pdb, handlers, stage, core_atoms,
                  restr_force, restr_alpha, restr_count):
    """
    Initialize a self-encompassing System object that we can serialize and simulate.

    Parameters
    ----------

    guest_mol: rdkit.ROMol

    protein: openmm.System


    """
    # host_system = protein_system

    guest_masses = np.array([a.GetMass() for a in guest_mol.GetAtoms()],
                            dtype=np.float64)

    amber_ff = app.ForceField('amber99sbildn.xml', 'amber99_obc.xml')
    host_system = amber_ff.createSystem(host_pdb.topology,
                                        nonbondedMethod=app.NoCutoff,
                                        constraints=None,
                                        rigidWater=False)

    host_fns, host_masses = openmm_deserializer.deserialize_system(host_system)

    num_host_atoms = len(host_masses)
    num_guest_atoms = guest_mol.GetNumAtoms()

    # Name, Args, vjp_fn
    final_gradients = []
    final_vjp_fns = []

    for item in host_fns:

        if item[0] == 'LennardJones':
            host_lj_params = item[1]
        elif item[0] == 'Charges':
            host_charge_params = item[1]
        elif item[0] == 'GBSA':
            host_gb_params = item[1][0]
            host_gb_props = item[1][1:]
        elif item[0] == 'Exclusions':
            host_exclusions = item[1]
        else:
            final_gradients.append((item[0], item[1]))
            final_vjp_fns.append(None)

    # print("Ligand A Name:", a_name)

    guest_exclusion_idxs, guest_scales = nonbonded.generate_exclusion_idxs(
        guest_mol, scale12=1.0, scale13=1.0, scale14=0.5)

    guest_exclusion_idxs += num_host_atoms
    guest_lj_exclusion_scales = guest_scales
    guest_charge_exclusion_scales = guest_scales

    host_exclusion_idxs = host_exclusions[0]
    host_lj_exclusion_scales = host_exclusions[1]
    host_charge_exclusion_scales = host_exclusions[2]

    combined_exclusion_idxs = np.concatenate(
        [host_exclusion_idxs, guest_exclusion_idxs])
    combined_lj_exclusion_scales = np.concatenate(
        [host_lj_exclusion_scales, guest_lj_exclusion_scales])
    combined_charge_exclusion_scales = np.concatenate(
        [host_charge_exclusion_scales, guest_charge_exclusion_scales])

    # handler_vjps = []

    for handle in handlers:
        results = handle.parameterize(guest_mol)

        if isinstance(handle, bonded.HarmonicBondHandler):
            bond_idxs, (bond_params, bond_vjp_fn) = results
            bond_idxs += num_host_atoms
            final_gradients.append(("HarmonicBond", (bond_idxs, bond_params)))
            final_vjp_fns.append((bond_vjp_fn))
            # handler_vjps.append(bond_vjp_fn)
        elif isinstance(handle, bonded.HarmonicAngleHandler):
            angle_idxs, (angle_params, angle_vjp_fn) = results
            angle_idxs += num_host_atoms
            final_gradients.append(
                ("HarmonicAngle", (angle_idxs, angle_params)))
            final_vjp_fns.append(angle_vjp_fn)
            # handler_vjps.append(angle_vjp_fn)
        elif isinstance(handle, bonded.ProperTorsionHandler):
            torsion_idxs, (torsion_params, torsion_vjp_fn) = results
            torsion_idxs += num_host_atoms
            final_gradients.append(
                ("PeriodicTorsion", (torsion_idxs, torsion_params)))
            final_vjp_fns.append(torsion_vjp_fn)
            # handler_vjps.append(torsion_vjp_fn)
            # guest_vjp_fns.append(torsion_vjp_fn)
        elif isinstance(handle, bonded.ImproperTorsionHandler):
            torsion_idxs, (torsion_params, torsion_vjp_fn) = results
            torsion_idxs += num_host_atoms
            final_gradients.append(
                ("PeriodicTorsion", (torsion_idxs, torsion_params)))
            final_vjp_fns.append(torsion_vjp_fn)
            # handler_vjps.append(torsion_vjp_fn)
        elif isinstance(handle, nonbonded.LennardJonesHandler):
            guest_lj_params, guest_lj_vjp_fn = results
            combined_lj_params, combined_lj_vjp_fn = concat_with_vjps(
                host_lj_params, guest_lj_params, None, guest_lj_vjp_fn)
            # handler_vjps.append(lj_adjoint_fn)
        elif isinstance(handle, nonbonded.SimpleChargeHandler):
            guest_charge_params, guest_charge_vjp_fn = results
            combined_charge_params, combined_charge_vjp_fn = concat_with_vjps(
                host_charge_params, guest_charge_params, None,
                guest_charge_vjp_fn)
            # handler_vjps.append(charge_adjoint_fn)
        elif isinstance(handle, nonbonded.GBSAHandler):
            guest_gb_params, guest_gb_vjp_fn = results
            combined_gb_params, combined_gb_vjp_fn = concat_with_vjps(
                host_gb_params, guest_gb_params, None, guest_gb_vjp_fn)
            # handler_vjps.append(gb_adjoint_fn)
        elif isinstance(handle, nonbonded.AM1BCCHandler):
            # ill defined behavior if both SimpleChargeHandler and AM1Handler is present
            guest_charge_params, guest_charge_vjp_fn = results
            combined_charge_params, combined_charge_vjp_fn = concat_with_vjps(
                host_charge_params, guest_charge_params, None,
                guest_charge_vjp_fn)
            # handler_vjps.append(gb_adjoint_fn)
        elif isinstance(handle, nonbonded.AM1CCCHandler):
            guest_charge_params, guest_charge_vjp_fn = results
            combined_charge_params, combined_charge_vjp_fn = concat_with_vjps(
                host_charge_params, guest_charge_params, None,
                guest_charge_vjp_fn)
            # handler_vjps.append(gb_adjoint_fn)
        else:
            raise Exception("Unknown Handler", handle)

    # (use the below vjps for correctness)
    # combined_charge_params, charge_adjoint_fn = concat_with_vjps(host_charge_params, guest_charge_params, None, guest_charge_vjp_fn)
    # combined_lj_params, lj_adjoint_fn = concat_with_vjps(host_lj_params, guest_lj_params, None, guest_lj_vjp_fn)
    # combined_gb_params, gb_adjoint_fn = concat_with_vjps(host_gb_params, guest_gb_params, None, guest_gb_vjp_fn)

    # WIP
    N_C = num_host_atoms + num_guest_atoms
    N_A = num_host_atoms

    if stage == 0:
        combined_lambda_plane_idxs = np.zeros(N_C, dtype=np.int32)
        combined_lambda_offset_idxs = np.zeros(N_C, dtype=np.int32)
    elif stage == 1:
        combined_lambda_plane_idxs = np.zeros(N_C, dtype=np.int32)
        combined_lambda_offset_idxs = np.zeros(N_C, dtype=np.int32)
        combined_lambda_offset_idxs[N_A:] = 1
    elif stage == 2:
        combined_lambda_plane_idxs = np.zeros(N_C, dtype=np.int32)
        combined_lambda_plane_idxs[N_A:] = 1
        combined_lambda_offset_idxs = np.zeros(N_C, dtype=np.int32)

    # assert 0

    cutoff = 100000.0

    final_gradients.append(
        ('Nonbonded',
         (np.asarray(combined_charge_params), np.asarray(combined_lj_params),
          combined_exclusion_idxs, combined_charge_exclusion_scales,
          combined_lj_exclusion_scales, combined_lambda_plane_idxs,
          combined_lambda_offset_idxs, cutoff)))
    final_vjp_fns.append((combined_charge_vjp_fn, combined_lj_vjp_fn))

    final_gradients.append(
        ('GBSA', (np.asarray(combined_charge_params),
                  np.asarray(combined_gb_params), combined_lambda_plane_idxs,
                  combined_lambda_offset_idxs, *host_gb_props, cutoff,
                  cutoff)))
    final_vjp_fns.append((combined_charge_vjp_fn, combined_gb_vjp_fn))

    host_conf = []
    for x, y, z in host_pdb.positions:
        host_conf.append([to_md_units(x), to_md_units(y), to_md_units(z)])
    host_conf = np.array(host_conf)

    conformer = guest_mol.GetConformer(0)
    mol_a_conf = np.array(conformer.GetPositions(), dtype=np.float64)
    mol_a_conf = mol_a_conf / 10  # convert to md_units

    x0 = np.concatenate([host_conf, mol_a_conf])  # combined geometry
    v0 = np.zeros_like(x0)

    # build restraints using the coordinates
    backbone_atoms = []
    for r_idx, residue in enumerate(host_pdb.getTopology().residues()):
        for a in residue.atoms():
            if a.name == 'CA':
                backbone_atoms.append(a.index)

    final_gradients.append(
        setup_core_restraints(restr_force,
                              restr_alpha,
                              restr_count,
                              x0,
                              num_host_atoms,
                              core_atoms,
                              backbone_atoms,
                              stage=stage))

    final_vjp_fns.append(None)

    combined_masses = np.concatenate([host_masses, guest_masses])

    return x0, combined_masses, final_gradients, final_vjp_fns
Пример #7
0
def create_system(guest_mol, host_pdb, handlers):
    """
    Initialize a self-encompassing System object that we can serialize and simulate.

    Parameters
    ----------

    guest_mol: rdkit.ROMol
        guest molecule
        
    host_pdb: openmm.PDBFile
        host system from OpenMM

    handlers: list of timemachine.ops.Gradients
        forcefield handlers used to parameterize the small molecule
 
    Returns
    -------
    3-tuple
        x0, combined_masses, final_gradients

    """

    guest_masses = np.array([a.GetMass() for a in guest_mol.GetAtoms()],
                            dtype=np.float64)

    amber_ff = app.ForceField('amber99sbildn.xml', 'amber99_obc.xml')
    host_system = amber_ff.createSystem(host_pdb.topology,
                                        nonbondedMethod=app.NoCutoff,
                                        constraints=None,
                                        rigidWater=False)

    host_fns, host_masses = openmm_deserializer.deserialize_system(host_system)

    num_host_atoms = len(host_masses)
    num_guest_atoms = guest_mol.GetNumAtoms()

    # Name, Args, vjp_fn
    final_gradients = []

    for item in host_fns:

        if item[0] == 'LennardJones':
            host_lj_params = item[1]
        elif item[0] == 'Charges':
            host_charge_params = item[1]
        elif item[0] == 'GBSA':
            host_gb_params = item[1][0]
            host_gb_props = item[1][1:]
        elif item[0] == 'Exclusions':
            host_exclusions = item[1]
        else:
            final_gradients.append((item[0], item[1]))

    guest_exclusion_idxs, guest_scales = nonbonded.generate_exclusion_idxs(
        guest_mol, scale12=1.0, scale13=1.0, scale14=0.5)

    guest_exclusion_idxs += num_host_atoms
    guest_lj_exclusion_scales = guest_scales
    guest_charge_exclusion_scales = guest_scales

    host_exclusion_idxs = host_exclusions[0]
    host_lj_exclusion_scales = host_exclusions[1]
    host_charge_exclusion_scales = host_exclusions[2]

    combined_exclusion_idxs = np.concatenate(
        [host_exclusion_idxs, guest_exclusion_idxs])
    combined_lj_exclusion_scales = np.concatenate(
        [host_lj_exclusion_scales, guest_lj_exclusion_scales])
    combined_charge_exclusion_scales = np.concatenate(
        [host_charge_exclusion_scales, guest_charge_exclusion_scales])

    for handle in handlers:
        results = handle.parameterize(guest_mol)

        if isinstance(handle, bonded.HarmonicBondHandler):
            bond_idxs, (bond_params, _) = results
            bond_idxs += num_host_atoms
            final_gradients.append(("HarmonicBond", (bond_idxs, bond_params)))
        elif isinstance(handle, bonded.HarmonicAngleHandler):
            angle_idxs, (angle_params, _) = results
            angle_idxs += num_host_atoms
            final_gradients.append(
                ("HarmonicAngle", (angle_idxs, angle_params)))
        elif isinstance(handle, bonded.ProperTorsionHandler):
            torsion_idxs, (torsion_params, _) = results
            torsion_idxs += num_host_atoms
            final_gradients.append(
                ("PeriodicTorsion", (torsion_idxs, torsion_params)))
        elif isinstance(handle, bonded.ImproperTorsionHandler):
            torsion_idxs, (torsion_params, _) = results
            torsion_idxs += num_host_atoms
            final_gradients.append(
                ("PeriodicTorsion", (torsion_idxs, torsion_params)))
        elif isinstance(handle, nonbonded.LennardJonesHandler):
            guest_lj_params, _ = results
            combined_lj_params = np.concatenate(
                [host_lj_params, guest_lj_params])
        elif isinstance(handle, nonbonded.SimpleChargeHandler):
            guest_charge_params, _ = results
            combined_charge_params = np.concatenate(
                [host_charge_params, guest_charge_params])
        elif isinstance(handle, nonbonded.GBSAHandler):
            guest_gb_params, _ = results
            combined_gb_params = np.concatenate(
                [host_gb_params, guest_gb_params])
        elif isinstance(handle, nonbonded.AM1BCCHandler):
            guest_charge_params, _ = results
            combined_charge_params = np.concatenate(
                [host_charge_params, guest_charge_params])
        elif isinstance(handle, nonbonded.AM1CCCHandler):
            guest_charge_params, _ = results
            combined_charge_params = np.concatenate(
                [host_charge_params, guest_charge_params])
        else:
            raise Exception("Unknown Handler", handle)

    host_conf = []
    for x, y, z in host_pdb.positions:
        host_conf.append([to_md_units(x), to_md_units(y), to_md_units(z)])
    host_conf = np.array(host_conf)

    conformer = guest_mol.GetConformer(0)
    mol_a_conf = np.array(conformer.GetPositions(), dtype=np.float64)
    mol_a_conf = mol_a_conf / 10  # convert to md_units

    center = np.mean(mol_a_conf, axis=0)

    mol_a_conf -= center

    from scipy.stats import special_ortho_group
    mol_a_conf = np.matmul(mol_a_conf, special_ortho_group.rvs(3))
    mol_a_conf += center

    # assert 0

    x0 = np.concatenate([host_conf, mol_a_conf])  # combined geometry
    v0 = np.zeros_like(x0)

    N_C = num_host_atoms + num_guest_atoms
    N_A = num_host_atoms

    cutoff = 100000.0

    combined_lambda_plane_idxs = np.zeros(N_C, dtype=np.int32)
    combined_lambda_offset_idxs = np.zeros(N_C, dtype=np.int32)
    combined_lambda_offset_idxs[num_host_atoms:] = 1

    final_gradients.append(
        ('Nonbonded',
         (np.asarray(combined_charge_params), np.asarray(combined_lj_params),
          combined_exclusion_idxs, combined_charge_exclusion_scales,
          combined_lj_exclusion_scales, combined_lambda_plane_idxs,
          combined_lambda_offset_idxs, cutoff)))

    final_gradients.append(
        ('GBSA', (np.asarray(combined_charge_params),
                  np.asarray(combined_gb_params), combined_lambda_plane_idxs,
                  combined_lambda_offset_idxs, *host_gb_props, cutoff,
                  cutoff)))

    combined_masses = np.concatenate([host_masses, guest_masses])

    return x0, combined_masses, final_gradients
Пример #8
0
def create_system(guest_mol, host_pdb, handlers, restr_search_radius,
                  restr_force_constant, intg_temperature, stage):
    """
    Initialize a self-encompassing System object that we can serialize and simulate.

    Parameters
    ----------

    guest_mol: rdkit.ROMol
        guest molecule
        
    host_pdb: openmm.PDBFile
        host system from OpenMM

    handlers: list of timemachine.ops.Gradients
        forcefield handlers used to parameterize the system

    restr_search_radius: float
        how far away we search from the ligand to define the binding pocket atoms.

    restr_force_constant: float
        strength of the harmonic oscillator for the restraint

    intg_temperature: float
        temperature of the integrator in Kelvin

    stage: int (0 or 1)
        a free energy specific variable that determines how we decouple.
 
    """

    guest_masses = np.array([a.GetMass() for a in guest_mol.GetAtoms()],
                            dtype=np.float64)

    amber_ff = app.ForceField('amber99sbildn.xml', 'amber99_obc.xml')
    host_system = amber_ff.createSystem(host_pdb.topology,
                                        nonbondedMethod=app.NoCutoff,
                                        constraints=None,
                                        rigidWater=False)

    host_fns, host_masses = openmm_deserializer.deserialize_system(host_system)

    num_host_atoms = len(host_masses)
    num_guest_atoms = guest_mol.GetNumAtoms()

    # Name, Args, vjp_fn
    final_gradients = []

    for item in host_fns:

        if item[0] == 'LennardJones':
            host_lj_params = item[1]
        elif item[0] == 'Charges':
            host_charge_params = item[1]
        elif item[0] == 'GBSA':
            host_gb_params = item[1][0]
            host_gb_props = item[1][1:]
        elif item[0] == 'Exclusions':
            host_exclusions = item[1]
        else:
            final_gradients.append((item[0], item[1]))

    guest_exclusion_idxs, guest_scales = nonbonded.generate_exclusion_idxs(
        guest_mol, scale12=1.0, scale13=1.0, scale14=0.5)

    guest_exclusion_idxs += num_host_atoms
    guest_lj_exclusion_scales = guest_scales
    guest_charge_exclusion_scales = guest_scales

    host_exclusion_idxs = host_exclusions[0]
    host_lj_exclusion_scales = host_exclusions[1]
    host_charge_exclusion_scales = host_exclusions[2]

    combined_exclusion_idxs = np.concatenate(
        [host_exclusion_idxs, guest_exclusion_idxs])
    combined_lj_exclusion_scales = np.concatenate(
        [host_lj_exclusion_scales, guest_lj_exclusion_scales])
    combined_charge_exclusion_scales = np.concatenate(
        [host_charge_exclusion_scales, guest_charge_exclusion_scales])

    # We build up a map of handles to a corresponding vjp_fn that takes in adjoints of output parameters
    # for nonbonded terms, the vjp_fn has been modified to take in combined parameters
    handler_vjp_fns = {}

    for handle in handlers:
        results = handle.parameterize(guest_mol)

        if isinstance(handle, bonded.HarmonicBondHandler):
            bond_idxs, (bond_params, handler_vjp_fn) = results
            bond_idxs += num_host_atoms
            final_gradients.append(("HarmonicBond", (bond_idxs, bond_params)))
        elif isinstance(handle, bonded.HarmonicAngleHandler):
            angle_idxs, (angle_params, handler_vjp_fn) = results
            angle_idxs += num_host_atoms
            final_gradients.append(
                ("HarmonicAngle", (angle_idxs, angle_params)))
        elif isinstance(handle, bonded.ProperTorsionHandler):
            torsion_idxs, (torsion_params, handler_vjp_fn) = results
            torsion_idxs += num_host_atoms
            final_gradients.append(
                ("PeriodicTorsion", (torsion_idxs, torsion_params)))
        elif isinstance(handle, bonded.ImproperTorsionHandler):
            torsion_idxs, (torsion_params, handler_vjp_fn) = results
            torsion_idxs += num_host_atoms
            final_gradients.append(
                ("PeriodicTorsion", (torsion_idxs, torsion_params)))
        elif isinstance(handle, nonbonded.LennardJonesHandler):
            guest_lj_params, guest_lj_vjp_fn = results
            combined_lj_params, handler_vjp_fn = concat_with_vjps(
                host_lj_params, guest_lj_params, None, guest_lj_vjp_fn)
        elif isinstance(handle, nonbonded.SimpleChargeHandler):
            guest_charge_params, guest_charge_vjp_fn = results
            combined_charge_params, handler_vjp_fn = concat_with_vjps(
                host_charge_params, guest_charge_params, None,
                guest_charge_vjp_fn)
        elif isinstance(handle, nonbonded.GBSAHandler):
            guest_gb_params, guest_gb_vjp_fn = results
            combined_gb_params, handler_vjp_fn = concat_with_vjps(
                host_gb_params, guest_gb_params, None, guest_gb_vjp_fn)
        elif isinstance(handle, nonbonded.AM1BCCHandler):
            guest_charge_params, guest_charge_vjp_fn = results
            combined_charge_params, handler_vjp_fn = concat_with_vjps(
                host_charge_params, guest_charge_params, None,
                guest_charge_vjp_fn)
        elif isinstance(handle, nonbonded.AM1CCCHandler):
            guest_charge_params, guest_charge_vjp_fn = results
            combined_charge_params, handler_vjp_fn = concat_with_vjps(
                host_charge_params, guest_charge_params, None,
                guest_charge_vjp_fn)
        else:
            raise Exception("Unknown Handler", handle)

        handler_vjp_fns[handle] = handler_vjp_fn

    host_conf = []
    for x, y, z in host_pdb.positions:
        host_conf.append([to_md_units(x), to_md_units(y), to_md_units(z)])
    host_conf = np.array(host_conf)

    conformer = guest_mol.GetConformer(0)
    mol_a_conf = np.array(conformer.GetPositions(), dtype=np.float64)
    mol_a_conf = mol_a_conf / 10  # convert to md_units

    x0 = np.concatenate([host_conf, mol_a_conf])  # combined geometry
    v0 = np.zeros_like(x0)

    pocket_atoms = find_protein_pocket_atoms(x0, num_host_atoms,
                                             restr_search_radius)

    N_C = num_host_atoms + num_guest_atoms
    N_A = num_host_atoms

    cutoff = 100000.0

    if stage == 0:
        combined_lambda_plane_idxs = np.zeros(N_C, dtype=np.int32)
        combined_lambda_offset_idxs = np.zeros(N_C, dtype=np.int32)
    elif stage == 1:
        combined_lambda_plane_idxs = np.zeros(N_C, dtype=np.int32)
        combined_lambda_offset_idxs = np.zeros(N_C, dtype=np.int32)
        combined_lambda_offset_idxs[num_host_atoms:] = 1
    else:
        assert 0

    final_gradients.append(
        ('Nonbonded',
         (np.asarray(combined_charge_params), np.asarray(combined_lj_params),
          combined_exclusion_idxs, combined_charge_exclusion_scales,
          combined_lj_exclusion_scales, combined_lambda_plane_idxs,
          combined_lambda_offset_idxs, cutoff)))

    final_gradients.append(
        ('GBSA', (np.asarray(combined_charge_params),
                  np.asarray(combined_gb_params), combined_lambda_plane_idxs,
                  combined_lambda_offset_idxs, *host_gb_props, cutoff,
                  cutoff)))

    ligand_idxs = np.arange(N_A, N_C, dtype=np.int32)

    # restraints
    if stage == 0:
        lamb_flag = 1
        lamb_offset = 0
    if stage == 1:
        lamb_flag = 0
        lamb_offset = 1

    # unweighted center of mass restraints
    avg_xi = np.mean(x0[ligand_idxs], axis=0)
    avg_xj = np.mean(x0[pocket_atoms], axis=0)
    ctr_dij = np.sqrt(np.sum((avg_xi - avg_xj)**2))

    combined_masses = np.concatenate([host_masses, guest_masses])

    # restraints
    final_gradients.append(
        ('CentroidRestraint',
         (ligand_idxs, pocket_atoms, combined_masses, restr_force_constant,
          ctr_dij, lamb_flag, lamb_offset)))

    ssc = standard_state.harmonic_com_ssc(restr_force_constant, ctr_dij,
                                          intg_temperature)

    return x0, combined_masses, ssc, final_gradients, handler_vjp_fns