1 """ @package forcebalance.amberio AMBER force field input/output. 3 This serves as a good template for writing future force matching I/O 4 modules for other programs because it's so simple. 9 from __future__
import division
10 from __future__
import print_function
12 from builtins
import str
13 from builtins
import zip
14 from builtins
import range
15 from builtins
import object
18 from re
import match, sub, split, findall
20 from forcebalance.nifty import isint, isfloat, _exec, LinkFile, warn_once, which, onefile, listfiles, warn_press_key, wopen, printcool, printcool_dictionary
22 from forcebalance
import BaseReader
23 from forcebalance.engine
import Engine
29 from collections
import OrderedDict, defaultdict, namedtuple
31 from scipy.io.netcdf
import netcdf_file
38 from forcebalance.output
import getLogger
39 logger = getLogger(__name__)
42 kb_kcal = 0.0019872041
44 mol2_pdict = {
'COUL':{
'Atom':[1], 8:
''}}
46 frcmod_pdict = {
'BONDS': {
'Atom':[0], 1:
'K', 2:
'B'},
47 'ANGLES':{
'Atom':[0], 1:
'K', 2:
'B'},
48 'PDIHS1':{
'Atom':[0], 2:
'K', 3:
'B'},
49 'PDIHS2':{
'Atom':[0], 2:
'K', 3:
'B'},
50 'PDIHS3':{
'Atom':[0], 2:
'K', 3:
'B'},
51 'PDIHS4':{
'Atom':[0], 2:
'K', 3:
'B'},
52 'PDIHS5':{
'Atom':[0], 2:
'K', 3:
'B'},
53 'PDIHS6':{
'Atom':[0], 2:
'K', 3:
'B'},
54 'IDIHS' :{
'Atom':[0], 1:
'K', 2:
'B'},
55 'VDW':{
'Atom':[0], 1:
'S', 2:
'T'}
64 def write_leap(fnm, mol2=[], frcmod=[], pdb=None, prefix='amber', spath = [], delcheck=False):
65 """ Parse and edit an AMBER LEaP input file. Output file is written to inputfile_ (with trailing underscore.) """ 70 aload = [
'loadamberparams',
'source',
'loadoff']
71 aload_eq = [
'loadmol2']
75 for line
in open(fnm):
77 if line.strip().startswith(
'#') :
continue 78 line = line.split(
'#')[0]
81 ls = line.lower().split()
84 if ll.split(
'=')[1].split()[0]
in aload_eq:
85 if not any([os.path.exists(os.path.join(d, s[-1]))
for d
in spath]):
86 logger.error(
"The file in this line cannot be loaded : " + line.strip())
88 elif len(ls) > 0
and ls[0]
in aload:
89 if not any([os.path.exists(os.path.join(d, s[-1]))
for d
in spath]):
90 logger.error(
"The file in this line cannot be loaded : " + line.strip())
92 if len(s) >= 2
and ls[0] ==
'loadamberparams':
93 have_fmod.append(s[1])
94 if len(s) >= 2
and 'loadmol2' in ll:
96 ambername = line.split(
'=')[0].strip()
97 have_mol2.append(s[-1])
98 if len(s) >= 2
and 'loadpdb' in ll:
100 ambername = line.split(
'=')[0].strip()
103 line =
'%s = loadpdb %s\n' % (ambername, pdb)
104 if len(s) >= 1
and ls[0] ==
'check' and delcheck:
107 if 'saveamberparm' in ll:
110 if len(s) >= 1
and ls[0] ==
'quit':
113 if not line.endswith(
'\n') : line +=
'\n' 114 line_out.append(line)
119 if i
not in have_fmod:
120 warn_press_key(
"WARNING: %s is not being loaded in %s" % (i, fnm))
122 if i
not in have_mol2:
123 warn_press_key(
"WARNING: %s is not being loaded in %s" % (i, fnm))
126 line_out.append(
'saveamberparm %s %s.prmtop %s.inpcrd\n' % (ambername, prefix, prefix))
127 line_out.append(
'quit\n')
128 if os.path.exists(fout): os.remove(fout)
129 with
wopen(fout)
as f: print(
''.join(line_out), file=f)
133 Remove the comment from a line in an AMBER namelist. Had to write a separate 134 function because I couldn't get regex to work 139 Input string such as: 140 restraintmask='!:WAT,NA&!@H=', ! Restraint mask for non-water, non-ions 145 Output string with comment removed (but keeping leading and trailing whitespace) such as: 146 restraintmask='!:WAT,NA&!@H=', 151 for i
in range(len(mystr)):
155 if i < (len(mystr)-1)
and mystr[i+1] !=
'\'' and i > 0
and mystr[i-1] !=
'\'':
157 if headStr
and i > 0
and mystr[i-1] ==
'\'':
167 print(
"\x1b[91m%s\x1b[0m" % mystr[i],end=
"")
169 print(mystr[i],end=
"")
184 Parse a file containing an AMBER namelist 185 (only significantly tested for sander input). 190 Name of file containing the namelist 194 comments (list) of lines) 195 List of lines containing comments before first namelist 197 List of names of each namelist (e.g. cntrl, ewald) 199 List of ordered dictionaries containing variable names and values for each namelist 201 List of list of lines coming after the "slash" for each suffix 208 lines = fobj.readlines()
214 for i
in range(len(lines)):
219 if strip.startswith(
'&'):
222 names.append(strip[1:].lower())
227 comments.append(line.replace(
'\n',
''))
229 suffixes[-1].append(line.replace(
'\n',
''))
231 if strip
in [
'/',
'&end']:
233 blocks.append(block_lines[:])
234 elif strip.startswith(
'&'):
235 raise RuntimeError(
'Cannot start a namelist within a namelist')
237 block_lines.append(line.replace(
'\n',
''))
240 for name, block
in zip(names, blocks):
241 block_string =
' '.join([
splitComment(line)
for line
in block])
245 block_split = re.findall(
"[A-Za-z0-9_]+ *= *(?:\'[^']*\'|[+-]?[0-9]+\.?[0-9]*),", block_string)
250 block_dict = OrderedDict()
251 for word
in block_split:
252 field1, field2 = word.split(
"=", 1)
253 key = field1.strip().lower()
254 val = re.sub(
',$',
'',field2).strip()
255 block_dict[key] = val
256 block_dicts.append(block_dict)
258 return comments, names, block_dicts, suffixes
260 def write_mdin(calctype, fout=None, nsteps=None, timestep=None, nsave=None, pbc=False, temperature=None, pressure=None, mdin_orig=None):
262 Write an AMBER .mdin file to carry out a calculation using sander or pmemd.cuda. 267 The type of calculation being performed 270 'md' : (production) MD 271 'sp' : Single-point calculation 274 If provided, file name that the .mdin file should be written to. 275 Each variable within a namelist will occupy one line. 276 Comments within namelist are not written to output. 279 Time step in picoseconds. For minimizations or 280 single-point calculations, this is not needed 283 How many MD or minimization steps to take 284 For single-point calculations, this is not needed 287 How often to write trajectory and velocity frames 288 (only production MD writes velocities) 289 For single-point calculations, this is not needed 292 Whether to use periodic boundary conditions 295 If not None, the simulation temperature 298 If not None, the simulation pressure 300 mdin_orig : str, optional 301 Custom mdin file provided by the user. 302 Non-&cntrl blocks will be written to output. 303 Top-of-file comments will be written to output. 308 key : value pairs in the &cntrl namelist, 309 useful for passing to cpptraj or sander/cpptraj 310 Python APIs in the future. 312 if calctype
not in [
'min',
'eq',
'md',
'sp']:
313 raise RuntimeError(
"Invalid calctype")
314 if calctype
in [
'eq',
'md']:
316 raise RuntimeError(
"eq and md requires timestep")
318 raise RuntimeError(
"eq and md requires nsteps")
320 raise RuntimeError(
"eq and md requires nsave")
321 if calctype ==
'min':
350 cntrl_vars = OrderedDict()
351 cntrl_var = namedtuple(
"cntrl_var", [
"name",
"value",
"comment",
"priority"])
352 cntrl_vars[
"imin"] = cntrl_var(name=
"imin", value={
"min":
"1",
"eq":
"0",
"md":
"0",
"sp":
"5"}, comment=
"0 = MD; 1 = Minimize; 5 = Trajectory analysis", priority=1)
354 cntrl_vars[
"ntmin"] = cntrl_var(name=
"ntmin", value={
"min":
"2"}, comment=
"Minimization algorithm; 2 = Steepest descent", priority=3)
355 cntrl_vars[
"dx0"] = cntrl_var(name=
"dx0", value={
"min":
"0.1"}, comment=
"Minimizer step length", priority=3)
356 cntrl_vars[
"maxcyc"] = cntrl_var(name=
"maxcyc", value={
"min":
"%i" % nsteps,
"sp":
"1"}, comment=
"Number of minimization steps", priority=3)
358 cntrl_vars[
"dt"] = cntrl_var(name=
"dt", value={
"eq":
"%.8f" % timestep,
"md":
"%.8f" % timestep}, comment=
"Time step (ps)", priority=2)
359 cntrl_vars[
"nstlim"] = cntrl_var(name=
"nstlim", value={
"eq":
"%i" % nsteps,
"md":
"%i" % nsteps}, comment=
"Number of MD steps", priority=2)
361 cntrl_vars[
"ntpr"] = cntrl_var(name=
"ntpr", value={
"min":
"%i" % nsave,
"eq":
"%i" % nsave,
"md":
"%i" % nsave}, comment=
"Interval for printing output", priority={
"min":1,
"eq":2,
"md":2,
"sp":1})
362 cntrl_vars[
"ntwx"] = cntrl_var(name=
"ntwx", value={
"min":
"%i" % nsave,
"eq":
"%i" % nsave,
"md":
"%i" % nsave}, comment=
"Interval for writing trajectory", priority={
"min":1,
"eq":2,
"md":2,
"sp":1})
363 cntrl_vars[
"ntwr"] = cntrl_var(name=
"ntwr", value={
"min":
"%i" % nsave,
"eq":
"%i" % nsteps,
"md":
"%i" % nsteps}, comment=
"Interval for writing restart", priority={
"min":1,
"eq":1,
"md":1,
"sp":1})
364 cntrl_vars[
"ntwv"] = cntrl_var(name=
"ntwv", value={
"md":
"-1"}, comment=
"Interval for writing velocities", priority={
"min":1,
"eq":1,
"md":2,
"sp":1})
365 cntrl_vars[
"ntwe"] = cntrl_var(name=
"ntwe", value={
"md":
"%i" % nsave}, comment=
"Interval for writing energies (disabled)", priority=1)
366 cntrl_vars[
"nscm"] = cntrl_var(name=
"nscm", value={
"eq":
"1000",
"md":
"1000"}, comment=
"Interval for removing COM translation/rotation", priority=3)
368 cntrl_vars[
"ntxo"] = cntrl_var(name=
"ntxo", value={
"min":
"2",
"eq":
"2",
"md":
"2"}, comment=
"Restart output format; 1 = ASCII, 2 = NetCDF", priority=1)
369 cntrl_vars[
"ioutfm"] = cntrl_var(name=
"ioutfm", value={
"min":
"1",
"eq":
"1",
"md":
"1"}, comment=
"Trajectory format; 0 = ASCII, 1 = NetCDF", priority=1)
371 cntrl_vars[
"ntx"] = cntrl_var(name=
"ntx", value={
"min":
"1",
"eq":
"1",
"md":
"5"}, comment=
"1 = Read coors only; 5 = Full restart", priority=1)
372 cntrl_vars[
"irest"] = cntrl_var(name=
"irest", value={
"min":
"0",
"eq":
"0",
"md":
"1"}, comment=
"0 = Do not restart ; 1 = Restart", priority=1)
376 ntb_eqmd =
"2" if pressure
is not None else "1" 377 ntp_eqmd =
"1" if pressure
is not None else "0" 378 cntrl_vars[
"cut"] = cntrl_var(name=
"cut", value={
"min":
"8.0",
"eq":
"8.0",
"md":
"8.0",
"sp":
"8.0"}, comment=
"Nonbonded cutoff", priority=3)
379 cntrl_vars[
"ntb"] = cntrl_var(name=
"ntb", value={
"min":
"1",
"eq":ntb_eqmd,
"md":ntb_eqmd,
"sp":ntb_eqmd}, comment=
"0 = no PBC ; 1 = constant V ; 2 = constant P", priority=1)
380 cntrl_vars[
"ntp"] = cntrl_var(name=
"ntp", value={
"min":
"0",
"eq":ntp_eqmd,
"md":ntp_eqmd,
"sp":ntp_eqmd}, comment=
"0 = constant V ; 1 = isotropic scaling", priority=1)
381 cntrl_vars[
"iwrap"] = cntrl_var(name=
"iwrap", value={
"min":
"1",
"eq":
"1",
"md":
"1"}, comment=
"Wrap molecules back into box", priority=3)
382 cntrl_vars[
"igb"] = cntrl_var(name=
"igb", value={
"min":
"0",
"eq":
"0",
"md":
"0",
"sp":
"0"}, comment=
"0 = No generalized Born model", priority=3)
383 if pressure
is not None:
385 cntrl_vars[
"barostat"] = cntrl_var(name=
"barostat", value={
"eq":
"1",
"md":
"2"}, comment=
"1 = Berendsen; 2 = Monte Carlo", priority=1)
386 cntrl_vars[
"mcbarint"] = cntrl_var(name=
"mcbarint", value={
"md":
"25"}, comment=
"MC barostat rescaling interval", priority=3)
389 cntrl_vars[
"barostat"] = cntrl_var(name=
"barostat", value={}, comment=
"1 = Berendsen; 2 = Monte Carlo", priority=1)
390 cntrl_vars[
"mcbarint"] = cntrl_var(name=
"mcbarint", value={}, comment=
"MC barostat rescaling interval", priority=1)
392 cntrl_vars[
"cut"] = cntrl_var(name=
"cut", value={
"min":
"9999.0",
"eq":
"9999.0",
"md":
"9999.0",
"sp":
"9999.0"}, comment=
"Nonbonded cutoff", priority=1)
393 cntrl_vars[
"ntb"] = cntrl_var(name=
"ntb", value={
"min":
"0",
"eq":
"0",
"md":
"0",
"sp":
"0"}, comment=
"0 = no PBC ; 1 = constant V ; 2 = constant P", priority=1)
394 cntrl_vars[
"ntp"] = cntrl_var(name=
"ntp", value={}, comment=
"0 = constant V ; 1 = isotropic scaling", priority=1)
395 cntrl_vars[
"igb"] = cntrl_var(name=
"igb", value={
"min":
"6",
"eq":
"6",
"md":
"6",
"sp":
"6"}, comment=
"6 = Vacuum phase simulation", priority=1)
396 cntrl_vars[
"iwrap"] = cntrl_var(name=
"iwrap", value={}, comment=
"Wrap molecules back into box", priority=1)
397 cntrl_vars[
"barostat"] = cntrl_var(name=
"barostat", value={}, comment=
"1 = Berendsen; 2 = Monte Carlo", priority=1)
398 cntrl_vars[
"mcbarint"] = cntrl_var(name=
"mcbarint", value={}, comment=
"MC barostat rescaling interval", priority=1)
400 if temperature
is not None:
401 cntrl_vars[
"tempi"] = cntrl_var(name=
"tempi", value={
"eq":
"%i" % temperature,
"md":
"%i" % temperature}, comment=
"Initial temperature", priority=1)
402 cntrl_vars[
"temp0"] = cntrl_var(name=
"temp0", value={
"eq":
"%i" % temperature,
"md":
"%i" % temperature}, comment=
"Reference temperature", priority=1)
403 cntrl_vars[
"ntt"] = cntrl_var(name=
"ntt", value={
"eq":
"3",
"md":
"3"}, comment=
"Thermostat ; 3 = Langevin", priority=1)
404 cntrl_vars[
"gamma_ln"] = cntrl_var(name=
"gamma_ln", value={
"eq":
"1.0",
"md":
"1.0"}, comment=
"Langevin collision frequency (ps^-1)", priority=3)
406 cntrl_vars[
"tempi"] = cntrl_var(name=
"tempi", value={}, comment=
"Initial temperature", priority=1)
407 cntrl_vars[
"temp0"] = cntrl_var(name=
"temp0", value={}, comment=
"Reference temperature", priority=1)
408 cntrl_vars[
"ntt"] = cntrl_var(name=
"ntt", value={}, comment=
"Thermostat ; 3 = Langevin", priority=1)
409 cntrl_vars[
"gamma_ln"] = cntrl_var(name=
"gamma_ln", value={}, comment=
"Langevin collision frequency (ps^-1)", priority=1)
412 cntrl_vars[
"ntc"] = cntrl_var(name=
"ntc", value={
"min":
"1",
"eq":
"1",
"md":
"1",
"sp":
"1"}, comment=
"SHAKE; 1 = none, 2 = H-bonds, 3 = All-bonds", priority={
"min":1,
"eq":3,
"md":3,
"sp":1})
413 cntrl_vars[
"ntf"] = cntrl_var(name=
"ntf", value={
"min":
"1",
"eq":
"1",
"md":
"1",
"sp":
"1"}, comment=
"No bonds involving H-atoms (use with NTC=2)", priority={
"min":1,
"eq":3,
"md":3,
"sp":1})
414 cntrl_vars[
"tol"] = cntrl_var(name=
"tol", value={}, comment=
"SHAKE tolerance,", priority=4)
416 cntrl_vars[
"ig"] = cntrl_var(name=
"ig", value={
"eq":
"-1",
"md":
"-1"}, comment=
"Random number seed; -1 based on date/time", priority=3)
418 def get_priority(prio_in):
419 if type(prio_in)
is int:
421 elif type(prio_in)
is dict:
422 return prio_in[calctype]
424 if mdin_orig
is not None:
426 comments.append(
"Generated by ForceBalance from %s" % mdin_orig)
428 comments = [
"Generated by ForceBalance"]
433 for name, block_dict
in zip(names, block_dicts):
435 user_cntrl = block_dict
438 cntrl_out = OrderedDict()
439 cntrl_comm = OrderedDict()
445 for name, var
in cntrl_vars.items():
446 priority = get_priority(var.priority)
447 if priority
in [1, 2]:
448 checked_list.append(name)
449 if calctype
in var.value:
450 cntrl_out[name] = var.value[calctype]
452 cntrl_comm[name] =
"Set by FB at runtime : %s" % var.comment
454 cntrl_comm[name] =
"From FB input file : %s" % var.comment
457 for name, value
in user_cntrl.items():
458 if name
not in checked_list:
459 checked_list.append(name)
460 cntrl_out[name] = value
461 cntrl_comm[name] =
"Set via user-provided mdin file" 464 for name, var
in cntrl_vars.items():
465 if name
not in checked_list
and get_priority(var.priority) == 3:
466 checked_list.append(name)
467 if calctype
in var.value:
468 cntrl_out[name] = var.value[calctype]
469 cntrl_comm[name] =
"FB set by default : %s" % var.comment
474 for iname, name,
in enumerate(names):
476 block_dicts[iname] = cntrl_out
479 with open(fout,
'w')
as f:
480 for line
in comments:
482 for name, block_dict, suffix
in zip(names, block_dicts, suffixes):
483 print(
"&%s" % name, file=f)
484 for key, val
in block_dict.items():
485 print(
"%-20s ! %s" % (
"%s=%s," % (key, val), cntrl_comm[key]), file=f)
488 print(
"%s" % line, file=f)
494 """Finite state machine for parsing Mol2 force field file. (just for parameterizing the charges)""" 496 def __init__(self,fnm):
498 super(Mol2_Reader,self).__init__(fnm)
514 if line.strip().lower() ==
'@<tripos>atom':
517 elif line.strip().lower() ==
'@<tripos>bond':
520 elif line.strip().lower() ==
'@<tripos>substructure':
523 elif line.strip().lower() ==
'@<tripos>molecule':
526 elif self.
section ==
'Molecule' and self.
mol is None:
527 self.
mol =
'_'.join(s)
535 self.adict.setdefault(self.
mol,[]).append(s[0])
538 if 'Atom' in self.
pdict[self.
itype]
and match(
' *[0-9]', line):
549 """Finite state machine for parsing FrcMod force field file.""" 553 super(FrcMod_Reader,self).
__init__(fnm)
555 self.
pdict = frcmod_pdict
561 self.
adict = {
None:
None}
563 def Split(self, line):
564 return split(
' +(?!-(?![0-9.]))', line.strip().replace(
'\n',
''))
567 return findall(
' +(?!-(?![0-9.]))', line.replace(
'\n',
''))
570 """ Returns the parameter type (e.g. K in BONDSK) based on the 571 current interaction type. 573 Both the 'pdict' dictionary (see gmxio.pdict) and the 574 interaction type 'state' (here, BONDS) are needed to get the 577 If, however, 'pdict' does not contain the ptype value, a suitable 578 substitute is simply the field number. 580 Note that if the interaction type state is not set, then it 581 defaults to the file name, so a generic parameter ID is 582 'filename.line_num.field_num' 587 if hasattr(self,
'overpfx'):
588 return self.overpfx +
':%i:' % pfld + self.oversfx
589 ptype = self.
pdict.get(self.
itype,{}).get(pfld,
':%i.%i' % (self.ln,pfld))
595 def feed(self, line):
599 if len(line.strip()) == 0:
601 if match(
'^dihe', line.strip().lower()):
604 elif match(
'^mass$', line.strip().lower()):
608 elif match(
'^bond$', line.strip().lower()):
612 elif match(
'^angle$', line.strip().lower()):
616 elif match(
'^improper$', line.strip().lower()):
620 elif match(
'^nonbon$', line.strip().lower()):
631 self.
itype =
'PDIHS%i' % int(np.abs(float(s[4])))
634 self.
itype =
'PDIHS%i' % int(np.abs(float(s[3])))
641 self.
atom = [s[i].replace(
" -",
"-")
for i
in self.
pdict[self.
itype][
'Atom']]
652 FORMAT_RE_PATTERN=re.compile(
"([0-9]+)([a-zA-Z]+)([0-9]+)\.?([0-9]*)")
656 NATOM, NTYPES, NBONH, MBONA, NTHETH, MTHETA, 657 NPHIH, MPHIA, NHPARM, NPARM, NEXT, NRES, 658 NBONA, NTHETA, NPHIA, NUMBND, NUMANG, NPTRA, 659 NATYP, NPHB, IFPERT, NBPER, NGPER, NDPER, 660 MBPER, MGPER, MDPER, IFBOX, NMXRS, IFCAP 664 POINTER_LABEL_LIST = POINTER_LABELS.replace(
',',
'').split()
667 """Parsed AMBER prmtop file. 669 ParmtopLoader reads, parses and manages content from a AMBER prmtop file. 673 Parse a prmtop file of alanine dipeptide in implicit solvent. 675 >>> import os, os.path 676 >>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-gbsa') 677 >>> prmtop_filename = os.path.join(directory, 'alanine-dipeptide.prmtop') 678 >>> prmtop = PrmtopLoader(prmtop_filename) 680 Parse a prmtop file of alanine dipeptide in explicit solvent. 682 >>> import os, os.path 683 >>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-explicit') 684 >>> prmtop_filename = os.path.join(directory, 'alanine-dipeptide.prmtop') 685 >>> prmtop = PrmtopLoader(prmtop_filename) 688 def __init__(self, inFilename):
690 Create a PrmtopLoader object from an AMBER prmtop file. 694 inFilename (string) - AMBER 'new-style' prmtop file, probably generated with one of the AMBER tleap/xleap/sleap 705 if line.startswith(
'%VERSION'):
707 elif line.startswith(
'%FLAG'):
708 tag, flag = line.rstrip().split(
None, 1)
711 elif line.startswith(
'%FORMAT'):
712 format = line.rstrip()
713 index0=format.index(
'(')
714 index1=format.index(
')')
715 format = format[index0+1:index1]
716 m = FORMAT_RE_PATTERN.search(format)
717 self.
_raw_format[self.
_flags[-1]] = (format, m.group(1), m.group(2), m.group(3), m.group(4))
719 and 'TITLE'==self.
_flags[-1] \
724 (format, numItems, itemType,
725 itemLength, itemPrecision) = self.
_getFormat(flag)
726 iLength=int(itemLength)
728 for index
in range(0, len(line), iLength):
729 item = line[index:index+iLength]
731 self.
_raw_data[flag].append(item.strip())
734 def _getFormat(self, flag=None):
739 def _getPointerValue(self, pointerLabel):
740 """Return pointer value given pointer label 743 - pointerLabel: a string matching one of the following: 745 NATOM : total number of atoms 746 NTYPES : total number of distinct atom types 747 NBONH : number of bonds containing hydrogen 748 MBONA : number of bonds not containing hydrogen 749 NTHETH : number of angles containing hydrogen 750 MTHETA : number of angles not containing hydrogen 751 NPHIH : number of dihedrals containing hydrogen 752 MPHIA : number of dihedrals not containing hydrogen 753 NHPARM : currently not used 754 NPARM : currently not used 755 NEXT : number of excluded atoms 756 NRES : number of residues 757 NBONA : MBONA + number of constraint bonds 758 NTHETA : MTHETA + number of constraint angles 759 NPHIA : MPHIA + number of constraint dihedrals 760 NUMBND : number of unique bond types 761 NUMANG : number of unique angle types 762 NPTRA : number of unique dihedral types 763 NATYP : number of atom types in parameter file, see SOLTY below 764 NPHB : number of distinct 10-12 hydrogen bond pair types 765 IFPERT : set to 1 if perturbation info is to be read in 766 NBPER : number of bonds to be perturbed 767 NGPER : number of angles to be perturbed 768 NDPER : number of dihedrals to be perturbed 769 MBPER : number of bonds with atoms completely in perturbed group 770 MGPER : number of angles with atoms completely in perturbed group 771 MDPER : number of dihedrals with atoms completely in perturbed groups 772 IFBOX : set to 1 if standard periodic box, 2 when truncated octahedral 773 NMXRS : number of atoms in the largest residue 774 IFCAP : set to 1 if the CAP option from edit was specified 776 index = POINTER_LABEL_LIST.index(pointerLabel)
777 return float(self.
_raw_data[
'POINTERS'][index])
780 """Return the number of atoms in the system""" 784 """Return the number of AMBER atoms types in the system""" 788 """Return True if the system was build with periodic boundary conditions (PBC)""" 792 """Return True if the system was build with the cap option)""" 796 """Return True if the system was build with the perturbation parameters)""" 800 """Return a list of atomic masses in the system""" 803 except AttributeError:
809 self.
_massList.append(float(raw_masses[ii]))
814 """Return a list of atomic charges in the system""" 817 except AttributeError:
823 self.
_chargeList.append(float(raw_charges[ii])/18.2223)
828 """Return the atom name for iAtom""" 830 return atomNames[iAtom]
833 """Return the list of the system atom names""" 836 def _getAtomTypeIndexes(self):
839 except AttributeError:
842 for atomTypeIndex
in self.
_raw_data[
'ATOM_TYPE_INDEX']:
847 """Return the AMBER atom type for iAtom""" 849 return atomTypes[iAtom]
852 """Return the list of the AMBER atom types""" 856 """Return iAtom's residue number""" 860 """Return residue label for iAtom OR iRes""" 861 if iRes==
None and iAtom==
None:
862 raise Exception(
"only specify iRes or iAtom, not both")
863 if iRes!=
None and iAtom!=
None:
864 raise Exception(
"iRes or iAtom must be set")
866 return self.
_raw_data[
'RESIDUE_LABEL'][iRes]
870 def _getResiduePointer(self, iAtom):
876 resPointers=self.
_raw_data[
'RESIDUE_POINTER']
877 firstAtom = [int(p)-1
for p
in resPointers]
881 while firstAtom[res+1] <= i:
887 """Return list of all rVdw, epsilon pairs for each atom. Work in the AMBER unit system.""" 890 except AttributeError:
893 lengthConversionFactor = 1.0
894 energyConversionFactor = 1.0
898 index=(numTypes+1)*(atomTypeIndexes[iAtom]-1)
899 nbIndex=int(self.
_raw_data[
'NONBONDED_PARM_INDEX'][index])-1
901 raise Exception(
"10-12 interactions are not supported")
902 acoef = float(self.
_raw_data[
'LENNARD_JONES_ACOEF'][nbIndex])
903 bcoef = float(self.
_raw_data[
'LENNARD_JONES_BCOEF'][nbIndex])
905 rMin = (2*acoef/bcoef)**(1/6.0)
906 epsilon = 0.25*bcoef*bcoef/acoef
907 except ZeroDivisionError:
910 rVdw = rMin/2.0*lengthConversionFactor
911 epsilon = epsilon*energyConversionFactor
915 def _getBonds(self, bondPointers):
916 forceConstant=self.
_raw_data[
"BOND_FORCE_CONSTANT"]
917 bondEquil=self.
_raw_data[
"BOND_EQUIL_VALUE"]
919 forceConstConversionFactor = 1.0
920 lengthConversionFactor = 1.0
921 for ii
in range(0,len(bondPointers),3):
922 if int(bondPointers[ii])<0
or \
923 int(bondPointers[ii+1])<0:
924 raise Exception(
"Found negative bonded atom pointers %s" 925 % ((bondPointers[ii],
926 bondPointers[ii+1]),))
927 iType=int(bondPointers[ii+2])-1
928 returnList.append((int(int(bondPointers[ii])/3),
929 int(int(bondPointers[ii+1])/3),
930 float(forceConstant[iType])*forceConstConversionFactor,
931 float(bondEquil[iType])*lengthConversionFactor))
935 """Return list of bonded atom pairs, K, and Rmin for each bond with a hydrogen""" 938 except AttributeError:
940 bondPointers=self.
_raw_data[
"BONDS_INC_HYDROGEN"]
946 """Return list of bonded atom pairs, K, and Rmin for each bond with no hydrogen""" 949 except AttributeError:
951 bondPointers=self.
_raw_data[
"BONDS_WITHOUT_HYDROGEN"]
956 """Return list of atom triplets, K, and ThetaMin for each bond angle""" 959 except AttributeError:
962 angleEquil=self.
_raw_data[
"ANGLE_EQUIL_VALUE"]
963 anglePointers = self.
_raw_data[
"ANGLES_INC_HYDROGEN"] \
964 +self.
_raw_data[
"ANGLES_WITHOUT_HYDROGEN"]
966 forceConstConversionFactor = 1.0
967 for ii
in range(0,len(anglePointers),4):
968 if int(anglePointers[ii])<0
or \
969 int(anglePointers[ii+1])<0
or \
970 int(anglePointers[ii+2])<0:
971 raise Exception(
"Found negative angle atom pointers %s" 972 % ((anglePointers[ii],
974 anglePointers[ii+2]),))
975 iType=int(anglePointers[ii+3])-1
976 self.
_angleList.append((int(int(anglePointers[ii])/3),
977 int(int(anglePointers[ii+1])/3),
978 int(int(anglePointers[ii+2])/3),
979 float(forceConstant[iType])*forceConstConversionFactor,
980 float(angleEquil[iType])))
984 """Return list of atom quads, K, phase and periodicity for each dihedral angle""" 987 except AttributeError:
989 forceConstant=self.
_raw_data[
"DIHEDRAL_FORCE_CONSTANT"]
991 periodicity=self.
_raw_data[
"DIHEDRAL_PERIODICITY"]
992 dihedralPointers = self.
_raw_data[
"DIHEDRALS_INC_HYDROGEN"] \
993 +self.
_raw_data[
"DIHEDRALS_WITHOUT_HYDROGEN"]
995 forceConstConversionFactor = 1.0
996 for ii
in range(0,len(dihedralPointers),5):
997 if int(dihedralPointers[ii])<0
or int(dihedralPointers[ii+1])<0:
998 raise Exception(
"Found negative dihedral atom pointers %s" 999 % ((dihedralPointers[ii],
1000 dihedralPointers[ii+1],
1001 dihedralPointers[ii+2],
1002 dihedralPointers[ii+3]),))
1003 iType=int(dihedralPointers[ii+4])-1
1004 self.
_dihedralList.append((int(int(dihedralPointers[ii])/3),
1005 int(int(dihedralPointers[ii+1])/3),
1006 int(abs(int(dihedralPointers[ii+2]))/3),
1007 int(abs(int(dihedralPointers[ii+3]))/3),
1008 float(forceConstant[iType])*forceConstConversionFactor,
1009 float(phase[iType]),
1010 int(0.5+float(periodicity[iType]))))
1014 """Return list of atom pairs, chargeProduct, rMin and epsilon for each 1-4 interaction""" 1015 dihedralPointers = self.
_raw_data[
"DIHEDRALS_INC_HYDROGEN"] \
1016 +self.
_raw_data[
"DIHEDRALS_WITHOUT_HYDROGEN"]
1020 for ii
in range(0,len(dihedralPointers),5):
1021 if int(dihedralPointers[ii+2])>0
and int(dihedralPointers[ii+3])>0:
1022 iAtom = int(int(dihedralPointers[ii])/3)
1023 lAtom = int(int(dihedralPointers[ii+3])/3)
1024 chargeProd = charges[iAtom]*charges[lAtom]
1025 (rVdwI, epsilonI) = nonbondTerms[iAtom]
1026 (rVdwL, epsilonL) = nonbondTerms[lAtom]
1027 rMin = (rVdwI+rVdwL)
1028 epsilon = math.sqrt(epsilonI*epsilonL)
1029 returnList.append((iAtom, lAtom, chargeProd, rMin, epsilon))
1033 """Return list of lists, giving all pairs of atoms that should have no non-bond interactions""" 1036 except AttributeError:
1039 numExcludedAtomsList=self.
_raw_data[
"NUMBER_EXCLUDED_ATOMS"]
1040 excludedAtomsList=self.
_raw_data[
"EXCLUDED_ATOMS_LIST"]
1044 n=int(numExcludedAtomsList[iAtom])
1048 for jAtom
in excludedAtomsList[index0:index1]:
1051 atomList.append(j-1)
1056 """Return list giving GB params, Radius and screening factor""" 1059 except AttributeError:
1066 for (i, symbl)
in enumerate(symbls):
1067 if symbl[0] == (
'c' or 'C'):
1068 screen[i] = 0.48435382330
1069 elif symbl[0] == (
'h' or 'H'):
1070 screen[i] = 1.09085413633
1071 elif symbl[0] == (
'n' or 'N'):
1072 screen[i] = 0.700147318409
1073 elif symbl[0] == (
'o' or 'O'):
1074 screen[i] = 1.06557401132
1075 elif symbl[0] == (
's' or 'S'):
1076 screen[i] = 0.602256336067
1079 lengthConversionFactor = 1.0
1080 for iAtom
in range(len(radii)):
1081 self.
_gb_List.append((float(radii[iAtom])*lengthConversionFactor, float(screen[iAtom])))
1085 """Return periodic boundary box beta angle and dimensions""" 1086 beta=float(self.
_raw_data[
"BOX_DIMENSIONS"][0])
1087 x=float(self.
_raw_data[
"BOX_DIMENSIONS"][1])
1089 z=float(self.
_raw_data[
"BOX_DIMENSIONS"][3])
1090 return (beta, x, y, z)
1092 class AMBER(Engine):
1094 """ Engine for carrying out general purpose AMBER calculations. """ 1096 def __init__(self, name="amber", **kwargs):
1098 self.valkwd = [
'amberhome',
'pdb',
'mol2',
'frcmod',
'leapcmd',
'mdin',
'reqpdb']
1099 super(AMBER,self).
__init__(name=name, **kwargs)
1101 def setopts(self, **kwargs):
1103 """ Called by __init__ ; Set AMBER-specific options. """ 1105 if 'amberhome' in kwargs:
1106 self.amberhome = kwargs[
'amberhome']
1107 if not os.path.exists(os.path.join(self.amberhome,
"bin",
"sander")):
1108 warn_press_key(
"The 'sander' executable indicated by %s doesn't exist! (Check amberhome)" \
1109 % os.path.join(self.amberhome,
"bin",
"sander"))
1111 warn_once(
"The 'amberhome' option was not specified; using default.")
1112 if which(
'sander') ==
'':
1113 warn_press_key(
"Please add AMBER executables to the PATH or specify amberhome.")
1114 self.amberhome = os.path.split(
which(
'sander'))[0]
1116 self.have_pmemd_cuda =
False 1117 if os.path.exists(os.path.join(self.amberhome,
"bin",
"pmemd.cuda")):
1118 self.callamber(
'pmemd.cuda -h', persist=
True)
1119 if _exec.returncode != 0:
1120 warn_press_key(
"pmemd.cuda gave a nonzero returncode; CUDA environment variables likely missing")
1122 logger.info(
"pmemd.cuda is available, using CUDA to accelerate calculations.\n")
1123 self.have_pmemd_cuda =
True 1125 with
wopen(
'.quit.leap')
as f:
1126 print(
'quit', file=f)
1131 if 'Adding' in line
and 'to search path' in line:
1132 self.
spath.append(line.split(
'Adding')[1].split()[0])
1133 os.remove(
'.quit.leap')
1137 """ Called by __init__ ; read files from the source directory. """ 1140 self.
mdin =
onefile(kwargs.get(
'mdin'),
'mdin', err=
False)
1142 if self.
mdin is not None:
1146 self.
mname =
'molecule' 1149 reqpdb = kwargs.get(
'reqpdb', 1)
1155 pdbfnm =
onefile(kwargs.get(
'pdb'),
'pdb' if reqpdb
else None, err=reqpdb)
1161 self.
mol = kwargs[
'mol']
1164 if 'coords' in kwargs:
1165 crdfile =
onefile(kwargs.get(
'coords'),
None, err=
True)
1166 elif pdbfnm
is not None:
1169 logger.error(
"Cannot find a coordinate file to use\n")
1171 self.
mol = Molecule(crdfile, top=pdbfnm, build_topology=
False)
1176 pdbfnm = self.name +
".pdb" 1178 self.
mol[0].write(pdbfnm, write_conect=
False)
1186 def callamber(self, command, stdin=None, print_to_screen=False, print_command=False, **kwargs):
1188 """ Call AMBER; prepend amberhome to calling the appropriate ambertools program. """ 1190 csplit = command.split()
1193 prog = os.path.join(self.
amberhome,
"bin", csplit[0])
1196 o = _exec(
' '.join(csplit), stdin=stdin, print_to_screen=print_to_screen, print_command=print_command, rbytes=1024, **kwargs)
1199 def prepare(self, pbc=False, **kwargs):
1201 """ Called by __init__ ; prepare the temp directory and figure out the topology. """ 1213 if hasattr(self,
'FF'):
1217 for fnm
in self.FF.amber_frcmod + self.FF.amber_mol2:
1218 if not os.path.exists(fnm):
1219 self.FF.make(np.zeros(self.FF.np))
1222 for mol2
in self.FF.amber_mol2:
1223 self.
mol2.append(mol2)
1224 for frcmod
in self.FF.amber_frcmod:
1225 self.
frcmod.append(frcmod)
1238 for mol2
in listfiles(kwargs.get(
'mol2'),
'mol2', err=
False):
1239 if mol2
not in self.
mol2:
1240 self.
mol2.append(mol2)
1243 for frcmod
in listfiles(kwargs.get(
'frcmod'),
'frcmod', err=
False):
1246 self.
absfrcmod.append(os.path.abspath(frcmod))
1249 self.
leap(read_prmtop=
True, count_mols=
True)
1252 if 'boxes' in self.
mol.Data.keys():
1253 logger.info(
"\x1b[91mWriting %s-all.crd file with no periodic box information\x1b[0m\n" % self.name)
1254 del self.
mol.Data[
'boxes']
1256 if hasattr(self,
'target')
and hasattr(self.target,
'loop_over_snapshots')
and self.target.loop_over_snapshots:
1257 if hasattr(self.target,
'qmatoms'):
1258 self.
qmatoms = self.target.qmatoms
1267 for f
in self.FF.fnms:
1270 def leap(self, read_prmtop=False, count_mols=False, name=None, delcheck=False):
1271 if not os.path.exists(self.
leapcmd):
1273 pdb = os.path.basename(self.
abspdb)
1274 if not os.path.exists(pdb):
1279 if not os.path.exists(os.path.split(mol2)[-1]):
1282 if not os.path.exists(os.path.split(frcmod)[-1]):
1283 LinkFile(frcmod, os.path.split(frcmod)[-1])
1284 if name
is None: name = self.name
1289 na = prmtop.getNumAtoms()
1291 self.
AtomLists[
'Charge'] = prmtop.getCharges()
1292 self.
AtomLists[
'Name'] = prmtop.getAtomNames()
1293 self.
AtomLists[
'Mass'] = prmtop.getMasses()
1294 self.
AtomLists[
'ResidueNumber'] = [prmtop.getResidueNumber(i)
for i
in range(na)]
1295 self.
AtomLists[
'ResidueName'] = [prmtop.getResidueLabel(i)
for i
in range(na)]
1299 if self.
pbc != prmtop.getIfBox():
1300 raise RuntimeError(
"Engine was created with pbc = %i but prmtop.getIfBox() = %i" % (self.
pbc, prmtop.getIfBox()))
1306 for b
in prmtop.getBondsNoH():
1307 G.add_edge(b[0], b[1])
1308 for b
in prmtop.getBondsWithH():
1309 G.add_edge(b[0], b[1])
1310 gs = [G.subgraph(c).copy()
for c
in nx.connected_components(G)]
1313 self.
AtomLists[
'MoleculeNumber'] = [
None for i
in range(na)]
1314 for ig, g
in enumerate(gs):
1316 self.
AtomLists[
'MoleculeNumber'][i] = ig
1319 self.
leap(read_prmtop=
True, count_mols=
False)
1320 return np.array(self.
AtomLists[
'Charge'])
1324 Utility function for computing energy and forces using AMBER. 1325 Coordinates (and boxes, if pbc) are obtained from the 1326 Molecule object stored internally 1330 snapshots : None or list 1331 If a list is provided, only compute energies / forces for snapshots listed. 1334 Result: Dictionary containing energies and forces. 1343 if traj_fnm
is None and hasattr(self,
'trajectory'):
1345 if traj_fnm
is not None:
1347 nc = netcdf_file(traj_fnm,
'r') 1350 print(
"Failed to load traj as netcdf, trying to load as Molecule object")
1351 mol = Molecule(traj_fnm)
1355 def get_coord_box(i):
1358 coords = mol.xyzs[i]
1360 box = [mol.boxes[i].a, mol.boxes[i].b, mol.boxes[i].c,
1361 mol.boxes[i].alpha, mol.boxes[i].beta, mol.boxes[i].gamma]
1363 coords = nc.variables[
'coordinates'].data[i].copy()
1365 cl = nc.variables[
'cell_lengths'].data[i].copy()
1366 ca = nc.variables[
'cell_angles'].data[i].copy()
1367 box = [cl[0], cl[1], cl[2], ca[0], ca[1], ca[2]]
1370 self.
leap(read_prmtop=
False, count_mols=
False, delcheck=
True)
1373 inp = sander.pme_input()
1375 inp = sander.gas_input()
1376 if 'ntc' in cntrl_vars: inp.ntc = int(cntrl_vars[
'ntc'])
1377 if 'ntf' in cntrl_vars: inp.ntf = int(cntrl_vars[
'ntf'])
1378 if 'cut' in cntrl_vars: inp.cut = float(cntrl_vars[
'cut'])
1379 coord, box = get_coord_box(0)
1380 sander.setup(
"%s.prmtop" % self.name, coord, box, inp)
1384 if snapshots ==
None:
1386 snapshots = range(len(self.
mol))
1388 snapshots = range(nc.variables[
'coordinates'].shape[0])
1396 coord, box = get_coord_box(i)
1398 sander.set_box(*box)
1399 sander.set_positions(coord)
1400 e, f = sander.energy_forces()
1401 Energies.append(e.tot * 4.184)
1402 frc = np.array(f).flatten() * 4.184 * 10
1407 Result = OrderedDict()
1408 Result[
"Energy"] = np.array(Energies)
1409 Result[
"Force"] = np.array(Forces)
1413 """ Computes the energy and force using AMBER for one snapshot. """ 1415 return np.hstack((Result[
"Energy"].reshape(-1,1), Result[
"Force"]))
1418 """ Computes the energy using AMBER over a trajectory. """ 1422 """ Computes the energy and force using AMBER over a trajectory. """ 1424 return np.hstack((Result[
"Energy"].reshape(-1,1), Result[
"Force"]))
1427 """ Use cpptraj to evaluate properties over a trajectory file. """ 1431 if traj_fnm
is None:
1432 if hasattr(self,
'trajectory'):
1435 raise RuntimeError(
"evaluate_cpptraj needs a trajectory file name")
1437 self.
leap(read_prmtop=
False, count_mols=
False, delcheck=
True)
1438 cpptraj_in=[
'parm %s.prmtop' % self.name]
1439 cpptraj_in.append(
"trajin %s" % traj_fnm)
1440 precision_lines = []
1443 for key
in [
'igb',
'ntb',
'cut',
'ntc',
'ntf']:
1444 if key
not in cntrl_vars:
1445 raise RuntimeError(
"Cannot use sander API because key %s not set" % key)
1446 cpptraj_in.append(
"esander POTENTIAL out esander.txt ntb %s igb %s cut %s ntc %s ntf %s" %
1447 (cntrl_vars[
'ntb'], cntrl_vars[
'igb'], cntrl_vars[
'cut'], cntrl_vars[
'ntc'], cntrl_vars[
'ntf']))
1448 precision_lines.append(
"precision esander.txt 18 8")
1449 cpptraj_in.append(
"vector DIPOLE dipole out dipoles.txt")
1450 precision_lines.append(
"precision dipoles.txt 18 8")
1452 cpptraj_in.append(
"volume VOLUME out volumes.txt")
1453 precision_lines.append(
"precision volumes.txt 18 8")
1454 cpptraj_in += precision_lines
1455 with open(
'%s-cpptraj.in' % self.name,
'w')
as f:
1456 print(
'\n'.join(cpptraj_in), file=f)
1457 self.
callamber(
"cpptraj -i %s-cpptraj.in" % self.name)
1459 Result = OrderedDict()
1461 esander_lines = list(open(
'esander.txt').readlines())
1463 for iw, w
in enumerate(esander_lines[0].split()):
1464 if w ==
"POTENTIAL[total]":
1467 raise RuntimeError(
"Cannot find field corresponding to total energies")
1468 potentials = np.array([float(line.split()[ie])
for line
in esander_lines[1:]])*4.184
1469 Result[
"Potentials"] = potentials
1471 dipoles = np.array([[float(w)
for w
in line.split()[1:4]]
for line
in list(open(
"dipoles.txt").readlines())[1:]]) / 0.20819434
1472 Result[
"Dips"] = dipoles
1477 conv = 1.6605387831627252
1479 volumes = np.array([float(line.split()[1])
for line
in list(open(
"volumes.txt").readlines())[1:]])/1000
1480 densities = conv * np.sum(self.
AtomLists[
'Mass']) / volumes
1481 Result[
"Volumes"] = volumes
1482 Result[
"Rhos"] = densities
1487 Evaluate the kinetic energy of each frame in a trajectory using cpptraj. 1488 This requires a netcdf-formatted trajectory containing velocities, which 1489 is generated using ntwv=-1 and ioutfm=1. 1494 if traj_fnm
is None:
1495 if hasattr(self,
'trajectory'):
1498 raise RuntimeError(
"evaluate_cpptraj needs a trajectory file name")
1500 self.
leap(read_prmtop=
False, count_mols=
False, delcheck=
True)
1501 cpptraj_in=[
'parm %s.prmtop' % self.name]
1502 cpptraj_in.append(
"trajin %s" % traj_fnm)
1503 cpptraj_in.append(
"temperature TEMPERATURE out temperature.txt")
1504 cpptraj_in.append(
"precision temperature.txt 18 8")
1505 with open(
'%s-cpptraj-temp.in' % self.name,
'w')
as f:
1506 print(
'\n'.join(cpptraj_in), file=f)
1507 self.
callamber(
"cpptraj -i %s-cpptraj-temp.in" % self.name)
1508 temps = np.array([float(line.split()[1])
for line
in list(open(
"temperature.txt").readlines())[1:]])
1510 kinetics = 4.184 * kb_kcal * dof * temps / 2.0
1511 print(
"Average temperature is %.2f, kinetic energy %.2f" % (np.mean(temps), np.mean(kinetics)))
1516 """ Computes the energy and dipole using AMBER over a trajectory. """ 1518 return np.hstack((Result[
"Potentials"].reshape(-1,1), Result[
"Dips"]))
1522 """ Calculate the interaction energy for two fragments. """ 1530 def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, nequil=0, nsave=1000, minimize=True, anisotropic=False, threads=1, verbose=False, **kwargs):
1533 Method for running a molecular dynamics simulation. 1536 nsteps = (int) Number of total time steps 1537 timestep = (float) Time step in FEMTOSECONDS 1538 temperature = (float) Temperature control (Kelvin) 1539 pressure = (float) Pressure control (atmospheres) 1540 nequil = (int) Number of additional time steps at the beginning for equilibration 1541 nsave = (int) Step interval for saving and printing data 1542 minimize = (bool) Perform an energy minimization prior to dynamics 1543 threads = (int) Specify how many OpenMP threads to use 1545 Returns simulation data: 1546 Rhos = (array) Density in kilogram m^-3 1547 Potentials = (array) Potential energies 1548 Kinetics = (array) Kinetic energies 1549 Volumes = (array) Box volumes 1550 Dips = (3xN array) Dipole moments 1551 EComps = (dict) Energy components 1555 raise RuntimeError(
"Anisotropic barostat not implemented in AMBER")
1557 raise RuntimeError(
"Multiple threads not implemented in AMBER - for fast runs, use pmemd.cuda")
1564 if verbose:
printcool(
"Minimizing the energy", color=0)
1566 self.
leap(read_prmtop=
False, count_mols=
False, delcheck=
True)
1567 self.
callamber(
"sander -i %s-min.mdin -o %s-min.mdout -p %s.prmtop -c %s.inpcrd -r %s-min.restrt -x %s-min.netcdf -inf %s-min.mdinfo -O" %
1568 (self.name, self.name, self.name, self.name, self.name, self.name, self.name), print_command=
True)
1569 nextrst =
"%s-min.restrt" % self.name
1572 self.
leap(read_prmtop=
False, count_mols=
False, delcheck=
True)
1573 nextrst =
"%s.inpcrd" % self.name
1577 write_mdin(
'eq',
'%s-eq.mdin' % self.name, nsteps=nequil, timestep=timestep/1000, nsave=nsave, pbc=self.
pbc,
1578 temperature=temperature, pressure=pressure, mdin_orig=self.
mdin)
1579 if verbose:
printcool(
"Running equilibration dynamics", color=0)
1580 self.
callamber(
"%s -i %s-eq.mdin -o %s-eq.mdout -p %s.prmtop -c %s -r %s-eq.restrt -x %s-eq.netcdf -inf %s-eq.mdinfo -O" %
1581 (md_command, self.name, self.name, self.name, nextrst, self.name, self.name, self.name), print_command=
True)
1582 nextrst =
"%s-eq.restrt" % self.name
1586 if verbose:
printcool(
"Running production dynamics", color=0)
1587 write_mdin(
'md',
'%s-md.mdin' % self.name, nsteps=nsteps, timestep=timestep/1000, nsave=nsave, pbc=self.
pbc,
1588 temperature=temperature, pressure=pressure, mdin_orig=self.
mdin)
1589 self.
callamber(
"%s -i %s-md.mdin -o %s-md.mdout -p %s.prmtop -c %s -r %s-md.restrt -x %s-md.netcdf -inf %s-md.mdinfo -O" %
1590 (md_command, self.name, self.name, self.name, nextrst, self.name, self.name, self.name), print_command=
True)
1591 nextrst =
"%s-md.restrt" % self.name
1596 ecomp = OrderedDict()
1597 ecomp[
"Potential Energy"] = prop_return[
"Potentials"].copy()
1598 ecomp[
"Kinetic Energy"] = prop_return[
"Kinetics"].copy()
1599 ecomp[
"Total Energy"] = prop_return[
"Potentials"] + prop_return[
"Kinetics"]
1600 prop_return[
"Ecomps"] = ecomp
1606 self.
leap(read_prmtop=
False, count_mols=
False, delcheck=
True)
1609 opt_temp =
""" Newton-Raphson minimization 1611 ntrun = 4, nsave=20, ndiag=2, 1613 drms = 0.000001, maxcyc=4000, bdwnhl=0.1, dfpred = 0.1, 1614 scnb=2.0, scee=1.2, idiel=1, 1617 with
wopen(
"%s-nr.in" % self.name)
as f: print(opt_temp.format(), file=f)
1618 self.
callamber(
"nmode -O -i %s-nr.in -c %s.inpcrd -p %s.prmtop -r %s.rst -o %s-nr.out" % (self.name, self.name, self.name, self.name, self.name))
1619 nmode_temp =
""" normal modes 1621 ntrun = 1, nsave=20, ndiag=2, 1623 drms = 0.0001, maxcyc=1, bdwnhl=1.1, dfpred = 0.1, 1624 scnb=2.0, scee=1.2, idiel=1, 1625 nvect={nvect}, eta=0.9, ivform=2, 1628 with
wopen(
"%s-nmode.in" % self.name)
as f: print(nmode_temp.format(nvect=3*self.
mol.na), file=f)
1629 self.
callamber(
"nmode -O -i %s-nmode.in -c %s.rst -p %s.prmtop -v %s-vecs.out -o %s-vibs.out" % (self.name, self.name, self.name, self.name, self.name))
1638 for line
in open(
"%s-vecs.out" % self.name).readlines():
1639 if line.strip() ==
"$FREQ":
1641 elif line.strip().startswith(
"$"):
1647 freqs += [float(i)
for i
in line.split()]
1649 modeA.append([float(i)
for i
in line.split()[0:3]])
1650 modeB.append([float(i)
for i
in line.split()[3:6]])
1651 modeC.append([float(i)
for i
in line.split()[6:9]])
1661 calc_eigvals = np.array(freqs)
1662 calc_eigvecs = np.array(vecs)
1664 calc_eigvecs = calc_eigvecs[np.argsort(np.abs(calc_eigvals))][6:]
1665 calc_eigvals = calc_eigvals[np.argsort(np.abs(calc_eigvals))][6:]
1667 calc_eigvecs = calc_eigvecs[np.argsort(calc_eigvals)]
1668 calc_eigvals = calc_eigvals[np.argsort(calc_eigvals)]
1669 os.system(
"rm -rf *.xyz_* *.[0-9][0-9][0-9]")
1670 return calc_eigvals, calc_eigvecs
1674 logger.error(
'Multipole moments are not yet implemented in AMBER interface')
1675 raise NotImplementedError
1677 """ Return the multipole moments of the 1st snapshot in Debye and Buckingham units. """ 1737 def optimize(self, shot=0, method="newton", crit=1e-4):
1739 """ Optimize the geometry and align the optimized geometry to the starting geometry. """ 1741 logger.error(
'Geometry optimizations are not yet implemented in AMBER interface')
1742 raise NotImplementedError
1782 """ Calculate energy of the selected structure (optionally minimize and return the minimized energy and RMSD). In kcal/mol. """ 1784 logger.error(
'Geometry optimization is not yet implemented in AMBER interface')
1785 raise NotImplementedError
1824 """Subclass of Target for force and energy matching 1827 def __init__(self,options,tgt_opts,forcefield):
1829 self.set_option(tgt_opts,
'coords',default=
"all.mdcrd")
1831 self.set_option(tgt_opts,
'pdb',default=
"conf.pdb")
1833 self.set_option(options,
'amberhome')
1835 self.set_option(tgt_opts,
'amber_leapcmd',
'leapcmd')
1837 self.engine_ = AMBER
1839 super(AbInitio_AMBER,self).
__init__(options,tgt_opts,forcefield)
1843 """Subclass of Target for calculating and matching ineraction energies 1846 def __init__(self,options,tgt_opts,forcefield):
1848 self.set_option(tgt_opts,
'coords')
1850 self.set_option(tgt_opts,
'pdb')
1852 self.set_option(options,
'amberhome')
1854 self.set_option(tgt_opts,
'amber_leapcmd',
'leapcmd')
1856 self.engine_ = AMBER
1858 super(Interaction_AMBER,self).
__init__(options,tgt_opts,forcefield)
1862 """Subclass of Target for calculating and matching vibrational modes using AMBER. """ 1864 def __init__(self,options,tgt_opts,forcefield):
1866 self.set_option(tgt_opts,
'coords')
1868 self.set_option(tgt_opts,
'pdb')
1870 self.set_option(options,
'amberhome')
1872 self.set_option(tgt_opts,
'amber_leapcmd',
'leapcmd')
1876 super(Vibration_AMBER,self).
__init__(options,tgt_opts,forcefield)
1880 """Subclass of Target for calculating and matching liquid properties using AMBER. """ 1882 def __init__(self,options,tgt_opts,forcefield):
1884 self.set_option(tgt_opts,
'liquid_coords',default=
'liquid.pdb',forceprint=
True)
1886 self.set_option(tgt_opts,
'gas_coords',default=
'gas.pdb',forceprint=
True)
1890 self.set_option(options,
'amberhome')
1892 self.gas_engine_args = {}
1896 self.extra_output = [
'liquid-md.restrt']
1900 self.engname =
"amber" 1904 self.nptfiles = [
'%s.leap' % os.path.splitext(f)[0]
for f
in [self.liquid_coords, self.gas_coords]]
1906 super(Liquid_AMBER,self).
__init__(options,tgt_opts,forcefield)
1907 for f
in [self.liquid_coords, self.gas_coords]:
1908 if os.path.exists(os.path.join(self.root, self.tgtdir,
'%s.mdin' % os.path.splitext(f)[0])):
1909 self.nptfiles.append(
'%s.mdin' % os.path.splitext(f)[0])
1910 if f == self.gas_coords:
1911 self.gas_engine_args[
'mdin'] = os.path.splitext(f)[0]
1912 for mol2
in listfiles(
None,
'mol2', err=
False, dnm=os.path.join(self.root, self.tgtdir)):
1913 self.nptfiles.append(mol2)
1914 for frcmod
in listfiles(
None,
'frcmod', err=
False, dnm=os.path.join(self.root, self.tgtdir)):
1915 self.nptfiles.append(frcmod)
1916 for i
in self.nptfiles:
1917 if not os.path.exists(os.path.join(self.root, self.tgtdir, i)):
1918 logger.error(
'Please provide %s; it is needed to proceed.\n' % i)
1921 if self.save_traj > 0:
1922 self.extra_output += [
'liquid-md.netcdf']
1924 self.post_init(options)
def getAtomTypes(self)
Return the list of the AMBER atom types.
def getIfPert(self)
Return True if the system was build with the perturbation parameters)
def __init__(self, inFilename)
Create a PrmtopLoader object from an AMBER prmtop file.
def __init__(self, name="amber", kwargs)
def readsrc(self, kwargs)
Called by init ; read files from the source directory.
Subclass of Target for calculating and matching ineraction energies using AMBER.
def write_leap(fnm, mol2=[], frcmod=[], pdb=None, prefix='amber', spath=[], delcheck=False)
Parse and edit an AMBER LEaP input file.
def __init__(self, options, tgt_opts, forcefield)
Vibrational mode fitting module.
def multipole_moments(self, shot=0, optimize=True, polarizability=False)
def interaction_energy(self, fraga, fragb)
Calculate the interaction energy for two fragments.
Engine for carrying out general purpose AMBER calculations.
def energy(self)
Computes the energy using AMBER over a trajectory.
Nifty functions, intended to be imported by any module within ForceBalance.
Ab-initio fitting module (energies, forces, resp).
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.
def getResidueLabel(self, iAtom=None, iRes=None)
Return residue label for iAtom OR iRes.
def energy_rmsd(self, shot=0, optimize=True)
Calculate energy of the selected structure (optionally minimize and return the minimized energy and R...
def getExcludedAtoms(self)
Return list of lists, giving all pairs of atoms that should have no non-bond interactions.
def _getResiduePointer(self, iAtom)
def normal_modes(self, shot=0, optimize=True)
def getNumAtoms(self)
Return the number of atoms in the system.
def kineticE_cpptraj(self, leap=False, traj_fnm=None)
Evaluate the kinetic energy of each frame in a trajectory using cpptraj.
def energy_force_one(self, shot)
Computes the energy and force using AMBER for one snapshot.
def getBoxBetaAndDimensions(self)
Return periodic boundary box beta angle and dimensions.
def LinkFile(src, dest, nosrcok=False)
def getAtomName(self, iAtom)
Return the atom name for iAtom.
def _getAtomTypeIndexes(self)
def evaluate_cpptraj(self, leap=True, traj_fnm=None, potential=False)
Use cpptraj to evaluate properties over a trajectory file.
atom
The atom numbers in the interaction (stored in the parser)
def isint(word)
ONLY matches integers! If you have a decimal point? None shall pass!
def build_pid(self, pfld)
Returns the parameter type (e.g.
def getDihedrals(self)
Return list of atom quads, K, phase and periodicity for each dihedral angle.
def getIfBox(self)
Return True if the system was build with periodic boundary conditions (PBC)
def energy_force(self)
Computes the energy and force using AMBER over a trajectory.
pdict
The parameter dictionary (defined in this file)
def write_mdin(calctype, fout=None, nsteps=None, timestep=None, nsave=None, pbc=False, temperature=None, pressure=None, mdin_orig=None)
Write an AMBER .mdin file to carry out a calculation using sander or pmemd.cuda.
def getResidueNumber(self, iAtom)
Return iAtom's residue number.
def evaluate_sander(self, leap=True, traj_fnm=None, snapshots=None)
Utility function for computing energy and forces using AMBER.
dihe
Whether we're inside the dihedral section.
Finite state machine for parsing Mol2 force field file.
def parse_amber_namelist(fin)
Parse a file containing an AMBER namelist (only significantly tested for sander input).
def getAtomNames(self)
Return the list of the system atom names.
Subclass of Target for calculating and matching vibrational modes using AMBER.
def leap(self, read_prmtop=False, count_mols=False, name=None, delcheck=False)
def getNumTypes(self)
Return the number of AMBER atoms types in the system.
def getBondsWithH(self)
Return list of bonded atom pairs, K, and Rmin for each bond with a hydrogen.
Parsed AMBER prmtop file.
def _getPointerValue(self, pointerLabel)
Return pointer value given pointer label.
def getBondsNoH(self)
Return list of bonded atom pairs, K, and Rmin for each bond with no hydrogen.
def warn_press_key(warning, timeout=10)
def __init__(self, options, tgt_opts, forcefield)
pdict
The parameter dictionary (defined in this file)
def getCharges(self)
Return a list of atomic charges in the system.
def prepare(self, pbc=False, kwargs)
Called by init ; prepare the temp directory and figure out the topology.
def printcool(text, sym="#", bold=False, color=2, ansi=None, bottom='-', minwidth=50, center=True, sym2="=")
Cool-looking printout for slick formatting of output.
atomnames
The mol2 file provides a list of atom names.
def callamber(self, command, stdin=None, print_to_screen=False, print_command=False, kwargs)
Call AMBER; prepend amberhome to calling the appropriate ambertools program.
Interaction energy fitting module.
def onefile(fnm=None, ext=None, err=False)
def listfiles(fnms=None, ext=None, err=False, dnm=None)
Finite state machine for parsing FrcMod force field file.
def warn_once(warning, warnhash=None)
Prints a warning but will only do so once in a given run.
def getGBParms(self, symbls=None)
Return list giving GB params, Radius and screening factor.
def getIfCap(self)
Return True if the system was build with the cap option)
def optimize(self, shot=0, method="newton", crit=1e-4)
Optimize the geometry and align the optimized geometry to the starting geometry.
section
The section that we're in.
adict
The frcmod file never has any atoms in it.
def get14Interactions(self)
Return list of atom pairs, chargeProduct, rMin and epsilon for each 1-4 interaction.
def isfloat(word)
Matches ANY number; it can be a decimal, scientific notation, integer, or what have you...
def splitComment(mystr, debug=False)
Remove the comment from a line in an AMBER namelist.
Subclass of Target for calculating and matching liquid properties using AMBER.
def wopen(dest, binary=False)
If trying to write to a symbolic link, remove it first.
def _getFormat(self, flag=None)
atom
The atom numbers in the interaction (stored in the parser)
def getNonbondTerms(self)
Return list of all rVdw, epsilon pairs for each atom.
Matching of liquid bulk properties.
Subclass of Target for force and energy matching using AMBER.
def _getBonds(self, bondPointers)
def energy_dipole(self)
Computes the energy and dipole using AMBER over a trajectory.
def getMasses(self)
Return a list of atomic masses in the system.
def getAtomType(self, iAtom)
Return the AMBER atom type for iAtom.
def getAngles(self)
Return list of atom triplets, K, and ThetaMin for each bond angle.