예제 #1
0
def create_compound_ghmc_integrator(testsystem):
    """
    Sets up a compound integrator that uses GHMC.
    Parameters
    ----------
    testsystem - a SystemSetup object that contains details such as the temperature, timestep, et cetera.

    Returns
    -------
    simtk.openmm.openmm.CompoundIntegrator
    """
    integrator = GHMCIntegrator(
        temperature=testsystem.temperature,
        collision_rate=testsystem.collision_rate,
        timestep=testsystem.timestep,
        nsteps=testsystem.nsteps_per_ghmc,
    )
    ncmc_propagation_integrator = GHMCIntegrator(
        temperature=testsystem.temperature,
        collision_rate=testsystem.collision_rate,
        timestep=testsystem.timestep,
        nsteps=testsystem.nsteps_per_ghmc,
    )
    compound_integrator = openmm.CompoundIntegrator()
    compound_integrator.addIntegrator(integrator)
    compound_integrator.addIntegrator(ncmc_propagation_integrator)
    compound_integrator.setCurrentIntegrator(0)
    return compound_integrator
예제 #2
0
def create_compound_gbaoab_integrator(testsystem):
    """
    Sets up a compound integrator that uses gBAOAB.
    Parameters
    ----------
    testsystem - a SystemSetup object that contains details such as the temperature, timestep, et cetera.

    Returns
    -------
    simtk.openmm.openmm.CompoundIntegrator
    """
    integrator = GBAOABIntegrator(
        temperature=testsystem.temperature,
        collision_rate=testsystem.collision_rate,
        timestep=testsystem.timestep,
        constraint_tolerance=testsystem.constraint_tolerance,
    )
    ncmc_propagation_integrator = GBAOABIntegrator(
        temperature=testsystem.temperature,
        collision_rate=testsystem.collision_rate,
        timestep=testsystem.timestep,
        constraint_tolerance=testsystem.constraint_tolerance,
    )
    compound_integrator = openmm.CompoundIntegrator()
    compound_integrator.addIntegrator(integrator)
    compound_integrator.addIntegrator(ncmc_propagation_integrator)
    compound_integrator.setCurrentIntegrator(0)
    return compound_integrator
예제 #3
0
def collect_switching_data(system, positions, functions, temperature, collision_rate, timestep, platform, ghmc_nsteps=200, ncmc_nsteps=50, niterations=100, direction='insert', ncmc_integrator=None):
    """
    Collect switching data.

    """

    work_n = np.zeros([niterations], np.float64) # work[iteration] is work (log probability) in kT from iteration `iteration`

    # Create integrators.
    integrator = openmm.CompoundIntegrator()
    # Create GHMC integrator.
    from openmmtools.integrators import GHMCIntegrator
    ghmc_integrator = GHMCIntegrator(temperature=temperature, collision_rate=collision_rate, timestep=timestep)
    integrator.addIntegrator(ghmc_integrator)
    # Create an NCMC switching integrator.
    integrator.addIntegrator(ncmc_integrator)

    # Create Context
    context = openmm.Context(system, integrator, platform)
    context.setPositions(positions)
    context.setVelocitiesToTemperature(temperature)

    naccept_n = np.zeros([niterations], np.int32)
    ntrials_n = np.zeros([niterations], np.int32)
    for iteration in range(niterations):
        # Equilibrate
        integrator.setCurrentIntegrator(0)
        if direction == 'insert':
            context.setParameter('x0', 0)
        elif direction == 'delete':
            context.setParameter('x0', 1)
        else:
            raise Exception("direction '%s' unknown; must be 'insert' or 'delete'." % direction)
        integrator.step(ghmc_nsteps)

        # Switch
        integrator.setCurrentIntegrator(1)
        ncmc_integrator.reset()
        if ncmc_nsteps == 0:
            integrator.step(1)
        else:
            integrator.step(ncmc_nsteps)
            #print("The step is %d" % ncmc_integrator.get_step())
        work_n[iteration] = - ncmc_integrator.getLogAcceptanceProbability(context)

        if ncmc_integrator.has_statistics:
            (naccept_n[iteration], ntrials_n[iteration]) = ncmc_integrator.getGHMCStatistics(context)

    if ncmc_integrator.has_statistics:
        print('GHMC: %d / %d accepted' % (naccept_n.sum(), ntrials_n.sum()))

    # Clean up
    del context, integrator
    return work_n
