def setopts(self, **kwargs): """ Called by __init__ ; Set AMBER-specific options. """ ## The directory containing TINKER executables (e.g. dynamic) if 'amberhome' in kwargs: self.amberhome = kwargs['amberhome'] if not os.path.exists(os.path.join(self.amberhome,"sander")): warn_press_key("The 'sander' executable indicated by %s doesn't exist! (Check amberhome)" \ % os.path.join(self.amberhome,"sander")) else: warn_once("The 'amberhome' option was not specified; using default.") if which('sander') == '': warn_press_key("Please add AMBER executables to the PATH or specify amberhome.") self.amberhome = os.path.split(which('sander'))[0] with wopen('.quit.leap') as f: print >> f, 'quit' # AMBER search path self.spath = [] for line in self.callamber('tleap -f .quit.leap'): if 'Adding' in line and 'to search path' in line: self.spath.append(line.split('Adding')[1].split()[0]) os.remove('.quit.leap')
def __init__(self, options, tgt_opts, forcefield): if not recharge_import_success: warn_once("Note: Failed to import the OpenFF Recharge package - FB Recharge_SMIRNOFF target will not work. ") if not toolkit_import_success: warn_once("Note: Failed to import the OpenFF Toolkit - FB Recharge_SMIRNOFF target will not work. ") super(Recharge_SMIRNOFF, self).__init__(options, tgt_opts, forcefield) # Store a mapping between the FB pval parameters and the expected recharge # ordering. self._parameter_to_bcc_map = None # Pre-calculate the expensive portion of the objective function. self._design_matrix = None self._target_residuals = None # Store a copy of the objective function details from the previous # optimisation cycle. self._molecule_residual_ranges = {} self._per_molecule_residuals = {} # Get the filename for the database which contains the ESP data # to train against. self.set_option(tgt_opts, "recharge_esp_store", forceprint=True) self.set_option(tgt_opts, "recharge_property", forceprint=True) assert self.recharge_property in ["esp", "electric-field"] # Initialize the target. self._initialize()
def setopts(self, **kwargs): """ Called by __init__ ; Set AMBER-specific options. """ ## The directory containing TINKER executables (e.g. dynamic) if 'amberhome' in kwargs: self.amberhome = kwargs['amberhome'] if not os.path.exists(os.path.join(self.amberhome, "sander")): warn_press_key("The 'sander' executable indicated by %s doesn't exist! (Check amberhome)" \ % os.path.join(self.amberhome,"sander")) else: warn_once( "The 'amberhome' option was not specified; using default.") if which('sander') == '': warn_press_key( "Please add AMBER executables to the PATH or specify amberhome." ) self.amberhome = os.path.split(which('sander'))[0] with wopen('.quit.leap') as f: print >> f, 'quit' # AMBER search path self.spath = [] for line in self.callamber('tleap -f .quit.leap'): if 'Adding' in line and 'to search path' in line: self.spath.append(line.split('Adding')[1].split()[0]) os.remove('.quit.leap')
def normal_modes(self, shot=0, optimize=True): logger.error('Normal modes are not yet implemented in AMBER interface') raise NotImplementedError # Copied from tinkerio.py if optimize: self.optimize(shot, crit=1e-6) o = self.calltinker("vibrate %s.xyz_2 a" % (self.name)) else: warn_once("Asking for normal modes without geometry optimization?") self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") o = self.calltinker("vibrate %s.xyz a" % (self.name)) # Read the TINKER output. The vibrational frequencies are ordered. # The six modes with frequencies closest to zero are ignored readev = False calc_eigvals = [] calc_eigvecs = [] for line in o: s = line.split() if "Vibrational Normal Mode" in line: freq = float(s[-2]) readev = False calc_eigvals.append(freq) calc_eigvecs.append([]) elif "Atom" in line and "Delta X" in line: readev = True elif readev and len(s) == 4 and all( [isint(s[0]), isfloat(s[1]), isfloat(s[2]), isfloat(s[3])]): calc_eigvecs[-1].append([float(i) for i in s[1:]]) calc_eigvals = np.array(calc_eigvals) calc_eigvecs = np.array(calc_eigvecs) # Sort by frequency absolute value and discard the six that are closest to zero calc_eigvecs = calc_eigvecs[np.argsort(np.abs(calc_eigvals))][6:] calc_eigvals = calc_eigvals[np.argsort(np.abs(calc_eigvals))][6:] # Sort again by frequency calc_eigvecs = calc_eigvecs[np.argsort(calc_eigvals)] calc_eigvals = calc_eigvals[np.argsort(calc_eigvals)] os.system("rm -rf *.xyz_* *.[0-9][0-9][0-9]") return calc_eigvals, calc_eigvecs
def __init__(self, options, tgt_opts, forcefield): if not evaluator_import_success: warn_once( "Note: Failed to import the OpenFF Evaluator - FB Evaluator target will not work. " ) if not toolkit_import_success: warn_once( "Note: Failed to import the OpenFF Toolkit - FB Evaluator target will not work. " ) super(Evaluator_SMIRNOFF, self).__init__(options, tgt_opts, forcefield) self._options = None # The options for this target loaded from JSON. self._default_units = ( {}) # The default units to convert each type of property to. self._client = None # The client object which will communicate with an already spun up server. self._reference_data_set = None # The data set of properties to estimate. self._normalised_weights = ( None # The normalised weights of the different properties. ) # Store a `Future` like object which can be queried for the results of # a property estimation. self._pending_estimate_request = None # Store a mapping between gradient keys and the force balance string representation. self._gradient_key_mappings = {} self._parameter_units = {} # Store a copy of the objective function details from the previous optimisation cycle. self._last_obj_details = {} # Get the filename for the evaluator input file. self.set_option(tgt_opts, "evaluator_input", forceprint=True) # Initialize the target. self._initialize()
def normal_modes(self, shot=0, optimize=True): logger.error('Normal modes are not yet implemented in AMBER interface') raise NotImplementedError # Copied from tinkerio.py if optimize: self.optimize(shot, crit=1e-6) o = self.calltinker("vibrate %s.xyz_2 a" % (self.name)) else: warn_once("Asking for normal modes without geometry optimization?") self.mol[shot].write('%s.xyz' % self.name, ftype="tinker") o = self.calltinker("vibrate %s.xyz a" % (self.name)) # Read the TINKER output. The vibrational frequencies are ordered. # The six modes with frequencies closest to zero are ignored readev = False calc_eigvals = [] calc_eigvecs = [] for line in o: s = line.split() if "Vibrational Normal Mode" in line: freq = float(s[-2]) readev = False calc_eigvals.append(freq) calc_eigvecs.append([]) elif "Atom" in line and "Delta X" in line: readev = True elif readev and len(s) == 4 and all([isint(s[0]), isfloat(s[1]), isfloat(s[2]), isfloat(s[3])]): calc_eigvecs[-1].append([float(i) for i in s[1:]]) calc_eigvals = np.array(calc_eigvals) calc_eigvecs = np.array(calc_eigvecs) # Sort by frequency absolute value and discard the six that are closest to zero calc_eigvecs = calc_eigvecs[np.argsort(np.abs(calc_eigvals))][6:] calc_eigvals = calc_eigvals[np.argsort(np.abs(calc_eigvals))][6:] # Sort again by frequency calc_eigvecs = calc_eigvecs[np.argsort(calc_eigvals)] calc_eigvals = calc_eigvals[np.argsort(calc_eigvals)] os.system("rm -rf *.xyz_* *.[0-9][0-9][0-9]") return calc_eigvals, calc_eigvecs
import os import numpy as np from forcebalance.nifty import printcool_dictionary, warn_once from forcebalance.output import getLogger from forcebalance.target import Target try: from openff.recharge.charges.charges import ChargeSettings from openff.recharge.esp.storage import MoleculeESPStore from openff.recharge.optimize import ESPOptimization from openff.recharge.smirnoff import from_smirnoff except ImportError: warn_once("Note: Failed to import the optional openff.recharge package.") try: from openforcefield.typing.engines import smirnoff except ImportError: warn_once("Note: Failed to import the optional openforcefield package. ") logger = getLogger(__name__) class Recharge_SMIRNOFF(Target): """A custom optimisation target which employs the `openff-recharge` package to train bond charge correction parameters against QM derived electrostatic potential data.""" def __init__(self, options, tgt_opts, forcefield):
def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, nequil=0, nsave=1000, minimize=True, anisotropic=False, threads=1, verbose=False, **kwargs): """ Method for running a molecular dynamics simulation. Required arguments: nsteps = (int) Number of total time steps timestep = (float) Time step in FEMTOSECONDS temperature = (float) Temperature control (Kelvin) pressure = (float) Pressure control (atmospheres) nequil = (int) Number of additional time steps at the beginning for equilibration nsave = (int) Step interval for saving and printing data minimize = (bool) Perform an energy minimization prior to dynamics threads = (int) Specify how many OpenMP threads to use Returns simulation data: Rhos = (array) Density in kilogram m^-3 Potentials = (array) Potential energies Kinetics = (array) Kinetic energies Volumes = (array) Box volumes Dips = (3xN array) Dipole moments EComps = (dict) Energy components """ logger.error('Molecular dynamics not yet implemented in AMBER interface') raise NotImplementedError md_defs = OrderedDict() md_opts = OrderedDict() # Print out averages only at the end. md_opts["printout"] = nsave md_opts["openmp-threads"] = threads # Langevin dynamics for temperature control. if temperature != None: md_defs["integrator"] = "stochastic" else: md_defs["integrator"] = "beeman" md_opts["thermostat"] = None # Periodic boundary conditions. if self.pbc: md_opts["vdw-correction"] = '' if temperature != None and pressure != None: md_defs["integrator"] = "beeman" md_defs["thermostat"] = "bussi" md_defs["barostat"] = "montecarlo" if anisotropic: md_opts["aniso-pressure"] = '' elif pressure != None: warn_once("Pressure is ignored because temperature is turned off.") else: if pressure != None: warn_once("Pressure is ignored because pbc is set to False.") # Use stochastic dynamics for the gas phase molecule. # If we use the regular integrators it may miss # six degrees of freedom in calculating the kinetic energy. md_opts["barostat"] = None eq_opts = deepcopy(md_opts) if self.pbc and temperature != None and pressure != None: eq_opts["integrator"] = "beeman" eq_opts["thermostat"] = "bussi" eq_opts["barostat"] = "berendsen" if minimize: if verbose: logger.info("Minimizing the energy...") self.optimize(method="bfgs", crit=1) os.system("mv %s.xyz_2 %s.xyz" % (self.name, self.name)) if verbose: logger.info("Done\n") # Run equilibration. if nequil > 0: write_key("%s-eq.key" % self.name, eq_opts, "%s.key" % self.name, md_defs) if verbose: printcool("Running equilibration dynamics", color=0) if self.pbc and pressure != None: self.calltinker("dynamic %s -k %s-eq %i %f %f 4 %f %f" % (self.name, self.name, nequil, timestep, float(nsave*timestep)/1000, temperature, pressure), print_to_screen=verbose) else: self.calltinker("dynamic %s -k %s-eq %i %f %f 2 %f" % (self.name, self.name, nequil, timestep, float(nsave*timestep)/1000, temperature), print_to_screen=verbose) os.system("rm -f %s.arc" % (self.name)) # Run production. if verbose: printcool("Running production dynamics", color=0) write_key("%s-md.key" % self.name, md_opts, "%s.key" % self.name, md_defs) if self.pbc and pressure != None: odyn = self.calltinker("dynamic %s -k %s-md %i %f %f 4 %f %f" % (self.name, self.name, nsteps, timestep, float(nsave*timestep/1000), temperature, pressure), print_to_screen=verbose) else: odyn = self.calltinker("dynamic %s -k %s-md %i %f %f 2 %f" % (self.name, self.name, nsteps, timestep, float(nsave*timestep/1000), temperature), print_to_screen=verbose) # Gather information. os.system("mv %s.arc %s-md.arc" % (self.name, self.name)) self.md_trajectory = "%s-md.arc" % self.name edyn = [] kdyn = [] temps = [] for line in odyn: s = line.split() if 'Current Potential' in line: edyn.append(float(s[2])) if 'Current Kinetic' in line: kdyn.append(float(s[2])) if len(s) > 0 and s[0] == 'Temperature' and s[2] == 'Kelvin': temps.append(float(s[1])) # Potential and kinetic energies converted to kJ/mol. edyn = np.array(edyn) * 4.184 kdyn = np.array(kdyn) * 4.184 temps = np.array(temps) if verbose: logger.info("Post-processing to get the dipole moments\n") oanl = self.calltinker("analyze %s-md.arc" % self.name, stdin="G,E,M", print_to_screen=False) # Read potential energy and dipole from file. eanl = [] dip = [] mass = 0.0 ecomp = OrderedDict() havekeys = set() first_shot = True for ln, line in enumerate(oanl): strip = line.strip() s = line.split() if 'Total System Mass' in line: mass = float(s[-1]) if 'Total Potential Energy : ' in line: eanl.append(float(s[4])) if 'Dipole X,Y,Z-Components :' in line: dip.append([float(s[i]) for i in range(-3,0)]) if first_shot: for key in eckeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2])*4.184) else: ecomp[key] = [float(s[-2])*4.184] if key in havekeys: first_shot = False havekeys.add(key) else: for key in havekeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2])*4.184) else: ecomp[key] = [float(s[-2])*4.184] for key in ecomp: ecomp[key] = np.array(ecomp[key]) ecomp["Potential Energy"] = edyn ecomp["Kinetic Energy"] = kdyn ecomp["Temperature"] = temps ecomp["Total Energy"] = edyn+kdyn # Energies in kilojoules per mole eanl = np.array(eanl) * 4.184 # Dipole moments in debye dip = np.array(dip) # Volume of simulation boxes in cubic nanometers # Conversion factor derived from the following: # In [22]: 1.0 * gram / mole / (1.0 * nanometer)**3 / AVOGADRO_CONSTANT_NA / (kilogram/meter**3) # Out[22]: 1.6605387831627252 conv = 1.6605387831627252 if self.pbc: vol = np.array([BuildLatticeFromLengthsAngles(*[float(j) for j in line.split()]).V \ for line in open("%s-md.arc" % self.name).readlines() \ if (len(line.split()) == 6 and isfloat(line.split()[1]) \ and all([isfloat(i) for i in line.split()[:6]]))]) / 1000 rho = conv * mass / vol else: vol = None rho = None prop_return = OrderedDict() prop_return.update({'Rhos': rho, 'Potentials': edyn, 'Kinetics': kdyn, 'Volumes': vol, 'Dips': dip, 'Ecomps': ecomp}) return prop_return
import numpy as np from forcebalance.nifty import warn_once, printcool, printcool_dictionary from forcebalance.output import getLogger from forcebalance.target import Target try: from openff.evaluator import unit from openff.evaluator.attributes import UNDEFINED from openff.evaluator.client import EvaluatorClient, ConnectionOptions, RequestOptions from openff.evaluator.datasets import PhysicalPropertyDataSet from openff.evaluator.utils.exceptions import EvaluatorException from openff.evaluator.utils.openmm import openmm_quantity_to_pint from openff.evaluator.utils.serialization import TypedJSONDecoder, TypedJSONEncoder from openff.evaluator.forcefield import ParameterGradientKey except ImportError: warn_once("Note: Failed to import the optional openff.evaluator package. ") try: from openforcefield.typing.engines import smirnoff except ImportError: warn_once("Note: Failed to import the optional openforcefield package. ") logger = getLogger(__name__) class Evaluator_SMIRNOFF(Target): """A custom optimisation target which employs the `openff-evaluator` package to rapidly estimate a collection of condensed phase physical properties at each optimisation epoch.""" class OptionsFile: """Represents the set of options that a `Evaluator_SMIRNOFF`
from forcebalance.target import Target logger = getLogger(__name__) try: import propertyestimator from propertyestimator import unit from propertyestimator.client import PropertyEstimatorClient, ConnectionOptions, PropertyEstimatorOptions from propertyestimator.datasets import ThermoMLDataSet, PhysicalPropertyDataSet from propertyestimator.utils.exceptions import PropertyEstimatorException from propertyestimator.utils.openmm import openmm_quantity_to_pint from propertyestimator.utils.serialization import TypedJSONDecoder, TypedJSONEncoder from propertyestimator.workflow import WorkflowOptions from propertyestimator.properties import ParameterGradientKey except ImportError: warn_once("Failed to import the propertyestimator package.") try: from openforcefield.typing.engines import smirnoff except ImportError: warn_once("Failed to import the openforcefield package.") class PropertyEstimate_SMIRNOFF(Target): """A custom optimisation target which employs the propertyestimator package to rapidly estimate a collection of condensed phase physical properties at each optimisation epoch.""" class OptionsFile: """Represents the set of options that a `PropertyEstimate_SMIRNOFF` target will be run with.
def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, nequil=0, nsave=1000, minimize=True, anisotropic=False, threads=1, verbose=False, **kwargs): """ Method for running a molecular dynamics simulation. Required arguments: nsteps = (int) Number of total time steps timestep = (float) Time step in FEMTOSECONDS temperature = (float) Temperature control (Kelvin) pressure = (float) Pressure control (atmospheres) nequil = (int) Number of additional time steps at the beginning for equilibration nsave = (int) Step interval for saving and printing data minimize = (bool) Perform an energy minimization prior to dynamics threads = (int) Specify how many OpenMP threads to use Returns simulation data: Rhos = (array) Density in kilogram m^-3 Potentials = (array) Potential energies Kinetics = (array) Kinetic energies Volumes = (array) Box volumes Dips = (3xN array) Dipole moments EComps = (dict) Energy components """ logger.error( 'Molecular dynamics not yet implemented in AMBER interface') raise NotImplementedError md_defs = OrderedDict() md_opts = OrderedDict() # Print out averages only at the end. md_opts["printout"] = nsave md_opts["openmp-threads"] = threads # Langevin dynamics for temperature control. if temperature != None: md_defs["integrator"] = "stochastic" else: md_defs["integrator"] = "beeman" md_opts["thermostat"] = None # Periodic boundary conditions. if self.pbc: md_opts["vdw-correction"] = '' if temperature != None and pressure != None: md_defs["integrator"] = "beeman" md_defs["thermostat"] = "bussi" md_defs["barostat"] = "montecarlo" if anisotropic: md_opts["aniso-pressure"] = '' elif pressure != None: warn_once( "Pressure is ignored because temperature is turned off.") else: if pressure != None: warn_once("Pressure is ignored because pbc is set to False.") # Use stochastic dynamics for the gas phase molecule. # If we use the regular integrators it may miss # six degrees of freedom in calculating the kinetic energy. md_opts["barostat"] = None eq_opts = deepcopy(md_opts) if self.pbc and temperature != None and pressure != None: eq_opts["integrator"] = "beeman" eq_opts["thermostat"] = "bussi" eq_opts["barostat"] = "berendsen" if minimize: if verbose: logger.info("Minimizing the energy...") self.optimize(method="bfgs", crit=1) os.system("mv %s.xyz_2 %s.xyz" % (self.name, self.name)) if verbose: logger.info("Done\n") # Run equilibration. if nequil > 0: write_key("%s-eq.key" % self.name, eq_opts, "%s.key" % self.name, md_defs) if verbose: printcool("Running equilibration dynamics", color=0) if self.pbc and pressure != None: self.calltinker( "dynamic %s -k %s-eq %i %f %f 4 %f %f" % (self.name, self.name, nequil, timestep, float(nsave * timestep) / 1000, temperature, pressure), print_to_screen=verbose) else: self.calltinker("dynamic %s -k %s-eq %i %f %f 2 %f" % (self.name, self.name, nequil, timestep, float(nsave * timestep) / 1000, temperature), print_to_screen=verbose) os.system("rm -f %s.arc" % (self.name)) # Run production. if verbose: printcool("Running production dynamics", color=0) write_key("%s-md.key" % self.name, md_opts, "%s.key" % self.name, md_defs) if self.pbc and pressure != None: odyn = self.calltinker( "dynamic %s -k %s-md %i %f %f 4 %f %f" % (self.name, self.name, nsteps, timestep, float(nsave * timestep / 1000), temperature, pressure), print_to_screen=verbose) else: odyn = self.calltinker( "dynamic %s -k %s-md %i %f %f 2 %f" % (self.name, self.name, nsteps, timestep, float(nsave * timestep / 1000), temperature), print_to_screen=verbose) # Gather information. os.system("mv %s.arc %s-md.arc" % (self.name, self.name)) self.md_trajectory = "%s-md.arc" % self.name edyn = [] kdyn = [] temps = [] for line in odyn: s = line.split() if 'Current Potential' in line: edyn.append(float(s[2])) if 'Current Kinetic' in line: kdyn.append(float(s[2])) if len(s) > 0 and s[0] == 'Temperature' and s[2] == 'Kelvin': temps.append(float(s[1])) # Potential and kinetic energies converted to kJ/mol. edyn = np.array(edyn) * 4.184 kdyn = np.array(kdyn) * 4.184 temps = np.array(temps) if verbose: logger.info("Post-processing to get the dipole moments\n") oanl = self.calltinker("analyze %s-md.arc" % self.name, stdin="G,E,M", print_to_screen=False) # Read potential energy and dipole from file. eanl = [] dip = [] mass = 0.0 ecomp = OrderedDict() havekeys = set() first_shot = True for ln, line in enumerate(oanl): strip = line.strip() s = line.split() if 'Total System Mass' in line: mass = float(s[-1]) if 'Total Potential Energy : ' in line: eanl.append(float(s[4])) if 'Dipole X,Y,Z-Components :' in line: dip.append([float(s[i]) for i in range(-3, 0)]) if first_shot: for key in eckeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2]) * 4.184) else: ecomp[key] = [float(s[-2]) * 4.184] if key in havekeys: first_shot = False havekeys.add(key) else: for key in havekeys: if strip.startswith(key): if key in ecomp: ecomp[key].append(float(s[-2]) * 4.184) else: ecomp[key] = [float(s[-2]) * 4.184] for key in ecomp: ecomp[key] = np.array(ecomp[key]) ecomp["Potential Energy"] = edyn ecomp["Kinetic Energy"] = kdyn ecomp["Temperature"] = temps ecomp["Total Energy"] = edyn + kdyn # Energies in kilojoules per mole eanl = np.array(eanl) * 4.184 # Dipole moments in debye dip = np.array(dip) # Volume of simulation boxes in cubic nanometers # Conversion factor derived from the following: # In [22]: 1.0 * gram / mole / (1.0 * nanometer)**3 / AVOGADRO_CONSTANT_NA / (kilogram/meter**3) # Out[22]: 1.6605387831627252 conv = 1.6605387831627252 if self.pbc: vol = np.array([BuildLatticeFromLengthsAngles(*[float(j) for j in line.split()]).V \ for line in open("%s-md.arc" % self.name).readlines() \ if (len(line.split()) == 6 and isfloat(line.split()[1]) \ and all([isfloat(i) for i in line.split()[:6]]))]) / 1000 rho = conv * mass / vol else: vol = None rho = None prop_return = OrderedDict() prop_return.update({ 'Rhos': rho, 'Potentials': edyn, 'Kinetics': kdyn, 'Volumes': vol, 'Dips': dip, 'Ecomps': ecomp }) return prop_return