1 """ @package forcebalance.torsion_profile Torsion profile fitting module. 6 from __future__
import division
11 from copy
import deepcopy
12 from collections
import OrderedDict
14 from forcebalance.target
import Target
17 from forcebalance.output
import getLogger
19 logger = getLogger(__name__)
22 """ Subclass of Target for fitting MM optimized geometries to QM optimized geometries. """ 23 def __init__(self, options, tgt_opts, forcefield):
24 super(TorsionProfileTarget, self).
__init__(options, tgt_opts, forcefield)
26 if not os.path.exists(os.path.join(self.tgtdir,
'metadata.json')):
27 raise RuntimeError(
'TorsionProfileTarget needs torsion drive metadata.json file')
28 with open(os.path.join(self.tgtdir,
'metadata.json'))
as f:
34 if hasattr(self,
'pdb')
and self.pdb
is not None:
35 self.
mol = Molecule(os.path.join(self.root,self.tgtdir,self.coords),
36 top=(os.path.join(self.root,self.tgtdir,self.pdb)))
38 self.
mol = Molecule(os.path.join(self.root,self.tgtdir,self.coords))
40 self.
ns = len(self.
mol)
42 self.set_option(tgt_opts,
'writelevel',
'writelevel')
44 self.set_option(tgt_opts,
'restrain_k',
'restrain_k')
46 self.set_option(tgt_opts,
'attenuate',
'attenuate')
48 self.set_option(tgt_opts,
'energy_denom',
'energy_denom')
50 self.set_option(tgt_opts,
'energy_upper',
'energy_upper')
54 engine_args = OrderedDict(list(self.OptionDict.items()) + list(options.items()))
55 engine_args.pop(
'name',
None)
58 self.
engine = self.engine_(target=self, mol=self.
mol, **engine_args)
62 """ Read the reference ab initio data from a file such as qdata.txt. 64 After reading in the information from qdata.txt, it is converted 65 into the GROMACS energy units (kind of an arbitrary choice). 70 self.
qfnm = os.path.join(self.tgtdir,
"qdata.txt")
72 for line
in open(os.path.join(self.root,self.
qfnm)):
74 if len(sline) == 0:
continue 75 elif sline[0] ==
'ENERGY':
76 self.
eqm.append(float(sline[1]))
78 if len(self.
eqm) != self.
ns:
79 raise RuntimeError(
"Length of qdata.txt should match number of structures")
82 self.
eqm = np.array(self.
eqm)
83 self.
eqm *= eqcgmx / 4.184
85 self.
eqm -= np.min(self.
eqm)
87 logger.info(
"Referencing all energies to the snapshot %i (minimum energy structure in QM)\n" % self.
smin)
92 eqm1 = self.
eqm - np.min(self.
eqm)
93 denom = self.energy_denom
94 upper = self.energy_upper
95 self.
wts = np.ones(self.
ns)
96 for i
in range(self.
ns):
100 self.
wts[i] = 1.0 / denom
102 self.
wts[i] = 1.0 / np.sqrt(denom**2 + (eqm1[i]-denom)**2)
104 self.
wts = np.ones(self.
ns)
110 title_str =
"Torsion Profile: %s, Objective = % .5e, Units = kcal/mol, Angstrom" % (self.name, self.
objective)
112 column_head_str1 =
"%-50s %-10s %-12s %-18s %-12s %-10s %-11s %-10s" % (
"System",
"Min(QM)",
"Min(MM)",
"Range(QM)",
"Range(MM)",
"Max-RMSD",
"Ene-RMSE",
"Obj-Fn")
115 def get(self, mvals, AGrad=False, AHess=False):
116 Answer = {
'X':0.0,
'G':np.zeros(self.FF.np),
'H':np.zeros((self.FF.np, self.FF.np))}
119 def compute(mvals_, indicate=False):
124 for i
in range(self.
ns):
125 energy, rmsd, M_opt = self.
engine.optimize(shot=i, align=
False)
127 compute.emm.append(energy)
128 compute.rmsd.append(rmsd)
130 M_opts = deepcopy(M_opt)
133 compute.emm = np.array(compute.emm)
134 compute.emm -= compute.emm[self.
smin]
135 compute.rmsd = np.array(compute.rmsd)
137 if self.writelevel > 0:
138 energy_comparison = np.array([
141 compute.emm - self.
eqm,
142 np.sqrt(self.
wts)/self.energy_denom
144 np.savetxt(
"EnergyCompare.txt", energy_comparison, header=
"%11s %12s %12s %12s" % (
"QMEnergy",
"MMEnergy",
"Delta(MM-QM)",
"Weight"), fmt=
"% 12.6e")
145 M_opts.write(
'mm_minimized.xyz')
148 import matplotlib.pyplot
as plt
149 plt.switch_backend(
'agg')
150 fig, ax = plt.subplots()
151 dihedrals = np.array([i[0]
for i
in self.
metadata[
'torsion_grid_ids']])
152 dsort = np.argsort(dihedrals)
153 ax.plot(dihedrals[dsort], self.
eqm[dsort], label=
'QM')
154 if hasattr(self,
'emm_orig'):
155 ax.plot(dihedrals[dsort], compute.emm[dsort], label=
'MM Current')
156 ax.plot(dihedrals[dsort], self.
emm_orig[dsort], label=
'MM Initial')
158 ax.plot(dihedrals[dsort], compute.emm[dsort], label=
'MM Initial')
161 ax.set_xlabel(
'Dihedral (degree)')
162 ax.set_ylabel(
'Energy (kcal/mol)')
163 fig.suptitle(
'Torsion profile: iteration %i\nSystem: %s' % (
Counter(), self.name))
164 fig.savefig(
'plot_torsion.pdf')
166 logger.warning(
"matplotlib package is needed to make torsion profile plots\n")
167 return (np.sqrt(self.
wts)/self.energy_denom) * (compute.emm - self.
eqm)
171 V = compute(mvals, indicate=
True)
173 Answer[
'X'] = np.dot(V,V)
176 e_rmse = np.sqrt(np.dot(self.
wts, (compute.emm - self.
eqm)**2))
178 self.
PrintDict[self.name] =
'%10s %10s %6.3f - %-6.3f % 6.3f - %-6.3f %6.3f %7.4f % 7.4f' % (
','.join([
'%i' % i
for i
in self.
metadata[
'torsion_grid_ids'][self.
smin]]),
179 ','.join([
'%i' % i
for i
in self.
metadata[
'torsion_grid_ids'][np.argmin(compute.emm)]]),
180 min(self.
eqm), max(self.
eqm), min(compute.emm), max(compute.emm), max(compute.rmsd), e_rmse, Answer[
'X'])
183 dV = np.zeros((self.FF.np,len(V)))
186 dV[p,:], _ =
f12d3p(
fdwrap(compute, mvals, p), h = self.h, f0 = V)
189 Answer[
'G'][p] = 2*np.dot(V, dV[p,:])
191 Answer[
'H'][p,q] = 2*np.dot(dV[p,:], dV[q,:])
Subclass of Target for fitting MM optimized geometries to QM optimized geometries.
Nifty functions, intended to be imported by any module within ForceBalance.
eqm
Reference (QM) energies.
def get(self, mvals, AGrad=False, AHess=False)
engine
Option for how much data to write to disk.
def read_reference_data(self)
Read the reference ab initio data from a file such as qdata.txt.
def __init__(self, options, tgt_opts, forcefield)
def in_fd()
Invoking this function from anywhere will tell us whether we're being called by a finite-difference f...
def fdwrap(func, mvals0, pidx, key=None, kwargs)
A function wrapper for finite difference designed for differentiating 'get'-type functions.
def printcool_dictionary(Dict, title="Dictionary Keys : Values", bold=False, color=2, keywidth=25, topwidth=50, center=True, leftpad=0)
See documentation for printcool; this is a nice way to print out keys/values in a dictionary...
qfnm
The qdata.txt file that contains the QM energies and forces.
def f12d3p(f, h, f0=None)
A three-point finite difference stencil.
mol
Read in the coordinate files and get topology information from PDB.