예제 #4
0
def run_prep_ffxml_main(jsonfile):
    """Main simulation loop."""

    log.info(f"Preparing a run from '{jsonfile}'")

    # TODO Validate json input with json schema?
    settings = yaml.load(open(jsonfile, "r"))

    log.debug(f"Loaded these settings. {settings}")

    try:
        format_vars: Dict[str, str] = settings["format_vars"]
    except KeyError:
        format_vars = dict()

    # Input files
    inp = settings["input"]
    idir = inp["dir"].format(**format_vars)

    # Make a ForceField object from user directed files

    # Look for block in input
    try:
        ff: Dict[str, List[str]] = settings["forcefield"]
    except KeyError:
        raise KeyError("No forcefield block specified")

    # Any files included with openmm/protons by default are retrieved here
    try:
        default_ff: List[str] = ff["default"]
    except KeyError:
        # In typical use case I wouldn't expect purely user files to be used.
        warn("'default' list missing from 'forcefield' block.", UserWarning)
        default_ff = []

    # all user provided files here
    try:
        user_ff: List[str] = ff["user"]
        user_ff_paths: List[str] = []
        for user_file in user_ff:
            rel_path = os.path.join(idir, user_file.format(**format_vars))
            user_ff_paths.append(os.path.abspath(rel_path))
    except KeyError:
        user_ff_paths = []

    if len(default_ff) + len(user_ff_paths) == 0:
        raise ValueError("No forcefield files provided.")
    forcefield = app.ForceField(*(user_ff_paths + default_ff))

    # Load structure
    # The input should be an mmcif/pdbx file'
    ifilename = inp["structure"].format(**format_vars)
    joined_path = os.path.join(idir, ifilename)
    input_pdbx_file = os.path.abspath(joined_path)
    pdb_object = app.PDBxFile(input_pdbx_file)

    # Atoms , connectivity, residues
    topology = pdb_object.topology
    # Store topology for serialization
    topology_file_content = open(input_pdbx_file, "r").read()

    # XYZ positions for every atom
    positions = pdb_object.positions

    # Quick fix for histidines in topology
    # Openmm relabels them HIS, which leads to them not being detected as
    # titratable. Renaming them fixes this.

    for residue in topology.residues():
        if residue.name == "HIS":
            residue.name = "HIP"
        # TODO doublecheck if ASH GLH need to be renamed
        elif residue.name == "ASP":
            residue.name = "ASH"
        elif residue.name == "GLU":
            residue.name = "GLH"

    # Naming the output files
    out = settings["output"]
    odir = out["dir"].format(**format_vars)
    obasename = out["basename"].format(**format_vars)
    if not os.path.isdir(odir):
        os.makedirs(odir)
    lastdir = os.getcwd()
    os.chdir(odir)

    # File for resuming simulation
    output_checkpoint_file = f"{obasename}-checkpoint-0.xml"

    # Structure preprocessing settings
    if "preprocessing" in settings:
        preproc: Dict[str, Any] = settings["preprocessing"]

        # Steps of MD before starting the main loop
        num_thermalization_steps = int(preproc["num_thermalization_steps"])
        pre_run_minimization_tolerance: unit.Quantity = float(
            preproc["minimization_tolerance_kjmol"]
        ) * unit.kilojoule / unit.mole
        minimization_max_iterations = int(preproc["minimization_max_iterations"])

    # System Configuration
    sysprops = settings["system"]
    temperature = float(sysprops["temperature_k"]) * unit.kelvin
    if "salt_concentration_molar" in sysprops:
        salt_concentration: unit.Quantity = float(
            sysprops["salt_concentration_molar"]
        ) * unit.molar
    elif "PME" in sysprops:
        salt_concentration = 0.0 * unit.molar
    else:
        salt_concentration = None

    rigidWater = True
    constraints = app.HBonds

    if "PME" in sysprops:
        pmeprops = sysprops["PME"]
        nonbondedMethod = app.PME
        ewaldErrorTolerance = float(pmeprops["ewald_error_tolerance"])
        barostatInterval = int(pmeprops["barostat_interval"])
        switching_distance = float(pmeprops["switching_distance_nm"]) * unit.nanometers
        nonbondedCutoff = float(pmeprops["nonbonded_cutoff_nm"]) * unit.nanometers
        pressure = float(pmeprops["pressure_atm"]) * unit.atmosphere
        disp_corr = bool(pmeprops["dispersion_correction"])

        system = forcefield.createSystem(
            topology,
            nonbondedMethod=nonbondedMethod,
            constraints=constraints,
            rigidWater=rigidWater,
            ewaldErrorTolerance=ewaldErrorTolerance,
            nonbondedCutoff=nonbondedCutoff,
        )
        for force in system.getForces():
            if isinstance(force, mm.NonbondedForce):
                force.setUseSwitchingFunction(True)
                force.setSwitchingDistance(switching_distance)
                force.setUseDispersionCorrection(disp_corr)

        # NPT simulation
        system.addForce(mm.MonteCarloBarostat(pressure, temperature, barostatInterval))
    else:
        pressure = None
        system = forcefield.createSystem(
            topology,
            nonbondedMethod=app.NoCutoff,
            constraints=app.HBonds,
            rigidWater=True,
        )

    # Integrator options
    integrator_opts = settings["integrator"]
    timestep = integrator_opts["timestep_fs"] * unit.femtosecond
    constraint_tolerance = integrator_opts["constraint_tolerance"]
    collision_rate = integrator_opts["collision_rate_per_ps"] / unit.picosecond
    number_R_steps = 1

    integrator = ExternalGBAOABIntegrator(
        number_R_steps=number_R_steps,
        temperature=temperature,
        collision_rate=collision_rate,
        timestep=timestep,
        constraint_tolerance=constraint_tolerance,
    )
    ncmc_propagation_integrator = ExternalGBAOABIntegrator(
        number_R_steps=number_R_steps,
        temperature=temperature,
        collision_rate=collision_rate,
        timestep=timestep,
        constraint_tolerance=constraint_tolerance,
    )

    # Define a compound integrator
    compound_integrator = mm.CompoundIntegrator()
    compound_integrator.addIntegrator(integrator)
    compound_integrator.addIntegrator(ncmc_propagation_integrator)
    compound_integrator.setCurrentIntegrator(0)

    # Script specific settings

    if "importance" in settings:
        sampling_method = SamplingMethod.IMPORTANCE
    else:
        sampling_method = SamplingMethod.MCMC

    driver = ForceFieldProtonDrive(
        temperature,
        topology,
        system,
        forcefield,
        user_ff_paths + ["amber10-constph.xml"],
        pressure=pressure,
        perturbations_per_trial=100_000,
        propagations_per_step=1,
    )

    if "reference_free_energies" in settings:
        # calibrated free energy values can be provided here
        gk_dict = settings["reference_free_energies"]

        # Clean comments inside dictionary
        to_delete = list()
        for key in gk_dict.keys():
            if key.startswith("_"):
                to_delete.append(key)

        for key in to_delete:
            del (gk_dict[key])

        # Make arrays
        for key, value in gk_dict.items():
            # Convert to array of float
            val_array = np.asarray(value).astype(np.float64)
            if not val_array.ndim == 1:
                raise ValueError("Reference free energies should be simple lists.")
            gk_dict[key] = val_array

        driver.import_gk_values(gk_dict)

    # TODO allow platform specification for setup

    platform = mm.Platform.getPlatformByName("OpenCL")
    properties = {"OpenCLPrecision": "double"}

    # Set up calibration mode
    # SAMS settings

    if "SAMS" in settings and "importance" in settings:
        raise NotImplementedError("Cannot combine SAMS and importance sampling.")

    elif "SAMS" in settings:
        sams = settings["SAMS"]

        beta_burnin = float(sams["beta"])
        min_burnin = int(sams["min_burn"])
        min_slow = int(sams["min_slow"])
        min_fast = int(sams["min_fast"])

        flatness_criterion = float(sams["flatness_criterion"])
        if sams["update_rule"] == "binary":
            update_rule = UpdateRule.BINARY
        elif sams["update_rule"] == "global":
            update_rule = UpdateRule.GLOBAL
        else:
            update_rule = UpdateRule.BINARY

        # Assumes calibration residue is always the last titration group if onesite

        if sams["sites"] == "multi":
            driver.enable_calibration(
                approach=SAMSApproach.MULTISITE,
                update_rule=update_rule,
                flatness_criterion=flatness_criterion,
                min_burn=min_burnin,
                min_slow=min_slow,
                min_fast=min_fast,
                beta_sams=beta_burnin,
            )
        elif sams["sites"] == "one":
            if "group_index" in sams:
                calibration_titration_group_index = int(sams["group_index"])
            else:
                calibration_titration_group_index = len(driver.titrationGroups) - 1

            driver.enable_calibration(
                approach=SAMSApproach.ONESITE,
                group_index=calibration_titration_group_index,
                update_rule=update_rule,
                flatness_criterion=flatness_criterion,
                min_burn=min_burnin,
                min_slow=min_slow,
                min_fast=min_fast,
            )
            # Define residue pools
            pools = {"calibration": [calibration_titration_group_index]}
            # TODO the pooling feature could eventually be exposed in the json
            driver.define_pools(pools)

    # Create simulation object
    # If calibration is required, this class will automatically deal with it.
    simulation = app.ConstantPHSimulation(
        topology,
        system,
        compound_integrator,
        driver,
        platform=platform,
        platformProperties=properties,
    )
    simulation.context.setPositions(positions)

    # After the simulation system has been defined, we can add salt to the system using saltswap.
    if salt_concentration is not None:
        salinator = Salinator(
            context=simulation.context,
            system=system,
            topology=topology,
            ncmc_integrator=compound_integrator.getIntegrator(1),
            salt_concentration=salt_concentration,
            pressure=pressure,
            temperature=temperature,
        )
        salinator.neutralize()
        salinator.initialize_concentration()
        if "neutral_charge_rule" not in sysprops:
            raise KeyError(
                "Specification of neutral_charge_rule for explicit solvent required in system."
            )

        charge_rule = NeutralChargeRule(sysprops["neutral_charge_rule"])
        driver.enable_neutralizing_ions(
            salinator.swapper, neutral_charge_rule=charge_rule
        )
    else:
        # Implicit solvent
        salinator = None

    # Set the fixed titration state in case of importance sampling
    if sampling_method is SamplingMethod.IMPORTANCE:
        if "titration_states" in settings["importance"]:
            fixed_states = settings["importance"]["titration_states"]

            if len(fixed_states) != len(driver.titrationStates):
                raise IndexError(
                    "The number of residues specified for importance sampling does not match the number of titratable residues."
                )

            else:
                for group_id, state_id in enumerate(fixed_states):
                    driver.set_titration_state(
                        group_id,
                        state_id,
                        updateContextParameters=True,
                        updateIons=True,
                    )

                # Minimize the initial configuration to remove bad contacts
                if "preprocessing" in settings:
                    simulation.minimizeEnergy(
                        tolerance=pre_run_minimization_tolerance,
                        maxIterations=minimization_max_iterations,
                    )
                    # Slightly equilibrate the system, detect early issues.
                    simulation.step(num_thermalization_steps)

                # export the context
                create_protons_checkpoint_file(
                    output_checkpoint_file,
                    driver,
                    simulation.context,
                    simulation.system,
                    simulation.integrator,
                    topology_file_content,
                    salinator=salinator,
                )

        elif "systematic" in settings["importance"]:
            if settings["importance"]["systematic"]:

                # Make checkpoint files for the combinatorial space of residue states.
                for importance_index, state_combination in enumerate(
                    product(*[np.arange(len(res)) for res in driver.titrationGroups])
                ):
                    for res_id, state_id in enumerate(state_combination):
                        driver.set_titration_state(
                            res_id,
                            state_id,
                            updateContextParameters=True,
                            updateIons=True,
                        )

                    # Minimize the initial configuration to remove bad contacts
                    if "preprocessing" in settings:
                        simulation.minimizeEnergy(
                            tolerance=pre_run_minimization_tolerance,
                            maxIterations=minimization_max_iterations,
                        )
                        # Slightly equilibrate the system, detect early issues.
                        simulation.step(num_thermalization_steps)

                    # export the context
                    create_protons_checkpoint_file(
                        f"{obasename}-importance-state-{importance_index}-checkpoint-0.xml",
                        driver,
                        simulation.context,
                        simulation.system,
                        simulation.integrator,
                        topology_file_content,
                        salinator=salinator,
                    )
            os.chdir(lastdir)

    else:

        # Minimize the initial configuration to remove bad contacts
        if "preprocessing" in settings:
            simulation.minimizeEnergy(
                tolerance=pre_run_minimization_tolerance,
                maxIterations=minimization_max_iterations,
            )
            # Slightly equilibrate the system, detect early issues.
            simulation.step(num_thermalization_steps)

        # export the context
        create_protons_checkpoint_file(
            output_checkpoint_file,
            driver,
            simulation.context,
            simulation.system,
            simulation.integrator,
            topology_file_content,
            salinator=salinator,
        )

    os.chdir(lastdir)
