1 """ @package forcebalance.interaction Interaction energy fitting module. 6 from __future__
import division
8 from builtins
import str
9 from builtins
import range
13 from forcebalance.nifty import col, eqcgmx, flat, floatornan, fqcgmx, invert_svd, kb, printcool, bohr2ang, commadash, uncommadash, printcool_dictionary
14 from forcebalance.target
import Target
16 from re
import match, sub
18 from subprocess
import PIPE
20 from collections
import OrderedDict
22 from forcebalance.output
import getLogger
23 logger = getLogger(__name__)
27 """ Subclass of Target for fitting force fields to interaction energies. 29 Currently TINKER is supported. 31 We introduce the following concepts: 32 - The number of snapshots 33 - The reference interaction energies and the file they belong in (qdata.txt) 35 This subclass contains the 'get' method for building the objective 36 function from any simulation software (a driver to run the program and 37 read output is still required).""" 39 def __init__(self,options,tgt_opts,forcefield):
41 super(Interaction,self).
__init__(options,tgt_opts,forcefield)
48 self.set_option(tgt_opts,
'shots',
'ns')
50 self.set_option(tgt_opts,
'do_cosmo',
'do_cosmo')
52 self.set_option(tgt_opts,
'cauchy',
'cauchy')
54 self.set_option(tgt_opts,
'attenuate',
'attenuate')
56 self.set_option(tgt_opts,
'normalize')
58 self.set_option(tgt_opts,
'energy_denom',
'energy_denom')
60 self.set_option(tgt_opts,
'fragment1',
'fragment1')
61 if len(self.fragment1) == 0:
62 logger.error(
'You need to define the first fragment using the fragment1 keyword\n')
66 self.set_option(tgt_opts,
'fragment2',
'fragment2')
67 if len(self.fragment2) != 0:
72 self.set_option(tgt_opts,
'energy_upper',
'energy_upper')
74 self.set_option(tgt_opts,
'writelevel',
'writelevel')
86 self.
qfnm = os.path.join(self.tgtdir,
"qdata.txt")
90 self.
mol = Molecule(os.path.join(self.root,self.tgtdir,self.coords),
91 top=(os.path.join(self.root,self.tgtdir,self.pdb)
if hasattr(self,
'pdb')
else None), build_topology=
False if self.coords.endswith(
'.pdb')
else True)
94 self.
ns = len(self.
mol)
97 logger.info(
'Fragment 2 is the complement of fragment 1 : %s\n' % (
commadash(self.
select2)))
99 engine_args = OrderedDict(list(self.OptionDict.items()) + list(options.items()))
100 engine_args.pop(
'name',
None)
101 self.
engine = self.engine_(target=self, mol=self.
mol, **engine_args)
104 logger.info(
"The energy denominator is: %s kcal/mol\n" % str(self.energy_denom))
105 denom = self.energy_denom
108 self.
divisor = np.sqrt(self.
eqm**2 + denom**2)
110 logger.error(
'attenuate and cauchy are mutually exclusive\n')
115 for i
in range(len(self.
eqm)):
116 if self.
eqm[i] < denom:
119 self.
divisor[i] = np.sqrt(denom**2 + (self.
eqm[i]-denom)**2)
124 logger.info(
"Each contribution to the interaction energy objective function will be scaled by 1.0 / ( energy_denom**2 + reference**2 )\n")
125 if self.energy_upper > 0:
126 ecut = self.energy_upper
128 logger.info(
"Interactions more repulsive than %s will not be fitted (%i/%i excluded) \n" % (str(self.energy_upper), sum(self.
eqm > ecut), len(self.
eqm)))
136 """ Read the reference ab initio data from a file such as qdata.txt. 138 After reading in the information from qdata.txt, it is converted 143 for line
in open(os.path.join(self.root,self.
qfnm)):
145 if len(sline) == 0:
continue 146 elif sline[0] ==
'INTERACTION':
147 self.
eqm.append(float(sline[1]))
148 elif sline[0] ==
'LABEL':
149 self.
label.append(sline[1])
150 if all(len(i)
in [self.
ns, 0]
for i
in [self.
eqm])
and len(self.
eqm) == self.
ns:
152 self.
ns = len(self.
eqm)
154 self.
eqm = np.array(self.
eqm)
155 self.
eqm *= (eqcgmx / 4.184)
158 delta = (self.
emm-self.
eqm)
161 PrintDict = OrderedDict()
162 for i,label
in enumerate(self.
label):
163 PrintDict[label] =
"% 9.3f % 9.3f % 9.3f % 9.3f % 11.5f" % (self.
emm[i], self.
eqm[i], delta[i], self.
divisor[i], deltanrm[i])
164 printcool_dictionary(PrintDict,title=
"Target: %s\nInteraction Energies (kcal/mol), Objective = % .5e\n %-10s %9s %9s %9s %9s %11s" %
165 (self.name, self.
objective,
"Label",
"Calc.",
"Ref.",
"Delta",
"Divisor",
"Term"),keywidth=15)
168 Headings = [
"Observable",
"Difference\nRMS (Calc-Ref)",
"Denominator\n(Specified)",
" Percent \nDifference"]
169 Data = OrderedDict([])
170 Data[
'Energy (kcal/mol)'] = [
"%8.4f" % np.sqrt(np.mean(delta**2)),
171 "%8.4f" % np.mean(self.
divisor),
172 "%.4f%%" % (np.sqrt(np.mean(delta/self.
divisor)**2)*100)]
173 self.printcool_table(data=Data, headings=Headings, color=0)
174 logger.info(
"add LABEL keywords in qdata.txt to print out each snapshot\n")
180 def get(self, mvals, AGrad=False, AHess=False):
181 """ Evaluate objective function. """ 182 Answer = {
'X':0.0,
'G':np.zeros(self.FF.np),
'H':np.zeros((self.FF.np, self.FF.np))}
189 def callM(mvals_, dielectric=False):
191 pvals = self.FF.make(mvals_)
194 logger.info(
"Executing\r")
198 dV = np.zeros((self.FF.np,len(emm)))
200 if self.writelevel > 0:
202 np.savetxt(
'M.txt',emm)
203 np.savetxt(
'Q.txt',self.
eqm)
205 pickle.dump((self.name, self.
label, self.
prefactor, self.
eqm, emm), open(
"qm_vs_mm.p",
'w'))
207 qm_data, mm_data = [], []
208 for i
in range(len(self.
eqm)):
210 qm_data.append(self.
eqm[i])
211 mm_data.append(emm[i])
217 dV[p,:], _ =
f12d3p(
fdwrap(callM, mvals, p), h = self.h, f0 = emm)
219 pvals = self.FF.make(mvals)
234 if hasattr(self.
engine,
'simulation'): del self.
engine.simulation
243 import matplotlib.pyplot
as plt
244 plt.plot(eqm, label=
'QM Data', marker=
'^')
245 plt.plot(emm, label=
'MM Data', marker=
'o')
247 plt.xlabel(
'Snapshots')
248 plt.ylabel(
'Interaction Energy (kcal/mol)')
250 plt.savefig(
"e_qm_vs_mm.pdf")
def plot_interaction_qm_vs_mm(eqm, emm, title='')
divisor
Read in the reference data.
Nifty functions, intended to be imported by any module within ForceBalance.
engine
Build keyword dictionaries to pass to engine.
mol
Read in the trajectory file.
select1
Number of snapshots.
eqm
Reference (QM) interaction energies.
def get(self, mvals, AGrad=False, AHess=False)
Evaluate objective function.
loop_over_snapshots
Set upper cutoff energy.
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.
qfnm
The qdata.txt file that contains the QM energies and forces.
label
Snapshot label, useful for graphing.
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...
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 f12d3p(f, h, f0=None)
A three-point finite difference stencil.
Subclass of Target for fitting force fields to interaction energies.