当前位置:   article > 正文

ACPYPE中FAILED: [Errno 2] No such file or directory: 'FFF_AC.prmtop'的解决方法_acpype failed: [errno 2] no such file or directory

acpype failed: [errno 2] no such file or directory: 'tmp

大家如果在github上面下载ACPYPE (https://github.com/t-/acpype),放入到LINUX上面安装后,百分百报错,出现的问题如下:

[root@pdynamo test]# ../acpype.py -i FFF.pdb
============================================================================
| ACPYPE: AnteChamber PYthon Parser interfacE v. 0 0 Rev: 0 (c) 2020 AWSdS |
============================================================================
==> ... charge set to 0
==> ... converting pdb input file to mol2 input file
==> * Babel OK *
==> Executing Antechamber...
==> * Antechamber OK *
++++++++++start_quote+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `which: no parmchk in (/usr/local/bin:/home/peter/Amber/amber18/bin:/home/peter/gmx2019.4/bin:/home/peter/fftw-3.3.8/bin:/home/peter/openmpi-3.1.3/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin/intel64:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/libfabric/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin/intel64:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/libfabric/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin/intel64:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/libfabric/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin:/home/peter/intel/debugger_2019/gdb/intel64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/home/peter/Amber/amber18/bin:/root/bin) -i FFF_bcc_gaff.mol2 -f mol2 -o FFF_AC.frcmod'
++++++++++end_quote+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ERROR: Parmchk failed
ERROR: Tleap failed
==> ... trying Sleap
==> Executing Sleap...
++++++++++start_quote+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

++++++++++end_quote+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++start_quote+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `which: no sleap in (/usr/local/bin:/home/peter/Amber/amber18/bin:/home/peter/gmx2019.4/bin:/home/peter/fftw-3.3.8/bin:/home/peter/openmpi-3.1.3/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin/intel64:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/libfabric/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin/intel64:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/libfabric/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin/intel64:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/libfabric/bin:/home/peter/intel/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin:/home/peter/intel/debugger_2019/gdb/intel64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/home/peter/Amber/amber18/bin:/root/bin) -f sleap.in'

++++++++++end_quote+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ERROR: Sleap failed
==> Removing temporary files...
ACPYPE FAILED: [Errno 2] No such file or directory: 'FFF_AC.prmtop'
Total time of execution: 3m 8s

其原因是这个源文件有毛病,请大家把底下这个复制,然后覆盖acpepy.py这个文件,直接就好用。

这个文件感谢计算化学领域国内最强的卢天大神提供:http://bbs.keinsci.com/thread-14021-1-1.html

  1. #!/usr/bin/env python
  2. from __future__ import print_function
  3. from datetime import datetime
  4. from shutil import copy2
  5. from shutil import rmtree
  6. import traceback
  7. import signal
  8. import time
  9. import optparse
  10. import math
  11. import os
  12. import pickle
  13. import sys
  14. import subprocess as sub
  15. import re
  16. """
  17. Requirements: Python 2.6 or higher or Python 3.x
  18. Antechamber (from AmberTools preferably)
  19. OpenBabel (optional, but strongly recommended)
  20. This code is released under GNU General Public License V3.
  21. <<< NO WARRANTY AT ALL!!! >>>
  22. It was inspired by:
  23. - amb2gmx.pl (Eric Sorin, David Mobley and John Chodera)
  24. and depends on Antechamber and Openbabel
  25. - YASARA Autosmiles:
  26. http://www.yasara.org/autosmiles.htm (Elmar Krieger)
  27. - topolbuild (Bruce Ray)
  28. - xplo2d (G.J. Kleywegt)
  29. For Antechamber, please cite:
  30. 1. Wang, J., Wang, W., Kollman P. A.; Case, D. A. "Automatic atom type and
  31. bond type perception in molecular mechanical calculations". Journal of
  32. Molecular Graphics and Modelling , 25, 2006, 247260.
  33. 2. Wang, J., Wolf, R. M.; Caldwell, J. W.; Kollman, P. A.; Case, D. A.
  34. "Development and testing of a general AMBER force field". Journal of
  35. Computational Chemistry, 25, 2004, 1157-1174.
  36. If you use this code, I am glad if you cite:
  37. SOUSA DA SILVA, A. W. & VRANKEN, W. F.
  38. ACPYPE - AnteChamber PYthon Parser interfacE.
  39. BMC Research Notes 2012, 5:367 doi:10.1186/1756-0500-5-367
  40. http://www.biomedcentral.com/1756-0500/5/367
  41. Alan Wilter Sousa da Silva, D.Sc.
  42. Bioinformatician, UniProt, EMBL-EBI
  43. Hinxton, Cambridge CB10 1SD, UK.
  44. >>http://www.ebi.ac.uk/~awilter<<
  45. alanwilter _at_ gmail _dot_ com
  46. """
  47. svnId = '$Id$'
  48. try:
  49. svnRev, svnDate, svnTime = svnId.split()[2:5]
  50. except:
  51. svnRev, svnDate, svnTime = '0', '0', '0'
  52. year = datetime.today().year
  53. tag = "%s %s Rev: %s" % (svnDate, svnTime, svnRev)
  54. lineHeader = \
  55. '''
  56. | ACPYPE: AnteChamber PYthon Parser interfacE v. %s (c) %s AWSdS |
  57. ''' % (tag, year)
  58. frameLine = (len(lineHeader) - 2) * '='
  59. header = '%s%s%s' % (frameLine, lineHeader, frameLine)
  60. # TODO:
  61. # Howto Charmm and Amber with NAMD
  62. # Howto build topology for a modified amino acid
  63. # CYANA topology files
  64. # List of Topology Formats created by acpype so far:
  65. outTopols = ['gmx', 'cns', 'charmm']
  66. qDict = {'mopac': 0, 'divcon': 1, 'sqm': 2}
  67. # Residues that are not solute, to be avoided when balancing charges in
  68. # amb2gmx mode
  69. ionOrSolResNameList = ['Cl-', 'Na+', 'K+', 'CIO', 'Cs+', 'IB', 'Li+', 'MG2',
  70. 'Rb+', 'WAT', 'MOH', 'NMA']
  71. # leapAmberFile = 'leaprc.ff99SB' # 'leaprc.ff10' and 'leaprc.ff99bsc0' has extra Atom Types not in parm99.dat
  72. leapAmberFile = 'leaprc.protein.ff14SB' # 'leaprc.ff14SB'
  73. # "qm_theory='AM1', grms_tol=0.0002, maxcyc=999, tight_p_conv=1, scfconv=1.d-10,"
  74. # "AM1 ANALYT MMOK GEO-OK PRECISE"
  75. cal = 4.184
  76. Pi = 3.141593
  77. qConv = 18.222281775 # 18.2223
  78. radPi = 57.295780 # 180/Pi
  79. maxDist = 3.0
  80. minDist = 0.5
  81. maxDist2 = maxDist ** 2 # squared Ang.
  82. minDist2 = minDist ** 2 # squared Ang.
  83. diffTol = 0.01
  84. dictAmbAtomType2AmbGmxCode = \
  85. {'BR': '1', 'C': '2', 'CA': '3', 'CB': '4', 'CC': '5', 'CK': '6', 'CM': '7', 'CN': '8', 'CQ': '9',
  86. 'CR': '10', 'CT': '11', 'CV': '12', 'CW': '13', 'C*': '14', 'Ca': '15', 'F': '16', 'H': '17',
  87. 'HC': '18', 'H1': '19', 'H2': '20', 'H3': '21', 'HA': '22', 'H4': '23', 'H5': '24', 'HO': '25',
  88. 'HS': '26', 'HW': '27', 'HP': '28', 'I': '29', 'Cl': '30', 'Na': '31', 'IB': '32', 'Mg': '33',
  89. 'N': '34', 'NA': '35', 'NB': '36', 'NC': '37', 'N2': '38', 'N3': '39', 'N*': '40', 'O': '41',
  90. 'OW': '42', 'OH': '43', 'OS': '44', 'O2': '45', 'P': '46', 'S': '47', 'SH': '48', 'CU': '49',
  91. 'FE': '50', 'K': '51', 'Rb': '52', 'Cs': '53', 'Li': '56', 'Zn': '57', 'Sr': '58', 'Ba': '59',
  92. 'MCH3A': 'MCH3A', 'MCH3B': 'MCH3B', 'MNH2': 'MNH2', 'MNH3': 'MNH3', 'MW': 'MW'}
  93. dictOplsAtomType2OplsGmxCode = \
  94. {'Ac3+': ['697'], 'Am3+': ['699'], 'Ar': ['Ar', '097'], 'Ba2+': ['414'],
  95. 'Br': ['722', '730'], 'Br-': ['402'],
  96. 'CT': ['064', '076', '122', '135', '136', '137', '138', '139', '148', '149', '152', '157', '158', '159', '161', '173', '174', '175', '181', '182', '183', '184', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', '217', '218', '219', '220', '223', '224', '225', '229', '230', '242', '243', '244', '256', '257', '258', '259', '273', '274', '275', '276', '291', '292', '293', '294', '297', '305', '306', '307', '308', '331', '371', '373', '375', '391', '396', '421', '431', '443', '448', '453', '455', '458', '461', '468', '476', '482', '484', '486', '490', '491', '492', '498', '499', '505', '515', '516', '645', '670', '671', '672', '673', '674', '675', '676', '677', '678', '679', '680', '681', '701', '725', '747', '748', '755', '756', '757', '758', '762', '764', '765', '766', '774', '775', '776', '782', '783', '903', '904', '905', '906', '907', '908', '912', '913', '914', '915', '942', '943', '944', '945', '951', '957', '959', '960', '961', '962', '963', '964'],
  97. 'CA': ['053', '145', '147', '166', '199', '221', '228', '260', '263', '266', '302', '312', '315', '317', '336', '351', '362', '380', '457', '460', '463', '472', '488', '521', '522', '523', '528', '532', '533', '538', '539', '551', '582', '590', '591', '592', '593', '604', '605', '606', '607', '608', '609', '610', '611', '612', '625', '644', '647', '648', '649', '650', '651', '652', '714', '716', '718', '720', '724', '727', '729', '731', '735', '736', '737', '738', '739', '742', '752', '768', '916', '917', '918'],
  98. 'C3': ['007', '010', '036', '039', '063', '065', '067', '068', '069', '070', '080', '088', '090', '092', '096', '106', '107', '109', '126', '132', '415', '418', '425', '429'],
  99. 'C': ['001', '017', '026', '058', '095', '131', '231', '234', '235', '247', '252', '267', '320', '322', '334', '366', '378', '470', '471', '772', '952'],
  100. 'C2': ['005', '009', '015', '016', '019', '022', '027', '028', '031', '034', '037', '056', '057', '061', '071', '081', '089', '091', '093', '110'],
  101. 'CT_2': ['223B', '224B', '225B', '246', '283', '284', '285', '292B', '293B', '295', '298', '299', '906B', '912B'],
  102. 'CM': ['141', '142', '143', '227', '323', '324', '337', '338', '381', '382', '517', '518', '708'],
  103. 'CW': ['508', '514', '543', '552', '561', '567', '575', '583', '588', '637'],
  104. 'CB': ['050', '349', '350', '364', '365', '501', '595', '623', '624'],
  105. 'CH': ['006', '008', '014', '025', '029', '030', '060', '073'],
  106. 'CZ': ['261', '423', '754', '925', '927', '928', '929', '931'],
  107. 'CO': ['189', '191', '193', '195', '197', '198'],
  108. 'C_2': ['232', '233', '277', '280', '465'],
  109. 'CR': ['506', '509', '558', '572', '634'],
  110. 'CQ': ['347', '531', '621', '642'],
  111. 'CV': ['507', '560', '574', '636'],
  112. 'CY': ['711', '712', '713', '733'],
  113. 'CS': ['544', '568', '589'],
  114. 'CK': ['353', '627'], 'CN': ['502', '594'], 'CP': ['043', '048'], 'CU': ['550', '581'],
  115. 'CT_3': ['245', '296'], 'C=': ['150', '178'], 'CD': ['011', '075'],
  116. 'C4': ['066'], 'C7': ['077'], 'C8': ['074'], 'C9': ['072'], 'CX': ['510'],
  117. 'C!': ['145B'], 'C*': ['500'], 'C+': ['700'], 'C_3': ['271'],
  118. 'CC': ['045'], 'CF': ['044'], 'CG': ['049'], 'CT_4': ['160'],
  119. 'Ca2+': ['412'],
  120. 'Cl': ['123', '151', '226', '264'],
  121. 'Cl-': ['401', '709'],
  122. 'Cs+': ['410'], 'Cu2+': ['Cu2+'], 'Eu3+': ['705'],
  123. 'F': ['164', '719', '721', '726', '728', '786', '956', '965'],
  124. 'F-': ['400'], 'Fe2+': ['Fe2+'], 'Gd3+': ['706'],
  125. 'HA': ['146', '316', '318', '389', '524', '525', '526', '529', '534', '535', '536', '540', '541', '546', '547', '554', '555', '556', '563', '564', '565', '569', '570', '576', '577', '578', '584', '585', '586', '597', '598', '599', '600', '601', '602', '613', '614', '615', '616', '617', '618', '619', '629', '630', '631', '638', '639', '640', '643', '653', '654', '655', '656', '715', '717', '740', '741', '746'],
  126. 'HC': ['140', '144', '153', '156', '165', '176', '185', '190', '192', '194', '196', '255', '279', '282', '329', '330', '332', '344', '372', '374', '376', '392', '416', '419', '422', '426', '430', '432', '444', '449', '454', '456', '459', '462', '469', '477', '483', '485', '487', '702', '710', '759', '763', '777', '778', '779', '784', '911', '926', '930', '950', '958'],
  127. 'H': ['004', '013', '041', '047', '128', '240', '241', '250', '254', '314', '325', '327', '339', '342', '343', '357', '358', '360', '367', '369', '383', '385', '387', '388', '428', '479', '481', '504', '513', '545', '553', '562', '596', '632', '744', '745', '909', '910'],
  128. 'H3': ['021', '052', '055', '104', '105', '289', '290', '301', '304', '310', '941', '955'],
  129. 'HO': ['024', '079', '155', '163', '168', '170', '172', '188', '270', '435'],
  130. 'HS': ['033', '086', '087', '204', '205'],
  131. 'HW': ['112', '114', '117', '119', '796'],
  132. 'H4': ['345', '390'], 'H5': ['355', '359'],
  133. 'He': ['130'], 'I': ['732'], 'I-': ['403'], 'K+': ['408'], 'Kr': ['098'],
  134. 'LP': ['433', '797'], 'La3+': ['703'], 'Li+': ['404', '406'],
  135. 'MCH3A': ['MCH3A'], 'MCH3B': ['MCH3B'], 'MNH2': ['MNH2'], 'MNH3': ['MNH3'],
  136. 'MW': ['MW', '115'], 'Mg2+': ['411'],
  137. 'NA': ['040', '046', '319', '321', '333', '354', '361', '377', '379', '503', '512', '542', '548', '557', '587', '628'],
  138. 'NC': ['311', '335', '346', '348', '363', '520', '527', '530', '537', '603', '620', '622', '641', '646'],
  139. 'N': ['003', '012', '094', '237', '238', '239', '249', '251', '265', '478', '480', '787'],
  140. 'N3': ['020', '101', '102', '103', '286', '287', '288', '309', '427', '940', '953'],
  141. 'N2': ['051', '054', '300', '303', '313', '341', '356', '368', '386', '743'],
  142. 'NB': ['042', '352', '511', '549', '559', '573', '580', '626', '635'],
  143. 'N*': ['319B', '333B', '354B', '377B'],
  144. 'NT': ['127', '900', '901', '902'],
  145. 'NZ': ['262', '424', '750', '753'],
  146. 'NO': ['760', '767'], 'NY': ['749', '751'],
  147. 'Na+': ['405', '407'], 'Nd3+': ['704'], 'Ne': ['129'],
  148. 'OS': ['062', '108', '179', '180', '186', '395', '442', '447', '452', '467', '473', '566', '571', '579', '773'],
  149. 'O': ['002', '059', '236', '248', '253', '326', '328', '340', '370', '384', '771', '788'],
  150. 'OH': ['023', '078', '154', '162', '167', '169', '171', '187', '268', '420', '434'],
  151. 'O2': ['018', '125', '272', '394', '441', '446', '451', '954'],
  152. 'OW': ['111', '113', '116', '118', '795'],
  153. 'O_2': ['278', '281', '466'],
  154. 'OY': ['475', '494', '497'],
  155. 'OL': ['120'], 'ON': ['761'], 'OU': ['437'], 'O_3': ['269'],
  156. 'P': ['393', '440', '445', '450', '785'],
  157. 'P+': ['781'], 'Rb+': ['409'],
  158. 'S': ['035', '038', '084', '085', '124', '202', '203', '222', '633'],
  159. 'SH': ['032', '082', '083', '200', '201', '417', '734'],
  160. 'SI': ['SI'], 'SY': ['474'], 'SY2': ['493'], 'SZ': ['496'], 'Sr2+': ['413'],
  161. 'Th4+': ['698'], 'U': ['436'], 'Xe': ['099'], 'Yb3+': ['707'], 'Zn2+': ['Zn2+']}
  162. # reverse dictOplsAtomType2OplsGmxCode
  163. oplsCode2AtomTypeDict = {}
  164. for k, v in list(dictOplsAtomType2OplsGmxCode.items()):
  165. for code in v:
  166. oplsCode2AtomTypeDict[code] = k
  167. # if code in oplsCode2AtomTypeDict.keys():
  168. # oplsCode2AtomTypeDict[code].append(k)
  169. # else:
  170. # oplsCode2AtomTypeDict[code] = [k]
  171. # Cross dictAmbAtomType2AmbGmxCode with dictOplsAtomType2OplsGmxCode & add H1,HP,H2
  172. dictAtomTypeAmb2OplsGmxCode = {'H1': ['140', '1.00800'], 'HP': ['140', '1.00800'], 'H2': ['140', '1.00800']}
  173. dictOplsMass = {'SY2': ['32.06000'], 'Zn2+': ['65.37000'], 'CQ': ['12.01100'], 'CP': ['12.01100'], 'Nd3+': ['144.24000'], 'Br-': ['79.90400'], 'Cu2+': ['63.54600'], 'Br': ['79.90400'], 'H': ['1.00800'], 'P': ['30.97376'], 'Sr2+': ['87.62000'], 'ON': ['15.99940'], 'OL': ['0.00000'], 'OH': ['15.99940'], 'OY': ['15.99940'], 'OW': ['15.99940'], 'OU': ['15.99940'], 'OS': ['15.99940'], 'Am3+': ['243.06000'], 'HS': ['1.00800'], 'HW': ['1.00800'], 'HO': ['1.00800'], 'HC': ['1.00800'], 'HA': ['1.00800'], 'O2': ['15.99940'], 'Ca2+': ['40.08000'], 'Th4+': ['232.04000'], 'He': ['4.00260'], 'C': ['12.01100'], 'Cs+': ['132.90540'], 'O': ['15.99940'], 'Gd3+': ['157.25000'], 'S': ['32.06000'], 'P+': ['30.97376'], 'La3+': ['138.91000'], 'H3': ['1.00800'], 'H4': ['1.00800'], 'MNH2': ['0.00000'], 'MW': ['0.00000'], 'NB': ['14.00670'], 'K+': ['39.09830'], 'Ne': ['20.17970'], 'Rb+': ['85.46780'], 'C+': ['12.01100'], 'C*': ['12.01100'], 'NO': ['14.00670'], 'CT_4': ['12.01100'], 'NA': ['14.00670'], 'C!': ['12.01100'], 'NC': ['14.00670'], 'NZ': ['14.00670'], 'CT_2': ['12.01100'], 'CT_3': ['12.01100'], 'NY': ['14.00670'], 'C9': ['14.02700'], 'C8': ['13.01900'], 'C=': ['12.01100'], 'Yb3+': ['173.04000'], 'C3': ['15.03500', '12.01100'], 'C2': ['14.02700'], 'C7': ['12.01100'], 'C4': ['16.04300'], 'CK': ['12.01100'], 'Cl-': ['35.45300'], 'N*': ['14.00670'], 'CH': ['13.01900'], 'CO': ['12.01100'], 'CN': ['12.01100'], 'CM': ['12.01100'], 'F': ['18.99840'], 'CC': ['12.01100'], 'CB': ['12.01100'], 'CA': ['12.01100'], 'CG': ['12.01100'], 'CF': ['12.01100'], 'N': ['14.00670'], 'CZ': ['12.01100'], 'CY': ['12.01100'], 'CX': ['12.01100'], 'Ac3+': ['227.03000'], 'CS': ['12.01100'], 'CR': ['12.01100'], 'N2': ['14.00670'], 'N3': ['14.00670'], 'CW': ['12.01100'], 'CV': ['12.01100'], 'CU': ['12.01100'], 'CT': ['12.01100'], 'SZ': ['32.06000'], 'SY': ['32.06000'], 'Cl': ['35.45300'], 'NT': ['14.00670'], 'O_2': ['15.99940'], 'Xe': ['131.29300'], 'SI': ['28.08000'], 'SH': ['32.06000'], 'Eu3+': ['151.96000'], 'F-': ['18.99840'], 'MNH3': ['0.00000'], 'H5': ['1.00800'], 'C_3': ['12.01100'], 'C_2': ['12.01100'], 'I-': ['126.90450'], 'LP': ['0.00000'], 'I': ['126.90450'], 'Na+': ['22.98977'], 'Li+': ['6.94100'], 'U': ['0.00000'], 'MCH3A': ['0.00000'], 'MCH3B': ['0.00000'], 'CD': ['13.01900', '12.01100'], 'O_3': ['15.99940'], 'Kr': ['83.79800'], 'Fe2+': ['55.84700'], 'Ar': ['39.94800'], 'Mg2+': ['24.30500'], 'Ba2+': ['137.33000']}
  174. for ambKey in dictAmbAtomType2AmbGmxCode:
  175. if ambKey in dictOplsAtomType2OplsGmxCode:
  176. dictAtomTypeAmb2OplsGmxCode[ambKey] = dictOplsAtomType2OplsGmxCode[ambKey] + list(dictOplsMass[ambKey])
  177. # learnt from 22 residues test.
  178. dictAtomTypeAmb2OplsGmxCode = {'HS': ['204', '1.008'], 'HP': ['140', '1.008'], 'HO': ['155', '168', '1.008'], 'HC': ['140', '1.008'], 'HA': ['146', '1.008'], 'O2': ['272', '15.9994'], 'C*': ['500', '12.011'], 'NA': ['503', '512', '14.0067'], 'NB': ['511', '14.0067'], 'CB': ['501', '12.011'], 'C': ['235', '271', '12.011'], 'CN': ['502', '12.011'], 'CM': ['302', '12.011'], 'CC': ['507', '508', '510', '12.011'], 'H': ['240', '241', '290', '301', '304', '310', '504', '513', '1.008'], 'CA': ['145', '166', '12.011'], 'O': ['236', '15.9994'], 'N': ['237', '238', '239', '14.0067'], 'S': ['202', '32.06'], 'CR': ['506', '509', '12.011'], 'N2': ['300', '303', '14.0067'], 'N3': ['287', '309', '14.0067'], 'CW': ['508', '510', '514', '12.011'], 'CV': ['507', '12.011'], 'CT': ['135', '136', '137', '149', '157', '158', '206', '209', '210', '223B', '224B', '245', '246', '274', '283', '284', '285', '292', '292B', '293B', '296', '307', '308', '505', '12.011'], 'OH': ['154', '167', '15.9994'], 'H1': ['140', '1.008'], 'H4': ['146', '1.008'], 'H5': ['146', '1.008'], 'SH': ['200', '32.06']}
  179. # learnt from 22 residues test.
  180. dictAtomTypeGaff2OplsGmxCode = {'cc': ['500', '506', '507', '508', '514', '12.011'], 'ca': ['145', '166', '501', '502', '12.011'], 'h1': ['140', '1.008'], 'h4': ['146', '1.008'], 'h5': ['146', '1.008'], 'cz': ['302', '12.011'], 'c2': ['509', '510', '12.011'], 'nh': ['300', '303', '14.0067'], 'ha': ['146', '1.008'], 'na': ['503', '512', '14.0067'], 'nc': ['511', '14.0067'], 'nd': ['511', '14.0067'], 'hx': ['140', '1.008'], 'hs': ['204', '1.008'], 'hn': ['240', '241', '290', '301', '304', '310', '504', '513', '1.008'], 'ho': ['155', '168', '1.008'], 'c3': ['135', '136', '137', '149', '157', '158', '206', '209', '210', '223B', '224B', '245', '246', '274', '283', '284', '285', '292', '292B', '293B', '296', '307', '308', '505', '12.011'], 'hc': ['140', '1.008'], 'cd': ['500', '506', '507', '508', '514', '12.011'], 'c': ['235', '271', '12.011'], 'oh': ['154', '167', '15.9994'], 'ss': ['202', '32.06'], 'o': ['236', '272', '15.9994'], 'n': ['237', '238', '239', '14.0067'], 'sh': ['200', '32.06'], 'n4': ['287', '309', '14.0067']}
  181. # draft
  182. atomTypeAmber2oplsDict = {'HS': ['HS'], 'HP': ['HC'], 'HO': ['HO'], 'HC': ['HC'],
  183. 'HA': ['HA'], 'O2': ['O2'], 'C*': ['C*'], 'NA': ['NA'],
  184. 'NB': ['NB'], 'CB': ['CB'], 'CN': ['CN'], 'CV': ['CV'],
  185. 'CM': ['CA'], 'CA': ['CA'], 'CR': ['CR'], 'OH': ['OH'],
  186. 'H1': ['HC'], 'H4': ['HA'], 'N2': ['N2'], 'N3': ['N3'],
  187. 'H5': ['HA'], 'SH': ['SH'], 'N': ['N'], 'S': ['S'], 'O': ['O'],
  188. 'C': ['C', 'C_3'], 'CW': ['CW', 'CX'], 'H': ['H', 'H3'],
  189. 'CC': ['CX', 'CW', 'CV'], 'CT': ['CT', 'CT_2', 'CT_3']}
  190. # draft
  191. a2oD = {'amber99_2': ['opls_235', 'opls_271'],
  192. 'amber99_3': ['opls_302', 'opls_145'],
  193. 'amber99_5': ['opls_507', 'opls_508', 'opls_510'],
  194. 'amber99_11': ['opls_209', 'opls_158', 'opls_283', 'opls_223B', 'opls_293B',
  195. 'opls_284', 'opls_292B', 'opls_274', 'opls_136', 'opls_135',
  196. 'opls_292', 'opls_157', 'opls_206', 'opls_137', 'opls_505',
  197. 'opls_224B', 'opls_307', 'opls_308', 'opls_210', 'opls_149'],
  198. 'amber99_13': ['opls_514'],
  199. 'amber99_14': ['opls_500'],
  200. 'amber99_17': ['opls_504', 'opls_241', 'opls_240', 'opls_290', 'opls_301',
  201. 'opls_310', 'opls_304', 'opls_513'],
  202. 'amber99_18': ['opls_140'],
  203. 'amber99_19': ['opls_140'],
  204. 'amber99_22': ['opls_146'],
  205. 'amber99_23': ['opls_146'],
  206. 'amber99_25': ['opls_155'],
  207. 'amber99_26': ['opls_204'],
  208. 'amber99_28': ['opls_140'],
  209. 'amber99_34': ['opls_238', 'opls_239', 'opls_237'],
  210. 'amber99_35': ['opls_512', 'opls_503'],
  211. 'amber99_36': ['opls_511'],
  212. 'amber99_38': ['opls_300', 'opls_303'],
  213. 'amber99_39': ['opls_309', 'opls_287'],
  214. 'amber99_41': ['opls_236'],
  215. 'amber99_43': ['opls_154'],
  216. 'amber99_45': ['opls_272'],
  217. 'amber99_47': ['opls_202'],
  218. 'amber99_48': ['opls_200'],
  219. }
  220. global pid
  221. pid = 0
  222. head = "%s created by acpype (Rev: " + svnRev + ") on %s\n"
  223. date = datetime.now().ctime()
  224. usage = \
  225. """
  226. acpype -i _file_ [-c _string_] [-n _int_] [-m _int_] [-a _string_] [-f] etc. or
  227. acpype -p _prmtop_ -x _inpcrd_ [-d]"""
  228. epilog = \
  229. """
  230. output: assuming 'root' is the basename of either the top input file,
  231. the 3-letter residue name or user defined (-b option)
  232. root_bcc_gaff.mol2: final mol2 file with 'bcc' charges and 'gaff' atom type
  233. root_AC.inpcrd : coord file for AMBER
  234. root_AC.prmtop : topology and parameter file for AMBER
  235. root_AC.lib : residue library file for AMBER
  236. root_AC.frcmod : modified force field parameters
  237. root_GMX.gro : coord file for GROMACS
  238. root_GMX.top : topology file for GROMACS
  239. root_GMX.itp : molecule unit topology and parameter file for GROMACS
  240. root_GMX_OPLS.itp : OPLS/AA mol unit topol & par file for GROMACS (experimental!)
  241. em.mdp, md.mdp : run parameters file for GROMACS
  242. root_NEW.pdb : final pdb file generated by ACPYPE
  243. root_CNS.top : topology file for CNS/XPLOR
  244. root_CNS.par : parameter file for CNS/XPLOR
  245. root_CNS.inp : run parameters file for CNS/XPLOR
  246. root_CHARMM.rtf : topology file for CHARMM
  247. root_CHARMM.prm : parameter file for CHARMM
  248. root_CHARMM.inp : run parameters file for CHARMM"""
  249. SLEAP_TEMPLATE = \
  250. """
  251. source %(leapAmberFile)s
  252. source %(leapGaffFile)s
  253. set default fastbld on
  254. #set default disulfide auto
  255. %(res)s = loadpdb %(baseOrg)s.pdb
  256. #check %(res)s
  257. saveamberparm %(res)s %(acBase)s.prmtop %(acBase)s.inpcrd
  258. saveoff %(res)s %(acBase)s.lib
  259. quit
  260. """
  261. TLEAP_TEMPLATE = \
  262. """
  263. verbosity 1
  264. source %(leapAmberFile)s
  265. source %(leapGaffFile)s
  266. mods = loadamberparams %(acBase)s.frcmod
  267. %(res)s = loadmol2 %(acMol2FileName)s
  268. check %(res)s
  269. saveamberparm %(res)s %(acBase)s.prmtop %(acBase)s.inpcrd
  270. saveoff %(res)s %(acBase)s.lib
  271. quit
  272. """
  273. def dotproduct(aa, bb):
  274. return sum((a * b) for a, b in zip(aa, bb))
  275. def crosproduct(a, b):
  276. c = [a[1] * b[2] - a[2] * b[1],
  277. a[2] * b[0] - a[0] * b[2],
  278. a[0] * b[1] - a[1] * b[0]]
  279. return c
  280. def length(v):
  281. return math.sqrt(dotproduct(v, v))
  282. def vec_sub(aa, bb):
  283. return [a - b for a, b in zip(aa, bb)]
  284. def imprDihAngle(a, b, c, d):
  285. ba = vec_sub(a, b)
  286. bc = vec_sub(c, b)
  287. cb = vec_sub(b, c)
  288. cd = vec_sub(d, c)
  289. n1 = crosproduct(ba, bc)
  290. n2 = crosproduct(cb, cd)
  291. angle = math.acos(dotproduct(n1, n2) / (length(n1) * length(n2))) * 180 / Pi
  292. cp = crosproduct(n1, n2)
  293. if (dotproduct(cp, bc) < 0):
  294. angle = -1 * angle
  295. return angle
  296. def invalidArgs(text=None):
  297. if text:
  298. print('ERROR: ' + text)
  299. sys.exit(1)
  300. # verNum = string.split(sys.version)[0]
  301. verNum = re.sub('[^0-9\.]', '', sys.version.split()[0])
  302. version = verNum.split('.') # string.split(verNum, ".")
  303. verList = list(map(int, version))
  304. if verList < [2, 6, 0]:
  305. invalidArgs(text="Python version %s\n Sorry, you need python 2.6 or higher" % verNum)
  306. try:
  307. set()
  308. except NameError:
  309. from sets import Set as set # @UnresolvedImport
  310. def elapsedTime(seconds, suffixes=['y', 'w', 'd', 'h', 'm', 's'], add_s=False, separator=' '):
  311. """
  312. Takes an amount of seconds and turns it into a human-readable amount of time.
  313. """
  314. # the formatted time string to be returned
  315. time = []
  316. # the pieces of time to iterate over (days, hours, minutes, etc)
  317. # - the first piece in each tuple is the suffix (d, h, w)
  318. # - the second piece is the length in seconds (a day is 60s * 60m * 24h)
  319. parts = [(suffixes[0], 60 * 60 * 24 * 7 * 52),
  320. (suffixes[1], 60 * 60 * 24 * 7),
  321. (suffixes[2], 60 * 60 * 24),
  322. (suffixes[3], 60 * 60),
  323. (suffixes[4], 60),
  324. (suffixes[5], 1)]
  325. # for each time piece, grab the value and remaining seconds, and add it to
  326. # the time string
  327. for suffix, length in parts:
  328. value = seconds // length
  329. if value > 0:
  330. seconds = seconds % length
  331. time.append('%s%s' % (str(value),
  332. (suffix, (suffix, suffix + 's')[value > 1])[add_s]))
  333. if seconds < 1:
  334. break
  335. return separator.join(time)
  336. def splitBlock(dat):
  337. '''split a amber parm dat file in blocks
  338. 0 = mass, 1 = extra + bond, 2 = angle, 3 = dihedral, 4 = improp, 5 = hbond
  339. 6 = equiv nbon, 7 = nbon, 8 = END, 9 = etc.
  340. '''
  341. dict_ = {}
  342. count = 0
  343. for line in dat:
  344. line = line.rstrip()
  345. if count in dict_:
  346. dict_[count].append(line)
  347. else:
  348. dict_[count] = [line]
  349. if not line:
  350. count += 1
  351. return dict_
  352. def getParCode(line):
  353. key = line.replace(' -', '-').replace('- ', '-').split()[0]
  354. return key
  355. def parseFrcmod(lista):
  356. heads = ['MASS', 'BOND', 'ANGL', 'DIHE', 'IMPR', 'HBON', 'NONB']
  357. dict_ = {}
  358. for line in lista[1:]:
  359. line = line.strip()
  360. if line[:4] in heads:
  361. head = line[:4]
  362. dict_[head] = []
  363. dd = {}
  364. continue
  365. elif line:
  366. key = line.replace(' -', '-').replace('- ', '-').split()[0]
  367. if key in dd:
  368. if not dd[key].count(line):
  369. dd[key].append(line)
  370. else:
  371. dd[key] = [line]
  372. dict_[head] = dd
  373. for k in dict_.keys():
  374. if not dict_[k]:
  375. dict_.pop(k)
  376. return dict_
  377. def parmMerge(fdat1, fdat2, frcmod=False):
  378. '''merge two amber parm dat/frcmod files and save in /tmp'''
  379. name1 = os.path.basename(fdat1).split('.dat')[0]
  380. if frcmod:
  381. name2 = os.path.basename(fdat2).split('.')[1]
  382. else:
  383. name2 = os.path.basename(fdat2).split('.dat')[0]
  384. mname = '/tmp/' + name1 + name2 + '.dat'
  385. mdatFile = open(mname, 'w')
  386. mdat = ['merged %s %s' % (name1, name2)]
  387. # if os.path.exists(mname): return mname
  388. dat1 = splitBlock(open(fdat1).readlines())
  389. if frcmod:
  390. dHeads = {'MASS': 0, 'BOND': 1, 'ANGL': 2, 'DIHE': 3, 'IMPR': 4, 'HBON': 5, 'NONB': 7}
  391. dat2 = parseFrcmod(open(fdat2).readlines()) # dict
  392. for k in dat2:
  393. for parEntry in dat2[k]:
  394. idFirst = None
  395. for line in dat1[dHeads[k]][:]:
  396. if line:
  397. key = line.replace(' -', '-').replace('- ', '-').split()[0]
  398. if key == parEntry:
  399. if not idFirst:
  400. idFirst = dat1[dHeads[k]].index(line)
  401. dat1[dHeads[k]].remove(line)
  402. rev = dat2[k][parEntry][:]
  403. rev.reverse()
  404. if idFirst is None:
  405. idFirst = 0
  406. for ll in rev:
  407. if dHeads[k] in [0, 1, 7]: # MASS has title in index 0 and so BOND, NONB
  408. dat1[dHeads[k]].insert(idFirst + 1, ll)
  409. else:
  410. dat1[dHeads[k]].insert(idFirst, ll)
  411. dat1[0][0] = mdat[0]
  412. for k in dat1:
  413. for line in dat1[k]:
  414. mdatFile.write(line + '\n')
  415. return mname
  416. dat2 = splitBlock(open(fdat2).readlines())
  417. for k in dat1.keys()[:8]:
  418. if k == 0:
  419. lines = dat1[k][1:-1] + dat2[k][1:-1] + ['']
  420. for line in lines:
  421. mdat.append(line)
  422. if k == 1:
  423. for i in dat1[k]:
  424. if '-' in i:
  425. id1 = dat1[k].index(i)
  426. break
  427. for j in dat2[k]:
  428. if '-' in j:
  429. id2 = dat2[k].index(j)
  430. break
  431. l1 = dat1[k][:id1]
  432. l2 = dat2[k][:id2]
  433. line = ''
  434. for item in l1 + l2:
  435. line += item.strip() + ' '
  436. mdat.append(line)
  437. lines = dat1[k][id1:-1] + dat2[k][id2:-1] + ['']
  438. for line in lines:
  439. mdat.append(line)
  440. if k in [2, 3, 4, 5, 6]: # angles, p dih, imp dih
  441. lines = dat1[k][:-1] + dat2[k][:-1] + ['']
  442. for line in lines:
  443. mdat.append(line)
  444. if k == 7:
  445. lines = dat1[k][:-1] + dat2[k][1:-1] + ['']
  446. for line in lines:
  447. mdat.append(line)
  448. for k in dat1.keys()[8:]:
  449. for line in dat1[k]:
  450. mdat.append(line)
  451. for k in dat2.keys()[9:]:
  452. for line in dat2[k]:
  453. mdat.append(line)
  454. for line in mdat:
  455. mdatFile.write(line + '\n')
  456. mdatFile.close()
  457. return mname
  458. def _getoutput(cmd):
  459. '''to simulate commands.getoutput in order to work with python 2.6 up to 3.x'''
  460. out = sub.Popen(cmd, shell=True, stderr=sub.STDOUT, stdout=sub.PIPE).communicate()[0][:-1]
  461. try:
  462. o = str(out.decode())
  463. except:
  464. o = str(out)
  465. return o
  466. class AbstractTopol(object):
  467. """
  468. Super class to build topologies
  469. """
  470. def __init__(self):
  471. if self.__class__ is AbstractTopol:
  472. raise TypeError("Attempt to create istance of abstract class AbstractTopol")
  473. def printDebug(self, text=''):
  474. if self.debug:
  475. print('DEBUG: %s' % text)
  476. def printWarn(self, text=''):
  477. if self.verbose:
  478. print('WARNING: %s' % text)
  479. def printError(self, text=''):
  480. if self.verbose:
  481. print('ERROR: %s' % text)
  482. def printMess(self, text=''):
  483. if self.verbose:
  484. print('==> %s' % text)
  485. def printQuoted(self, text=''):
  486. if self.verbose:
  487. print(10 * '+' + 'start_quote' + 59 * '+')
  488. print(text)
  489. print(10 * '+' + 'end_quote' + 61 * '+')
  490. def guessCharge(self):
  491. """
  492. Guess the charge of a system based on antechamber
  493. Returns None in case of error
  494. """
  495. done = False
  496. error = False
  497. charge = self.chargeVal
  498. localDir = os.path.abspath('.')
  499. if not os.path.exists(self.tmpDir):
  500. os.mkdir(self.tmpDir)
  501. if not os.path.exists(os.path.join(self.tmpDir, self.inputFile)):
  502. copy2(self.absInputFile, self.tmpDir)
  503. os.chdir(self.tmpDir)
  504. if self.chargeType == 'user':
  505. if self.ext == '.mol2':
  506. self.printMess("Reading user's charges from mol2 file...")
  507. charge = self.readMol2TotalCharge(self.inputFile)
  508. done = True
  509. else:
  510. self.printWarn("cannot read charges from a PDB file")
  511. self.printWarn("using now 'bcc' method for charge")
  512. if self.chargeVal is None and not done:
  513. self.printWarn("no charge value given, trying to guess one...")
  514. mol2FileForGuessCharge = self.inputFile
  515. if self.ext == ".pdb":
  516. cmd = '%s -ipdb %s -omol2 %s.mol2' % (self.babelExe, self.inputFile,
  517. self.baseName)
  518. self.printDebug("guessCharge: " + cmd)
  519. out = _getoutput(cmd)
  520. self.printDebug(out)
  521. mol2FileForGuessCharge = os.path.abspath(self.baseName + ".mol2")
  522. in_mol = 'mol2'
  523. else:
  524. in_mol = self.ext[1:]
  525. if in_mol == 'mol':
  526. in_mol = 'mdl'
  527. cmd = '%s -i %s -fi %s -o tmp -fo mol2 -c gas -pf y' % \
  528. (self.acExe, mol2FileForGuessCharge, in_mol)
  529. if self.debug:
  530. self.printMess("Debugging...")
  531. cmd = cmd.replace('-pf y', '-pf n')
  532. print(cmd)
  533. log = _getoutput(cmd).strip()
  534. if os.path.exists('tmp'):
  535. charge = self.readMol2TotalCharge('tmp')
  536. else:
  537. try:
  538. charge = float(log.strip().split('equal to the total charge (')[-1].split(') based on Gasteiger atom type, exit')[0])
  539. except:
  540. error = True
  541. if error:
  542. self.printError("guessCharge failed")
  543. os.chdir(localDir)
  544. self.printQuoted(log)
  545. self.printMess("Trying with net charge = 0 ...")
  546. # self.chargeVal = 0
  547. return None
  548. charge = float(charge)
  549. charge2 = int(round(charge))
  550. drift = abs(charge2 - charge)
  551. self.printDebug("Net charge drift '%3.6f'" % drift)
  552. if drift > diffTol:
  553. self.printError("Net charge drift '%3.5f' bigger than tolerance '%3.5f'" % (drift, diffTol))
  554. if not self.force:
  555. sys.exit(1)
  556. self.chargeVal = str(charge2)
  557. self.printMess("... charge set to %i" % charge2)
  558. os.chdir(localDir)
  559. def setResNameCheckCoords(self):
  560. """Set a 3 letter residue name
  561. and check coords duplication
  562. """
  563. exit_ = False
  564. localDir = os.path.abspath('.')
  565. if not os.path.exists(self.tmpDir):
  566. os.mkdir(self.tmpDir)
  567. # if not os.path.exists(os.path.join(tmpDir, self.inputFile)):
  568. copy2(self.absInputFile, self.tmpDir)
  569. os.chdir(self.tmpDir)
  570. exten = self.ext[1:]
  571. if self.ext == '.pdb':
  572. tmpFile = open(self.inputFile, 'r')
  573. else:
  574. if exten == 'mol':
  575. exten = 'mdl'
  576. cmd = '%s -i %s -fi %s -o tmp -fo ac -pf y' % \
  577. (self.acExe, self.inputFile, exten)
  578. self.printDebug(cmd)
  579. out = _getoutput(cmd)
  580. if not out.isspace():
  581. self.printDebug(out)
  582. try:
  583. tmpFile = open('tmp', 'r')
  584. except:
  585. rmtree(self.tmpDir)
  586. raise
  587. tmpData = tmpFile.readlines()
  588. residues = set()
  589. coords = {}
  590. for line in tmpData:
  591. if 'ATOM ' in line or 'HETATM' in line:
  592. residues.add(line[17:20])
  593. at = line[0:17]
  594. cs = line[30:54]
  595. if cs in coords:
  596. coords[cs].append(at)
  597. else:
  598. coords[cs] = [at]
  599. # self.printDebug(coords)
  600. if len(residues) > 1:
  601. self.printError("more than one residue detected '%s'" % str(residues))
  602. self.printError("verify your input file '%s'. Aborting ..." % self.inputFile)
  603. sys.exit(1)
  604. dups = ""
  605. shortd = ""
  606. longd = ""
  607. longSet = set()
  608. id_ = 0
  609. items = list(coords.items())
  610. l = len(items)
  611. for item in items:
  612. id_ += 1
  613. if len(item[1]) > 1: # if True means atoms with same coordinates
  614. for i in item[1]:
  615. dups += "%s %s\n" % (i, item[0])
  616. # for i in xrange(0,len(data),f):
  617. # fdata += (data[i:i+f])+' '
  618. for id2 in range(id_, l):
  619. item2 = items[id2]
  620. c1 = list(map(float, [item[0][i:i + 8] for i in range(0, 24, 8)]))
  621. c2 = list(map(float, [item2[0][i:i + 8] for i in range(0, 24, 8)]))
  622. dist2 = self.distance(c1, c2)
  623. if dist2 < minDist2:
  624. dist = math.sqrt(dist2)
  625. shortd += "%8.5f %s %s\n" % (dist, item[1], item2[1])
  626. if dist2 < maxDist2: # and not longOK:
  627. longSet.add(str(item[1]))
  628. longSet.add(str(item2[1]))
  629. if str(item[1]) not in longSet and l > 1:
  630. longd += "%s\n" % item[1]
  631. if dups:
  632. self.printError("Atoms with same coordinates in '%s'!" % self.inputFile)
  633. self.printQuoted(dups[:-1])
  634. exit_ = True
  635. if shortd:
  636. self.printError("Atoms TOO close (< %s Ang.)" % minDist)
  637. self.printQuoted("Dist (Ang.) Atoms\n" + shortd[:-1])
  638. exit_ = True
  639. if longd:
  640. self.printError("Atoms TOO alone (> %s Ang.)" % maxDist)
  641. self.printQuoted(longd[:-1])
  642. exit_ = True
  643. if exit_:
  644. if self.force:
  645. self.printWarn("You chose to proceed anyway with '-f' option. GOOD LUCK!")
  646. else:
  647. self.printError("Use '-f' option if you want to proceed anyway. Aborting ...")
  648. rmtree(self.tmpDir)
  649. sys.exit(1)
  650. resname = list(residues)[0].strip()
  651. newresname = resname
  652. # To avoid resname likes: 001 (all numbers), 1e2 (sci number), ADD : reserved terms for leap
  653. leapWords = ['_cmd_options_', '_types_', 'add', 'addAtomTypes', 'addIons',
  654. 'addIons2', 'addPath', 'addPdbAtomMap', 'addPdbResMap', 'alias',
  655. 'alignAxes', 'bond', 'bondByDistance', 'center', 'charge',
  656. 'check', 'clearPdbAtomMap', 'clearPdbResMap', 'clearVariables',
  657. 'combine', 'copy', 'createAtom', 'createParmset', 'createResidue',
  658. 'createUnit', 'crossLink', 'debugOff', 'debugOn', 'debugStatus',
  659. 'deleteBond', 'deleteOffLibEntry', 'deleteRestraint', 'desc',
  660. 'deSelect', 'displayPdbAtomMap', 'displayPdbResMap', 'edit',
  661. 'flip', 'groupSelectedAtoms', 'help', 'impose', 'list', 'listOff',
  662. 'loadAmberParams', 'loadAmberPrep', 'loadMol2', 'loadOff',
  663. 'loadPdb', 'loadPdbUsingSeq', 'logFile', 'matchVariables',
  664. 'measureGeom', 'quit', 'relax', 'remove', 'restrainAngle',
  665. 'restrainBond', 'restrainTorsion', 'saveAmberParm',
  666. 'saveAmberParmPert', 'saveAmberParmPol', 'saveAmberParmPolPert',
  667. 'saveAmberPrep', 'saveMol2', 'saveOff', 'saveOffParm', 'savePdb',
  668. 'scaleCharges', 'select', 'sequence', 'set', 'setBox', 'solvateBox',
  669. 'solvateCap', 'solvateDontClip', 'solvateOct', 'solvateShell',
  670. 'source', 'transform', 'translate', 'verbosity', 'zMatrix']
  671. isLeapWord = False
  672. for word in leapWords:
  673. if resname.upper().startswith(word.upper()):
  674. self.printDebug("Residue name is a reserved word: '%s'" % word.upper())
  675. isLeapWord = True
  676. try:
  677. float(resname)
  678. self.printDebug("Residue name is a 'number': '%s'" % resname)
  679. isNumber = True
  680. except ValueError:
  681. isNumber = False
  682. if resname[0].isdigit() or isNumber or isLeapWord:
  683. newresname = 'R' + resname
  684. if not resname.isalnum():
  685. newresname = 'MOL'
  686. if newresname != resname:
  687. self.printWarn("In %s.lib, residue name will be '%s' instead of '%s' elsewhere"
  688. % (self.acBaseName, newresname, resname))
  689. self.resName = newresname
  690. os.chdir(localDir)
  691. self.printDebug("setResNameCheckCoords done")
  692. def distance(self, c1, c2):
  693. # print c1, c2
  694. dist2 = (c1[0] - c2[0]) ** 2 + (c1[1] - c2[1]) ** 2 + (c1[0] - c2[0]) ** 2 + \
  695. (c1[2] - c2[2]) ** 2
  696. # dist2 = math.sqrt(dist2)
  697. return dist2
  698. def readMol2TotalCharge(self, mol2File):
  699. """Reads the charges in given mol2 file and returns the total
  700. """
  701. charge = 0.0
  702. ll = []
  703. cmd = '%s -i %s -fi mol2 -o tmp -fo mol2 -c wc -cf tmp.crg -pf y' % \
  704. (self.acExe, mol2File)
  705. if self.debug:
  706. self.printMess("Debugging...")
  707. cmd = cmd.replace('-pf y', '-pf n')
  708. self.printDebug(cmd)
  709. log = _getoutput(cmd)
  710. if os.path.exists('tmp.crg'):
  711. tmpFile = open('tmp.crg', 'r')
  712. tmpData = tmpFile.readlines()
  713. for line in tmpData:
  714. ll += line.split()
  715. charge = sum(map(float, ll))
  716. if not log.isspace() and self.debug:
  717. self.printQuoted(log)
  718. self.printDebug("readMol2TotalCharge: " + str(charge))
  719. return charge
  720. def execAntechamber(self, chargeType=None, atomType=None):
  721. """ AmaberTools 1.3
  722. To call Antechamber and execute it
  723. Usage: antechamber -i input file name
  724. -fi input file format
  725. -o output file name
  726. -fo output file format
  727. -c charge method
  728. -cf charge file name
  729. -nc net molecular charge (int)
  730. -a additional file name
  731. -fa additional file format
  732. -ao additional file operation
  733. crd only read in coordinate
  734. crg only read in charge
  735. name only read in atom name
  736. type only read in atom type
  737. bond only read in bond type
  738. -m multiplicity (2S+1), default is 1
  739. -rn residue name, overrides input file, default is MOL
  740. -rf residue toplogy file name in prep input file,
  741. default is molecule.res
  742. -ch check file name for gaussian, default is molecule
  743. -ek mopac or sqm keyword, inside quotes
  744. -gk gaussian keyword, inside quotes
  745. -df am1-bcc flag, 2 - use sqm(default); 0 - use mopac
  746. -at atom type, can be gaff (default), amber, bcc and sybyl
  747. -du fix duplicate atom names: yes(y)[default] or no(n)
  748. -j atom type and bond type prediction index, default is 4
  749. 0 no assignment
  750. 1 atom type
  751. 2 full bond types
  752. 3 part bond types
  753. 4 atom and full bond type
  754. 5 atom and part bond type
  755. -s status information: 0(brief), 1(default) or 2(verbose)
  756. -pf remove intermediate files: yes(y) or no(n)[default]
  757. -i -o -fi and -fo must appear; others are optional
  758. List of the File Formats
  759. file format type abbre. index | file format type abbre. index
  760. ---------------------------------------------------------------
  761. Antechamber ac 1 | Sybyl Mol2 mol2 2
  762. PDB pdb 3 | Modified PDB mpdb 4
  763. AMBER PREP (int) prepi 5 | AMBER PREP (car) prepc 6
  764. Gaussian Z-Matrix gzmat 7 | Gaussian Cartesian gcrt 8
  765. Mopac Internal mopint 9 | Mopac Cartesian mopcrt 10
  766. Gaussian Output gout 11 | Mopac Output mopout 12
  767. Alchemy alc 13 | CSD csd 14
  768. MDL mdl 15 | Hyper hin 16
  769. AMBER Restart rst 17 | Jaguar Cartesian jcrt 18
  770. Jaguar Z-Matrix jzmat 19 | Jaguar Output jout 20
  771. Divcon Input divcrt 21 | Divcon Output divout 22
  772. Charmm charmm 23 | SQM Output sqmout 24
  773. --------------------------------------------------------------
  774. AMBER restart file can only be read in as additional file.
  775. List of the Charge Methods
  776. charge method abbre. index | charge method abbre. index
  777. ----------------------------------------------------------------
  778. RESP resp 1 | AM1-BCC bcc 2
  779. CM1 cm1 3 | CM2 cm2 4
  780. ESP (Kollman) esp 5 | Mulliken mul 6
  781. Gasteiger gas 7 | Read in charge rc 8
  782. Write out charge wc 9 | Delete Charge dc 10
  783. ----------------------------------------------------------------
  784. a """
  785. global pid
  786. self.printMess("Executing Antechamber...")
  787. self.makeDir()
  788. ct = chargeType or self.chargeType
  789. at = atomType or self.atomType
  790. if 'amber2' in at:
  791. at = 'amber'
  792. if ct == 'user':
  793. ct = ''
  794. else:
  795. ct = '-c %s' % ct
  796. exten = self.ext[1:]
  797. if exten == 'mol':
  798. exten = 'mdl'
  799. cmd = '%s -i %s -fi %s -o %s -fo mol2 %s -nc %s -m %s -s 2 -df %i -at\
  800. %s -pf y %s' % (self.acExe, self.inputFile, exten, self.acMol2FileName,
  801. ct, self.chargeVal, self.multiplicity, self.qFlag, at,
  802. self.ekFlag)
  803. if self.debug:
  804. self.printMess("Debugging...")
  805. cmd = cmd.replace('-pf y', '-pf n')
  806. self.printDebug(cmd)
  807. if os.path.exists(self.acMol2FileName) and not self.force:
  808. self.printMess("AC output file present... doing nothing")
  809. else:
  810. try:
  811. os.remove(self.acMol2FileName)
  812. except:
  813. pass
  814. signal.signal(signal.SIGALRM, self.signal_handler)
  815. signal.alarm(self.timeTol)
  816. p = sub.Popen(cmd, shell=True, stderr=sub.STDOUT, stdout=sub.PIPE)
  817. pid = p.pid
  818. out = str(p.communicate()[0].decode()) # p.stdout.read()
  819. self.acLog = out
  820. if os.path.exists(self.acMol2FileName):
  821. self.printMess("* Antechamber OK *")
  822. else:
  823. self.printQuoted(self.acLog)
  824. return True
  825. def signal_handler(self, _signum, _frame): # , pid = 0):
  826. global pid
  827. pids = self.job_pids_family(pid)
  828. self.printDebug("PID: %s, PIDS: %s" % (pid, pids))
  829. self.printMess("Timed out! Process %s killed, max exec time (%ss) exceeded"
  830. % (pids, self.timeTol))
  831. # os.system('kill -15 %s' % pids)
  832. for i in pids.split():
  833. os.kill(int(i), 15)
  834. raise Exception("Semi-QM taking too long to finish... aborting!")
  835. def job_pids_family(self, jpid):
  836. '''INTERNAL: Return all job processes (PIDs)'''
  837. pid = repr(jpid)
  838. dict_pids = {}
  839. pids = [pid]
  840. cmd = "ps -A -o uid,pid,ppid|grep %i" % os.getuid()
  841. out = _getoutput(cmd).split('\n') # getoutput("ps -A -o uid,pid,ppid|grep %i" % os.getuid()).split('\n')
  842. for item in out:
  843. vec = item.split()
  844. dict_pids[vec[2]] = vec[1]
  845. while 1:
  846. try:
  847. pid = dict_pids[pid]
  848. pids.append(pid)
  849. except KeyError:
  850. break
  851. return ' '.join(pids)
  852. def delOutputFiles(self):
  853. delFiles = ['mopac.in', 'tleap.in', 'sleap.in', 'fixbo.log',
  854. 'addhs.log', 'ac_tmp_ot.mol2', 'frcmod.ac_tmp', 'fragment.mol2',
  855. self.tmpDir] # , 'divcon.pdb', 'mopac.pdb', 'mopac.out'] #'leap.log'
  856. self.printMess("Removing temporary files...")
  857. for file_ in delFiles:
  858. file_ = os.path.join(self.absHomeDir, file_)
  859. if os.path.exists(file_):
  860. if os.path.isdir(file_):
  861. rmtree(file_)
  862. else:
  863. os.remove(file_)
  864. def checkXyzAndTopFiles(self):
  865. fileXyz = self.acXyzFileName
  866. fileTop = self.acTopFileName
  867. if os.path.exists(fileXyz) and os.path.exists(fileTop):
  868. # self.acXyz = fileXyz
  869. # self.acTop = fileTop
  870. return True
  871. return False
  872. def execSleap(self):
  873. global pid
  874. self.makeDir()
  875. if self.ext == '.mol2':
  876. self.printWarn("Sleap doesn't work with mol2 files yet...")
  877. return True
  878. if self.chargeType != 'bcc':
  879. self.printWarn("Sleap works only with bcc charge method")
  880. return True
  881. if self.atomType != 'gaff':
  882. self.printWarn("Sleap works only with gaff atom type")
  883. return True
  884. sleapScpt = SLEAP_TEMPLATE % self.acParDict
  885. fp = open('sleap.in', 'w')
  886. fp.write(sleapScpt)
  887. fp.close()
  888. cmd = '%s -f sleap.in' % self.sleapExe
  889. if self.checkXyzAndTopFiles() and not self.force:
  890. self.printMess("Topologies files already present... doing nothing")
  891. else:
  892. try:
  893. os.remove(self.acTopFileName)
  894. os.remove(self.acXyzFileName)
  895. except:
  896. pass
  897. self.printMess("Executing Sleap...")
  898. self.printDebug(cmd)
  899. p = sub.Popen(cmd, shell=True, stderr=sub.STDOUT, stdout=sub.PIPE)
  900. pid = p.pid
  901. signal.signal(signal.SIGALRM, self.signal_handler)
  902. signal.alarm(self.timeTol)
  903. out = str(p.communicate()[0].decode()) # p.stdout.read()
  904. self.sleapLog = out
  905. self.checkLeapLog(self.sleapLog)
  906. if self.checkXyzAndTopFiles():
  907. self.printMess(" * Sleap OK *")
  908. else:
  909. self.printQuoted(self.sleapLog)
  910. return True
  911. def execTleap(self):
  912. fail = False
  913. self.makeDir()
  914. if self.ext == ".pdb":
  915. self.printMess('... converting pdb input file to mol2 input file')
  916. if self.convertPdbToMol2():
  917. self.printError("convertPdbToMol2 failed")
  918. # print self.chargeVal
  919. if self.execAntechamber():
  920. self.printError("Antechamber failed")
  921. fail = True
  922. # sys.exit(1)
  923. if self.execParmchk():
  924. self.printError("Parmchk failed")
  925. fail = True
  926. # sys.exit(1)
  927. if fail:
  928. return True
  929. tleapScpt = TLEAP_TEMPLATE % self.acParDict
  930. fp = open('tleap.in', 'w')
  931. fp.write(tleapScpt)
  932. fp.close()
  933. cmd = '%s -f tleap.in' % self.tleapExe
  934. if self.checkXyzAndTopFiles() and not self.force:
  935. self.printMess("Topologies files already present... doing nothing")
  936. else:
  937. try:
  938. os.remove(self.acTopFileName)
  939. os.remove(self.acXyzFileName)
  940. except:
  941. pass
  942. self.printMess("Executing Tleap...")
  943. self.printDebug(cmd)
  944. self.tleapLog = _getoutput(cmd)
  945. self.checkLeapLog(self.tleapLog)
  946. if self.checkXyzAndTopFiles():
  947. self.printMess("* Tleap OK *")
  948. else:
  949. self.printQuoted(self.tleapLog)
  950. return True
  951. def checkLeapLog(self, log):
  952. log = log.splitlines(True)
  953. check = ''
  954. block = False
  955. for line in log:
  956. # print "*"+line+"*"
  957. if "Checking '" in line:
  958. # check += line
  959. block = True
  960. if "Checking Unit." in line:
  961. block = False
  962. if block:
  963. check += line
  964. self.printQuoted(check[:-1])
  965. def locateDat(self, aFile):
  966. '''locate a file pertinent to $AMBERHOME/dat/leap/parm/'''
  967. amberhome = os.environ.get('AMBERHOME')
  968. if amberhome:
  969. aFileF = os.path.join(amberhome, 'dat/leap/parm', aFile)
  970. if os.path.exists(aFileF):
  971. return aFileF
  972. aFileF = os.path.join(os.path.dirname(self.acExe), '../dat/leap/parm', aFile)
  973. if os.path.exists(aFileF):
  974. return aFileF
  975. return None
  976. def execParmchk(self):
  977. self.makeDir()
  978. cmd = '%s -i %s -f mol2 -o %s' % (self.parmchkExe, self.acMol2FileName,
  979. self.acFrcmodFileName)
  980. if 'amber' in self.atomType:
  981. gaffFile = self.locateDat(self.gaffDatfile)
  982. parmfile = self.locateDat('parm10.dat')
  983. frcmodffxxSB = self.locateDat('frcmod.ff14SB')
  984. # frcmodparmbsc0 = self.locateDat('frcmod.parmbsc0')
  985. parmGaffFile = parmMerge(parmfile, gaffFile)
  986. parmGaffffxxSBFile = parmMerge(parmGaffFile, frcmodffxxSB, frcmod=True)
  987. # parm99gaffff99SBparmbsc0File = parmMerge(parm99gaffff99SBFile, frcmodparmbsc0, frcmod = True)
  988. # parm10file = self.locateDat('parm10.dat') # PARM99 + frcmod.ff99SB + frcmod.parmbsc0 in AmberTools 1.4
  989. cmd += ' -p %s' % parmGaffffxxSBFile # Ignoring BSC0
  990. elif 'gaff2' in self.atomType:
  991. cmd += ' -s 2'
  992. self.parmchkLog = _getoutput(cmd)
  993. self.printDebug(cmd)
  994. if os.path.exists(self.acFrcmodFileName):
  995. check = self.checkFrcmod()
  996. if check:
  997. self.printWarn("Couldn't determine all parameters:")
  998. self.printMess("From file '%s'\n" % self.acFrcmodFileName + check)
  999. else:
  1000. self.printMess("* Parmchk OK *")
  1001. else:
  1002. self.printQuoted(self.parmchkLog)
  1003. return True
  1004. def checkFrcmod(self):
  1005. check = ""
  1006. frcmodContent = open(self.acFrcmodFileName, 'r').readlines()
  1007. for line in frcmodContent:
  1008. if "ATTN, need revision" in line:
  1009. check += line
  1010. return check
  1011. def convertPdbToMol2(self):
  1012. if self.ext == '.pdb':
  1013. if self.execBabel():
  1014. self.printError("convert pdb to mol2 via babel failed")
  1015. return True
  1016. def execBabel(self):
  1017. self.makeDir()
  1018. cmd = '%s -ipdb %s -omol2 %s.mol2' % (self.babelExe, self.inputFile,
  1019. self.baseName)
  1020. self.printDebug(cmd)
  1021. self.babelLog = _getoutput(cmd)
  1022. self.ext = '.mol2'
  1023. self.inputFile = self.baseName + self.ext
  1024. self.acParDict['ext'] = 'mol2'
  1025. if os.path.exists(self.inputFile):
  1026. self.printMess("* Babel OK *")
  1027. else:
  1028. self.printQuoted(self.babelLog)
  1029. return True
  1030. def makeDir(self):
  1031. os.chdir(self.rootDir)
  1032. self.absHomeDir = os.path.abspath(self.homeDir)
  1033. if not os.path.exists(self.homeDir):
  1034. os.mkdir(self.homeDir)
  1035. os.chdir(self.homeDir)
  1036. copy2(self.absInputFile, '.')
  1037. return True
  1038. def createACTopol(self):
  1039. """
  1040. If successful, Amber Top and Xyz files will be generated
  1041. """
  1042. # sleap = False
  1043. if self.engine == 'sleap':
  1044. if self.execSleap():
  1045. self.printError("Sleap failed")
  1046. self.printMess("... trying Tleap")
  1047. if self.execTleap():
  1048. self.printError("Tleap failed")
  1049. if self.engine == 'tleap':
  1050. if self.execTleap():
  1051. self.printError("Tleap failed")
  1052. if self.extOld == '.pdb':
  1053. self.printMess("... trying Sleap")
  1054. self.ext = self.extOld
  1055. self.inputFile = self.baseName + self.ext
  1056. if self.execSleap():
  1057. self.printError("Sleap failed")
  1058. if not self.debug:
  1059. self.delOutputFiles()
  1060. def createMolTopol(self):
  1061. """
  1062. Create molTop obj
  1063. """
  1064. self.topFileData = open(self.acTopFileName, 'r').readlines()
  1065. self.molTopol = MolTopol(self, verbose=self.verbose, debug=self.debug,
  1066. gmx4=self.gmx4, disam=self.disam, direct=self.direct,
  1067. is_sorted=self.sorted, chiral=self.chiral)
  1068. if self.outTopols:
  1069. if 'cns' in self.outTopols:
  1070. self.molTopol.writeCnsTopolFiles()
  1071. if 'gmx' in self.outTopols:
  1072. self.molTopol.writeGromacsTopolFiles()
  1073. if 'charmm' in self.outTopols:
  1074. self.writeCharmmTopolFiles()
  1075. self.pickleSave()
  1076. def pickleSave(self):
  1077. """
  1078. To restore:
  1079. from acpype import *
  1080. #import cPickle as pickle
  1081. import pickle
  1082. o = pickle.load(open('DDD.pkl','rb'))
  1083. NB: It fails to restore with ipython in Mac (Linux OK)
  1084. """
  1085. pklFile = self.baseName + ".pkl"
  1086. dumpFlag = False
  1087. if not os.path.exists(pklFile):
  1088. mess = "Writing pickle file %s" % pklFile
  1089. dumpFlag = True
  1090. elif self.force:
  1091. mess = "Overwriting pickle file %s" % pklFile
  1092. dumpFlag = True
  1093. else:
  1094. mess = "Pickle file %s already present... doing nothing" % pklFile
  1095. self.printMess(mess)
  1096. if dumpFlag:
  1097. with open(pklFile, "wb") as f: # for python 2.6 or higher
  1098. # f = open(pklFile, "wb")
  1099. if verList[0] == 3:
  1100. pickle.dump(self, f, protocol=2, fix_imports=True)
  1101. else:
  1102. pickle.dump(self, f, protocol=2)
  1103. def getFlagData(self, flag):
  1104. """
  1105. For a given acFileTop flag, return a list of the data related
  1106. """
  1107. block = False
  1108. tFlag = '%FLAG ' + flag
  1109. data = ''
  1110. if len(self.topFileData) == 0:
  1111. raise Exception("PRMTOP file empty?")
  1112. for rawLine in self.topFileData:
  1113. if '%COMMENT' in rawLine:
  1114. continue
  1115. line = rawLine.replace('\r', '').replace('\n', '')
  1116. if tFlag in line:
  1117. block = True
  1118. continue
  1119. if block and '%FLAG ' in line:
  1120. break
  1121. if block:
  1122. if '%FORMAT' in line:
  1123. line = line.strip().strip('%FORMAT()').split('.')[0]
  1124. for c in line:
  1125. if c.isalpha():
  1126. f = int(line.split(c)[1])
  1127. break
  1128. continue
  1129. data += line
  1130. # data need format
  1131. sdata = [data[i:i + f].strip() for i in range(0, len(data), f)]
  1132. if '+' and '.' in data and flag != 'RESIDUE_LABEL': # it's a float
  1133. ndata = list(map(float, sdata))
  1134. elif flag != 'RESIDUE_LABEL':
  1135. try: # try if it's integer
  1136. ndata = list(map(int, sdata))
  1137. except: # it's string
  1138. ndata = sdata
  1139. else:
  1140. ndata = sdata
  1141. if flag == 'AMBER_ATOM_TYPE':
  1142. nn = []
  1143. ll = set()
  1144. prefixed = False
  1145. for ii in ndata:
  1146. prefixed = True
  1147. if ii[0].isdigit():
  1148. ll.add(ii)
  1149. ii = 'A' + ii
  1150. nn.append(ii)
  1151. if prefixed and ll:
  1152. self.printDebug("GMX does not like atomtype starting with Digit")
  1153. self.printDebug("prefixing AtomType %s with 'A'." % list(ll))
  1154. ndata = nn
  1155. return ndata # a list
  1156. def getResidueLabel(self):
  1157. """
  1158. Get a 3 capital letters code from acFileTop
  1159. Returns a list.
  1160. """
  1161. residueLabel = self.getFlagData('RESIDUE_LABEL')
  1162. residueLabel = list(map(str, residueLabel))
  1163. if residueLabel[0] != residueLabel[0].upper():
  1164. self.printWarn("residue label '%s' in '%s' is not all UPPERCASE" %
  1165. (residueLabel[0], self.inputFile))
  1166. self.printWarn("this may raise problem with some applications like CNS")
  1167. self.residueLabel = residueLabel
  1168. def getCoords(self):
  1169. """
  1170. For a given acFileXyz file, return a list of coords as:
  1171. [[x1,y1,z1],[x2,y2,z2], etc.]
  1172. """
  1173. if len(self.xyzFileData) == 0:
  1174. raise Exception("INPCRD file empty?")
  1175. data = ''
  1176. for rawLine in self.xyzFileData[2:]:
  1177. line = rawLine.replace('\r', '').replace('\n', '')
  1178. data += line
  1179. l = len(data)
  1180. ndata = list(map(float, [data[i:i + 12] for i in range(0, l, 12)]))
  1181. gdata = []
  1182. for i in range(0, len(ndata), 3):
  1183. gdata.append([ndata[i], ndata[i + 1], ndata[i + 2]])
  1184. self.printDebug("getCoords done")
  1185. return gdata
  1186. def getAtoms(self):
  1187. """
  1188. Set a list with all atoms objects build from dat in acFileTop
  1189. Set also if molTopol atom type system is gaff or amber
  1190. Set also list atomTypes
  1191. Set also resid
  1192. Set also molTopol total charge
  1193. """
  1194. atomNameList = self.getFlagData('ATOM_NAME')
  1195. atomTypeNameList = self.getFlagData('AMBER_ATOM_TYPE')
  1196. self._atomTypeNameList = atomTypeNameList
  1197. massList = self.getFlagData('MASS')
  1198. chargeList = self.getFlagData('CHARGE')
  1199. # totalCharge = sum(chargeList)
  1200. # self.printDebug('charge to be balanced: total %13.10f' % (totalCharge/qConv))
  1201. resIds = self.getFlagData('RESIDUE_POINTER') + [0]
  1202. # to guess the resId of the last residue before ion or water
  1203. # for resTemp in self.residueLabel:
  1204. # if resTemp in ionOrWaterResNameList:
  1205. # lastSoluteResId = self.residueLabel.index(resTemp) - 1
  1206. # break
  1207. # print lastSoluteResId, self.residueLabel[lastSoluteResId]
  1208. # uniqAtomTypeId = self.getFlagData('ATOM_TYPE_INDEX') # for LJ
  1209. # balanceChargeList = self.balanceCharges(chargeList)
  1210. coords = self.getCoords()
  1211. ACOEFs, BCOEFs = self.getABCOEFs()
  1212. atoms = []
  1213. atomTypes = []
  1214. tmpList = [] # a list with unique atom types
  1215. totalCharge = 0.0
  1216. countRes = 0
  1217. id_ = 0
  1218. FirstNonSoluteId = None
  1219. for atomName in atomNameList:
  1220. if atomName != atomName.upper():
  1221. self.printDebug("atom name '%s' HAS to be all UPPERCASE... Applying this here." %
  1222. atomName)
  1223. atomName = atomName.upper()
  1224. atomTypeName = atomTypeNameList[id_]
  1225. if id_ + 1 == resIds[countRes]:
  1226. resid = countRes # self.residueLabel[countRes]
  1227. countRes += 1
  1228. resName = self.residueLabel[resid]
  1229. if resName in ionOrSolResNameList and not FirstNonSoluteId:
  1230. FirstNonSoluteId = id_
  1231. # print id_, resid, resName
  1232. mass = massList[id_]
  1233. # charge = balanceChargeList[id_]
  1234. charge = chargeList[id_]
  1235. chargeConverted = charge / qConv
  1236. totalCharge += charge
  1237. coord = coords[id_]
  1238. ACOEF = ACOEFs[id_]
  1239. BCOEF = BCOEFs[id_]
  1240. atomType = AtomType(atomTypeName, mass, ACOEF, BCOEF)
  1241. if atomTypeName not in tmpList:
  1242. tmpList.append(atomTypeName)
  1243. atomTypes.append(atomType)
  1244. atom = Atom(atomName, atomType, id_ + 1, resid, mass, chargeConverted, coord)
  1245. atoms.append(atom)
  1246. id_ += 1
  1247. balanceChargeList, balanceValue, balanceIds = self.balanceCharges(chargeList, FirstNonSoluteId)
  1248. for id_ in balanceIds:
  1249. atoms[id_].charge = balanceValue / qConv
  1250. # self.printDebug("atom ids and balanced charges: %s, %3f10" % (balanceIds, balanceValue/qConv))
  1251. if atomTypeName[0].islower():
  1252. self.atomTypeSystem = 'gaff'
  1253. else:
  1254. self.atomTypeSystem = 'amber'
  1255. self.printDebug('Balanced TotalCharge %13.10f' % float(sum(balanceChargeList) / qConv))
  1256. self.totalCharge = int(totalCharge)
  1257. self.atoms = atoms
  1258. self.atomTypes = atomTypes
  1259. self.pbc = None
  1260. if len(coords) == len(atoms) + 2 or len(coords) == len(atoms) * 2 + 2:
  1261. self.pbc = [coords[-2], coords[-1]]
  1262. self.printDebug("PBC = %s" % self.pbc)
  1263. self.printDebug("getAtoms done")
  1264. def getBonds(self):
  1265. uniqKbList = self.getFlagData('BOND_FORCE_CONSTANT')
  1266. uniqReqList = self.getFlagData('BOND_EQUIL_VALUE')
  1267. bondCodeHList = self.getFlagData('BONDS_INC_HYDROGEN')
  1268. bondCodeNonHList = self.getFlagData('BONDS_WITHOUT_HYDROGEN')
  1269. bondCodeList = bondCodeHList + bondCodeNonHList
  1270. bonds = []
  1271. for i in range(0, len(bondCodeList), 3):
  1272. idAtom1 = bondCodeList[i] // 3 # remember python starts with id 0
  1273. idAtom2 = bondCodeList[i + 1] // 3
  1274. bondTypeId = bondCodeList[i + 2] - 1
  1275. atom1 = self.atoms[idAtom1]
  1276. atom2 = self.atoms[idAtom2]
  1277. kb = uniqKbList[bondTypeId]
  1278. req = uniqReqList[bondTypeId]
  1279. atoms = [atom1, atom2]
  1280. bond = Bond(atoms, kb, req)
  1281. bonds.append(bond)
  1282. self.bonds = bonds
  1283. self.printDebug("getBonds done")
  1284. def getAngles(self):
  1285. uniqKtList = self.getFlagData('ANGLE_FORCE_CONSTANT')
  1286. uniqTeqList = self.getFlagData('ANGLE_EQUIL_VALUE')
  1287. # for list below, true atom number = index/3 + 1
  1288. angleCodeHList = self.getFlagData('ANGLES_INC_HYDROGEN')
  1289. angleCodeNonHList = self.getFlagData('ANGLES_WITHOUT_HYDROGEN')
  1290. angleCodeList = angleCodeHList + angleCodeNonHList
  1291. angles = []
  1292. for i in range(0, len(angleCodeList), 4):
  1293. idAtom1 = angleCodeList[i] // 3 # remember python starts with id 0
  1294. idAtom2 = angleCodeList[i + 1] // 3
  1295. idAtom3 = angleCodeList[i + 2] // 3
  1296. angleTypeId = angleCodeList[i + 3] - 1
  1297. atom1 = self.atoms[idAtom1]
  1298. atom2 = self.atoms[idAtom2]
  1299. atom3 = self.atoms[idAtom3]
  1300. kt = uniqKtList[angleTypeId]
  1301. teq = uniqTeqList[angleTypeId] # angle given in rad in prmtop
  1302. atoms = [atom1, atom2, atom3]
  1303. angle = Angle(atoms, kt, teq)
  1304. angles.append(angle)
  1305. self.angles = angles
  1306. self.printDebug("getAngles done")
  1307. def getDihedrals(self):
  1308. """
  1309. Get dihedrals (proper and imp), condensed list of prop dih and
  1310. atomPairs
  1311. """
  1312. uniqKpList = self.getFlagData('DIHEDRAL_FORCE_CONSTANT')
  1313. uniqPeriodList = self.getFlagData('DIHEDRAL_PERIODICITY')
  1314. uniqPhaseList = self.getFlagData('DIHEDRAL_PHASE')
  1315. # for list below, true atom number = abs(index)/3 + 1
  1316. dihCodeHList = self.getFlagData('DIHEDRALS_INC_HYDROGEN')
  1317. dihCodeNonHList = self.getFlagData('DIHEDRALS_WITHOUT_HYDROGEN')
  1318. dihCodeList = dihCodeHList + dihCodeNonHList
  1319. properDih = []
  1320. improperDih = []
  1321. condProperDih = [] # list of dihedrals condensed by the same quartet
  1322. # atomPairs = []
  1323. atomPairs = set()
  1324. for i in range(0, len(dihCodeList), 5):
  1325. idAtom1 = dihCodeList[i] // 3 # remember python starts with id 0
  1326. idAtom2 = dihCodeList[i + 1] // 3
  1327. # 3 and 4 indexes can be negative: if id3 < 0, end group interations
  1328. # in amber are to be ignored; if id4 < 0, dihedral is improper
  1329. idAtom3raw = dihCodeList[i + 2] // 3 # can be negative -> exclude from 1-4vdw
  1330. idAtom4raw = dihCodeList[i + 3] // 3 # can be negative -> Improper
  1331. idAtom3 = abs(idAtom3raw)
  1332. idAtom4 = abs(idAtom4raw)
  1333. dihTypeId = dihCodeList[i + 4] - 1
  1334. atom1 = self.atoms[idAtom1]
  1335. atom2 = self.atoms[idAtom2]
  1336. atom3 = self.atoms[idAtom3]
  1337. atom4 = self.atoms[idAtom4]
  1338. kPhi = uniqKpList[dihTypeId] # already divided by IDIVF
  1339. period = int(uniqPeriodList[dihTypeId]) # integer
  1340. phase = uniqPhaseList[dihTypeId] # angle given in rad in prmtop
  1341. if phase == kPhi == 0:
  1342. period = 0 # period is set to 0
  1343. atoms = [atom1, atom2, atom3, atom4]
  1344. dihedral = Dihedral(atoms, kPhi, period, phase)
  1345. if idAtom4raw > 0:
  1346. try:
  1347. atomsPrev = properDih[-1].atoms
  1348. except:
  1349. atomsPrev = []
  1350. properDih.append(dihedral)
  1351. if idAtom3raw < 0 and atomsPrev == atoms:
  1352. condProperDih[-1].append(dihedral)
  1353. else:
  1354. condProperDih.append([dihedral])
  1355. pair = (atom1, atom4)
  1356. # if atomPairs.count(pair) == 0 and idAtom3raw > 0:
  1357. if idAtom3raw > 0:
  1358. atomPairs.add(pair)
  1359. else:
  1360. improperDih.append(dihedral)
  1361. try:
  1362. atomPairs = sorted(atomPairs)
  1363. except:
  1364. pass
  1365. self.properDihedrals = properDih
  1366. self.improperDihedrals = improperDih
  1367. self.condensedProperDihedrals = condProperDih # [[],[],...]
  1368. self.atomPairs = atomPairs # set((atom1, atom2), ...)
  1369. self.printDebug("getDihedrals done")
  1370. def getChirals(self):
  1371. """
  1372. Get chiral atoms, its 4 neighbours and improper dihedral angle
  1373. """
  1374. self.chiralGroups = []
  1375. if self.obchiralExe:
  1376. # print (self.obchiralExe, os.getcwd())
  1377. cmd = '%s %s' % (self.obchiralExe, self.inputFile)
  1378. # print(cmd)
  1379. out = map(int, re.findall('Atom (\d+) Is', _getoutput(cmd)))
  1380. # print("*%s*" % out)
  1381. chiralGroups = []
  1382. for id_ in out:
  1383. atChi = self.atoms[id_ - 1]
  1384. quad = []
  1385. for bb in self.bonds:
  1386. bAts = bb.atoms[:]
  1387. if atChi in bAts:
  1388. bAts.remove(atChi)
  1389. quad.append(bAts[0])
  1390. if len(quad) != 4:
  1391. if self.chiral:
  1392. self.printWarn("Atom %s has less than 4 connections to 4 different atoms. It's NOT Chiral!" % atChi)
  1393. continue
  1394. v1, v2, v3, v4 = [x.coords for x in quad]
  1395. chiralGroups.append((atChi, quad, imprDihAngle(v1, v2, v3, v4)))
  1396. self.chiralGroups = chiralGroups
  1397. def sortAtomsForGromacs(self):
  1398. """
  1399. Re-sort atoms for gromacs, which expects all hydrogens to immediately
  1400. follow the heavy atom they are bonded to and belong to the same charge
  1401. group.
  1402. Currently, atom mass < 1.2 is taken to denote a proton. This behavior
  1403. may be changed by modifying the 'is_hydrogen' function within.
  1404. JDC 2011-02-03
  1405. """
  1406. # Build dictionary of bonded atoms.
  1407. bonded_atoms = dict()
  1408. for atom in self.atoms:
  1409. bonded_atoms[atom] = list()
  1410. for bond in self.bonds:
  1411. [atom1, atom2] = bond.atoms
  1412. bonded_atoms[atom1].append(atom2)
  1413. bonded_atoms[atom2].append(atom1)
  1414. # Define hydrogen and heavy atom classes.
  1415. def is_hydrogen(atom):
  1416. return (atom.mass < 1.2)
  1417. def is_heavy(atom):
  1418. return not is_hydrogen(atom)
  1419. # Build list of sorted atoms, assigning charge groups by heavy atom.
  1420. sorted_atoms = list()
  1421. cgnr = 1 # charge group number: each heavy atoms is assigned its own charge group
  1422. # First pass: add heavy atoms, followed by the hydrogens bonded to them.
  1423. for atom in self.atoms:
  1424. if is_heavy(atom):
  1425. # Append heavy atom.
  1426. atom.cgnr = cgnr
  1427. sorted_atoms.append(atom)
  1428. # Append all hydrogens.
  1429. for bonded_atom in bonded_atoms[atom]:
  1430. if is_hydrogen(bonded_atom) and not (bonded_atom in sorted_atoms):
  1431. # Append bonded hydrogen.
  1432. bonded_atom.cgnr = cgnr
  1433. sorted_atoms.append(bonded_atom)
  1434. cgnr += 1
  1435. # Second pass: Add any remaining atoms.
  1436. if len(sorted_atoms) < len(self.atoms):
  1437. for atom in self.atoms:
  1438. if not (atom in sorted_atoms):
  1439. atom.cgnr = cgnr
  1440. sorted_atoms.append(atom)
  1441. cgnr += 1
  1442. # Replace current list of atoms with sorted list.
  1443. self.atoms = sorted_atoms
  1444. # Renumber atoms in sorted list, starting from 1.
  1445. for (index, atom) in enumerate(self.atoms):
  1446. atom.id = index + 1
  1447. return
  1448. def setAtomPairs(self):
  1449. """
  1450. Set a list of pair of atoms pertinent to interaction 1-4 for vdw.
  1451. WRONG: Deprecated
  1452. """
  1453. atomPairs = []
  1454. for item in self.condensedProperDihedrals:
  1455. dih = item[0]
  1456. atom1 = dih.atoms[0]
  1457. atom2 = dih.atoms[3]
  1458. pair = [atom1, atom2]
  1459. if atomPairs.count(pair) == 0:
  1460. atomPairs.append(pair)
  1461. self.atomPairs = atomPairs # [[atom1, atom2], ...]
  1462. self.printDebug("atomPairs done")
  1463. def getExcludedAtoms(self):
  1464. """
  1465. Returns a list of atoms with a list of its excluded atoms up to 3rd
  1466. neighbour.
  1467. It's implicitly indexed, i.e., a sequence of atoms in position n in
  1468. the excludedAtomsList corresponds to atom n (self.atoms) and so on.
  1469. NOT USED
  1470. """
  1471. excludedAtomsIdList = self.getFlagData('EXCLUDED_ATOMS_LIST')
  1472. numberExcludedAtoms = self.getFlagData('NUMBER_EXCLUDED_ATOMS')
  1473. atoms = self.atoms
  1474. interval = 0
  1475. excludedAtomsList = []
  1476. for number in numberExcludedAtoms:
  1477. temp = excludedAtomsIdList[interval:interval + number]
  1478. if temp == [0]:
  1479. excludedAtomsList.append([])
  1480. else:
  1481. excludedAtomsList.append([atoms[a - 1] for a in temp])
  1482. interval += number
  1483. self.excludedAtoms = excludedAtomsList
  1484. self.printDebug("getExcludedAtoms")
  1485. def balanceCharges(self, chargeList, FirstNonSoluteId=None):
  1486. """
  1487. Note that python is very annoying about floating points.
  1488. Even after balance, there will always be some residue of order e-12
  1489. to e-16, which is believed to vanished once one writes a topology
  1490. file, say, for CNS or GMX, where floats are represented with 4 or 5
  1491. maximum decimals.
  1492. """
  1493. limIds = []
  1494. # self.printDebug(chargeList)
  1495. total = sum(chargeList)
  1496. totalConverted = total / qConv
  1497. self.printDebug('charge to be balanced: total %13.10f' % (totalConverted))
  1498. maxVal = max(chargeList[:FirstNonSoluteId])
  1499. minVal = min(chargeList[:FirstNonSoluteId])
  1500. if abs(maxVal) >= abs(minVal):
  1501. lim = maxVal
  1502. else:
  1503. lim = minVal
  1504. nLims = chargeList.count(lim)
  1505. # limId = chargeList.index(lim)
  1506. diff = totalConverted - round(totalConverted)
  1507. fix = lim - diff * qConv / nLims
  1508. id_ = 0
  1509. for c in chargeList:
  1510. if c == lim:
  1511. limIds.append(id_)
  1512. chargeList[id_] = fix
  1513. id_ += 1
  1514. # self.printDebug(chargeList)
  1515. self.printDebug("balanceCharges done")
  1516. return chargeList, fix, limIds
  1517. def getABCOEFs(self):
  1518. uniqAtomTypeIdList = self.getFlagData('ATOM_TYPE_INDEX')
  1519. nonBonIdList = self.getFlagData('NONBONDED_PARM_INDEX')
  1520. rawACOEFs = self.getFlagData('LENNARD_JONES_ACOEF')
  1521. rawBCOEFs = self.getFlagData('LENNARD_JONES_BCOEF')
  1522. # print nonBonIdList, len(nonBonIdList), rawACOEFs, len(rawACOEFs)
  1523. ACOEFs = []
  1524. BCOEFs = []
  1525. ntypes = max(uniqAtomTypeIdList)
  1526. # id_ = 0
  1527. # for atName in self._atomTypeNameList:
  1528. for id_ in range(len(self._atomTypeNameList)):
  1529. # id_ = self._atomTypeNameList.index(atName)
  1530. atomTypeId = uniqAtomTypeIdList[id_]
  1531. index = ntypes * (atomTypeId - 1) + atomTypeId
  1532. nonBondId = nonBonIdList[index - 1]
  1533. # print "*****", index, ntypes, atName, id_, atomTypeId, nonBondId
  1534. ACOEFs.append(rawACOEFs[nonBondId - 1])
  1535. BCOEFs.append(rawBCOEFs[nonBondId - 1])
  1536. # id_ += 1
  1537. # print ACOEFs
  1538. self.printDebug("getABCOEFs done")
  1539. return ACOEFs, BCOEFs
  1540. def setProperDihedralsCoef(self):
  1541. """
  1542. It takes self.condensedProperDihedrals and returns
  1543. self.properDihedralsCoefRB, a reduced list of quartet atoms + RB.
  1544. Coeficients ready for GMX (multiplied by 4.184)
  1545. self.properDihedralsCoefRB = [ [atom1,..., atom4], C[0:5] ]
  1546. For proper dihedrals: a quartet of atoms may appear with more than
  1547. one set of parameters and to convert to GMX they are treated as RBs.
  1548. The resulting coefs calculated here may look slighted different from
  1549. the ones calculated by amb2gmx.pl because python is taken full float
  1550. number from prmtop and not rounded numbers from rdparm.out as
  1551. amb2gmx.pl does.
  1552. """
  1553. properDihedralsCoefRB = []
  1554. properDihedralsAlphaGamma = []
  1555. properDihedralsGmx45 = []
  1556. for item in self.condensedProperDihedrals:
  1557. V = 6 * [0.0]
  1558. C = 6 * [0.0]
  1559. for dih in item:
  1560. period = dih.period # Pn
  1561. kPhi = dih.kPhi # in rad
  1562. phaseRaw = dih.phase * radPi # in degree
  1563. phase = int(phaseRaw) # in degree
  1564. if period > 4 and self.gmx4:
  1565. self.printError("Likely trying to convert ILDN to RB, DO NOT use option '-z'")
  1566. sys.exit(1)
  1567. if phase in [0, 180]:
  1568. properDihedralsGmx45.append([item[0].atoms, phaseRaw, kPhi, period])
  1569. if self.gmx4:
  1570. if kPhi > 0:
  1571. V[period] = 2 * kPhi * cal
  1572. if period == 1:
  1573. C[0] += 0.5 * V[period]
  1574. if phase == 0:
  1575. C[1] -= 0.5 * V[period]
  1576. else:
  1577. C[1] += 0.5 * V[period]
  1578. elif period == 2:
  1579. if phase == 180:
  1580. C[0] += V[period]
  1581. C[2] -= V[period]
  1582. else:
  1583. C[2] += V[period]
  1584. elif period == 3:
  1585. C[0] += 0.5 * V[period]
  1586. if phase == 0:
  1587. C[1] += 1.5 * V[period]
  1588. C[3] -= 2 * V[period]
  1589. else:
  1590. C[1] -= 1.5 * V[period]
  1591. C[3] += 2 * V[period]
  1592. elif period == 4:
  1593. if phase == 180:
  1594. C[2] += 4 * V[period]
  1595. C[4] -= 4 * V[period]
  1596. else:
  1597. C[0] += V[period]
  1598. C[2] -= 4 * V[period]
  1599. C[4] += 4 * V[period]
  1600. else:
  1601. properDihedralsAlphaGamma.append([item[0].atoms, phaseRaw, kPhi, period])
  1602. # print phaseRaw, kPhi, period
  1603. if phase in [0, 180]:
  1604. properDihedralsCoefRB.append([item[0].atoms, C])
  1605. # print properDihedralsCoefRB
  1606. # print properDihedralsAlphaGamma
  1607. self.printDebug("setProperDihedralsCoef done")
  1608. self.properDihedralsCoefRB = properDihedralsCoefRB
  1609. self.properDihedralsAlphaGamma = properDihedralsAlphaGamma
  1610. self.properDihedralsGmx45 = properDihedralsGmx45
  1611. def writeCharmmTopolFiles(self):
  1612. self.printMess("Writing CHARMM files\n")
  1613. # self.makeDir()
  1614. at = self.atomType
  1615. self.getResidueLabel()
  1616. res = self.resName # self.residueLabel[0]
  1617. # print res, self.residueLabel, type(self.residueLabel)
  1618. cmd = '%s -i %s -fi mol2 -o %s -fo charmm -s 2 -at %s \
  1619. -pf y -rn %s' % (self.acExe, self.acMol2FileName, self.charmmBase,
  1620. at, res)
  1621. if self.debug:
  1622. cmd = cmd.replace('-pf y', '-pf n')
  1623. self.printDebug(cmd)
  1624. _log = _getoutput(cmd)
  1625. def writePdb(self, file_):
  1626. """
  1627. Write a new PDB file_ with the atom names defined by Antechamber
  1628. Input: file_ path string
  1629. The format generated here use is slightly different from
  1630. http://www.wwpdb.org/documentation/format23/sect9.html respected to
  1631. atom name
  1632. """
  1633. # TODO: assuming only one residue ('1')
  1634. pdbFile = open(file_, 'w')
  1635. fbase = os.path.basename(file_)
  1636. pdbFile.write("REMARK " + head % (fbase, date))
  1637. id_ = 1
  1638. for atom in self.atoms:
  1639. # id_ = self.atoms.index(atom) + 1
  1640. aName = atom.atomName
  1641. if len(aName) == 2:
  1642. aName = ' %s ' % aName
  1643. elif len(aName) == 1:
  1644. aName = ' %s ' % aName
  1645. for l in aName:
  1646. if l.isalpha():
  1647. s = l
  1648. break
  1649. rName = self.residueLabel[0]
  1650. x = atom.coords[0]
  1651. y = atom.coords[1]
  1652. z = atom.coords[2]
  1653. line = "%-6s%5d %4s %3s Z%4d%s%8.3f%8.3f%8.3f%6.2f%6.2f%s%2s\n" % \
  1654. ('ATOM', id_, aName, rName, 1, 4 * ' ', x, y, z, 1.0, 0.0, 10 * ' ', s)
  1655. pdbFile.write(line)
  1656. id_ += 1
  1657. pdbFile.write('END\n')
  1658. def writeGromacsTopolFiles(self, amb2gmx=False):
  1659. """
  1660. # from ~/Programmes/amber10/dat/leap/parm/gaff.dat
  1661. #atom type atomic mass atomic polarizability comments
  1662. ca 12.01 0.360 Sp2 C in pure aromatic systems
  1663. ha 1.008 0.135 H bonded to aromatic carbon
  1664. #bonded atoms harmonic force kcal/mol/A^2 eq. dist. Ang. comments
  1665. ca-ha 344.3* 1.087** SOURCE3 1496 0.0024 0.0045
  1666. * for gmx: 344.3 * 4.184 * 100 * 2 = 288110 kJ/mol/nm^2 (why factor 2?)
  1667. ** convert Ang to nm ( div by 10) for gmx: 1.087 A = 0.1087 nm
  1668. # CA HA 1 0.10800 307105.6 ; ged from 340. bsd on C6H6 nmodes; PHE,TRP,TYR (from ffamber99bon.itp)
  1669. # CA-HA 367.0 1.080 changed from 340. bsd on C6H6 nmodes; PHE,TRP,TYR (from parm99.dat)
  1670. # angle HF kcal/mol/rad^2 eq angle degrees comments
  1671. ca-ca-ha 48.5* 120.01 SOURCE3 2980 0.1509 0.2511
  1672. * to convert to gmx: 48.5 * 4.184 * 2 = 405.848 kJ/mol/rad^2 (why factor 2?)
  1673. # CA CA HA 1 120.000 418.400 ; new99 (from ffamber99bon.itp)
  1674. # CA-CA-HA 50.0 120.00 (from parm99.dat)
  1675. # dihedral idivf barrier hight/2 kcal/mol phase degrees periodicity comments
  1676. X -ca-ca-X 4 14.500* 180.000 2.000 intrpol.bsd.on C6H6
  1677. * to convert to gmx: 14.5/4 * 4.184 * 2 (?) (yes in amb2gmx, not in topolbuild, why?) = 30.334 or 15.167 kJ/mol
  1678. # X -CA-CA-X 4 14.50 180.0 2. intrpol.bsd.on C6H6 (from parm99.dat)
  1679. # X CA CA X 3 30.33400 0.00000 -30.33400 0.00000 0.00000 0.00000 ; intrpol.bsd.on C6H6
  1680. ;propers treated as RBs in GROMACS to use combine multiple AMBER torsions per quartet (from ffamber99bon.itp)
  1681. # impr. dihedral barrier hight/2 phase degrees periodicity comments
  1682. X -X -ca-ha 1.1* 180. 2. bsd.on C6H6 nmodes
  1683. * to convert to gmx: 1.1 * 4.184 = 4.6024 kJ/mol/rad^2
  1684. # X -X -CA-HA 1.1 180. 2. bsd.on C6H6 nmodes (from parm99.dat)
  1685. # X X CA HA 1 180.00 4.60240 2 ; bsd.on C6H6 nmodes
  1686. ;impropers treated as propers in GROMACS to use correct AMBER analytical function (from ffamber99bon.itp)
  1687. # 6-12 parms sigma = 2 * r * 2^(-1/6) epsilon
  1688. # atomtype radius Ang. pot. well depth kcal/mol comments
  1689. ha 1.4590* 0.0150** Spellmeyer
  1690. ca 1.9080 0.0860 OPLS
  1691. * to convert to gmx:
  1692. sigma = 1.4590 * 2^(-1/6) * 2 = 2 * 1.29982 Ang. = 2 * 0.129982 nm = 1.4590 * 2^(5/6)/10 = 0.259964 nm
  1693. ** to convert to gmx: 0.0150 * 4.184 = 0.06276 kJ/mol
  1694. # amber99_3 CA 0.0000 0.0000 A 3.39967e-01 3.59824e-01 (from ffamber99nb.itp)
  1695. # amber99_22 HA 0.0000 0.0000 A 2.59964e-01 6.27600e-02 (from ffamber99nb.itp)
  1696. # C* 1.9080 0.0860 Spellmeyer
  1697. # HA 1.4590 0.0150 Spellmeyer (from parm99.dat)
  1698. # to convert r and epsilon to ACOEF and BCOEF
  1699. # ACOEF = sqrt(e1*e2) * (r1 + r2)^12 ; BCOEF = 2 * sqrt(e1*e2) * (r1 + r2)^6 = 2 * ACOEF/(r1+r2)^6
  1700. # to convert ACOEF and BCOEF to r and epsilon
  1701. # r = 0.5 * (2*ACOEF/BCOEF)^(1/6); ep = BCOEF^2/(4*ACOEF)
  1702. # to convert ACOEF and BCOEF to sigma and epsilon (GMX)
  1703. # sigma = (ACOEF/BCOEF)^(1/6) * 0.1 ; epsilon = 4.184 * BCOEF^2/(4*ACOEF)
  1704. # ca ca 819971.66 531.10
  1705. # ca ha 76245.15 104.66
  1706. # ha ha 5716.30 18.52
  1707. For proper dihedrals: a quartet of atoms may appear with more than
  1708. one set of parameters and to convert to GMX they are treated as RBs;
  1709. use the algorithm:
  1710. for(my $j=$i;$j<=$lines;$j++){
  1711. my $period = $pn{$j};
  1712. if($pk{$j}>0) {
  1713. $V[$period] = 2*$pk{$j}*$cal;
  1714. }
  1715. # assign V values to C values as predefined #
  1716. if($period==1){
  1717. $C[0]+=0.5*$V[$period];
  1718. if($phase{$j}==0){
  1719. $C[1]-=0.5*$V[$period];
  1720. }else{
  1721. $C[1]+=0.5*$V[$period];
  1722. }
  1723. }elsif($period==2){
  1724. if(($phase{$j}==180)||($phase{$j}==3.14)){
  1725. $C[0]+=$V[$period];
  1726. $C[2]-=$V[$period];
  1727. }else{
  1728. $C[2]+=$V[$period];
  1729. }
  1730. }elsif($period==3){
  1731. $C[0]+=0.5*$V[$period];
  1732. if($phase{$j}==0){
  1733. $C[1]+=1.5*$V[$period];
  1734. $C[3]-=2*$V[$period];
  1735. }else{
  1736. $C[1]-=1.5*$V[$period];
  1737. $C[3]+=2*$V[$period];
  1738. }
  1739. }elsif($period==4){
  1740. if(($phase{$j}==180)||($phase{$j}==3.14)){
  1741. $C[2]+=4*$V[$period];
  1742. $C[4]-=4*$V[$period];
  1743. }else{
  1744. $C[0]+=$V[$period];
  1745. $C[2]-=4*$V[$period];
  1746. $C[4]+=4*$V[$period];
  1747. }
  1748. }
  1749. }
  1750. """
  1751. self.printMess("Writing GROMACS files\n")
  1752. self.setAtomType4Gromacs()
  1753. self.writeGroFile()
  1754. self.writeGromacsTop(amb2gmx=amb2gmx)
  1755. self.writeMdpFiles()
  1756. def setAtomType4Gromacs(self):
  1757. """Atom types names in Gromacs TOP file are not case sensitive;
  1758. this routine will append a '_' to lower case atom type.
  1759. E.g.: CA and ca -> CA and ca_
  1760. """
  1761. if self.disam:
  1762. self.printMess("Disambiguating lower and uppercase atomtypes in GMX top file.\n")
  1763. self.atomTypesGromacs = self.atomTypes
  1764. self.atomsGromacs = self.atoms
  1765. return
  1766. atNames = [at.atomTypeName for at in self.atomTypes]
  1767. # print atNames
  1768. delAtomTypes = []
  1769. modAtomTypes = []
  1770. atomTypesGromacs = []
  1771. dictAtomTypes = {}
  1772. for at in self.atomTypes:
  1773. atName = at.atomTypeName
  1774. dictAtomTypes[atName] = at
  1775. if atName.islower() and atName.upper() in atNames:
  1776. # print atName, atName.upper()
  1777. atUpper = self.atomTypes[atNames.index(atName.upper())]
  1778. # print at.atomTypeName,at.mass, at.ACOEF, at.BCOEF
  1779. # print atUpper.atomTypeName, atUpper.mass, atUpper.ACOEF, atUpper.BCOEF
  1780. if at.ACOEF is atUpper.ACOEF and at.BCOEF is at.BCOEF:
  1781. delAtomTypes.append(atName)
  1782. else:
  1783. newAtName = atName + '_'
  1784. modAtomTypes.append(atName)
  1785. atomType = AtomType(newAtName, at.mass, at.ACOEF, at.BCOEF)
  1786. atomTypesGromacs.append(atomType)
  1787. dictAtomTypes[newAtName] = atomType
  1788. else:
  1789. atomTypesGromacs.append(at)
  1790. atomsGromacs = []
  1791. for a in self.atoms:
  1792. atName = a.atomType.atomTypeName
  1793. if atName in delAtomTypes:
  1794. atom = Atom(a.atomName, dictAtomTypes[atName.upper()], a.id,
  1795. a.resid, a.mass, a.charge, a.coords)
  1796. atom.cgnr = a.cgnr
  1797. atomsGromacs.append(atom)
  1798. elif atName in modAtomTypes:
  1799. atom = Atom(a.atomName, dictAtomTypes[atName + '_'], a.id,
  1800. a.resid, a.mass, a.charge, a.coords)
  1801. atom.cgnr = a.cgnr
  1802. atomsGromacs.append(atom)
  1803. else:
  1804. atomsGromacs.append(a)
  1805. self.atomTypesGromacs = atomTypesGromacs
  1806. self.atomsGromacs = atomsGromacs
  1807. # print [i.atomTypeName for i in atomTypesGromacs]
  1808. # print modAtomTypes
  1809. # print delAtomTypes
  1810. def writeGromacsTop(self, amb2gmx=False):
  1811. if self.atomTypeSystem == 'amber':
  1812. d2opls = dictAtomTypeAmb2OplsGmxCode
  1813. else:
  1814. d2opls = dictAtomTypeGaff2OplsGmxCode
  1815. topText = []
  1816. itpText = []
  1817. oitpText = []
  1818. otopText = []
  1819. top = self.baseName + '_GMX.top'
  1820. itp = self.baseName + '_GMX.itp'
  1821. otop = self.baseName + '_GMX_OPLS.top'
  1822. oitp = self.baseName + '_GMX_OPLS.itp'
  1823. headDefault = \
  1824. """
  1825. [ defaults ]
  1826. ; nbfunc comb-rule gen-pairs fudgeLJ fudgeQQ
  1827. 1 2 yes 0.5 0.8333
  1828. """
  1829. headItp = \
  1830. """
  1831. ; Include %s topology
  1832. #include "%s"
  1833. """
  1834. headOpls = \
  1835. """
  1836. ; Include forcefield parameters
  1837. #include "ffoplsaa.itp"
  1838. """
  1839. headSystem = \
  1840. """
  1841. [ system ]
  1842. %s
  1843. """
  1844. headMols = \
  1845. """
  1846. [ molecules ]
  1847. ; Compound nmols
  1848. """
  1849. headAtomtypes = \
  1850. """
  1851. [ atomtypes ]
  1852. ;name bond_type mass charge ptype sigma epsilon Amb
  1853. """
  1854. headAtomtypesOpls = \
  1855. """
  1856. ; For OPLS atomtypes manual fine tuning
  1857. ; AC_at:OPLS_at:OPLScode: Possible_Aternatives (see ffoplsaa.atp and ffoplsaanb.itp)
  1858. """
  1859. headMoleculetype = \
  1860. """
  1861. [ moleculetype ]
  1862. ;name nrexcl
  1863. %-16s 3
  1864. """
  1865. headAtoms = \
  1866. """
  1867. [ atoms ]
  1868. ; nr type resi res atom cgnr charge mass ; qtot bond_type
  1869. """
  1870. headBonds = \
  1871. """
  1872. [ bonds ]
  1873. ; ai aj funct r k
  1874. """
  1875. headPairs = \
  1876. """
  1877. [ pairs ]
  1878. ; ai aj funct
  1879. """
  1880. headAngles = \
  1881. """
  1882. [ angles ]
  1883. ; ai aj ak funct theta cth
  1884. """
  1885. headProDih = \
  1886. """
  1887. [ dihedrals ] ; propers
  1888. ; treated as RBs in GROMACS to use combine multiple AMBER torsions per quartet
  1889. ; i j k l func C0 C1 C2 C3 C4 C5
  1890. """
  1891. headProDihAlphaGamma = """; treated as usual propers in GROMACS since Phase angle diff from 0 or 180 degrees
  1892. ; i j k l func phase kd pn
  1893. """
  1894. headProDihGmx45 = \
  1895. """
  1896. [ dihedrals ] ; propers
  1897. ; for gromacs 4.5 or higher, using funct 9
  1898. ; i j k l func phase kd pn
  1899. """
  1900. headImpDih = \
  1901. """
  1902. [ dihedrals ] ; impropers
  1903. ; treated as propers in GROMACS to use correct AMBER analytical function
  1904. ; i j k l func phase kd pn
  1905. """
  1906. _headTopWaterTip3p = \
  1907. """
  1908. [ bondtypes ]
  1909. ; i j func b0 kb
  1910. OW HW 1 0.09572 462750.4 ; TIP3P water
  1911. HW HW 1 0.15139 462750.4 ; TIP3P water
  1912. [ angletypes ]
  1913. ; i j k func th0 cth
  1914. HW OW HW 1 104.520 836.800 ; TIP3P water
  1915. HW HW OW 1 127.740 0.000 ; (found in crystallographic water with 3 bonds)
  1916. """
  1917. _headTopWaterSpce = \
  1918. """
  1919. [ bondtypes ]
  1920. ; i j func b0 kb
  1921. OW HW 1 0.1 462750.4 ; SPCE water
  1922. HW HW 1 0.1633 462750.4 ; SPCE water
  1923. [ angletypes ]
  1924. ; i j k func th0 cth
  1925. HW OW HW 1 109.47 836.800 ; SPCE water
  1926. HW HW OW 1 125.265 0.000 ; SPCE water
  1927. """
  1928. # NOTE: headTopWaterTip3p and headTopWaterSpce actually do NOTHING
  1929. headNa = \
  1930. """
  1931. [ moleculetype ]
  1932. ; molname nrexcl
  1933. NA+ 1
  1934. [ atoms ]
  1935. ; id_ at type res nr residu name at name cg nr charge mass
  1936. 1 IP 1 NA+ NA+ 1 1 22.9898
  1937. """
  1938. headCl = \
  1939. """
  1940. [ moleculetype ]
  1941. ; molname nrexcl
  1942. CL- 1
  1943. [ atoms ]
  1944. ; id_ at type res nr residu name at name cg nr charge mass
  1945. 1 IM 1 CL- CL- 1 -1 35.45300
  1946. """
  1947. headK = \
  1948. """
  1949. [ moleculetype ]
  1950. ; molname nrexcl
  1951. K+ 1
  1952. [ atoms ]
  1953. ; id_ at type res nr residu name at name cg nr charge mass
  1954. 1 K 1 K+ K+ 1 1 39.100
  1955. """
  1956. headWaterTip3p = \
  1957. """
  1958. [ moleculetype ]
  1959. ; molname nrexcl ; TIP3P model
  1960. WAT 2
  1961. [ atoms ]
  1962. ; nr type resnr residue atom cgnr charge mass
  1963. 1 OW 1 WAT O 1 -0.834 16.00000
  1964. 2 HW 1 WAT H1 1 0.417 1.00800
  1965. 3 HW 1 WAT H2 1 0.417 1.00800
  1966. #ifdef FLEXIBLE
  1967. [ bonds ]
  1968. ; i j funct length force.c.
  1969. 1 2 1 0.09572 462750.4 0.09572 462750.4
  1970. 1 3 1 0.09572 462750.4 0.09572 462750.4
  1971. [ angles ]
  1972. ; i j k funct angle force.c.
  1973. 2 1 3 1 104.520 836.800 104.520 836.800
  1974. #else
  1975. [ settles ]
  1976. ; i j funct length
  1977. 1 1 0.09572 0.15139
  1978. [ exclusions ]
  1979. 1 2 3
  1980. 2 1 3
  1981. 3 1 2
  1982. #endif
  1983. """
  1984. headWaterSpce = \
  1985. """
  1986. [ moleculetype ]
  1987. ; molname nrexcl ; SPCE model
  1988. WAT 2
  1989. [ atoms ]
  1990. ; nr type resnr residue atom cgnr charge mass
  1991. 1 OW 1 WAT O 1 -0.8476 15.99940
  1992. 2 HW 1 WAT H1 1 0.4238 1.00800
  1993. 3 HW 1 WAT H2 1 0.4238 1.00800
  1994. #ifdef FLEXIBLE
  1995. [ bonds ]
  1996. ; i j funct length force.c.
  1997. 1 2 1 0.1 462750.4 0.1 462750.4
  1998. 1 3 1 0.1 462750.4 0.1 462750.4
  1999. [ angles ]
  2000. ; i j k funct angle force.c.
  2001. 2 1 3 1 109.47 836.800 109.47 836.800
  2002. #else
  2003. [ settles ]
  2004. ; OW funct doh dhh
  2005. 1 1 0.1 0.16330
  2006. [ exclusions ]
  2007. 1 2 3
  2008. 2 1 3
  2009. 3 1 2
  2010. #endif
  2011. """
  2012. if self.direct and amb2gmx:
  2013. self.printMess("Converting directly from AMBER to GROMACS.\n")
  2014. # Dict of ions dealt by acpype emulating amb2gmx
  2015. ionsDict = {'Na+': headNa, 'Cl-': headCl, 'K+': headK}
  2016. ionsSorted = []
  2017. # NOTE: headWaterTip3p and headWaterSpce actually do the real thing
  2018. # so, skipping headTopWaterTip3p and headWaterTip3p
  2019. # headTopWater = headTopWaterTip3p
  2020. headWater = headWaterTip3p
  2021. nWat = 0
  2022. # topFile.write("; " + head % (top, date))
  2023. topText.append("; " + head % (top, date))
  2024. otopText.append("; " + head % (otop, date))
  2025. # topFile.write(headDefault)
  2026. topText.append(headDefault)
  2027. nSolute = 0
  2028. if not amb2gmx:
  2029. topText.append(headItp % (itp, itp))
  2030. otopText.append(headOpls)
  2031. otopText.append(headItp % (itp, itp))
  2032. itpText.append("; " + head % (itp, date))
  2033. oitpText.append("; " + head % (oitp, date))
  2034. self.printDebug("atomTypes %i" % len(self.atomTypesGromacs))
  2035. temp = []
  2036. otemp = []
  2037. for aType in self.atomTypesGromacs:
  2038. aTypeName = aType.atomTypeName
  2039. oaCode = d2opls.get(aTypeName, ['x', '0'])[:-1]
  2040. aTypeNameOpls = oplsCode2AtomTypeDict.get(oaCode[0], 'x')
  2041. A = aType.ACOEF
  2042. B = aType.BCOEF
  2043. # one cannot infer sigma or epsilon for B = 0, assuming 0 for them
  2044. if B == 0.0:
  2045. sigma, epsilon, r0, epAmber = 0, 0, 0, 0
  2046. else:
  2047. r0 = 0.5 * math.pow((2 * A / B), (1.0 / 6))
  2048. epAmber = 0.25 * B * B / A
  2049. sigma = 0.1 * math.pow((A / B), (1.0 / 6))
  2050. epsilon = cal * epAmber
  2051. if aTypeName == 'OW':
  2052. if A == 629362.166 and B == 625.267765:
  2053. # headTopWater = headTopWaterSpce
  2054. headWater = headWaterSpce
  2055. # OW 629362.166 625.267765 spce
  2056. # OW 581935.564 594.825035 tip3p
  2057. # print aTypeName, A, B
  2058. line = " %-8s %-11s %3.5f %3.5f A %13.5e %13.5e" % \
  2059. (aTypeName, aTypeName, 0.0, 0.0, sigma, epsilon) + \
  2060. " ; %4.2f %1.4f\n" % (r0, epAmber)
  2061. oline = "; %s:%s:opls_%s: %s\n" % (aTypeName, aTypeNameOpls, oaCode[0], repr(oaCode[1:]))
  2062. # tmpFile.write(line)
  2063. temp.append(line)
  2064. otemp.append(oline)
  2065. if amb2gmx:
  2066. topText.append(headAtomtypes)
  2067. topText += temp
  2068. nWat = self.residueLabel.count('WAT')
  2069. for ion in ionsDict:
  2070. nIon = self.residueLabel.count(ion)
  2071. if nIon > 0:
  2072. idIon = self.residueLabel.index(ion)
  2073. ionsSorted.append((idIon, nIon, ion))
  2074. ionsSorted.sort()
  2075. else:
  2076. itpText.append(headAtomtypes)
  2077. itpText += temp
  2078. oitpText.append(headAtomtypesOpls)
  2079. oitpText += otemp
  2080. self.printDebug("GMX atomtypes done")
  2081. if len(self.atoms) > 3 * nWat + sum([x[1] for x in ionsSorted]):
  2082. nSolute = 1
  2083. if nWat:
  2084. # topText.append(headTopWater)
  2085. self.printDebug("type of water '%s'" % headWater[43:48].strip())
  2086. if nSolute:
  2087. if amb2gmx:
  2088. topText.append(headMoleculetype % self.baseName)
  2089. else:
  2090. itpText.append(headMoleculetype % self.baseName)
  2091. oitpText.append(headMoleculetype % self.baseName)
  2092. self.printDebug("atoms %i" % len(self.atoms))
  2093. qtot = 0.0
  2094. count = 1
  2095. temp = []
  2096. otemp = []
  2097. id2oplsATDict = {}
  2098. for atom in self.atomsGromacs:
  2099. resid = atom.resid
  2100. resname = self.residueLabel[resid]
  2101. if not self.direct:
  2102. if resname in list(ionsDict.keys()) + ['WAT']:
  2103. break
  2104. aName = atom.atomName
  2105. aType = atom.atomType.atomTypeName
  2106. oItem = d2opls.get(aType, ['x', 0])
  2107. oplsAtName = oplsCode2AtomTypeDict.get(oItem[0], 'x')
  2108. id_ = atom.id
  2109. id2oplsATDict[id_] = oplsAtName
  2110. oaCode = 'opls_' + oItem[0]
  2111. cgnr = id_
  2112. if self.sorted:
  2113. cgnr = atom.cgnr # JDC
  2114. charge = atom.charge
  2115. mass = atom.mass
  2116. omass = float(oItem[-1])
  2117. qtot += charge
  2118. resnr = resid + 1
  2119. line = "%6d %4s %5d %5s %5s %4d %12.6f %12.5f ; qtot %1.3f\n" % \
  2120. (id_, aType, resnr, resname, aName, cgnr, charge, mass, qtot) # JDC
  2121. oline = "%6d %4s %5d %5s %5s %4d %12.6f %12.5f ; qtot % 3.3f %-4s\n" % \
  2122. (id_, oaCode, resnr, resname, aName, cgnr, charge, omass, qtot, oplsAtName) # JDC
  2123. count += 1
  2124. temp.append(line)
  2125. otemp.append(oline)
  2126. if temp:
  2127. if amb2gmx:
  2128. topText.append(headAtoms)
  2129. topText += temp
  2130. else:
  2131. itpText.append(headAtoms)
  2132. itpText += temp
  2133. oitpText.append(headAtoms)
  2134. oitpText += otemp
  2135. self.printDebug("GMX atoms done")
  2136. # remove bond of water
  2137. self.printDebug("bonds %i" % len(self.bonds))
  2138. temp = []
  2139. otemp = []
  2140. for bond in self.bonds:
  2141. res1 = self.residueLabel[bond.atoms[0].resid]
  2142. res2 = self.residueLabel[bond.atoms[0].resid]
  2143. if 'WAT' in [res1, res2]:
  2144. continue
  2145. a1Name = bond.atoms[0].atomName
  2146. a2Name = bond.atoms[1].atomName
  2147. id1 = bond.atoms[0].id
  2148. id2 = bond.atoms[1].id
  2149. oat1 = id2oplsATDict.get(id1)
  2150. oat2 = id2oplsATDict.get(id2)
  2151. line = "%6i %6i %3i %13.4e %13.4e ; %6s - %-6s\n" % (id1, id2, 1,
  2152. bond.rEq * 0.1, bond.kBond * 200 * cal, a1Name, a2Name)
  2153. oline = "%6i %6i %3i ; %13.4e %13.4e ; %6s - %-6s %6s - %-6s\n" % \
  2154. (id1, id2, 1, bond.rEq * 0.1, bond.kBond * 200 * cal, a1Name,
  2155. a2Name, oat1, oat2)
  2156. temp.append(line)
  2157. otemp.append(oline)
  2158. temp.sort()
  2159. otemp.sort()
  2160. if temp:
  2161. if amb2gmx:
  2162. topText.append(headBonds)
  2163. topText += temp
  2164. else:
  2165. itpText.append(headBonds)
  2166. itpText += temp
  2167. oitpText.append(headBonds)
  2168. oitpText += otemp
  2169. self.printDebug("GMX bonds done")
  2170. self.printDebug("atomPairs %i" % len(self.atomPairs))
  2171. temp = []
  2172. for pair in self.atomPairs:
  2173. # if not printed:
  2174. # tmpFile.write(headPairs)
  2175. # printed = True
  2176. a1Name = pair[0].atomName
  2177. a2Name = pair[1].atomName
  2178. id1 = pair[0].id
  2179. id2 = pair[1].id
  2180. # id1 = self.atoms.index(pair[0]) + 1
  2181. # id2 = self.atoms.index(pair[1]) + 1
  2182. line = "%6i %6i %6i ; %6s - %-6s\n" % (id1, id2, 1, a1Name,
  2183. a2Name)
  2184. temp.append(line)
  2185. temp.sort()
  2186. if temp:
  2187. if amb2gmx:
  2188. topText.append(headPairs)
  2189. topText += temp
  2190. else:
  2191. itpText.append(headPairs)
  2192. itpText += temp
  2193. oitpText.append(headPairs)
  2194. oitpText += temp
  2195. self.printDebug("GMX pairs done")
  2196. self.printDebug("angles %i" % len(self.angles))
  2197. temp = []
  2198. otemp = []
  2199. for angle in self.angles:
  2200. a1 = angle.atoms[0].atomName
  2201. a2 = angle.atoms[1].atomName
  2202. a3 = angle.atoms[2].atomName
  2203. id1 = angle.atoms[0].id
  2204. id2 = angle.atoms[1].id
  2205. id3 = angle.atoms[2].id
  2206. oat1 = id2oplsATDict.get(id1)
  2207. oat2 = id2oplsATDict.get(id2)
  2208. oat3 = id2oplsATDict.get(id3)
  2209. line = "%6i %6i %6i %6i %13.4e %13.4e ; %6s - %-6s - %-6s\n" % (id1, id2,
  2210. id3, 1, angle.thetaEq * radPi, 2 * cal * angle.kTheta, a1, a2, a3)
  2211. oline = "%6i %6i %6i %6i ; %13.4e %13.4e ; %6s - %-4s - %-6s %4s - %+4s - %-4s\n" % \
  2212. (id1, id2, id3, 1, angle.thetaEq * radPi, 2 * cal * angle.kTheta,
  2213. a1, a2, a3, oat1, oat2, oat3)
  2214. temp.append(line)
  2215. otemp.append(oline)
  2216. temp.sort()
  2217. otemp.sort()
  2218. if temp:
  2219. if amb2gmx:
  2220. topText.append(headAngles)
  2221. topText += temp
  2222. else:
  2223. itpText.append(headAngles)
  2224. itpText += temp
  2225. oitpText.append(headAngles)
  2226. oitpText += otemp
  2227. self.printDebug("GMX angles done")
  2228. self.setProperDihedralsCoef()
  2229. self.printDebug("properDihedralsCoefRB %i" % len(self.properDihedralsCoefRB))
  2230. self.printDebug("properDihedralsAlphaGamma %i" % len(self.properDihedralsAlphaGamma))
  2231. self.printDebug("properDihedralsGmx45 %i" % len(self.properDihedralsGmx45))
  2232. temp = []
  2233. otemp = []
  2234. if self.gmx4:
  2235. self.printMess("Writing RB dihedrals for old GMX 4.\n")
  2236. for dih in self.properDihedralsCoefRB:
  2237. a1 = dih[0][0].atomName
  2238. a2 = dih[0][1].atomName
  2239. a3 = dih[0][2].atomName
  2240. a4 = dih[0][3].atomName
  2241. id1 = dih[0][0].id
  2242. id2 = dih[0][1].id
  2243. id3 = dih[0][2].id
  2244. id4 = dih[0][3].id
  2245. oat1 = id2oplsATDict.get(id1)
  2246. oat2 = id2oplsATDict.get(id2)
  2247. oat3 = id2oplsATDict.get(id3)
  2248. oat4 = id2oplsATDict.get(id4)
  2249. c0, c1, c2, c3, c4, c5 = dih[1]
  2250. line = \
  2251. "%6i %6i %6i %6i %6i %10.5f %10.5f %10.5f %10.5f %10.5f %10.5f" % \
  2252. (id1, id2, id3, id4, 3, c0, c1, c2, c3, c4, c5) \
  2253. + " ; %6s-%6s-%6s-%6s\n" % (a1, a2, a3, a4)
  2254. oline = \
  2255. "%6i %6i %6i %6i %6i ; %10.5f %10.5f %10.5f %10.5f %10.5f %10.5f" % \
  2256. (id1, id2, id3, id4, 3, c0, c1, c2, c3, c4, c5) \
  2257. + " ; %6s-%6s-%6s-%6s %4s-%4s-%4s-%4s\n" % (a1, a2, a3, a4, oat1, oat2, oat3, oat4)
  2258. temp.append(line)
  2259. otemp.append(oline)
  2260. temp.sort()
  2261. otemp.sort()
  2262. if temp:
  2263. if amb2gmx:
  2264. topText.append(headProDih)
  2265. topText += temp
  2266. else:
  2267. itpText.append(headProDih)
  2268. itpText += temp
  2269. oitpText.append(headProDih)
  2270. oitpText += otemp
  2271. self.printDebug("GMX proper dihedrals done")
  2272. else:
  2273. self.printMess("Writing GMX dihedrals for GMX 4.5 and higher.\n")
  2274. funct = 9 # 9
  2275. for dih in self.properDihedralsGmx45:
  2276. a1 = dih[0][0].atomName
  2277. a2 = dih[0][1].atomName
  2278. a3 = dih[0][2].atomName
  2279. a4 = dih[0][3].atomName
  2280. id1 = dih[0][0].id
  2281. id2 = dih[0][1].id
  2282. id3 = dih[0][2].id
  2283. id4 = dih[0][3].id
  2284. ph = dih[1] # phase already in degree
  2285. kd = dih[2] * cal # kPhi PK
  2286. pn = dih[3] # .period
  2287. line = "%6i %6i %6i %6i %6i %8.2f %9.5f %3i ; %6s-%6s-%6s-%6s\n" % \
  2288. (id1, id2, id3, id4, funct, ph, kd, pn, a1, a2, a3, a4)
  2289. oline = "%6i %6i %6i %6i %6i ; %8.2f %9.5f %3i ; %6s-%6s-%6s-%6s\n" % \
  2290. (id1, id2, id3, id4, funct, ph, kd, pn, a1, a2, a3, a4)
  2291. temp.append(line)
  2292. otemp.append(oline)
  2293. temp.sort()
  2294. otemp.sort()
  2295. if temp:
  2296. if amb2gmx:
  2297. topText.append(headProDihGmx45)
  2298. topText += temp
  2299. else:
  2300. itpText.append(headProDihGmx45)
  2301. itpText += temp
  2302. oitpText.append(headProDihGmx45)
  2303. oitpText += otemp
  2304. # for properDihedralsAlphaGamma
  2305. if not self.gmx4:
  2306. funct = 4 # 4
  2307. else:
  2308. funct = 1
  2309. temp = []
  2310. otemp = []
  2311. for dih in self.properDihedralsAlphaGamma:
  2312. a1 = dih[0][0].atomName
  2313. a2 = dih[0][1].atomName
  2314. a3 = dih[0][2].atomName
  2315. a4 = dih[0][3].atomName
  2316. id1 = dih[0][0].id
  2317. id2 = dih[0][1].id
  2318. id3 = dih[0][2].id
  2319. id4 = dih[0][3].id
  2320. ph = dih[1] # phase already in degree
  2321. kd = dih[2] * cal # kPhi PK
  2322. pn = dih[3] # .period
  2323. line = "%6i %6i %6i %6i %6i %8.2f %9.5f %3i ; %6s-%6s-%6s-%6s\n" % \
  2324. (id1, id2, id3, id4, funct, ph, kd, pn, a1, a2, a3, a4)
  2325. oline = "%6i %6i %6i %6i %6i ; %8.2f %9.5f %3i ; %6s-%6s-%6s-%6s\n" % \
  2326. (id1, id2, id3, id4, funct, ph, kd, pn, a1, a2, a3, a4)
  2327. temp.append(line)
  2328. otemp.append(oline)
  2329. temp.sort()
  2330. otemp.sort()
  2331. if temp:
  2332. if amb2gmx:
  2333. topText.append(headProDihAlphaGamma)
  2334. topText += temp
  2335. else:
  2336. itpText.append(headProDihAlphaGamma)
  2337. itpText += temp
  2338. oitpText.append(headProDihAlphaGamma)
  2339. oitpText += otemp
  2340. self.printDebug("GMX special proper dihedrals done")
  2341. self.printDebug("improperDihedrals %i" % len(self.improperDihedrals))
  2342. temp = []
  2343. otemp = []
  2344. for dih in self.improperDihedrals:
  2345. a1 = dih.atoms[0].atomName
  2346. a2 = dih.atoms[1].atomName
  2347. a3 = dih.atoms[2].atomName
  2348. a4 = dih.atoms[3].atomName
  2349. id1 = dih.atoms[0].id
  2350. id2 = dih.atoms[1].id
  2351. id3 = dih.atoms[2].id
  2352. id4 = dih.atoms[3].id
  2353. kd = dih.kPhi * cal
  2354. pn = dih.period
  2355. ph = dih.phase * radPi
  2356. line = "%6i %6i %6i %6i %6i %8.2f %9.5f %3i ; %6s-%6s-%6s-%6s\n" % \
  2357. (id1, id2, id3, id4, funct, ph, kd, pn, a1, a2, a3, a4)
  2358. oline = "%6i %6i %6i %6i %6i ; %8.2f %9.5f %3i ; %6s-%6s-%6s-%6s\n" % \
  2359. (id1, id2, id3, id4, funct, ph, kd, pn, a1, a2, a3, a4)
  2360. temp.append(line)
  2361. otemp.append(oline)
  2362. temp.sort()
  2363. otemp.sort()
  2364. if temp:
  2365. if amb2gmx:
  2366. topText.append(headImpDih)
  2367. topText += temp
  2368. else:
  2369. itpText.append(headImpDih)
  2370. itpText += temp
  2371. oitpText.append(headImpDih)
  2372. oitpText += otemp
  2373. self.printDebug("GMX improper dihedrals done")
  2374. if not self.direct:
  2375. for ion in ionsSorted:
  2376. topText.append(ionsDict[ion[2]])
  2377. if nWat:
  2378. topText.append(headWater)
  2379. topText.append(headSystem % (self.baseName))
  2380. topText.append(headMols)
  2381. otopText.append(headSystem % (self.baseName))
  2382. otopText.append(headMols)
  2383. if nSolute > 0:
  2384. topText.append(" %-16s %-6i\n" % (self.baseName, nSolute))
  2385. otopText.append(" %-16s %-6i\n" % (self.baseName, nSolute))
  2386. if not self.direct:
  2387. for ion in ionsSorted:
  2388. topText.append(" %-16s %-6i\n" % (ion[2].upper(), ion[1]))
  2389. if nWat:
  2390. topText.append(" %-16s %-6i\n" % ('WAT', nWat))
  2391. gmxDir = os.path.abspath('.')
  2392. topFileName = os.path.join(gmxDir, top)
  2393. topFile = open(topFileName, 'w')
  2394. topFile.writelines(topText)
  2395. if not amb2gmx:
  2396. itpFileName = os.path.join(gmxDir, itp)
  2397. itpFile = open(itpFileName, 'w')
  2398. itpFile.writelines(itpText)
  2399. oitpFileName = os.path.join(gmxDir, oitp)
  2400. oitpFile = open(oitpFileName, 'w')
  2401. oitpFile.writelines(oitpText)
  2402. otopFileName = os.path.join(gmxDir, otop)
  2403. otopFile = open(otopFileName, 'w')
  2404. otopFile.writelines(otopText)
  2405. def writeGroFile(self):
  2406. # print "Writing GROMACS GRO file\n"
  2407. self.printDebug("writing GRO file")
  2408. gro = self.baseName + '_GMX.gro'
  2409. gmxDir = os.path.abspath('.')
  2410. groFileName = os.path.join(gmxDir, gro)
  2411. groFile = open(groFileName, 'w')
  2412. groFile.write(head % (gro, date))
  2413. groFile.write(" %i\n" % len(self.atoms))
  2414. count = 1
  2415. for atom in self.atoms:
  2416. coords = [c * 0.1 for c in atom.coords]
  2417. resid = atom.resid
  2418. line = "%5d%5s%5s%5d%8.3f%8.3f%8.3f\n" % \
  2419. (resid + 1, self.residueLabel[resid], atom.atomName,
  2420. count, coords[0], coords[1], coords[2])
  2421. count += 1
  2422. if count == 100000:
  2423. count = 0
  2424. groFile.write(line)
  2425. if self.pbc:
  2426. boxX = self.pbc[0][0] * 0.1
  2427. boxY = self.pbc[0][1] * 0.1
  2428. boxZ = self.pbc[0][2] * 0.1
  2429. vX = self.pbc[1][0]
  2430. # vY = self.pbc[1][1]
  2431. # vZ = self.pbc[1][2]
  2432. if vX == 90.0:
  2433. self.printDebug("PBC triclinic")
  2434. text = "%11.5f %11.5f %11.5f\n" % (boxX, boxY, boxZ)
  2435. elif round(vX, 2) == 109.47:
  2436. self.printDebug("PBC octahedron")
  2437. f1 = 0.471405 # 1/3 * sqrt(2)
  2438. f2 = 0.333333 * boxX
  2439. v22 = boxY * 2 * f1
  2440. v33 = boxZ * f1 * 1.73205 # f1 * sqrt(3)
  2441. v21 = v31 = v32 = 0.0
  2442. v12 = f2
  2443. v13 = -f2
  2444. v23 = f1 * boxX
  2445. text = "%11.5f %11.5f %11.5f %11.5f %11.5f %11.5f %11.5f %11.5f %11.5f\n" % \
  2446. (boxX, v22, v33, v21, v31, v12, v32, v13, v23)
  2447. else:
  2448. self.printDebug("Box size estimated")
  2449. X = [a.coords[0] * 0.1 for a in self.atoms]
  2450. Y = [a.coords[1] * 0.1 for a in self.atoms]
  2451. Z = [a.coords[2] * 0.1 for a in self.atoms]
  2452. boxX = max(X) - min(X) # + 2.0 # 2.0 is double of rlist
  2453. boxY = max(Y) - min(Y) # + 2.0
  2454. boxZ = max(Z) - min(Z) # + 2.0
  2455. text = "%11.5f %11.5f %11.5f\n" % (boxX * 20.0, boxY * 20.0, boxZ * 20.0)
  2456. groFile.write(text)
  2457. def writeMdpFiles(self):
  2458. emMdp = """; to test
  2459. ; gmx grompp -f em.mdp -c {base}_GMX.gro -p {base}_GMX.top -o em.tpr -v
  2460. ; gmx mdrun -ntmpi 1 -v -deffnm em
  2461. integrator = steep
  2462. nsteps = 500
  2463. """.format(base=self.baseName)
  2464. mdMdp = """; to test
  2465. ; gmx grompp -f md.mdp -c em.gro -p {base}_GMX.top -o md.tpr
  2466. ; gmx mdrun -ntmpi 1 -v -deffnm md
  2467. integrator = md
  2468. nsteps = 10000
  2469. """.format(base=self.baseName)
  2470. emMdpFile = open('em.mdp', 'w')
  2471. mdMdpFile = open('md.mdp', 'w')
  2472. emMdpFile.write(emMdp)
  2473. mdMdpFile.write(mdMdp)
  2474. def writeCnsTopolFiles(self):
  2475. autoAngleFlag = True
  2476. autoDihFlag = True
  2477. cnsDir = os.path.abspath('.')
  2478. pdb = self.baseName + '_NEW.pdb'
  2479. par = self.baseName + '_CNS.par'
  2480. top = self.baseName + '_CNS.top'
  2481. inp = self.baseName + '_CNS.inp'
  2482. pdbFileName = os.path.join(cnsDir, pdb)
  2483. parFileName = os.path.join(cnsDir, par)
  2484. topFileName = os.path.join(cnsDir, top)
  2485. inpFileName = os.path.join(cnsDir, inp)
  2486. self.CnsTopFileName = topFileName
  2487. self.CnsInpFileName = inpFileName
  2488. self.CnsParFileName = parFileName
  2489. self.CnsPdbFileName = pdbFileName
  2490. parFile = open(parFileName, 'w')
  2491. topFile = open(topFileName, 'w')
  2492. inpFile = open(inpFileName, 'w')
  2493. self.printMess("Writing NEW PDB file\n")
  2494. self.writePdb(pdbFileName)
  2495. self.printMess("Writing CNS/XPLOR files\n")
  2496. # print "Writing CNS PAR file\n"
  2497. parFile.write("Remarks " + head % (par, date))
  2498. parFile.write("\nset echo=false end\n")
  2499. parFile.write("\n{ Bonds: atomType1 atomType2 kb r0 }\n")
  2500. lineSet = []
  2501. for bond in self.bonds:
  2502. a1Type = bond.atoms[0].atomType.atomTypeName + '_'
  2503. a2Type = bond.atoms[1].atomType.atomTypeName + '_'
  2504. kb = 1000.0
  2505. if not self.allhdg:
  2506. kb = bond.kBond
  2507. r0 = bond.rEq
  2508. line = "BOND %5s %5s %8.1f %8.4f\n" % (a1Type, a2Type, kb, r0)
  2509. lineRev = "BOND %5s %5s %8.1f %8.4f\n" % (a2Type, a1Type, kb, r0)
  2510. if line not in lineSet:
  2511. if lineRev not in lineSet:
  2512. lineSet.append(line)
  2513. for item in lineSet:
  2514. parFile.write(item)
  2515. parFile.write("\n{ Angles: aType1 aType2 aType3 kt t0 }\n")
  2516. lineSet = []
  2517. for angle in self.angles:
  2518. a1 = angle.atoms[0].atomType.atomTypeName + '_'
  2519. a2 = angle.atoms[1].atomType.atomTypeName + '_'
  2520. a3 = angle.atoms[2].atomType.atomTypeName + '_'
  2521. kt = 500.0
  2522. if not self.allhdg:
  2523. kt = angle.kTheta
  2524. t0 = angle.thetaEq * radPi
  2525. line = "ANGLe %5s %5s %5s %8.1f %8.2f\n" % (a1, a2, a3, kt, t0)
  2526. lineRev = "ANGLe %5s %5s %5s %8.1f %8.2f\n" % (a3, a2, a1, kt, t0)
  2527. if line not in lineSet:
  2528. if lineRev not in lineSet:
  2529. lineSet.append(line)
  2530. for item in lineSet:
  2531. parFile.write(item)
  2532. parFile.write("\n{ Proper Dihedrals: aType1 aType2 aType3 aType4 kt per\
  2533. iod phase }\n")
  2534. lineSet = set()
  2535. for item in self.condensedProperDihedrals:
  2536. seq = ''
  2537. id_ = 0
  2538. for dih in item:
  2539. # id_ = item.index(dih)
  2540. l = len(item)
  2541. a1 = dih.atoms[0].atomType.atomTypeName + '_'
  2542. a2 = dih.atoms[1].atomType.atomTypeName + '_'
  2543. a3 = dih.atoms[2].atomType.atomTypeName + '_'
  2544. a4 = dih.atoms[3].atomType.atomTypeName + '_'
  2545. kp = 750.0
  2546. if not self.allhdg:
  2547. kp = dih.kPhi
  2548. p = dih.period
  2549. ph = dih.phase * radPi
  2550. if l > 1:
  2551. if id_ == 0:
  2552. line = "DIHEdral %5s %5s %5s %5s MULT %1i %7.3f %4i %8\
  2553. .2f\n" % (a1, a2, a3, a4, l, kp, p, ph)
  2554. else:
  2555. line = "%s %7.3f %4i %8.2f\n" % (40 * " ", kp, p, ph)
  2556. else:
  2557. line = "DIHEdral %5s %5s %5s %5s %15.3f %4i %8.2f\n" % (a1,
  2558. a2, a3, a4, kp, p, ph)
  2559. seq += line
  2560. id_ += 1
  2561. lineSet.add(seq)
  2562. for item in lineSet:
  2563. parFile.write(item)
  2564. parFile.write("\n{ Improper Dihedrals: aType1 aType2 aType3 aType4 kt p\
  2565. eriod phase }\n")
  2566. lineSet = set()
  2567. for idh in self.improperDihedrals:
  2568. a1 = idh.atoms[0].atomType.atomTypeName + '_'
  2569. a2 = idh.atoms[1].atomType.atomTypeName + '_'
  2570. a3 = idh.atoms[2].atomType.atomTypeName + '_'
  2571. a4 = idh.atoms[3].atomType.atomTypeName + '_'
  2572. kp = 750.0
  2573. if not self.allhdg:
  2574. kp = idh.kPhi
  2575. p = idh.period
  2576. ph = idh.phase * radPi
  2577. line = "IMPRoper %5s %5s %5s %5s %13.1f %4i %8.2f\n" % (a1, a2, a3,
  2578. a4, kp, p, ph)
  2579. lineSet.add(line)
  2580. if self.chiral:
  2581. for idhc in self.chiralGroups:
  2582. _atc, neig, angle = idhc
  2583. a1 = neig[0].atomType.atomTypeName + '_'
  2584. a2 = neig[1].atomType.atomTypeName + '_'
  2585. a3 = neig[2].atomType.atomTypeName + '_'
  2586. a4 = neig[3].atomType.atomTypeName + '_'
  2587. kp = 11000.0
  2588. p = 0
  2589. ph = angle
  2590. line = "IMPRoper %5s %5s %5s %5s %13.1f %4i %8.2f\n" % (a1, a2, a3,
  2591. a4, kp, p, ph)
  2592. lineSet.add(line)
  2593. for item in lineSet:
  2594. parFile.write(item)
  2595. parFile.write("\n{ Nonbonded: Type Emin sigma; (1-4): Emin/2 sigma }\n")
  2596. for at in self.atomTypes:
  2597. A = at.ACOEF
  2598. B = at.BCOEF
  2599. atName = at.atomTypeName + '_'
  2600. if B == 0.0:
  2601. sigma = epAmber = ep2 = sig2 = 0.0
  2602. else:
  2603. epAmber = 0.25 * B * B / A
  2604. ep2 = epAmber / 2.0
  2605. sigma = math.pow((A / B), (1.0 / 6))
  2606. sig2 = sigma
  2607. line = "NONBonded %5s %11.6f %11.6f %11.6f %11.6f\n" % (atName,
  2608. epAmber, sigma, ep2, sig2)
  2609. parFile.write(line)
  2610. parFile.write("\nset echo=true end\n")
  2611. # print "Writing CNS TOP file\n"
  2612. topFile.write("Remarks " + head % (top, date))
  2613. topFile.write("\nset echo=false end\n")
  2614. topFile.write("\nautogenerate angles=%s dihedrals=%s end\n" %
  2615. (autoAngleFlag, autoDihFlag))
  2616. topFile.write("\n{ atomType mass }\n")
  2617. for at in self.atomTypes:
  2618. atType = at.atomTypeName + '_'
  2619. mass = at.mass
  2620. line = "MASS %-5s %8.3f\n" % (atType, mass)
  2621. topFile.write(line)
  2622. topFile.write("\nRESIdue %s\n" % self.residueLabel[0])
  2623. topFile.write("\nGROUP\n")
  2624. topFile.write("\n{ atomName atomType Charge }\n")
  2625. for at in self.atoms:
  2626. atName = at.atomName
  2627. atType = at.atomType.atomTypeName + '_'
  2628. charge = at.charge
  2629. line = "ATOM %-5s TYPE= %-5s CHARGE= %8.4f END\n" % (atName, atType,
  2630. charge)
  2631. topFile.write(line)
  2632. topFile.write("\n{ Bonds: atomName1 atomName2 }\n")
  2633. for bond in self.bonds:
  2634. a1Name = bond.atoms[0].atomName
  2635. a2Name = bond.atoms[1].atomName
  2636. line = "BOND %-5s %-5s\n" % (a1Name, a2Name)
  2637. topFile.write(line)
  2638. if not autoAngleFlag or 1: # generating angles anyway
  2639. topFile.write("\n{ Angles: atomName1 atomName2 atomName3}\n")
  2640. for angle in self.angles:
  2641. a1Name = angle.atoms[0].atomName
  2642. a2Name = angle.atoms[1].atomName
  2643. a3Name = angle.atoms[2].atomName
  2644. line = "ANGLe %-5s %-5s %-5s\n" % (a1Name, a2Name, a3Name)
  2645. topFile.write(line)
  2646. if not autoDihFlag or 1: # generating angles anyway
  2647. topFile.write("\n{ Proper Dihedrals: name1 name2 name3 name4 }\n")
  2648. for item in self.condensedProperDihedrals:
  2649. for dih in item:
  2650. l = len(item)
  2651. a1Name = dih.atoms[0].atomName
  2652. a2Name = dih.atoms[1].atomName
  2653. a3Name = dih.atoms[2].atomName
  2654. a4Name = dih.atoms[3].atomName
  2655. line = "DIHEdral %-5s %-5s %-5s %-5s\n" % (a1Name, a2Name,
  2656. a3Name, a4Name)
  2657. break
  2658. topFile.write(line)
  2659. topFile.write("\n{ Improper Dihedrals: aName1 aName2 aName3 aName4 }\n")
  2660. for dih in self.improperDihedrals:
  2661. a1Name = dih.atoms[0].atomName
  2662. a2Name = dih.atoms[1].atomName
  2663. a3Name = dih.atoms[2].atomName
  2664. a4Name = dih.atoms[3].atomName
  2665. line = "IMPRoper %-5s %-5s %-5s %-5s\n" % (a1Name, a2Name, a3Name,
  2666. a4Name)
  2667. topFile.write(line)
  2668. if self.chiral:
  2669. for idhc in self.chiralGroups:
  2670. _atc, neig, angle = idhc
  2671. a1Name = neig[0].atomName
  2672. a2Name = neig[1].atomName
  2673. a3Name = neig[2].atomName
  2674. a4Name = neig[3].atomName
  2675. line = "IMPRoper %-5s %-5s %-5s %-5s\n" % (a1Name, a2Name, a3Name,
  2676. a4Name)
  2677. topFile.write(line)
  2678. topFile.write("\nEND {RESIdue %s}\n" % self.residueLabel[0])
  2679. topFile.write("\nset echo=true end\n")
  2680. # print "Writing CNS INP file\n"
  2681. inpFile.write("Remarks " + head % (inp, date))
  2682. inpData = \
  2683. """
  2684. topology
  2685. @%(CNS_top)s
  2686. end
  2687. parameters
  2688. @%(CNS_par)s
  2689. nbonds
  2690. atom cdie shift eps=1.0 e14fac=0.4 tolerance=0.5
  2691. cutnb=9.0 ctonnb=7.5 ctofnb=8.0
  2692. nbxmod=5 vswitch wmin 1.0
  2693. end
  2694. remark dielectric constant eps set to 1.0
  2695. end
  2696. flags exclude elec ? end
  2697. segment name=" "
  2698. chain
  2699. coordinates @%(NEW_pdb)s
  2700. end
  2701. end
  2702. coordinates @%(NEW_pdb)s
  2703. coord copy end
  2704. ! Remarks If you want to shake up the coordinates a bit ...
  2705. vector do (x=x+6*(rand()-0.5)) (all)
  2706. vector do (y=y+6*(rand()-0.5)) (all)
  2707. vector do (z=z+6*(rand()-0.5)) (all)
  2708. write coordinates output=%(CNS_ran)s end
  2709. ! Remarks RMS diff after randomisation and before minimisation
  2710. coord rms sele=(known and not hydrogen) end
  2711. print threshold=0.02 bonds
  2712. print threshold=3.0 angles
  2713. print threshold=3.0 dihedrals
  2714. print threshold=3.0 impropers
  2715. ! Remarks Do Powell energy minimisation
  2716. minimise powell
  2717. nstep=250 drop=40.0
  2718. end
  2719. write coordinates output=%(CNS_min)s end
  2720. write structure output=%(CNS_psf)s end
  2721. ! constraints interaction (not hydro) (not hydro) end
  2722. print threshold=0.02 bonds
  2723. print threshold=3.0 angles
  2724. print threshold=3.0 dihedrals
  2725. print threshold=3.0 impropers
  2726. flags exclude * include vdw end energy end
  2727. distance from=(not hydro) to=(not hydro) cutoff=2.6 end
  2728. ! Remarks RMS fit after minimisation
  2729. coord fit sele=(known and not hydrogen) end
  2730. stop
  2731. """
  2732. dictInp = {}
  2733. dictInp['CNS_top'] = top
  2734. dictInp['CNS_par'] = par
  2735. dictInp['NEW_pdb'] = pdb
  2736. dictInp['CNS_min'] = self.baseName + '_NEW_min.pdb'
  2737. dictInp['CNS_psf'] = self.baseName + '_CNS.psf'
  2738. dictInp['CNS_ran'] = self.baseName + '_rand.pdb'
  2739. line = inpData % dictInp
  2740. inpFile.write(line)
  2741. if os.path.exists(self.obchiralExe):
  2742. self.printDebug("chiralGroups %i" % len(self.chiralGroups))
  2743. else:
  2744. self.printDebug("No 'obchiral' to process chiral atoms. Consider installing http://openbabel.org")
  2745. class ACTopol(AbstractTopol):
  2746. """
  2747. Class to build the AC topologies (Antechamber AmberTools)
  2748. """
  2749. def __init__(self, inputFile, chargeType='bcc', chargeVal=None,
  2750. multiplicity='1', atomType='gaff', force=False, basename=None,
  2751. debug=False, outTopol='all', engine='tleap', allhdg=False,
  2752. timeTol=36000, qprog='sqm', ekFlag=None, verbose=True,
  2753. gmx4=False, disam=False, direct=False, is_sorted=False, chiral=False):
  2754. self.debug = debug
  2755. self.verbose = verbose
  2756. self.gmx4 = gmx4
  2757. self.disam = disam
  2758. self.direct = direct
  2759. self.sorted = is_sorted
  2760. self.chiral = chiral
  2761. self.inputFile = os.path.basename(inputFile)
  2762. self.rootDir = os.path.abspath('.')
  2763. self.absInputFile = os.path.abspath(inputFile)
  2764. if not os.path.exists(self.absInputFile):
  2765. self.printWarn("input file doesn't exist")
  2766. baseOriginal, ext = os.path.splitext(self.inputFile)
  2767. base = basename or baseOriginal
  2768. self.baseOriginal = baseOriginal
  2769. self.baseName = base # name of the input file without ext.
  2770. self.timeTol = timeTol
  2771. self.printDebug("Max execution time tolerance is %s" % elapsedTime(self.timeTol))
  2772. self.ext = ext
  2773. if ekFlag == '"None"' or ekFlag is None:
  2774. self.ekFlag = ''
  2775. else:
  2776. self.ekFlag = '-ek %s' % ekFlag
  2777. self.extOld = ext
  2778. self.homeDir = self.baseName + '.acpype'
  2779. self.chargeType = chargeType
  2780. self.chargeVal = chargeVal
  2781. self.multiplicity = multiplicity
  2782. self.atomType = atomType
  2783. self.gaffDatfile = 'gaff.dat'
  2784. leapGaffFile = 'leaprc.gaff'
  2785. if '2' in self.atomType:
  2786. leapGaffFile = 'leaprc.gaff2'
  2787. self.gaffDatfile = 'gaff2.dat'
  2788. self.force = force
  2789. self.engine = engine
  2790. self.allhdg = allhdg
  2791. self.acExe = ''
  2792. dirAmber = os.getenv('AMBERHOME', os.getenv('ACHOME'))
  2793. if dirAmber:
  2794. for ac_bin in ['bin', 'exe']:
  2795. ac_path = os.path.join(dirAmber, ac_bin, 'antechamber')
  2796. if os.path.exists(ac_path):
  2797. self.acExe = ac_path
  2798. break
  2799. if not self.acExe:
  2800. self.acExe = _getoutput('which antechamber') or '' # '/Users/alan/Programmes/antechamber-1.27/exe/antechamber'
  2801. if not os.path.exists(self.acExe):
  2802. self.printError("no 'antechamber' executable!")
  2803. return None
  2804. self.tleapExe = _getoutput('which tleap') or ''
  2805. self.sleapExe = _getoutput('which sleap') or ''
  2806. self.parmchkExe = _getoutput('which parmchk2') or ''
  2807. self.babelExe = _getoutput('which babel') or ''
  2808. if not os.path.exists(self.babelExe):
  2809. if self.ext != '.mol2' and self.ext != '.mdl': # and self.ext != '.mol':
  2810. self.printError("no 'babel' executable; you need it if input is PDB")
  2811. self.printError("otherwise use only MOL2 or MDL file as input ... aborting!")
  2812. sys.exit(1)
  2813. else:
  2814. self.printWarn("no 'babel' executable, no PDB file as input can be used!")
  2815. acBase = base + '_AC'
  2816. self.acBaseName = acBase
  2817. self.acXyzFileName = acBase + '.inpcrd'
  2818. self.acTopFileName = acBase + '.prmtop'
  2819. self.acFrcmodFileName = acBase + '.frcmod'
  2820. self.tmpDir = os.path.join(self.rootDir, '.acpype_tmp_%s' % os.path.basename(base))
  2821. self.setResNameCheckCoords()
  2822. self.guessCharge()
  2823. acMol2FileName = '%s_%s_%s.mol2' % (base, chargeType, atomType)
  2824. self.acMol2FileName = acMol2FileName
  2825. self.charmmBase = '%s_CHARMM' % base
  2826. # check for which version of antechamber
  2827. if 'amber10' in self.acExe:
  2828. if qprog == 'sqm':
  2829. self.printWarn("SQM is not implemented in AmberTools 1.2")
  2830. self.printWarn("Setting mopac for antechamber")
  2831. qprog = 'mopac'
  2832. elif qprog == 'divcon':
  2833. if not os.path.exists(os.path.join(os.path.dirname(self.acExe), qprog)):
  2834. self.printWarn("DIVCON is not installed")
  2835. self.printWarn("Setting mopac for antechamber")
  2836. qprog = 'mopac'
  2837. elif 'amber1' in self.acExe:
  2838. if qprog == 'divcon':
  2839. self.printWarn("DIVCON is not implemented in AmberTools > 1.3 anymore")
  2840. self.printWarn("Setting sqm for antechamber")
  2841. qprog = 'sqm'
  2842. elif qprog == 'mopac':
  2843. if not os.path.exists(os.path.join(os.path.dirname(self.acExe), qprog)):
  2844. self.printWarn("MOPAC is not installed")
  2845. self.printWarn("Setting sqm for antechamber")
  2846. return None
  2847. qprog = 'sqm'
  2848. else:
  2849. self.printWarn("Old version of antechamber. Strongly consider upgrading to AmberTools")
  2850. self.printWarn("Setting mopac for antechamber")
  2851. qprog = 'mopac'
  2852. self.qFlag = qDict[qprog]
  2853. self.outTopols = [outTopol]
  2854. if outTopol == 'all':
  2855. self.outTopols = outTopols
  2856. self.acParDict = {'base': base, 'ext': ext[1:], 'acBase': acBase,
  2857. 'acMol2FileName': acMol2FileName, 'res': self.resName,
  2858. 'leapAmberFile': leapAmberFile, 'baseOrg': self.baseOriginal,
  2859. 'leapGaffFile': leapGaffFile}
  2860. class MolTopol(ACTopol):
  2861. """"
  2862. Class to write topologies and parameters files for several applications
  2863. http://amber.scripps.edu/formats.html (not updated to amber 10 yet)
  2864. Parser, take information in AC xyz and top files and convert to objects
  2865. INPUTS: acFileXyz and acFileTop
  2866. RETURN: molTopol obj or None
  2867. """
  2868. def __init__(self, acTopolObj=None, acFileXyz=None, acFileTop=None,
  2869. debug=False, basename=None, verbose=True, gmx4=False,
  2870. disam=False, direct=False, is_sorted=False, chiral=False):
  2871. self.chiral = chiral
  2872. self.obchiralExe = _getoutput('which obchiral') or ''
  2873. self.allhdg = False
  2874. self.debug = debug
  2875. self.gmx4 = gmx4
  2876. self.disam = disam
  2877. self.direct = direct
  2878. self.sorted = is_sorted
  2879. self.verbose = verbose
  2880. self.inputFile = acFileTop
  2881. if acTopolObj:
  2882. if not acFileXyz:
  2883. acFileXyz = acTopolObj.acXyzFileName
  2884. if not acFileTop:
  2885. acFileTop = acTopolObj.acTopFileName
  2886. self._parent = acTopolObj
  2887. self.allhdg = self._parent.allhdg
  2888. self.debug = self._parent.debug
  2889. self.inputFile = self._parent.inputFile
  2890. if not os.path.exists(acFileXyz) and not os.path.exists(acFileTop):
  2891. self.printError("Files '%s' and '%s' don't exist")
  2892. self.printError("molTopol object won't be created")
  2893. return None
  2894. # if not os.path.exists(self.obchiralExe) and self.chiral:
  2895. # self.printError("no 'obchiral' executable, it won't work to store non-planar improper dihedrals!")
  2896. # self.printWarn("Consider installing http://openbabel.org")
  2897. self.xyzFileData = open(acFileXyz, 'r').readlines()
  2898. self.topFileData = open(acFileTop, 'r').readlines()
  2899. self.printDebug("prmtop and inpcrd files loaded")
  2900. # self.pointers = self.getFlagData('POINTERS')
  2901. self.getResidueLabel()
  2902. if len(self.residueLabel) > 1:
  2903. self.baseName = basename or os.path.splitext(os.path.basename(acFileTop))[0] # 'solute'
  2904. else:
  2905. self.baseName = basename or self.residueLabel[0] # 3 caps letters
  2906. if acTopolObj:
  2907. self.baseName = basename or acTopolObj.baseName
  2908. self.printDebug("basename defined = '%s'" % self.baseName)
  2909. self.getAtoms()
  2910. self.getBonds()
  2911. self.getAngles()
  2912. self.getDihedrals()
  2913. self.getChirals()
  2914. if not os.path.exists(self.obchiralExe) and self.chiral:
  2915. self.printError("no 'obchiral' executable, it won't work to store non-planar improper dihedrals!")
  2916. self.printWarn("Consider installing http://openbabel.org")
  2917. elif self.chiral and not self.chiralGroups:
  2918. self.printWarn("No chiral atoms found")
  2919. # self.setAtomPairs()
  2920. # self.getExcludedAtoms()
  2921. # a list of FLAGS from acTopFile that matter
  2922. # self.flags = ( 'POINTERS', 'ATOM_NAME', 'CHARGE', 'MASS', 'ATOM_TYPE_INDEX',
  2923. # 'NUMBER_EXCLUDED_ATOMS', 'NONBONDED_PARM_INDEX',
  2924. # 'RESIDUE_LABEL', 'BOND_FORCE_CONSTANT', 'BOND_EQUIL_VALUE',
  2925. # 'ANGLE_FORCE_CONSTANT', 'ANGLE_EQUIL_VALUE',
  2926. # 'DIHEDRAL_FORCE_CONSTANT', 'DIHEDRAL_PERIODICITY',
  2927. # 'DIHEDRAL_PHASE', 'AMBER_ATOM_TYPE' )
  2928. # Sort atoms for gromacs output. # JDC
  2929. if self.sorted:
  2930. self.printMess("Sorting atoms for gromacs ordering.\n")
  2931. self.sortAtomsForGromacs()
  2932. class Atom(object):
  2933. """
  2934. Charges in prmtop file has to be divide by 18.2223 to convert to charge
  2935. in units of the electron charge.
  2936. To convert ACOEF and BCOEF to r0 (Ang.) and epsilon (kcal/mol), as seen
  2937. in gaff.dat for example; same atom type (i = j):
  2938. r0 = 1/2 * (2 * ACOEF/BCOEF)^(1/6)
  2939. epsilon = 1/(4 * A) * BCOEF^2
  2940. To convert r0 and epsilon to ACOEF and BCOEF
  2941. ACOEF = sqrt(ep_i * ep_j) * (r0_i + r0_j)^12
  2942. BCOEF = 2 * sqrt(ep_i * ep_j) * (r0_i + r0_j)^6
  2943. = 2 * ACOEF/(r0_i + r0_j)^6
  2944. where index i and j for atom types.
  2945. Coord is given in Ang. and mass in Atomic Mass Unit.
  2946. """
  2947. def __init__(self, atomName, atomType, id_, resid, mass, charge, coord):
  2948. self.atomName = atomName
  2949. self.atomType = atomType
  2950. self.id = id_
  2951. self.cgnr = id_
  2952. self.resid = resid
  2953. self.mass = mass
  2954. self.charge = charge # / qConv
  2955. self.coords = coord
  2956. def __str__(self):
  2957. return '<Atom id=%s, name=%s, %s>' % (self.id, self.atomName, self.atomType)
  2958. def __repr__(self):
  2959. return '<Atom id=%s, name=%s, %s>' % (self.id, self.atomName, self.atomType)
  2960. class AtomType(object):
  2961. """
  2962. AtomType per atom in gaff or amber.
  2963. """
  2964. def __init__(self, atomTypeName, mass, ACOEF, BCOEF):
  2965. self.atomTypeName = atomTypeName
  2966. self.mass = mass
  2967. self.ACOEF = ACOEF
  2968. self.BCOEF = BCOEF
  2969. def __str__(self):
  2970. return '<AtomType=%s>' % self.atomTypeName
  2971. def __repr__(self):
  2972. return '<AtomType=%s>' % self.atomTypeName
  2973. class Bond(object):
  2974. """
  2975. attributes: pair of Atoms, spring constant (kcal/mol), dist. eq. (Ang)
  2976. """
  2977. def __init__(self, atoms, kBond, rEq):
  2978. self.atoms = atoms
  2979. self.kBond = kBond
  2980. self.rEq = rEq
  2981. def __str__(self):
  2982. return '<%s, r=%s>' % (self.atoms, self.rEq)
  2983. def __repr__(self):
  2984. return '<%s, r=%s>' % (self.atoms, self.rEq)
  2985. class Angle(object):
  2986. """
  2987. attributes: 3 Atoms, spring constant (kcal/mol/rad^2), angle eq. (rad)
  2988. """
  2989. def __init__(self, atoms, kTheta, thetaEq):
  2990. self.atoms = atoms
  2991. self.kTheta = kTheta
  2992. self.thetaEq = thetaEq # rad, to convert to degree: thetaEq * 180/Pi
  2993. def __str__(self):
  2994. return '<%s, ang=%.2f>' % (self.atoms, self.thetaEq * 180 / Pi)
  2995. def __repr__(self):
  2996. return '<%s, ang=%.2f>' % (self.atoms, self.thetaEq * 180 / Pi)
  2997. class Dihedral(object):
  2998. """
  2999. attributes: 4 Atoms, spring constant (kcal/mol), periodicity,
  3000. phase (rad)
  3001. """
  3002. def __init__(self, atoms, kPhi, period, phase):
  3003. self.atoms = atoms
  3004. self.kPhi = kPhi
  3005. self.period = period
  3006. self.phase = phase # rad, to convert to degree: kPhi * 180/Pi
  3007. def __str__(self):
  3008. return '<%s, ang=%.2f>' % (self.atoms, self.phase * 180 / Pi)
  3009. def __repr__(self):
  3010. return '<%s, ang=%.2f>' % (self.atoms, self.phase * 180 / Pi)
  3011. if __name__ == '__main__':
  3012. t0 = time.time()
  3013. print(header)
  3014. parser = optparse.OptionParser(usage=usage + epilog)
  3015. parser.add_option('-i', '--input',
  3016. action="store",
  3017. dest='input',
  3018. help="input file name with either extension '.pdb', '.mdl' or '.mol2' (mandatory if -p and -x not set)",)
  3019. parser.add_option('-b', '--basename',
  3020. action="store",
  3021. dest='basename',
  3022. help='a basename for the project (folder and output files)',)
  3023. parser.add_option('-x', '--inpcrd',
  3024. action="store",
  3025. dest='inpcrd',
  3026. help="amber inpcrd file name (always used with -p)",)
  3027. parser.add_option('-p', '--prmtop',
  3028. action="store",
  3029. dest='prmtop',
  3030. help="amber prmtop file name (always used with -x)",)
  3031. parser.add_option('-c', '--charge_method',
  3032. type='choice',
  3033. choices=['gas', 'bcc', 'user'],
  3034. action="store",
  3035. default='bcc',
  3036. dest='charge_method',
  3037. help="charge method: gas, bcc (default), user (user's charges in mol2 file)",)
  3038. parser.add_option('-n', '--net_charge',
  3039. action="store",
  3040. type='int',
  3041. default=0,
  3042. dest='net_charge',
  3043. help="net molecular charge (int), for gas default is 0",)
  3044. parser.add_option('-m', '--multiplicity',
  3045. action="store",
  3046. type='int',
  3047. default=1,
  3048. dest='multiplicity',
  3049. help="multiplicity (2S+1), default is 1",)
  3050. parser.add_option('-a', '--atom_type',
  3051. type='choice',
  3052. choices=['gaff', 'amber', 'gaff2', 'amber2'], # , 'bcc', 'sybyl']
  3053. action="store",
  3054. default='gaff',
  3055. dest='atom_type',
  3056. help="atom type, can be gaff, gaff2, amber (AMBER14SB) or amber2 (AMBER14SB + GAFF2), default is gaff",)
  3057. parser.add_option('-q', '--qprog',
  3058. type='choice',
  3059. choices=['mopac', 'sqm', 'divcon'],
  3060. action="store",
  3061. default='sqm',
  3062. dest='qprog',
  3063. help="am1-bcc flag, sqm (default), divcon, mopac",)
  3064. parser.add_option('-k', '--keyword',
  3065. action="store",
  3066. dest='keyword',
  3067. help="mopac or sqm keyword, inside quotes",)
  3068. parser.add_option('-f', '--force',
  3069. action="store_true",
  3070. dest='force',
  3071. help='force topologies recalculation anew',)
  3072. parser.add_option('-d', '--debug',
  3073. action="store_true",
  3074. dest='debug',
  3075. help='for debugging purposes, keep any temporary file created',)
  3076. parser.add_option('-o', '--outtop',
  3077. type='choice',
  3078. choices=['all'] + outTopols,
  3079. action="store",
  3080. default='all',
  3081. dest='outtop',
  3082. help="output topologies: all (default), gmx, cns or charmm",)
  3083. parser.add_option('-z', '--gmx4',
  3084. action="store_true",
  3085. dest='gmx4',
  3086. help='write RB dihedrals old GMX 4.0',)
  3087. parser.add_option('-t', '--cnstop',
  3088. action="store_true",
  3089. dest='cnstop',
  3090. help='write CNS topology with allhdg-like parameters (experimental)',)
  3091. parser.add_option('-e', '--engine',
  3092. type='choice',
  3093. choices=['tleap', 'sleap'],
  3094. action="store",
  3095. default='tleap',
  3096. dest='engine',
  3097. help="engine: tleap (default) or sleap (not fully matured)",)
  3098. parser.add_option('-s', '--max_time',
  3099. action="store",
  3100. type='int',
  3101. default=36000,
  3102. dest='max_time',
  3103. help="max time (in sec) tolerance for sqm/mopac, default is 10 hours",)
  3104. parser.add_option('-y', '--ipython',
  3105. action="store_true",
  3106. dest='ipython',
  3107. help='start iPython interpreter',)
  3108. parser.add_option('-w', '--verboseless',
  3109. action="store_false",
  3110. default=True,
  3111. dest='verboseless',
  3112. help='print nothing',)
  3113. parser.add_option('-g', '--disambiguate',
  3114. action="store_true",
  3115. dest='disambiguate',
  3116. help='disambiguate lower and uppercase atomtypes in GMX top file',)
  3117. parser.add_option('-u', '--direct',
  3118. action="store_true",
  3119. dest='direct',
  3120. help="for 'amb2gmx' mode, does a direct conversion, for any solvent",)
  3121. parser.add_option('-l', '--sorted',
  3122. action="store_true",
  3123. dest='sorted',
  3124. help="sort atoms for GMX ordering",)
  3125. parser.add_option('-j', '--chiral',
  3126. action="store_true",
  3127. dest='chiral',
  3128. help="create improper dihedral parameters for chiral atoms in CNS",)
  3129. options, remainder = parser.parse_args()
  3130. amb2gmx = False
  3131. # if options.chiral:
  3132. # options.cnstop = True
  3133. if not options.input:
  3134. amb2gmx = True
  3135. if not options.inpcrd or not options.prmtop:
  3136. parser.error("missing input files")
  3137. elif options.inpcrd or options.prmtop:
  3138. parser.error("either '-i' or ('-p', '-x'), but not both")
  3139. if options.debug:
  3140. text = "Python Version %s" % verNum
  3141. print('DEBUG: %s' % text)
  3142. if options.direct and not amb2gmx:
  3143. parser.error("option -u is only meaningful in 'amb2gmx' mode")
  3144. try:
  3145. if amb2gmx:
  3146. print("Converting Amber input files to Gromacs ...")
  3147. system = MolTopol(acFileXyz=options.inpcrd, acFileTop=options.prmtop,
  3148. debug=options.debug, basename=options.basename,
  3149. verbose=options.verboseless, gmx4=options.gmx4,
  3150. disam=options.disambiguate, direct=options.direct,
  3151. is_sorted=options.sorted, chiral=options.chiral)
  3152. system.printDebug("prmtop and inpcrd files parsed")
  3153. system.writeGromacsTopolFiles(amb2gmx=True)
  3154. else:
  3155. molecule = ACTopol(options.input, chargeType=options.charge_method,
  3156. chargeVal=options.net_charge, debug=options.debug,
  3157. multiplicity=options.multiplicity, atomType=options.atom_type,
  3158. force=options.force, outTopol=options.outtop,
  3159. engine=options.engine, allhdg=options.cnstop,
  3160. basename=options.basename, timeTol=options.max_time,
  3161. qprog=options.qprog, ekFlag='''"%s"''' % options.keyword,
  3162. verbose=options.verboseless, gmx4=options.gmx4,
  3163. disam=options.disambiguate, direct=options.direct,
  3164. is_sorted=options.sorted, chiral=options.chiral)
  3165. if not molecule.acExe:
  3166. molecule.printError("no 'antechamber' executable... aborting ! ")
  3167. hint1 = "HINT1: is 'AMBERHOME' or 'ACHOME' environment variable set?"
  3168. hint2 = "HINT2: is 'antechamber' in your $PATH?\n What 'which antechamber' in your terminal says?\n 'alias' doesn't work for ACPYPE."
  3169. molecule.printMess(hint1)
  3170. molecule.printMess(hint2)
  3171. sys.exit(1)
  3172. molecule.createACTopol()
  3173. molecule.createMolTopol()
  3174. acpypeFailed = False
  3175. except:
  3176. exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
  3177. print("ACPYPE FAILED: %s" % exceptionValue)
  3178. if options.debug:
  3179. traceback.print_tb(exceptionTraceback, file=sys.stdout)
  3180. acpypeFailed = True
  3181. execTime = int(round(time.time() - t0))
  3182. if execTime == 0:
  3183. msg = "less than a second"
  3184. else:
  3185. msg = elapsedTime(execTime)
  3186. print("Total time of execution: %s" % msg)
  3187. if options.ipython:
  3188. try:
  3189. from IPython.Shell import IPShellEmbed # @UnresolvedImport @UnusedImport
  3190. except:
  3191. from IPython.frontend.terminal.embed import InteractiveShellEmbed as IPShellEmbed # @UnresolvedImport @Reimport
  3192. ipshell = IPShellEmbed()
  3193. ipshell()
  3194. try:
  3195. rmtree(molecule.tmpDir)
  3196. except:
  3197. pass
  3198. if acpypeFailed:
  3199. sys.exit(1)
  3200. try:
  3201. os.chdir(molecule.rootDir)
  3202. except:
  3203. pass

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/903151
推荐阅读
相关标签
  

闽ICP备14008679号