예제 #5
0
    def test_system_charge_reporting(self):
        """Test if the system_charge is correctly reported."""

        pdb = app.PDBxFile(
            get_test_data("glu_ala_his-solvated-minimized-renamed.cif",
                          "testsystems/tripeptides"))
        initial_charge = (
            0
        )  # Ion totals are 0, and the system starts in state 0 for both, GLU deprotonated, HIS protonated
        forcefield = app.ForceField("amber10-constph.xml", "ions_tip3p.xml",
                                    "tip3p.xml")

        system = forcefield.createSystem(
            pdb.topology,
            nonbondedMethod=app.PME,
            nonbondedCutoff=1.0 * unit.nanometers,
            constraints=app.HBonds,
            rigidWater=True,
            ewaldErrorTolerance=0.0005,
        )

        temperature = 300 * unit.kelvin
        integrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=False,
        )
        ncmcintegrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=True,
        )

        compound_integrator = mm.CompoundIntegrator()
        compound_integrator.addIntegrator(integrator)
        compound_integrator.addIntegrator(ncmcintegrator)
        pressure = 1.0 * unit.atmosphere

        system.addForce(mm.MonteCarloBarostat(pressure, temperature))
        driver = ForceFieldProtonDrive(
            temperature,
            pdb.topology,
            system,
            forcefield,
            ["amber10-constph.xml"],
            pressure=pressure,
            perturbations_per_trial=0,
        )

        # pools defined by their residue index for convenience later on
        driver.define_pools({"0": [0], "1": [1]})
        simulation = app.ConstantPHSimulation(
            pdb.topology,
            system,
            compound_integrator,
            driver,
            platform=self._default_platform,
        )
        simulation.context.setPositions(pdb.positions)
        simulation.context.setVelocitiesToTemperature(temperature)
        filename = uuid.uuid4().hex + ".nc"
        ncfile = netCDF4.Dataset(filename, "w")
        print("Temporary file: ", filename)
        newreporter = tr.TitrationReporter(ncfile, 2)
        simulation.update_reporters.append(newreporter)

        # Regular MD step
        simulation.step(1)
        # Update the titration states forcibly from a pregenerated series

        glu_states = np.asarray([
            1, 4, 4, 1, 0, 2, 0, 2, 4, 3, 2, 1, 0, 2, 0, 0, 0, 0, 0, 0, 1, 2,
            1, 3, 1
        ])
        his_states = np.asarray([
            2, 1, 0, 1, 2, 2, 1, 2, 2, 1, 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0, 2,
            2, 2, 1
        ])

        for i in range(len(glu_states)):

            simulation.drive.set_titration_state(0,
                                                 glu_states[i],
                                                 updateContextParameters=False)
            simulation.drive.set_titration_state(1,
                                                 his_states[i],
                                                 updateContextParameters=False)
            simulation.update_reporters[0].report(simulation)
            tot_charge = 0
            for resi, residue in enumerate(simulation.drive.titrationGroups):
                icharge = int(floor(0.5 + residue.total_charge))
                tot_charge += icharge
                assert (
                    ncfile["Protons/Titration/{}_charge".format(resi)][i] ==
                    icharge), "Residue charge is not recorded correctly."
            assert (
                ncfile["Protons/Titration/complex_charge"][i] == tot_charge
            ), "The recorded complex total charge does not match the actual charge."

        # close files to avoid segfaults, possibly
        ncfile.close()
예제 #6
0
    def test_atom_status_reporting(self):
        """Test if the atom_status is correctly reported."""

        pdb = app.PDBxFile(
            get_test_data("glu_ala_his-solvated-minimized-renamed.cif",
                          "testsystems/tripeptides"))
        forcefield = app.ForceField("amber10-constph.xml", "ions_tip3p.xml",
                                    "tip3p.xml")

        system = forcefield.createSystem(
            pdb.topology,
            nonbondedMethod=app.PME,
            nonbondedCutoff=1.0 * unit.nanometers,
            constraints=app.HBonds,
            rigidWater=True,
            ewaldErrorTolerance=0.0005,
        )

        temperature = 300 * unit.kelvin
        integrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=False,
        )
        ncmcintegrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=True,
        )

        compound_integrator = mm.CompoundIntegrator()
        compound_integrator.addIntegrator(integrator)
        compound_integrator.addIntegrator(ncmcintegrator)
        pressure = 1.0 * unit.atmosphere

        system.addForce(mm.MonteCarloBarostat(pressure, temperature))
        driver = ForceFieldProtonDrive(
            temperature,
            pdb.topology,
            system,
            forcefield,
            ["amber10-constph.xml"],
            pressure=pressure,
            perturbations_per_trial=0,
        )

        simulation = app.ConstantPHSimulation(
            pdb.topology,
            system,
            compound_integrator,
            driver,
            platform=self._default_platform,
        )
        simulation.context.setPositions(pdb.positions)
        simulation.context.setVelocitiesToTemperature(temperature)
        filename = uuid.uuid4().hex + ".nc"
        ncfile = netCDF4.Dataset(filename, "w")
        print("Temporary file: ", filename)
        newreporter = tr.TitrationReporter(ncfile, 2)
        simulation.update_reporters.append(newreporter)

        # Regular MD step
        simulation.step(1)
        # Update the titration states forcibly from a pregenerated series
        glu_states = np.asarray([
            1, 4, 4, 1, 0, 2, 0, 2, 4, 3, 2, 1, 0, 2, 0, 0, 0, 0, 0, 0, 1, 2,
            1, 3, 1
        ])
        his_states = np.asarray([
            2, 1, 0, 1, 2, 2, 1, 2, 2, 1, 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0, 2,
            2, 2, 1
        ])

        for i in range(len(glu_states)):
            simulation.drive.set_titration_state(0,
                                                 glu_states[i],
                                                 updateContextParameters=False)
            simulation.drive.set_titration_state(1,
                                                 his_states[i],
                                                 updateContextParameters=False)
            simulation.update_reporters[0].report(simulation)
            # check glu
            self._verify_atom_status(i, 0, ncfile, simulation)
            # check his
            self._verify_atom_status(i, 1, ncfile, simulation)

        ncfile.close()
