simulation.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. import glob
  2. import subprocess as sp
  3. import vmd
  4. from auto_namd.functions import *
  5. class Simulation:
  6. """
  7. A class representing a simulation of a job
  8. """
  9. def __init__(self, job, ffs_path, steps, namdbin, params):
  10. self.job = job
  11. self.steps = int(steps)
  12. self.namdbin = namdbin
  13. self.params = params
  14. # NAMD requires FF paths relative to the NAMD configuration file
  15. # and not the CWD. So we make the paths to the ffs absolute
  16. self.job.ffs_path = abs_path(san_path(ffs_path))
  17. self.job.ffs = self.get_ffs()
  18. self.job.next_stage, self.job.next_step = self.get_next_stage()
  19. self.job.conf, self.job.out = self.set_conf_out()
  20. print(self.info())
  21. self.namd_conf()
  22. self.namd()
  23. def get_next_stage(self):
  24. if self.job.stage == '4-sim':
  25. next_stage = '4-sim'
  26. next_step = self.job.step + self.steps
  27. elif self.job.stage == '3-heat':
  28. next_stage = '4-sim'
  29. next_step = self.steps
  30. elif self.job.stage == '2-min':
  31. next_stage = '3-heat'
  32. next_step = 0
  33. elif self.job.stage == '1-min':
  34. next_stage = '2-min'
  35. next_step = 0
  36. elif self.job.stage == '':
  37. next_stage = '1-min'
  38. next_step = 0
  39. return next_stage, int(next_step)
  40. def get_ffs(self):
  41. ffs = glob.glob(os.path.join(self.job.ffs_path, '*'))
  42. return ffs
  43. def set_conf_out(self):
  44. """Set the NAMD configration and NAMD output filenames"""
  45. if self.job.next_stage == '4-sim':
  46. conf = f'{self.job.prefix}_{self.job.next_stage}' \
  47. f'_{str(self.next_step)}.conf'
  48. out = f'{self.job.prefix}_{self.job.next_stage}' \
  49. f'_{str(self.job.next_step)}.out'
  50. else:
  51. conf = f'{self.job.prefix}_{self.job.next_stage}.conf'
  52. out = f'{self.job.prefix}_{self.job.next_stage}.out'
  53. return conf, out
  54. def namd_conf(self):
  55. if self.job.next_stage == '1-min':
  56. self.min1()
  57. if self.job.next_stage == '2-min':
  58. self.min2()
  59. if self.job.next_stage == '3-heat':
  60. self.heat()
  61. if self.job.next_stage == '4-sim':
  62. self.sim()
  63. def min1(self):
  64. steps = 15000
  65. with open(self.job.conf, 'w') as conf:
  66. conf.write('# Input\n')
  67. conf.write(f'structure {self.job.psf}\n')
  68. conf.write(f'coordinates {self.job.pdb}\n')
  69. conf.write('paraTypeCharmm on\n')
  70. for ff in job.ffs:
  71. conf.write(f'parameters {ff}\n')
  72. conf.write('\n')
  73. conf.write('# Temperature\n')
  74. conf.write('temperature 0\n')
  75. conf.write('\n')
  76. conf.write('# Force-Field Parameters\n')
  77. conf.write('exclude scaled1-4\n')
  78. conf.write('1-4scaling 1.0\n')
  79. conf.write('cutoff 12.\n')
  80. conf.write('switching on\n')
  81. conf.write('switchdist 10.\n')
  82. conf.write('pairlistdist 14\n')
  83. conf.write('\n')
  84. conf.write('# Integrator Parameters\n')
  85. conf.write('timestep 1.0 ;# 1fs/step\n')
  86. conf.write('nonbondedFreq 1\n')
  87. conf.write('fullElectFrequency 2\n')
  88. conf.write('stepspercycle 10\n')
  89. conf.write('\n')
  90. conf.write('# Output\n')
  91. conf.write(f'outputName {self.job.name}_{self.job.next_stage}_{steps}\n')
  92. conf.write('outputEnergies 100\n')
  93. conf.write('outputPressure 100\n')
  94. conf.write('\n')
  95. conf.write('# Run\n')
  96. conf.write(f'minimize {steps}')
  97. def min2(self):
  98. solv_ion(self.job)
  99. cbvx, cbvy, cbvz, corx, cory, corz = self.calc_pcell(self.job)
  100. steps = 15000
  101. with open(self.job.conf, 'w') as conf:
  102. conf.write('# Input\n')
  103. conf.write(f'structure {self.job.psf}\n')
  104. conf.write(f'coordinates {self.job.pdb}\n')
  105. conf.write('paraTypeCharmm on\n')
  106. for ff in self.job.ffs:
  107. conf.write(f'parameters {ff}\n')
  108. conf.write('\n')
  109. conf.write('# Temperature\n')
  110. conf.write('temperature 0\n')
  111. conf.write('\n')
  112. conf.write('# Periodic Boundary Conditions\n')
  113. conf.write('wrapWater on\n')
  114. conf.write('wrapAll on\n')
  115. conf.write(f'cellOrigin\t{corx}\t{cory}\t{corz}\n')
  116. conf.write(f'cellBasisVector1\t{cbvx}\t0.0\t0.0\n')
  117. conf.write(f'cellBasisVector2\t0.0\t{cbvy}\t0.0\n')
  118. conf.write(f'cellBasisVector3\t0.0\t0.0\t{cbvz}\n')
  119. conf.write('\n')
  120. conf.write('# Force-Field Parameters\n')
  121. conf.write('exclude scaled1-4\n')
  122. conf.write('1-4scaling 1.0\n')
  123. conf.write('cutoff 12.\n')
  124. conf.write('switching on\n')
  125. conf.write('switchdist 10.\n')
  126. conf.write('pairlistdist 14\n')
  127. conf.write('\n')
  128. conf.write('# Integrator Parameters\n')
  129. conf.write('timestep 1.0 ;# 1fs/step\n')
  130. conf.write('nonbondedFreq 1\n')
  131. conf.write('fullElectFrequency 2\n')
  132. conf.write('stepspercycle 10\n')
  133. conf.write('\n')
  134. conf.write('# Output\n')
  135. conf.write(f'outputName {self.job.name}_{self.job.next_stage}_{steps}\n')
  136. conf.write('outputEnergies 100\n')
  137. conf.write('outputPressure 100\n')
  138. conf.write('\n')
  139. conf.write('# Run\n')
  140. conf.write(f'minimize {steps}')
  141. def heat(self):
  142. temp_reinit_steps = 100
  143. steps = 10000
  144. final_steps = 30 * temp_reinit_steps + steps
  145. cbvx, cbvy, cbvz, corx, cory, corz = self.calc_pcell()
  146. with open(self.job.conf, 'w') as conf:
  147. conf.write('# Input\n')
  148. conf.write(f'structure {self.job.psf}\n')
  149. conf.write(f'coordinates {self.job.pdb}\n')
  150. conf.write(f'bincoordinates {self.job.coor}\n')
  151. conf.write('paraTypeCharmm on\n')
  152. for ff in self.job.ffs:
  153. conf.write(f'parameters {ff}\n')
  154. conf.write('\n')
  155. conf.write('# Temperature\n')
  156. conf.write('temperature 0\n')
  157. conf.write('\n')
  158. conf.write('# Periodic Boundary Conditions\n')
  159. conf.write('wrapWater on\n')
  160. conf.write('wrapAll on\n')
  161. conf.write(f'cellOrigin\t{corx}\t{cory}\t{corz}\n')
  162. conf.write(f'cellBasisVector1\t{cbvx}\t0.0\t0.0\n')
  163. conf.write(f'cellBasisVector2\t0.0\t{cbvy}\t0.0\n')
  164. conf.write(f'cellBasisVector3\t0.0\t0.0\t{cbvz}\n')
  165. conf.write('# Force-Field Parameters\n')
  166. conf.write('exclude scaled1-4\n')
  167. conf.write('1-4scaling 1.0\n')
  168. conf.write('cutoff 12.\n')
  169. conf.write('switching on\n')
  170. conf.write('switchdist 10.\n')
  171. conf.write('pairlistdist 14\n')
  172. conf.write('\n')
  173. conf.write('# Full Electrostatics\n')
  174. conf.write('PME on\n')
  175. conf.write('PMEGridSpacing 1.0\n')
  176. conf.write('\n')
  177. conf.write('# Integrator Parameters\n')
  178. conf.write('timestep 1.0 ;# 1fs/step\n')
  179. conf.write('nonbondedFreq 1\n')
  180. conf.write('fullElectFrequency 2\n')
  181. conf.write('stepspercycle 10\n')
  182. conf.write('\n')
  183. conf.write('# Output\n')
  184. conf.write(f'outputName {self.job.name}_{self.job.next_stage}_{self.job.next_step}\n')
  185. conf.write('outputEnergies 100\n')
  186. conf.write('outputPressure 100\n')
  187. conf.write('dcdfreq 1000\n')
  188. conf.write('\n')
  189. conf.write('# Constant Temperature Control\n')
  190. conf.write('langevin on ;# do langevin dynamics\n')
  191. conf.write('langevinDamping 0.5 ;# damping coefficient (gamma) of 0.5/ps\n')
  192. conf.write('langevinTemp 310\n')
  193. conf.write('langevinHydrogen yes ;# couple langevin bath to hydrogens\n')
  194. conf.write('\n')
  195. conf.write('# Constant Pressure Control\n')
  196. conf.write('useGroupPressure no ;# needed for 2fs steps\n')
  197. conf.write('useFlexibleCell yes ;# no for water box, yes for membrane\n')
  198. conf.write('useConstantRatio yes ;# no for water box, yes for membrane\n')
  199. conf.write('langevinPiston on\n')
  200. conf.write('langevinPistonTarget 1.01325 ;# in bar -> 1 atm\n')
  201. conf.write('langevinPistonPeriod 100.\n')
  202. conf.write('langevinPistonDecay 50.\n')
  203. conf.write('langevinPistonTemp 310\n')
  204. conf.write('\n')
  205. conf.write('# Run equilibration\n')
  206. conf.write(f'set freq {temp_reinit_steps}\n')
  207. conf.write('for {set i 10} {$i <= 310} {incr i 10} {\n')
  208. conf.write('reinitvels $i\n')
  209. conf.write('langevinTemp $i\n')
  210. conf.write('run $freq\n')
  211. conf.write('}\n')
  212. conf.write('# Run stabilization\n')
  213. conf.write(f'run {steps}')
  214. def sim(self):
  215. cbvx, cbvy, cbvz, corx, cory, corz = self.calc_pcell()
  216. with open(self.job.conf, 'w') as conf:
  217. conf.write('# Input\n')
  218. conf.write(f'structure {self.job.psf}\n')
  219. conf.write(f'coordinates {self.job.pdb}\n')
  220. conf.write(f'bincoordinates {self.job.coor}\n')
  221. conf.write('paraTypeCharmm on\n')
  222. for ff in self.job.ffs:
  223. conf.write(f'parameters {ff}\n')
  224. conf.write('\n')
  225. conf.write('# Temperature\n')
  226. conf.write('temperature 0\n')
  227. conf.write('\n')
  228. conf.write('# Periodic Boundary Conditions\n')
  229. conf.write('wrapWater on\n')
  230. conf.write('wrapAll on\n')
  231. conf.write(f'cellOrigin\t{corx}\t{cory}\t{corz}\n')
  232. conf.write(f'cellBasisVector1\t{cbvx}\t0.0\t0.0\n')
  233. conf.write(f'cellBasisVector2\t0.0\t{cbvy}\t0.0\n')
  234. conf.write(f'cellBasisVector3\t0.0\t0.0\t{cbvz}\n')
  235. conf.write('# Force-Field Parameters\n')
  236. conf.write('exclude scaled1-4\n')
  237. conf.write('1-4scaling 1.0\n')
  238. conf.write('cutoff 12.\n')
  239. conf.write('switching on\n')
  240. conf.write('switchdist 10.\n')
  241. conf.write('pairlistdist 14\n')
  242. conf.write('\n')
  243. conf.write('# Full Electrostatics\n')
  244. conf.write('PME on\n')
  245. conf.write('PMEGridSpacing 1.0\n')
  246. conf.write('\n')
  247. conf.write('# Integrator Parameters\n')
  248. conf.write('timestep 2.0 ;# 2fs/step\n')
  249. conf.write('rigidBonds all ;# needed for 2fs steps\n')
  250. conf.write('nonbondedFreq 1\n')
  251. conf.write('fullElectFrequency 2\n')
  252. conf.write('stepspercycle 10\n')
  253. conf.write('\n')
  254. conf.write('# Output\n')
  255. conf.write(f'outputName {self.job.name}_{self.job.next_stage}_{self.job.next_step}\n')
  256. conf.write('outputEnergies 10000\n')
  257. conf.write('outputPressure 10000\n')
  258. conf.write('dcdfreq 10000\n')
  259. conf.write('\n')
  260. conf.write('# Constant Temperature Control\n')
  261. conf.write('langevin on ;# do langevin dynamics\n')
  262. conf.write('langevinDamping 0.5 ;# damping coefficient (gamma) of 0.5/ps\n')
  263. conf.write('langevinTemp 310\n')
  264. conf.write('langevinHydrogen no ;# couple langevin bath to hydrogens\n')
  265. conf.write('\n')
  266. conf.write('# Constant Pressure Control\n')
  267. conf.write('useGroupPressure yes ;# needed for 2fs steps\n')
  268. conf.write('useFlexibleCell yes ;# no for water box, yes for membrane\n')
  269. conf.write('useConstantRatio yes ;# no for water box, yes for membrane\n')
  270. conf.write('langevinPiston on\n')
  271. conf.write('langevinPistonTarget 1.01325 ;# in bar -> 1 atm\n')
  272. conf.write('langevinPistonPeriod 100.\n')
  273. conf.write('langevinPistonDecay 50.\n')
  274. conf.write('langevinPistonTemp 310\n')
  275. conf.write('\n')
  276. conf.write('# Run\n')
  277. conf.write(f'run {self.job.steps}')
  278. def solv_ion(self):
  279. pdb_f = f'{self.job.prefix}_{self.job.stage}.pdb'
  280. psf_f = f'{self.job.prefix}.psf'
  281. solv_f = f'{self.job.prefix}_{self.job.stage}_solv'
  282. solv_ion_f = f'{self.job.prefix}_{self.job.stage}_solv_ion'
  283. molid = vmd.molecule.load('psf', psf_f, 'namdbin', self.job.coor)
  284. vmd.molecule.write(molid, 'pdb', pdb_f)
  285. vmd.evaltcl('package require solvate')
  286. vmd.evaltcl(f'solvate {self.job.psf} {pdb_f} -o {solv_f} '
  287. f'-s WT -x 13 -y 13 -z 13 +x 13 +y 13 +z 13 -b 2.4')
  288. vmd.evaltcl('package require autoionize')
  289. vmd.evaltcl(f'autoionize -psf {solv_f}.psf -pdb {solv_f}.pdb -o {solv_ion_f} '
  290. f'-sc 0.15')
  291. self.del_all_mols()
  292. def calc_pcell(self):
  293. if self.job.next_stage == '2-min' or self.job.next_stage == '3-min':
  294. molid = vmd.molecule.load('psf', self.job.psf, 'pdb', self.job.pdb)
  295. else:
  296. molid = vmd.molecule.load('psf', self.job.psf, 'namdbin', self.job.coor)
  297. all = vmd.atomsel("all", molid=molid)
  298. minmax = all.minmax()
  299. center = all.center()
  300. cbvx = minmax[1][0] - minmax[0][0]
  301. cbvy = minmax[1][1] - minmax[0][1]
  302. cbvz = minmax[1][2] - minmax[0][2]
  303. corx = center[0]
  304. cory = center[1]
  305. corz = center[2]
  306. self.del_all_mols()
  307. return cbvx, cbvy, cbvz, corx, cory, corz
  308. def del_all_mols(self):
  309. for mol in vmd.molecule.listall():
  310. vmd.molecule.delete(mol)
  311. def namd(self):
  312. cmd = f'{self.namdbin} {self.params} {self.job.conf} > {self.job.out}'
  313. print(f'Running: {cmd}')
  314. p1 = sp.run(cmd, shell=True)
  315. def info(self):
  316. print(f'Job Path: {self.job.path}\n'
  317. f'Name: {self.job.name}\n'
  318. f'Working PDB: {self.job.pdb}\n'
  319. f'Working PSF: {self.job.psf}\n'
  320. f'Working COOR: {self.job.coor}\n'
  321. f'Previous Step: {self.job.stage}\n'
  322. f'Previous Step Number: {str(self.job.step)}\n'
  323. f'Next Stage: {self.job.next_stage}\n'
  324. f'Next Step Number: {str(self.job.next_step)}\n'
  325. f'FF Path: {self.job.ffs_path}\n'
  326. f'FFs: {self.job.ffs}\n'
  327. )