예제 #7
0
    def test_reports(self):
        """Instantiate a ConstantPHSimulation at 300K/1 atm for a small peptide."""

        pdb = app.PDBxFile(
            get_test_data("glu_ala_his-solvated-minimized-renamed.cif",
                          "testsystems/tripeptides"))
        num_atoms = pdb.topology.getNumAtoms()
        forcefield = app.ForceField("amber10-constph.xml", "ions_tip3p.xml",
                                    "tip3p.xml")

        system = forcefield.createSystem(
            pdb.topology,
            nonbondedMethod=app.PME,
            nonbondedCutoff=1.0 * unit.nanometers,
            constraints=app.HBonds,
            rigidWater=True,
            ewaldErrorTolerance=0.0005,
        )

        temperature = 300 * unit.kelvin
        integrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=False,
        )
        ncmcintegrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=True,
        )

        compound_integrator = mm.CompoundIntegrator()
        compound_integrator.addIntegrator(integrator)
        compound_integrator.addIntegrator(ncmcintegrator)
        pressure = 1.0 * unit.atmosphere

        system.addForce(mm.MonteCarloBarostat(pressure, temperature))
        driver = ForceFieldProtonDrive(
            temperature,
            pdb.topology,
            system,
            forcefield,
            ["amber10-constph.xml"],
            pressure=pressure,
            perturbations_per_trial=0,
        )

        num_titratable = len(driver.titrationGroups)
        simulation = app.ConstantPHSimulation(
            pdb.topology,
            system,
            compound_integrator,
            driver,
            platform=self._default_platform,
        )
        simulation.context.setPositions(pdb.positions)
        simulation.context.setVelocitiesToTemperature(temperature)
        filename = uuid.uuid4().hex + ".nc"
        print("Temporary file: ", filename)
        newreporter = tr.TitrationReporter(filename, 2)
        simulation.update_reporters.append(newreporter)

        # Regular MD step
        simulation.step(1)
        # Update the titration states using the uniform proposal
        simulation.update(6)
        # Basic checks for dimension
        assert (newreporter.ncfile["Protons/Titration"].dimensions["update"].
                size == 3), "There should be 3 updates recorded."
        assert (
            newreporter.ncfile["Protons/Titration"].dimensions["residue"].size
            == num_titratable
        ), "There should be {} residues recorded.".format(num_titratable)
        assert (
            newreporter.ncfile["Protons/Titration"].dimensions["atom"].size ==
            num_atoms), "There should be {} atoms recorded.".format(num_atoms)
        newreporter.ncfile.close()
예제 #8
0
    # Create the compound integrator
    langevin = integrators.LangevinIntegrator(splitting=splitting,
                                              temperature=temperature,
                                              timestep=timestep,
                                              collision_rate=collision_rate,
                                              measure_shadow_work=False,
                                              measure_heat=False)
    ncmc_langevin = integrators.ExternalPerturbationLangevinIntegrator(
        splitting=splitting,
        temperature=temperature,
        timestep=timestep,
        collision_rate=collision_rate,
        measure_shadow_work=False,
        measure_heat=False)
    integrator = openmm.CompoundIntegrator()
    integrator.addIntegrator(langevin)
    integrator.addIntegrator(ncmc_langevin)

    # Create context
    if args.platform == 'CUDA':
        platform = openmm.Platform.getPlatformByName('CUDA')
        platform.setPropertyDefaultValue('DeterministicForces', 'true')
        properties = {'CudaPrecision': 'mixed'}
        context = openmm.Context(wbox.system, integrator, platform, properties)
    elif args.platform == 'OpenCL':
        platform = openmm.Platform.getPlatformByName('OpenCL')
        properties = {'OpenCLPrecision': 'mixed'}
        context = openmm.Context(wbox.system, integrator, platform, properties)
    elif args.platform == 'CPU':
        platform = openmm.Platform.getPlatformByName('CPU')
예제 #9
0
def main(jsonfile):
    """Main simulation loop."""

    settings = json.load(open(jsonfile))
    # Parameters include format strings that are used to format the names of input and output files
    prms = settings["parameters"]

    # Input files
    inp = settings["input"]
    idir = inp["dir"].format(**prms)
    input_pdbx_file = os.path.join(idir,
                                   inp["calibration_system"].format(**prms))

    # If supplied, tell the code to find and load supplied ffxml file
    custom_xml_provided = False
    if "ffxml" in inp:
        custom_xml_provided = True

    # Load the PDBxfile and the forcefield files
    if custom_xml_provided:
        custom_xml = os.path.join(idir, inp["ffxml"].format(**prms))
        custom_xml = os.path.abspath(custom_xml)
        forcefield = app.ForceField('amber10-constph.xml', 'gaff.xml',
                                    custom_xml, 'tip3p.xml', 'ions_tip3p.xml')
    else:
        forcefield = app.ForceField('amber10-constph.xml', 'gaff.xml',
                                    'tip3p.xml', 'ions_tip3p.xml')

    pdb_object = app.PDBxFile(input_pdbx_file)

    # Prepare the Simulation
    topology = pdb_object.topology
    positions = pdb_object.positions

    # Quick fix for histidines in topology
    # Openmm relabels them HIS, which leads to them not being detected as
    # titratable. Renaming them fixes this.
    for residue in topology.residues():
        if residue.name == 'HIS':
            residue.name = 'HIP'

    # Naming the output files
    out = settings["output"]
    odir = out["dir"].format(**prms)

    if not os.path.isdir(odir):
        os.makedirs(odir)
    lastdir = os.getcwd()
    os.chdir(odir)

    name_netcdf = out["netcdf"].format(**prms)
    dcd_output_name = out["dcd"].format(**prms)

    # Files for resuming simulation
    resumes = out["resume_files"]

    output_context_xml = resumes["state"].format(**prms)
    output_drive_xml = resumes["drive"].format(**prms)
    output_calibration_json = resumes["calibration"].format(**prms)

    # Integrator options
    integrator_opts = prms["integrator"]
    timestep = integrator_opts["timestep_fs"] * unit.femtosecond
    constraint_tolerance = integrator_opts["constraint_tolerance"]
    collision_rate = integrator_opts["collision_rate_per_ps"] / unit.picosecond
    number_R_steps = 1

    # Steps of MD before starting the main loop
    num_thermalization_steps = int(prms["num_thermalization_steps"])
    # Steps of MD in between MC moves
    steps_between_updates = int(prms["steps_between_updates"])

    ncmc = prms["ncmc"]
    counterion_method = ncmc["counterion_method"].lower()
    if counterion_method not in ["chen-roux", "chenroux", "background"]:
        raise ValueError(
            "Invalid ncmc counterion method, {}. Please pick Chen-Roux or background."
            .format(counterion_method))
    ncmc_steps_per_trial = int(ncmc["steps_per_trial"])
    prop_steps_per_trial = int(ncmc["propagations_per_step"])
    total_iterations = int(prms["total_attempts"])

    # settings for minimization
    minimization = prms["minimization"]
    pre_run_minimization_tolerance = float(
        minimization["tolerance_kjmol"]) * unit.kilojoule / unit.mole
    minimization_max_iterations = int(minimization["max_iterations"])

    # SAMS settings
    sams = prms["SAMS"]
    beta_burnin = sams["beta_sams"]
    flatness_criterion = sams["flatness_criterion"]

    # Script specific settings

    # Register the timeout handling
    signal.signal(signal.SIGALRM, timeout_handler)

    script_timeout = 428400  # 119 hours

    # Platform Options

    platform = mm.Platform.getPlatformByName('CUDA')
    properties = {
        'CudaPrecision': 'mixed',
        'DeterministicForces': 'true',
        'CudaDeviceIndex': os.environ['CUDA_VISIBLE_DEVICES']
    }
    # System Configuration
    sysprops = prms["system"]
    nonbondedMethod = app.PME
    constraints = app.HBonds
    rigidWater = True
    ewaldErrorTolerance = float(sysprops["ewald_error_tolerance"])
    barostatInterval = int(sysprops["barostat_interval"])
    switching_distance = float(
        sysprops["switching_distance_nm"]) * unit.nanometers
    nonbondedCutoff = float(sysprops["nonbonded_cutoff_nm"]) * unit.nanometers
    pressure = float(sysprops["pressure_atm"]) * unit.atmosphere
    temperature = float(sysprops["temperature_k"]) * unit.kelvin

    system = forcefield.createSystem(topology,
                                     nonbondedMethod=nonbondedMethod,
                                     constraints=constraints,
                                     rigidWater=rigidWater,
                                     ewaldErrorTolerance=ewaldErrorTolerance,
                                     nonbondedCutoff=nonbondedCutoff)

    #
    for force in system.getForces():
        if isinstance(force, mm.NonbondedForce):
            force.setUseSwitchingFunction(True)

            force.setSwitchingDistance(switching_distance)

    # NPT simulation
    system.addForce(
        mm.MonteCarloBarostat(pressure, temperature, barostatInterval))

    integrator = ExternalGBAOABIntegrator(
        number_R_steps=number_R_steps,
        temperature=temperature,
        collision_rate=collision_rate,
        timestep=timestep,
        constraint_tolerance=constraint_tolerance)
    ncmc_propagation_integrator = ExternalGBAOABIntegrator(
        number_R_steps=number_R_steps,
        temperature=temperature,
        collision_rate=collision_rate,
        timestep=timestep,
        constraint_tolerance=constraint_tolerance)

    # Define a compound integrator
    compound_integrator = mm.CompoundIntegrator()
    compound_integrator.addIntegrator(integrator)
    compound_integrator.addIntegrator(ncmc_propagation_integrator)
    compound_integrator.setCurrentIntegrator(0)

    if custom_xml_provided:
        driver = ForceFieldProtonDrive(
            temperature,
            topology,
            system,
            forcefield, ['amber10-constph.xml', custom_xml],
            pressure=pressure,
            perturbations_per_trial=ncmc_steps_per_trial,
            propagations_per_step=prop_steps_per_trial)
    else:
        driver = ForceFieldProtonDrive(
            temperature,
            topology,
            system,
            forcefield, ['amber10-constph.xml'],
            pressure=pressure,
            perturbations_per_trial=ncmc_steps_per_trial,
            propagations_per_step=prop_steps_per_trial)

    # Assumes calibration residue is always the last titration group
    calibration_titration_group_index = len(driver.titrationGroups) - 1

    # Define residue pools
    pools = {'calibration': [calibration_titration_group_index]}
    driver.define_pools(pools)
    # Create SAMS sampler
    simulation = app.ConstantPHCalibration(
        topology,
        system,
        compound_integrator,
        driver,
        group_index=calibration_titration_group_index,
        platform=platform,
        platformProperties=properties,
        samsProperties=sams)
    simulation.context.setPositions(positions)

    # After the simulation system has been defined, we can add salt to the system using saltswap.
    salinator = Salinator(context=simulation.context,
                          system=system,
                          topology=topology,
                          ncmc_integrator=compound_integrator.getIntegrator(1),
                          salt_concentration=0.150 * unit.molar,
                          pressure=pressure,
                          temperature=temperature)
    salinator.neutralize()
    salinator.initialize_concentration()
    swapper = salinator.swapper

    # Protons can use the scheme from [Chen2015]_ to maintain charge neutrality.
    # If the Chen-Roux scheme is requested, attach swapper. Else, use neutralizing background charge (happens under the hood of openmm).
    if counterion_method in ["chenroux", "chen-roux"]:
        simulation.drive.attach_swapper(swapper)

    # Minimize the initial configuration to remove bad contacts
    simulation.minimizeEnergy(tolerance=pre_run_minimization_tolerance,
                              maxIterations=minimization_max_iterations)
    # Slightly equilibrate the system, detect early issues.
    simulation.step(num_thermalization_steps)

    # Add reporters, these write out simulation data at regular intervals
    dcdreporter = app.DCDReporter(dcd_output_name,
                                  int(steps_between_updates / 10))
    ncfile = netCDF4.Dataset(name_netcdf, "w")
    metdatarep = MetadataReporter(ncfile)
    ncmcrep = NCMCReporter(ncfile, 1)
    titrep = TitrationReporter(ncfile, 1)
    simulation.reporters.append(dcdreporter)
    simulation.update_reporters.append(metdatarep)
    simulation.update_reporters.append(ncmcrep)
    simulation.update_reporters.append(titrep)
    samsrep = SAMSReporter(ncfile, 1)
    simulation.calibration_reporters.append(samsrep)

    # MAIN SIMULATION LOOP STARTS HERE

    # Raises an exception if the simulation runs out of time, so that the script can be killed cleanly from within python
    signal.alarm(script_timeout)

    try:
        for i in range(total_iterations):
            log.info("Iteration %i", i)
            if i == 5:
                log.info(
                    "Simulation seems to be working. Suppressing debugging info."
                )
                log.setLevel(logging.INFO)
            # Regular MD
            simulation.step(steps_between_updates)
            # Update protonation state
            simulation.update(1, pool='calibration')
            # Adapt SAMS weight
            simulation.adapt()
        # Reset timer
        signal.alarm(0)

    except TimeOutError:
        log.warn("Simulation ran out of time, saving current results.")

    finally:
        # export the context
        serialize_state(simulation.context, output_context_xml)
        # export the driver
        serialize_drive(simulation.drive, output_drive_xml)
        # export the calibration status
        serialize_sams_status(simulation, output_calibration_json)

        ncfile.close()
        os.chdir(lastdir)
예제 #10
0
def create_ideal_system(npert=50, nprop=1, deltachem=0.0, platform='CPU'):
    """
    Create small box of water that can impliment ideal mixing with the SaltSwap osmostat.

    Parameters
    ----------
    npert: int
        the number of NCMC perturbations
    nprop: int
        the number of Langevin propagation steps per NCMC perturbation.
    deltachem: float
        the difference in chemical potential between two water molecules and NaCl that has the same nonbonded parameters
        as two water molecules.
    platform: str
        The computational platform. Either 'CPU', 'CUDA', or 'OpenCL'.

    Returns
    -------
    ncmc_swapper: saltswap.swapper
        the driver that can perform NCMC exchanges
    langevin: openmmtools.integrator
        the integrator for equilibrium sampling.
    """
    # Setting the parameters of the simulation
    timestep = 2.0 * unit.femtoseconds
    box_edge = 25.0 * unit.angstrom
    splitting = 'V R O R V'
    temperature = 300. * unit.kelvin
    collision_rate = 1. / unit.picoseconds
    pressure = 1. * unit.atmospheres

    # Make the water box test system with a fixed pressure
    wbox = WaterBox(box_edge=box_edge,
                    model='tip3p',
                    nonbondedMethod=app.PME,
                    cutoff=10 * unit.angstrom,
                    ewaldErrorTolerance=1E-4)
    wbox.system.addForce(openmm.MonteCarloBarostat(pressure, temperature))

    # Create the compound integrator
    langevin = integrators.LangevinIntegrator(splitting=splitting,
                                              temperature=temperature,
                                              timestep=timestep,
                                              collision_rate=collision_rate,
                                              measure_shadow_work=False,
                                              measure_heat=False)
    ncmc_langevin = integrators.ExternalPerturbationLangevinIntegrator(
        splitting=splitting,
        temperature=temperature,
        timestep=timestep,
        collision_rate=collision_rate,
        measure_shadow_work=False,
        measure_heat=False)
    integrator = openmm.CompoundIntegrator()
    integrator.addIntegrator(langevin)
    integrator.addIntegrator(ncmc_langevin)

    # Create context
    if platform == 'CUDA':
        platform = openmm.Platform.getPlatformByName('CUDA')
        platform.setPropertyDefaultValue('DeterministicForces', 'true')
        properties = {'CudaPrecision': 'mixed'}
        context = openmm.Context(wbox.system, integrator, platform, properties)
    elif platform == 'OpenCL':
        platform = openmm.Platform.getPlatformByName('OpenCL')
        properties = {'OpenCLPrecision': 'mixed'}
        context = openmm.Context(wbox.system, integrator, platform, properties)
    elif platform == 'CPU':
        platform = openmm.Platform.getPlatformByName('CPU')
        context = openmm.Context(wbox.system, integrator, platform)
    else:
        raise Exception('Platform name {0} not recognized.'.format(
            args.platform))

    context.setPositions(wbox.positions)
    context.setVelocitiesToTemperature(temperature)

    # Create the swapper object for the insertion and deletion of salt
    ncmc_swapper = Swapper(system=wbox.system,
                           topology=wbox.topology,
                           temperature=temperature,
                           delta_chem=deltachem,
                           ncmc_integrator=ncmc_langevin,
                           pressure=pressure,
                           npert=npert,
                           nprop=nprop)

    # Set the nonbonded parameters of the ions to be the same as water. This is critical for ideal mixing.
    ncmc_swapper.cation_parameters = ncmc_swapper.water_parameters
    ncmc_swapper.anion_parameters = ncmc_swapper.water_parameters
    ncmc_swapper._set_parampath()

    return context, ncmc_swapper, langevin
예제 #11
0
    def test_reports(self):
        """Instantiate a simulation at 300K/1 atm for a small peptide with reporter."""

        pdb = app.PDBxFile(
            get_test_data(
                "glu_ala_his-solvated-minimized-renamed.cif", "testsystems/tripeptides"
            )
        )
        forcefield = app.ForceField(
            "amber10-constph.xml", "ions_tip3p.xml", "tip3p.xml"
        )

        system = forcefield.createSystem(
            pdb.topology,
            nonbondedMethod=app.PME,
            nonbondedCutoff=1.0 * unit.nanometers,
            constraints=app.HBonds,
            rigidWater=True,
            ewaldErrorTolerance=0.0005,
        )

        temperature = 300 * unit.kelvin
        integrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=False,
        )
        ncmcintegrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=True,
        )

        compound_integrator = mm.CompoundIntegrator()
        compound_integrator.addIntegrator(integrator)
        compound_integrator.addIntegrator(ncmcintegrator)
        pressure = 1.0 * unit.atmosphere

        system.addForce(mm.MonteCarloBarostat(pressure, temperature))
        driver = ForceFieldProtonDrive(
            temperature,
            pdb.topology,
            system,
            forcefield,
            ["amber10-constph.xml"],
            pressure=pressure,
            perturbations_per_trial=3,
        )

        # prep the driver for calibration
        driver.enable_calibration(
            SAMSApproach.ONESITE, group_index=1, update_rule=UpdateRule.BINARY
        )

        calibration = app.ConstantPHSimulation(
            pdb.topology,
            system,
            compound_integrator,
            driver,
            platform=self._default_platform,
        )
        calibration.context.setPositions(pdb.positions)
        calibration.context.setVelocitiesToTemperature(temperature)
        filename = uuid.uuid4().hex + ".nc"
        print("Temporary file: ", filename)
        newreporter = sr.SAMSReporter(filename, 2)
        calibration.calibration_reporters.append(newreporter)

        # Regular MD step
        for iteration in range(4):
            calibration.step(1)
            # Update the titration states using the uniform proposal
            calibration.update(1)
            # adapt sams weights
            calibration.adapt()

        # Basic checks for dimension
        assert (
            newreporter.ncfile["Protons/SAMS"].dimensions["adaptation"].size == 2
        ), "There should be 2 updates recorded."
        assert (
            newreporter.ncfile["Protons/SAMS"].dimensions["state"].size == 3
        ), "There should be 3 states reported."

        newreporter.ncfile.close()
예제 #12
0
def run_alchemical_langevin_integrator(nsteps=0,
                                       splitting="O { V R H R V } O"):
    """Check that the AlchemicalLangevinSplittingIntegrator reproduces the analytical free energy difference for a harmonic oscillator deformation, using BAR.
    Up to 6*sigma is tolerated for error.
    The total work (protocol work + shadow work) is used.
    """

    #max deviation from the calculated free energy
    NSIGMA_MAX = 6
    n_iterations = 200  # number of forward and reverse protocols

    # These are the alchemical functions that will be used to control the system
    temperature = 298.0 * unit.kelvin
    sigma = 1.0 * unit.angstrom  # stddev of harmonic oscillator
    kT = kB * temperature  # thermal energy
    beta = 1.0 / kT  # inverse thermal energy
    K = kT / sigma**2  # spring constant corresponding to sigma
    mass = 39.948 * unit.amu
    period = unit.sqrt(mass / K)  # period of harmonic oscillator
    timestep = period / 20.0
    collision_rate = 1.0 / period
    dF_analytical = 1.0
    parameters = dict()
    parameters['testsystems_HarmonicOscillator_x0'] = (0 * sigma, 2 * sigma)
    parameters['testsystems_HarmonicOscillator_U0'] = (0 * kT, 1 * kT)
    alchemical_functions = {
        'forward': {
            name: '(1-lambda)*%f + lambda*%f' %
            (value[0].value_in_unit_system(unit.md_unit_system),
             value[1].value_in_unit_system(unit.md_unit_system))
            for (name, value) in parameters.items()
        },
        'reverse': {
            name: '(1-lambda)*%f + lambda*%f' %
            (value[1].value_in_unit_system(unit.md_unit_system),
             value[0].value_in_unit_system(unit.md_unit_system))
            for (name, value) in parameters.items()
        },
    }

    # Create harmonic oscillator testsystem
    testsystem = testsystems.HarmonicOscillator(K=K, mass=mass)
    system = testsystem.system
    positions = testsystem.positions

    # Get equilibrium samples from initial and final states
    burn_in = 5 * 20  # 5 periods
    thinning = 5 * 20  # 5 periods

    # Collect forward and reverse work values
    directions = ['forward', 'reverse']
    work = {
        direction: np.zeros([n_iterations], np.float64)
        for direction in directions
    }
    platform = openmm.Platform.getPlatformByName("Reference")
    for direction in directions:
        positions = testsystem.positions

        # Create equilibrium and nonequilibrium integrators
        equilibrium_integrator = GHMCIntegrator(temperature=temperature,
                                                collision_rate=collision_rate,
                                                timestep=timestep)
        nonequilibrium_integrator = AlchemicalNonequilibriumLangevinIntegrator(
            temperature=temperature,
            collision_rate=collision_rate,
            timestep=timestep,
            alchemical_functions=alchemical_functions[direction],
            splitting=splitting,
            nsteps_neq=nsteps,
            measure_shadow_work=True)

        # Create compound integrator
        compound_integrator = openmm.CompoundIntegrator()
        compound_integrator.addIntegrator(equilibrium_integrator)
        compound_integrator.addIntegrator(nonequilibrium_integrator)

        # Create Context
        context = openmm.Context(system, compound_integrator, platform)
        context.setPositions(positions)

        # Collect work samples
        for iteration in range(n_iterations):
            #
            # Generate equilibrium sample
            #

            compound_integrator.setCurrentIntegrator(0)
            equilibrium_integrator.reset()
            compound_integrator.step(thinning)

            #
            # Generate nonequilibrium work sample
            #

            compound_integrator.setCurrentIntegrator(1)
            nonequilibrium_integrator.reset()

            # Check initial conditions after reset
            current_lambda = nonequilibrium_integrator.getGlobalVariableByName(
                'lambda')
            assert current_lambda == 0.0, 'initial lambda should be 0.0 (was %f)' % current_lambda
            current_step = nonequilibrium_integrator.getGlobalVariableByName(
                'step')
            assert current_step == 0.0, 'initial step should be 0 (was %f)' % current_step

            compound_integrator.step(max(
                1, nsteps))  # need to execute at least one step
            work[direction][
                iteration] = nonequilibrium_integrator.get_total_work(
                    dimensionless=True)

            # Check final conditions before reset
            current_lambda = nonequilibrium_integrator.getGlobalVariableByName(
                'lambda')
            assert current_lambda == 1.0, 'final lambda should be 1.0 (was %f) for splitting %s' % (
                current_lambda, splitting)
            current_step = nonequilibrium_integrator.getGlobalVariableByName(
                'step')
            assert int(current_step) == max(
                1, nsteps
            ), 'final step should be %d (was %f) for splitting %s' % (max(
                1, nsteps), current_step, splitting)
            nonequilibrium_integrator.reset()

        # Clean up
        del context
        del compound_integrator

    dF, ddF = pymbar.BAR(work['forward'], work['reverse'])
    nsigma = np.abs(dF - dF_analytical) / ddF
    print(
        "analytical DeltaF: {:12.4f}, DeltaF: {:12.4f}, dDeltaF: {:12.4f}, nsigma: {:12.1f}"
        .format(dF_analytical, dF, ddF, nsigma))
    if nsigma > NSIGMA_MAX:
        raise Exception(
            "The free energy difference for the nonequilibrium switching for splitting '%s' and %d steps is not zero within statistical error."
            % (splitting, nsteps))
예제 #13
0
    def test_reports_every_perturbation_saltswap(self):
        """Instantiate a ConstantPHSimulation at 300K/1 atm for a small peptide, save every perturbation step, with saltswap."""

        pdb = app.PDBxFile(
            get_test_data("glu_ala_his-solvated-minimized-renamed.cif",
                          "testsystems/tripeptides"))
        forcefield = app.ForceField("amber10-constph.xml", "ions_tip3p.xml",
                                    "tip3p.xml")

        system = forcefield.createSystem(
            pdb.topology,
            nonbondedMethod=app.PME,
            nonbondedCutoff=1.0 * unit.nanometers,
            constraints=app.HBonds,
            rigidWater=True,
            ewaldErrorTolerance=0.0005,
        )

        temperature = 300 * unit.kelvin
        integrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=False,
        )
        ncmcintegrator = GBAOABIntegrator(
            temperature=temperature,
            collision_rate=1.0 / unit.picoseconds,
            timestep=2.0 * unit.femtoseconds,
            constraint_tolerance=1.0e-7,
            external_work=True,
        )

        compound_integrator = mm.CompoundIntegrator()
        compound_integrator.addIntegrator(integrator)
        compound_integrator.addIntegrator(ncmcintegrator)
        pressure = 1.0 * unit.atmosphere

        system.addForce(mm.MonteCarloBarostat(pressure, temperature))
        driver = ForceFieldProtonDrive(
            temperature,
            pdb.topology,
            system,
            forcefield,
            ["amber10-constph.xml"],
            pressure=pressure,
            perturbations_per_trial=3,
        )

        simulation = app.ConstantPHSimulation(
            pdb.topology,
            system,
            compound_integrator,
            driver,
            platform=self._default_platform,
        )
        simulation.context.setPositions(pdb.positions)
        simulation.context.setVelocitiesToTemperature(temperature)
        filename = uuid.uuid4().hex + ".nc"
        print("Temporary file: ", filename)
        # The salinator initializes the system salts
        salinator = Salinator(
            context=simulation.context,
            system=simulation.system,
            topology=simulation.topology,
            ncmc_integrator=simulation.integrator.getIntegrator(1),
            salt_concentration=0.2 * unit.molar,
            pressure=pressure,
            temperature=temperature,
        )
        salinator.neutralize()
        salinator.initialize_concentration()
        swapper = salinator.swapper
        driver.enable_neutralizing_ions(swapper)

        newreporter = ncr.NCMCReporter(filename, 1, cumulativeworkInterval=1)
        simulation.update_reporters.append(newreporter)

        # Regular MD step
        simulation.step(1)
        # Update the titration states using the uniform proposal
        simulation.update(4)
        # Basic checks for dimension
        assert (newreporter.ncfile["Protons/NCMC"].dimensions["update"].size ==
                4), "There should be 4 updates recorded."
        assert (newreporter.ncfile["Protons/NCMC"].dimensions["residue"].size
                == 2), "There should be 2 residues recorded."
        assert (newreporter.ncfile["Protons/NCMC"].dimensions["perturbation"].
                size == 3), "There should be max 3 perturbations recorded."
        assert (newreporter.ncfile["Protons/NCMC"].dimensions["ion_site"].size
                == 1269), "The system should have 1269 potential ion sites."

        # Ensure clean exit
        newreporter.ncfile.sync()
        newreporter.ncfile.close()
예제 #14
0
def generate_simulation_and_driver(settings):

    ofolder = settings['output']['dir']
    input_pdbx_file = settings['input']['dir'] + '/' + settings['name'] + '.cif'
    custom_xml = settings['input']['dir'] + '/' + settings['name'] + '.ffxml'
    forcefield = app.ForceField('amber10-constph.xml', 'gaff.xml', custom_xml,
                                'tip3p.xml', 'ions_tip3p.xml')

    # Load structure
    # The input should be an mmcif/pdbx file'
    pdb_object = app.PDBxFile(input_pdbx_file)

    # Atoms , connectivity, residues
    topology = pdb_object.topology

    # XYZ positions for every atom
    positions = pdb_object.positions

    # Quick fix for histidines in topology
    # Openmm relabels them HIS, which leads to them not being detected as
    # titratable. Renaming them fixes this.

    for residue in topology.residues():
        if residue.name == "HIS":
            residue.name = "HIP"
        # TODO doublecheck if ASH GLH need to be renamed
        elif residue.name == "ASP":
            residue.name = "ASH"
        elif residue.name == "GLU":
            residue.name = "GLH"

    if os.path.isdir(ofolder):
        shutil.rmtree(ofolder)
        os.makedirs(ofolder)

    # Naming the output files
    os.chdir(ofolder)

    if not os.path.isdir('tmp'):
        os.makedirs('tmp')

    # Structure preprocessing settings
    if "preprocessing" in settings:
        preproc: Dict[str, Any] = settings["preprocessing"]

        # Steps of MD before starting the main loop
        num_thermalization_steps = int(preproc["num_thermalization_steps"])
        pre_run_minimization_tolerance: unit.Quantity = float(
            preproc["minimization_tolerance_kjmol"]
        ) * unit.kilojoule / unit.mole
        minimization_max_iterations = int(
            preproc["minimization_max_iterations"])

    # System Configuration
    sysprops = settings["system"]
    temperature = float(sysprops["temperature_k"]) * unit.kelvin
    if "salt_concentration_molar" in sysprops:
        salt_concentration: unit.Quantity = float(
            sysprops["salt_concentration_molar"]) * unit.molar
    else:
        salt_concentration = None

    rigidWater = True
    constraints = app.HBonds

    if "PME" in sysprops:
        pmeprops = sysprops["PME"]
        nonbondedMethod = app.PME
        ewaldErrorTolerance = float(pmeprops["ewald_error_tolerance"])
        barostatInterval = int(pmeprops["barostat_interval"])
        switching_distance = float(
            pmeprops["switching_distance_nm"]) * unit.nanometers
        nonbondedCutoff = float(
            pmeprops["nonbonded_cutoff_nm"]) * unit.nanometers
        pressure = float(pmeprops["pressure_atm"]) * unit.atmosphere

        system = forcefield.createSystem(
            topology,
            nonbondedMethod=nonbondedMethod,
            constraints=constraints,
            rigidWater=rigidWater,
            ewaldErrorTolerance=ewaldErrorTolerance,
            nonbondedCutoff=nonbondedCutoff,
        )
        for force in system.getForces():
            if isinstance(force, mm.NonbondedForce):
                force.setUseSwitchingFunction(True)

                force.setSwitchingDistance(switching_distance)

        # TODO disable in implicit solvent
        # NPT simulation
        system.addForce(
            mm.MonteCarloBarostat(pressure, temperature, barostatInterval))
    else:
        pressure = None
        system = forcefield.createSystem(
            topology,
            nonbondedMethod=app.NoCutoff,
            constraints=app.HBonds,
            rigidWater=True,
        )

    # Integrator options
    integrator_opts = settings["integrator"]
    timestep = integrator_opts["timestep_fs"] * unit.femtosecond
    constraint_tolerance = integrator_opts["constraint_tolerance"]
    collision_rate = integrator_opts["collision_rate_per_ps"] / unit.picosecond
    number_R_steps = 1

    integrator = ExternalGBAOABIntegrator(
        number_R_steps=number_R_steps,
        temperature=temperature,
        collision_rate=collision_rate,
        timestep=timestep,
        constraint_tolerance=constraint_tolerance,
    )
    ncmc_propagation_integrator = ExternalGBAOABIntegrator(
        number_R_steps=number_R_steps,
        temperature=temperature,
        collision_rate=collision_rate,
        timestep=timestep,
        constraint_tolerance=constraint_tolerance,
    )

    # Define a compound integrator
    compound_integrator = mm.CompoundIntegrator()
    compound_integrator.addIntegrator(integrator)
    compound_integrator.addIntegrator(ncmc_propagation_integrator)
    compound_integrator.setCurrentIntegrator(0)

    # Script specific settings

    # Register the timeout handling
    driver = TautomerForceFieldProtonDrive(
        temperature,
        topology,
        system,
        forcefield,
        [custom_xml] + ["amber10-constph.xml"],
        pressure=pressure,
        perturbations_per_trial=10000,
        propagations_per_step=1,
    )

    if "reference_free_energies" in settings:
        # calibrated free energy values can be provided here
        gk_dict = settings["reference_free_energies"]

        # Clean comments inside dictionary
        to_delete = list()
        for key in gk_dict.keys():
            if key.startswith("_"):
                to_delete.append(key)

        for key in to_delete:
            del (gk_dict[key])

        # Make arrays
        for key, value in gk_dict.items():
            # Convert to array of float
            val_array = np.asarray(value).astype(np.float64)
            if not val_array.ndim == 1:
                raise ValueError(
                    "Reference free energies should be simple lists.")
            gk_dict[key] = val_array

        driver.import_gk_values(gk_dict)

    # TODO allow platform specification for setup

    #platform = mm.Platform.getPlatformByName("CUDA")
#    properties = {"Precision": "double"}
    platform = mm.Platform.getPlatformByName("CPU")

    # Set up calibration mode
    # SAMS settings

    if "SAMS" in settings:
        sams = settings["SAMS"]

        beta_burnin = float(sams["beta"])
        min_burnin = int(sams["min_burn"])
        min_slow = int(sams["min_slow"])
        min_fast = int(sams["min_fast"])

        flatness_criterion = float(sams["flatness_criterion"])
        if sams["update_rule"] == "binary":
            update_rule = UpdateRule.BINARY
        elif sams["update_rule"] == "global":
            update_rule = UpdateRule.GLOBAL
        else:
            update_rule = UpdateRule.BINARY

        # Assumes calibration residue is always the last titration group if onesite

        if sams["sites"] == "multi":
            driver.enable_calibration(
                approach=SAMSApproach.MULTISITE,
                update_rule=update_rule,
                flatness_criterion=flatness_criterion,
                min_burn=min_burnin,
                min_slow=min_slow,
                min_fast=min_fast,
                beta_sams=beta_burnin,
            )
        elif sams["sites"] == "one":
            if "group_index" in sams:
                calibration_titration_group_index = int(sams["group_index"])
            else:
                calibration_titration_group_index = len(
                    driver.titrationGroups) - 1

            driver.enable_calibration(
                approach=SAMSApproach.ONESITE,
                group_index=calibration_titration_group_index,
                update_rule=update_rule,
                flatness_criterion=flatness_criterion,
                min_burn=min_burnin,
                min_slow=min_slow,
                min_fast=min_fast,
            )
            # Define residue pools
            pools = {"calibration": [calibration_titration_group_index]}
            # TODO the pooling feature could eventually be exposed in the json
            driver.define_pools(pools)
    properties = None
    # Create simulation object
    # If calibration is required, this class will automatically deal with it.
    simulation = app.ConstantPHSimulation(
        topology,
        system,
        compound_integrator,
        driver,
        platform=platform,
        platformProperties=properties,
    )
    simulation.context.setPositions(positions)

    # After the simulation system has been defined, we can add salt to the system using saltswap.
    if salt_concentration is not None and "PME" in sysprops:
        salinator = Salinator(
            context=simulation.context,
            system=system,
            topology=topology,
            ncmc_integrator=compound_integrator.getIntegrator(1),
            salt_concentration=salt_concentration,
            pressure=pressure,
            temperature=temperature,
        )
        salinator.neutralize()
        salinator.initialize_concentration()
    else:
        salinator = None

    # Minimize the initial configuration to remove bad contacts
    if "preprocessing" in settings:
        simulation.minimizeEnergy(
            tolerance=pre_run_minimization_tolerance,
            maxIterations=minimization_max_iterations,
        )
        # Slightly equilibrate the system, detect early issues.
        simulation.step(num_thermalization_steps)

    topology_file_content = open(input_pdbx_file, "r").read()
    return simulation, driver, pdb_object
예제 #15
0
    def create_system(args, splitting):
        """
        Create a test system that's able to run saltswap.

        Parameters
        ----------
        args:
        splitting:
        """
        # Fixed simulation parameters
        temperature = 300.0 * unit.kelvin
        collision_rate = 1.0 / unit.picoseconds
        pressure = 1.0 * unit.atmospheres
        salt_concentration = args.conc * unit.molar

        # Get the test system and add the barostat.
        testobj = getattr(testsystems, args.testsystem)
        testsys = testobj(nonbondedMethod=app.PME,
                          cutoff=10 * unit.angstrom,
                          ewaldErrorTolerance=1E-4,
                          switch_width=1.5 * unit.angstrom)
        testsys.system.addForce(
            openmm.MonteCarloBarostat(pressure, temperature))

        # Create the compound integrator
        langevin = integrators.LangevinIntegrator(
            splitting=splitting,
            temperature=temperature,
            timestep=timestep,
            collision_rate=collision_rate,
            measure_shadow_work=False,
            measure_heat=False)
        ncmc_langevin = integrators.ExternalPerturbationLangevinIntegrator(
            splitting=splitting,
            temperature=temperature,
            timestep=timestep,
            collision_rate=collision_rate,
            measure_shadow_work=False,
            measure_heat=False)
        integrator = openmm.CompoundIntegrator()
        integrator.addIntegrator(langevin)
        integrator.addIntegrator(ncmc_langevin)

        # Create context
        if args.platform == 'CUDA':
            platform = openmm.Platform.getPlatformByName('CUDA')
            platform.setPropertyDefaultValue('DeterministicForces', 'true')
            properties = {'CudaPrecision': 'mixed'}
            context = openmm.Context(testsys.system, integrator, platform,
                                     properties)
        elif args.platform == 'OpenCL':
            platform = openmm.Platform.getPlatformByName('OpenCL')
            properties = {'OpenCLPrecision': 'mixed'}
            context = openmm.Context(testsys.system, integrator, platform,
                                     properties)
        elif args.platform == 'CPU':
            platform = openmm.Platform.getPlatformByName('CPU')
            context = openmm.Context(testsys.system, integrator, platform)
        else:
            raise Exception('Platform name {0} not recognized.'.format(
                args.platform))

        context.setPositions(testsys.positions)
        context.setVelocitiesToTemperature(temperature)

        # Create the swapper object for the insertion and deletion of salt
        salinator = wrappers.Salinator(context=context,
                                       system=testsys.system,
                                       topology=testsys.topology,
                                       ncmc_integrator=ncmc_langevin,
                                       salt_concentration=salt_concentration,
                                       pressure=pressure,
                                       temperature=temperature,
                                       npert=npert,
                                       water_name=args.water_name)

        # Neutralize the system and initialize the number of salt pairs.
        salinator.neutralize()
        salinator.initialize_concentration()

        return salinator, langevin, integrator