packmol-memgen-minimal 1.1.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. packmol_memgen/__init__.py +2 -0
  2. packmol_memgen/__version__.py +34 -0
  3. packmol_memgen/data/LICENSE.Apache-2.0 +201 -0
  4. packmol_memgen/data/extra_solvents.lib +789 -0
  5. packmol_memgen/data/frcmod.lipid_ext +97 -0
  6. packmol_memgen/data/frcmod.solvents +129 -0
  7. packmol_memgen/data/insane_lipids.txt +138 -0
  8. packmol_memgen/data/insane_solvents.txt +45 -0
  9. packmol_memgen/data/leaprc.extra_solvents +42 -0
  10. packmol_memgen/data/leaprc.lipid_ext +48 -0
  11. packmol_memgen/data/lipid_ext.lib +12312 -0
  12. packmol_memgen/data/martini_v3.0.0.itp +356605 -0
  13. packmol_memgen/data/memgen.parm +4082 -0
  14. packmol_memgen/data/pdbs.tar.gz +0 -0
  15. packmol_memgen/data/solvent.parm +14 -0
  16. packmol_memgen/example/example.sh +31 -0
  17. packmol_memgen/lib/__init__.py +0 -0
  18. packmol_memgen/lib/amber.py +77 -0
  19. packmol_memgen/lib/charmmlipid2amber/__init__.py +0 -0
  20. packmol_memgen/lib/charmmlipid2amber/charmmlipid2amber.csv +7164 -0
  21. packmol_memgen/lib/charmmlipid2amber/charmmlipid2amber.py +225 -0
  22. packmol_memgen/lib/pdbremix/LICENSE +21 -0
  23. packmol_memgen/lib/pdbremix/__init__.py +0 -0
  24. packmol_memgen/lib/pdbremix/_version.py +1 -0
  25. packmol_memgen/lib/pdbremix/amber.py +1103 -0
  26. packmol_memgen/lib/pdbremix/asa.py +227 -0
  27. packmol_memgen/lib/pdbremix/data/aminoacid.pdb +334 -0
  28. packmol_memgen/lib/pdbremix/data/binaries.json +26 -0
  29. packmol_memgen/lib/pdbremix/data/charmm22.parameter +2250 -0
  30. packmol_memgen/lib/pdbremix/data/charmm22.topology +1635 -0
  31. packmol_memgen/lib/pdbremix/data/color_b.py +682 -0
  32. packmol_memgen/lib/pdbremix/data/hin.lib +130 -0
  33. packmol_memgen/lib/pdbremix/data/hydroxide.lib +88 -0
  34. packmol_memgen/lib/pdbremix/data/make_chi.py +92 -0
  35. packmol_memgen/lib/pdbremix/data/opls.parameter +1108 -0
  36. packmol_memgen/lib/pdbremix/data/opls.topology +1869 -0
  37. packmol_memgen/lib/pdbremix/data/phd.frcmod +82 -0
  38. packmol_memgen/lib/pdbremix/data/phd.leaprc +4 -0
  39. packmol_memgen/lib/pdbremix/data/phd.prepin +35 -0
  40. packmol_memgen/lib/pdbremix/data/template.pdb +334 -0
  41. packmol_memgen/lib/pdbremix/data/znb.frcmod +24 -0
  42. packmol_memgen/lib/pdbremix/data/znb.leaprc +7 -0
  43. packmol_memgen/lib/pdbremix/data/znb.lib +69 -0
  44. packmol_memgen/lib/pdbremix/data.py +264 -0
  45. packmol_memgen/lib/pdbremix/fetch.py +102 -0
  46. packmol_memgen/lib/pdbremix/force.py +627 -0
  47. packmol_memgen/lib/pdbremix/gromacs.py +978 -0
  48. packmol_memgen/lib/pdbremix/lib/__init__.py +0 -0
  49. packmol_memgen/lib/pdbremix/lib/docopt.py +579 -0
  50. packmol_memgen/lib/pdbremix/lib/pyqcprot.py +305 -0
  51. packmol_memgen/lib/pdbremix/namd.py +1078 -0
  52. packmol_memgen/lib/pdbremix/pdbatoms.py +543 -0
  53. packmol_memgen/lib/pdbremix/pdbtext.py +120 -0
  54. packmol_memgen/lib/pdbremix/protein.py +311 -0
  55. packmol_memgen/lib/pdbremix/pymol.py +480 -0
  56. packmol_memgen/lib/pdbremix/rmsd.py +203 -0
  57. packmol_memgen/lib/pdbremix/simulate.py +420 -0
  58. packmol_memgen/lib/pdbremix/spacehash.py +73 -0
  59. packmol_memgen/lib/pdbremix/trajectory.py +286 -0
  60. packmol_memgen/lib/pdbremix/util.py +273 -0
  61. packmol_memgen/lib/pdbremix/v3.py +16 -0
  62. packmol_memgen/lib/pdbremix/v3array.py +482 -0
  63. packmol_memgen/lib/pdbremix/v3numpy.py +350 -0
  64. packmol_memgen/lib/pdbremix/volume.py +155 -0
  65. packmol_memgen/lib/utils.py +1017 -0
  66. packmol_memgen/main.py +2827 -0
  67. packmol_memgen_minimal-1.1.16.dist-info/METADATA +664 -0
  68. packmol_memgen_minimal-1.1.16.dist-info/RECORD +71 -0
  69. packmol_memgen_minimal-1.1.16.dist-info/WHEEL +4 -0
  70. packmol_memgen_minimal-1.1.16.dist-info/entry_points.txt +2 -0
  71. packmol_memgen_minimal-1.1.16.dist-info/licenses/LICENSE +338 -0
@@ -0,0 +1,480 @@
1
+ # encoding: utf-8
2
+
3
+ __doc__ = """
4
+
5
+ Intrface to PYMOL with useful pre-processing.
6
+
7
+ As well various functions use PYMOL as an image generator of
8
+ protein structures.
9
+
10
+ A key concept in this module is that a viewing frame can be
11
+ defined by two residues:
12
+
13
+ 1. The center residue defines the viewing frame where the center
14
+ residue is in the middle of the screen directly over the
15
+ center of the system.
16
+ 2. The top residue defines the z-rotation of the above frame such
17
+ that the top residue is directly above the center residue
18
+ in the viewing frame.
19
+
20
+ This can be used to define reasonably close viewing frames to
21
+ any conceivable viewing frame.Several of the functions thus take
22
+ center_res and top_res parameters to define the viewing frame of
23
+ reference in PYMOL.
24
+ """
25
+
26
+ import os
27
+ from . import pdbatoms
28
+ from . import v3
29
+ from . import util
30
+ from . import data
31
+ from . import pdbtext
32
+ from . import protein
33
+
34
+
35
+ def get_pymol_id_from_res_tag(tag):
36
+ chain_id, res_num, insert = pdbatoms.split_tag(tag)
37
+ if chain_id == " ":
38
+ return "resi %d" % res_num
39
+ else:
40
+ return "(chain %s and resi %d%s)" % (chain_id, res_num, insert)
41
+
42
+
43
+ # Functions to transform PDB before rendering in PYMOL
44
+
45
+
46
+ def get_scale_max(max_bfactor, upper_bfactor):
47
+ scale_max = 4.0
48
+ if max_bfactor is not None and upper_bfactor is not None:
49
+ if max_bfactor < upper_bfactor:
50
+ scale_max *= max_bfactor / upper_bfactor
51
+ if scale_max < 1:
52
+ scale_max = 1
53
+ return scale_max
54
+
55
+
56
+ def add_fake_water_atom(soup, res_type, bfactor):
57
+ dummy_atom = pdbatoms.Atom()
58
+ dummy_atom.pos = soup.atoms()[0].pos.copy()
59
+ dummy_atom.type = "O"
60
+ dummy_atom.bfactor = bfactor
61
+ dummy_res = pdbatoms.Residue(res_type, '', 9999)
62
+ dummy_res.insert_atom(dummy_atom)
63
+ soup.append_residue(dummy_res)
64
+
65
+
66
+ def rescale_positive_bfactors_pdb(pdb, lower_bfactor, upper_bfactor):
67
+ """
68
+ Returns max_bfactor after rescale (needed for worm
69
+ calculation)
70
+ """
71
+ soup = pdbatoms.Soup(pdb)
72
+ bfactors = [a.bfactor for a in soup.atoms()]
73
+ # cut-off max_values
74
+ if upper_bfactor:
75
+ bfactors = [upper_bfactor if b > upper_bfactor else b
76
+ for b in bfactors]
77
+ # will delete later within pymol script
78
+ add_fake_water_atom(soup, 'XXX', upper_bfactor)
79
+ # cut-off below min_val to zero
80
+ if lower_bfactor:
81
+ for j in range(len(bfactors)):
82
+ bfactors = [0 if b < lower_bfactor else b for b in bfactors]
83
+ for a, bfactor in zip(soup.atoms(), bfactors):
84
+ a.bfactor = bfactor
85
+ new_pdb = util.fname_variant(pdb)
86
+ soup.write_pdb(new_pdb)
87
+ return new_pdb, max(bfactors)
88
+
89
+
90
+ def rescale_positive_bfactors_of_pdbs(pdbs, lower_bfactor, upper_bfactor):
91
+ "Returns list of new_pdbs, and max_bfactor"
92
+ max_bfactor = 0
93
+ new_pdbs = []
94
+ for pdb in pdbs:
95
+ new_pdb, this_max_bfactor = rescale_positive_bfactors_pdb(
96
+ pdb, lower_bfactor, upper_bfactor)
97
+ if this_max_bfactor > max_bfactor:
98
+ max_bfactor = this_max_bfactor
99
+ new_pdbs.append(new_pdb)
100
+ return new_pdbs, max_bfactor
101
+
102
+
103
+ def rescale_positive_negative_bfactors_pdb(
104
+ pdb, lower_bfactor, upper_bfactor):
105
+ """
106
+ Returns max_bfactor after rescale
107
+ """
108
+ soup = pdbatoms.Soup(pdb)
109
+ bfactors = [a.bfactor for a in soup.atoms()]
110
+ if upper_bfactor is None:
111
+ upper_bfactor = max(bfactors)
112
+ # cut-off max_values
113
+ if upper_bfactor:
114
+ for j in range(len(bfactors)):
115
+ if bfactors[j] > upper_bfactor:
116
+ bfactors[j] = upper_bfactor
117
+ if bfactors[j] < -upper_bfactor:
118
+ bfactors[j] = -upper_bfactor
119
+ # will delete later within pymol script
120
+ add_fake_water_atom(soup, 'XXX', upper_bfactor)
121
+ add_fake_water_atom(soup, 'XXX', -upper_bfactor)
122
+ # cut-off below min_val to zero
123
+ if lower_bfactor:
124
+ for j in range(len(bfactors)):
125
+ if -lower_bfactor < bfactors[j] < lower_bfactor:
126
+ bfactors[j] = 0.0
127
+ for a, bfactor in zip(soup.atoms(), bfactors):
128
+ a.bfactor = bfactor
129
+ new_pdb = util.fname_variant(pdb)
130
+ soup.write_pdb(new_pdb)
131
+ return new_pdb, max(bfactors)
132
+
133
+
134
+ def rescale_positive_negative_bfactor_pdbs(
135
+ pdbs, lower_bfactor, upper_bfactor):
136
+ "Returns list of new_pdbs, and max_bfactor"
137
+ max_bfactor = 0
138
+ new_pdbs = []
139
+ for pdb in pdbs:
140
+ new_pdb, this_max_bfactor = \
141
+ rescale_positive_negative_bfactors_pdb(
142
+ pdb, lower_bfactor, upper_bfactor)
143
+ if this_max_bfactor > max_bfactor:
144
+ max_bfactor = this_max_bfactor
145
+ new_pdbs.append(new_pdb)
146
+ return new_pdbs, max_bfactor
147
+
148
+
149
+ # PYMOL script functions and snippets
150
+
151
+ def make_bgcolor_script(bg_color):
152
+ return "cmd.bg_color('%s');\n" % bg_color
153
+
154
+
155
+ def make_load_pdbs_script(pdbs):
156
+ "Returns pymol script, name of pdbs"
157
+ script = ""
158
+ for pdb in pdbs:
159
+ script += "load %s\n" % pdb
160
+ script += "hide everything\n"
161
+ return script
162
+
163
+
164
+ def make_separate_chain_colors_script(pdbs):
165
+ names = [os.path.basename(p).replace('.pdb', '')
166
+ for p in pdbs]
167
+ colors = ['util.color_chains("(%s and elem c)")\n' % n
168
+ for n in names]
169
+ return ''.join(colors)
170
+
171
+
172
+ red_white_gradient_script = """\
173
+ run %s
174
+ color_b all, gradient=wr
175
+ """ % os.path.join(data.data_dir, "color_b.py")
176
+
177
+
178
+ blue_white_red_gradient_script = """\
179
+ cmd.spectrum("b", "blue_white_red", selection="all");
180
+ """
181
+
182
+
183
+ cartoon_script = """
184
+ set cartoon_flat_sheets, 0
185
+ set cartoon_rect_width, 0.2
186
+ set cartoon_oval_width, 0.2
187
+ set cartoon_loop_radius, 0.2
188
+ set cartoon_tube_radius, 0.2
189
+ cartoon auto
190
+ show cartoon
191
+ """
192
+
193
+
194
+ putty_script = """
195
+ set cartoon_flat_sheets, 0
196
+ set cartoon_putty_scale_max, %(scale_max)f
197
+ set cartoon_putty_radius, 0.4
198
+ set cartoon_putty_scale_power, 1
199
+ cartoon putty
200
+ show cartoon
201
+ """
202
+
203
+
204
+ def make_putty_script(scale_max):
205
+ return putty_script % { 'scale_max': scale_max }
206
+
207
+
208
+ def make_sticks_above_bfactor_script(lower_bfactor):
209
+ script = ""
210
+ script += "select hot, b > %f or b < -%f\n" % \
211
+ (lower_bfactor, lower_bfactor)
212
+ script += "select cold, b < %f and b > -%f\n" % \
213
+ (lower_bfactor, lower_bfactor)
214
+ script += "show stick, hot\n"
215
+ script += "hide stick, cold\n"
216
+ script += "deselect\n"
217
+ return script
218
+
219
+
220
+ def make_ligands_as_sticks_script(pdbs, color=""):
221
+ script = ""
222
+ for pdb in pdbs:
223
+ name = os.path.basename(pdb).replace('.pdb', '')
224
+ soup = pdbatoms.Soup(pdb)
225
+ for res in soup.residues():
226
+ if res.type not in data.res_name_to_char:
227
+ if res.type not in "HOH":
228
+ chain_id_script = ""
229
+ if res.chain_id.strip():
230
+ chain_id_script = "and chain %s" % res.chain_id
231
+ script += \
232
+ "show stick, %s %s and resn %s and resi %d\n" \
233
+ % (name, chain_id_script, res.type, res.num)
234
+ if color:
235
+ script += \
236
+ "color %s, %s %s and resn %s and resi %d\n" \
237
+ % (color, name, chain_id_script, res.type, res.num)
238
+ script += "show nonbonded\n"
239
+ return script
240
+
241
+
242
+ highlight_res_script = """
243
+ select highlight, %s
244
+ show stick, highlight
245
+ color green, highlight
246
+ """
247
+
248
+
249
+ def make_highlight_res_script(pymol_res_id):
250
+ return highlight_res_script % pymol_res_id
251
+
252
+
253
+ peptide_style_script = """
254
+ select bb, name ca+n+h+o+c+oxt+h1+h2+h3+ch3+hh31+hh32+hh33+3hh3+2hh3+1hh3
255
+ show sphere, bb
256
+ hide stick, bb
257
+ util.cbaw bb
258
+ select sc, not bb and not hydro
259
+ show stick, sc
260
+ hide sphere, sc
261
+ util.cbag sc
262
+ set sphere_quality, 2
263
+ """
264
+
265
+
266
+ hide_backbone_sticks_script = """
267
+ hide stick, hydro
268
+ select bb, name c+o+n+h+oxt
269
+ hide stick, bb
270
+ select nuc, resn A+U+T+C+G+A3+U3+T3+C3+G3+A5+U5+T5+C5+G5+DA+DT+DC+DG
271
+ select nuc_bb, name P+O1P+O2P+OP1+Op2+O3'+C3'+C2'+C1'+O4'+C4'+C5'+O5'
272
+ hide cartoon, nuc and not nuc_bb
273
+ deselect
274
+ """
275
+
276
+
277
+ def bfactor_script(pdb, lower_bfactor=None, upper_bfactor=None,
278
+ max_bfactor=None, is_putty=False):
279
+ "Returns script that displays bfactors of pdb"
280
+ script = make_load_pdbs_script([pdb])
281
+ script += red_white_gradient_script
282
+ if is_putty:
283
+ script += make_putty_script(get_scale_max(max_bfactor, upper_bfactor))
284
+ else:
285
+ script += cartoon_script
286
+ script += "cartoon tube\n"
287
+ if not is_putty:
288
+ if lower_bfactor is not None:
289
+ script += make_sticks_above_bfactor_script(lower_bfactor)
290
+ else:
291
+ script += "show stick\n"
292
+ script += make_ligands_as_sticks_script([pdb])
293
+ script += hide_backbone_sticks_script
294
+ return script
295
+
296
+
297
+
298
+ def split_resname(resname):
299
+ "Returns (chain_id, res_num)"
300
+ words = resname.split(":")
301
+ if len(words) == 2:
302
+ return (words[0], int(words[1]))
303
+ else:
304
+ return (' ', int(words[0]))
305
+
306
+
307
+ def find_ca_of_resname(atoms, resname):
308
+ chain_id, res_num = split_resname(resname)
309
+ for atom in atoms:
310
+ if chain_id == atom.chain_id and res_num == atom.res_num:
311
+ if "CA" == atom.type:
312
+ return atom
313
+ return None
314
+
315
+
316
+ def get_pdb_transform(pdb, center_res, top_res):
317
+ """
318
+ Returns a transformation matrix that centers pdb to
319
+ center_res on the z-axis and moves top_res above center_res
320
+ on the y-axis
321
+ """
322
+ soup = pdbatoms.Soup(pdb)
323
+ atoms = soup.atoms()
324
+ soup_center = pdbatoms.get_center(atoms)
325
+ translation = v3.translation(-soup_center)
326
+ soup.transform(translation)
327
+ result = translation
328
+
329
+ center_atom = find_ca_of_resname(soup.atoms(), center_res)
330
+ view = v3.vector(0, 0, 1)
331
+ axis = v3.cross(view, center_atom.pos)
332
+ angle = v3.vec_dihedral(view, axis, center_atom.pos)
333
+ rotation = v3.rotation(axis, angle)
334
+ soup.transform(rotation)
335
+ result = v3.combine(rotation, result)
336
+
337
+ top_atom = find_ca_of_resname(soup.atoms(), top_res)
338
+ top_dir = v3.vector(0, 1, 0)
339
+ axis = view.copy()
340
+ angle = v3.vec_dihedral(top_dir, axis, top_atom.pos)
341
+ rotation2 = v3.rotation(axis, angle)
342
+ result = v3.combine(rotation2, result)
343
+
344
+ del soup
345
+ return result
346
+
347
+
348
+
349
+ def run_pymol_script(pml, width=500, height=500):
350
+ is_quit = 'quit' in util.words_in_file(pml)
351
+ if is_quit:
352
+ pymol_batch = data.binary("pymol_batch")
353
+ cmd = pymol_batch + ' -c '
354
+ else:
355
+ pymol = data.binary("pymol")
356
+ cmd = pymol + " -q " # no splash screen
357
+ cmd += " -W %d -H %d " % (width, height)
358
+ cmd += pml
359
+ util.run_with_output(cmd)
360
+
361
+
362
+ # Functions to generate PNG's with PYMOL
363
+
364
+
365
+ def pdb_to_bfactor_png(
366
+ bfactor_pdb, png, lower_bfactor=None, upper_bfactor=None,
367
+ highlight_res=None, is_putty=False, is_sticks=True,
368
+ center_res=None, top_res=None, height=480, width=480):
369
+ """
370
+ Generates a bfactor-colored .png using the standard white-to-red
371
+ color scheme with a useful set of options. highlight_res,
372
+ center_res & top_res follow the 'A:10' style of residue naming.
373
+ """
374
+
375
+ pdb, max_bfactor = rescale_positive_bfactors_pdb(
376
+ bfactor_pdb, lower_bfactor, upper_bfactor)
377
+ temp_fnames = [pdb]
378
+
379
+ if center_res or top_res:
380
+ pdb = get_pdb_transform(pdb, center_res, top_res)
381
+ temp_fnames.append(pdb)
382
+
383
+ script = ""
384
+
385
+ script += bfactor_script(
386
+ pdb, lower_bfactor, upper_bfactor,
387
+ max_bfactor, is_putty)
388
+
389
+ if highlight_res is not None:
390
+ pymol_res_id = get_pymol_id_from_res_tag(highlight_res)
391
+ script += make_highlight_res_script(pymol_res_id)
392
+ script += hide_backbone_sticks_script
393
+
394
+ script += "clip far, -20\n"
395
+ script += "save %s\n" % png
396
+ script += "quit"
397
+
398
+ pml = util.fname_variant('temp.pml')
399
+ open(pml, 'w').write(script)
400
+ run_pymol_script(pml, width, height)
401
+ temp_fnames.append(pml)
402
+
403
+ util.clean_fname(*temp_fnames)
404
+
405
+
406
+ def soup_to_bfactor_png(
407
+ soup, png, bfactors, lower_bfactor=None, upper_bfactor=None,
408
+ highlight_res=None, is_putty=False, is_sticks=True,
409
+ center_res=None, top_res=None, height=480, width=480):
410
+ """
411
+ Wrapper around pdb_to_bfactor that loads in external values
412
+ for the residue bfactors with a reusable soup object.
413
+ """
414
+ pdb = util.temp_fname('.pdb')
415
+ temp_fnames = [pdb]
416
+ soup.load_residue_bfactors(bfactors)
417
+ soup.write_pdb(pdb)
418
+ pdb_to_bfactor_png(
419
+ pdb, png, lower_bfactor, upper_bfactor,
420
+ highlight_res, is_putty, is_sticks,
421
+ center_res, top_res, height, width)
422
+ util.clean_fname(*temp_fnames)
423
+
424
+
425
+ def make_pdbs_png(
426
+ png, pdbs, bgcolor="white", center_res=None, top_res=None,
427
+ highlight_res=None, is_sticks=True, is_putty=False,
428
+ width=480, height=480):
429
+
430
+ if 'transparent' in bgcolor:
431
+ script = 'set opaque_background, off\n'
432
+ else:
433
+ script = make_bgcolor_script(bgcolor)
434
+
435
+ temp_fnames = []
436
+ if center_res and top_res:
437
+ transform = get_pdb_transform(pdbs[0], center_res, top_res)
438
+ for i in range(len(pdbs)):
439
+ soup = pdbatoms.Soup(pdbs[i])
440
+ soup.transform(transform)
441
+ new_pdb = util.fname_variant(pdbs[i])
442
+ soup.write_pdb(new_pdb)
443
+ temp_fnames.append(new_pdb)
444
+ pdbs[i] = new_pdb
445
+ del soup
446
+
447
+ script += make_load_pdbs_script(pdbs)
448
+ script += make_separate_chain_colors_script(pdbs)
449
+
450
+ if is_putty:
451
+ script += make_putty_script(get_scale_max(
452
+ max_bfactor, upper_bfactor))
453
+ else:
454
+ script += cartoon_script
455
+
456
+ if not is_sticks:
457
+ script += "hide stick\n"
458
+ else:
459
+ script += "show stick\n"
460
+
461
+ script += make_ligands_as_sticks_script(pdbs)
462
+
463
+ if highlight_res:
464
+ script += make_highlight_res_script(highlight_res)
465
+ script += hide_backbone_sticks_script
466
+
467
+ # script += "clip far, 5\n"
468
+ script += "save %s\n" % png
469
+ script += "quit"
470
+
471
+ pml = util.fname_variant('temp.pml')
472
+ open(pml, 'w').write(script)
473
+ run_pymol_script(pml, width, height)
474
+ temp_fnames.append(pml)
475
+
476
+ util.clean_fname(*temp_fnames)
477
+
478
+
479
+
480
+
@@ -0,0 +1,203 @@
1
+ # encoding: utf-8
2
+
3
+ __doc__ = """
4
+
5
+ RMSD calculators and optimal rotation of sets of coordinates.
6
+
7
+ Two algorithms are provided:
8
+
9
+ 1. The standard SVD decomposition using the numpy library.
10
+ 2. The qcp quaternion-based method that doesn't need numpy.
11
+
12
+ The qcp method is particularly useful because it allows the
13
+ library to function without numpy such as when run with pypy.
14
+ """
15
+
16
+ from . import v3
17
+ from . import pdbatoms
18
+ import math
19
+ from .lib import pyqcprot
20
+ try:
21
+ import numpy
22
+ is_numpy = True
23
+ except:
24
+ is_numpy = False
25
+
26
+ standard_residues = {"CYS","MET","HIS","HSD","HIE","SER","GLN","ASP","GLU","TYR","THR","ALA","LEU","ILE","PHE","TRP","ARG","ASN","LYS","VAL","PRO","GLY"}
27
+
28
+ def numpy_svd_rmsd_rot(in_crds1, in_crds2):
29
+ """
30
+ Returns rmsd and optional rotation between 2 sets of [nx3] arrays.
31
+
32
+ This requires numpy for svd decomposition.
33
+ The transform direction: transform(m, ref_crd) => target_crd.
34
+ """
35
+
36
+ crds1 = numpy.array(in_crds1)
37
+ crds2 = numpy.array(in_crds2)
38
+ assert(crds1.shape[1] == 3)
39
+ assert(crds1.shape == crds2.shape)
40
+
41
+
42
+ n_vec = numpy.shape(crds1)[0]
43
+ correlation_matrix = numpy.dot(numpy.transpose(crds1), crds2)
44
+ v, s, w = numpy.linalg.svd(correlation_matrix)
45
+ is_reflection = (numpy.linalg.det(v) * numpy.linalg.det(w)) < 0.0
46
+
47
+ if is_reflection:
48
+ s[-1] = - s[-1]
49
+ E0 = sum(sum(crds1 * crds1)) + \
50
+ sum(sum(crds2 * crds2))
51
+ rmsd_sq = (E0 - 2.0*sum(s)) / float(n_vec)
52
+ rmsd_sq = max([rmsd_sq, 0.0])
53
+ rmsd = numpy.sqrt(rmsd_sq)
54
+
55
+ if is_reflection:
56
+ v[-1,:] = -v[-1,:]
57
+ rot33 = numpy.dot(v, w)
58
+ m = v3.identity()
59
+ m[:3,:3] = rot33.transpose()
60
+
61
+ return rmsd, m
62
+
63
+
64
+ def pyqcprot_rmsd_rot(crds1, crds2):
65
+ """
66
+ Returns rmsd and optional rotation between 2 sets of [nx3] arrays.
67
+
68
+ This requires Joshua Adelman's pyqcrot library for quaternion-based
69
+ calculation of Theobauld. The transform direction:
70
+ transform(m, ref_crd) => target_crd.
71
+ """
72
+ rms, rot9 = lib.pyqcprot.calc_rms_rot(crds1, crds2)
73
+ matrix = v3.identity()
74
+ for i in range(3):
75
+ for j in range(3):
76
+ v3.matrix_elem(matrix, i, j, rot9[i*3+j])
77
+ return rms, matrix
78
+
79
+
80
+ def calc_rmsd_rot(crds1, crds2):
81
+ """
82
+ Returns the rmsd and optimal rotation and chooses the method
83
+ depending on whether numpy is installed.
84
+ """
85
+ if is_numpy:
86
+ return numpy_svd_rmsd_rot(crds1, crds2)
87
+ else:
88
+ return pyqcprot_rmsd_rot(crds1, crds2)
89
+
90
+
91
+ def sum_rmsd(crds1, crds2):
92
+ """
93
+ Returns the direct rmsd between two sets of vectors *without*
94
+ doing any optimal rotation. If calculated between optimal sets,
95
+ should give the proper RMSD.
96
+ """
97
+ sum_squared = 0.0
98
+ for crd1, crd2 in zip(crds1, crds2):
99
+ sum_squared += v3.distance(crd1, crd2)**2
100
+ return math.sqrt(sum_squared/float(len(crds1)))
101
+
102
+
103
+ def get_superposable_atoms(soup, segments, atom_types, standard=False):
104
+ """
105
+ Returns a list of atom indices to a soup, built from segments.
106
+
107
+ Args:
108
+ segments (list): list of pairs of residue names in the soup,
109
+ such as ['A:1','A:3'], interpreted as the
110
+ two ends of a fragment in soup that we want
111
+ the atom index of
112
+ atom_types (list): list of atom_types in the residues that
113
+ we want to generate the indices from.
114
+ """
115
+ result = []
116
+ allowed_i = []
117
+ residues = soup.residues()
118
+ if segments:
119
+ for res_tag_i, res_tag_j in segments:
120
+ i = soup.get_i_residue(str(res_tag_i))
121
+ j = soup.get_i_residue(str(res_tag_j))
122
+ if i > j:
123
+ i, j = j, i
124
+ allowed_i.extend(list(range(i,j+1)))
125
+ else:
126
+ allowed_i = list(range(len(residues)))
127
+ for i, residue in enumerate(residues):
128
+ if i in allowed_i:
129
+ if standard:
130
+ result.extend([a for a in residue.atoms()
131
+ if a.type in atom_types and residue.type in standard_residues])
132
+ else:
133
+ result.extend([a for a in residue.atoms()
134
+ if a.type in atom_types])
135
+ return result
136
+
137
+
138
+ def rmsd_of_soups(
139
+ soup1, soup2, segments1=[], segments2=[],
140
+ atom_types=['CA'], transform_pdb1=None, standard=False):
141
+ """
142
+ Returns the RMSD between two PDB structures and optionally
143
+ writes the best transformed structure of pdb1 in transform_pdb.
144
+
145
+ By default, it chooses the CA atoms in the soup.
146
+
147
+ Args:
148
+ segments1 (list): list of pairs of residue names in pdb1,
149
+ such as ['A:1','A:3'], interpreted as the
150
+ two ends of a fragment in soup that we want
151
+ the atom index of
152
+ segments2 (list): same as above but for pdb2
153
+ atom_types (list): list of atom_types in the residues that
154
+ we want to generate the indices from.
155
+ """
156
+ atoms1 = get_superposable_atoms(soup1, segments1, atom_types, standard)
157
+ atoms2 = get_superposable_atoms(soup2, segments2, atom_types, standard)
158
+
159
+ crds1 = [a.pos for a in atoms1]
160
+ crds2 = [a.pos for a in atoms2]
161
+
162
+ center1 = v3.get_center(crds1)
163
+ center2 = v3.get_center(crds2)
164
+
165
+ soup1.transform(v3.translation(-center1))
166
+ soup2.transform(v3.translation(-center2))
167
+
168
+ rmsd, transform_1_to_2 = calc_rmsd_rot(crds1, crds2)
169
+
170
+ if not transform_pdb1:
171
+ return rmsd
172
+
173
+ soup1.transform(transform_1_to_2)
174
+
175
+ soup1.transform(v3.translation(center2))
176
+ soup2.transform(v3.translation(center2))
177
+
178
+ soup1.write_pdb(transform_pdb1)
179
+ return sum_rmsd(crds1, crds2)
180
+
181
+
182
+ def rmsd_of_pdbs(
183
+ pdb1, pdb2, segments1=[], segments2=[],
184
+ atom_types=['CA'], transform_pdb1=None, standard=False):
185
+ """
186
+ Returns the RMSD between two PDB structures and optionally
187
+ writes the best transformed structure of pdb1 in transform_pdb.
188
+
189
+ Args:
190
+ segments1 (list): list of pairs of residue names in pdb1,
191
+ such as ['A:1','A:3'], interpreted as the
192
+ two ends of a fragment in soup that we want
193
+ the atom index of
194
+ segments2 (list): same as above but for pdb2
195
+ atom_types (list): list of atom_types in the residues that
196
+ we want to generate the indices from.
197
+ """
198
+ soup1 = pdbatoms.Soup(pdb1)
199
+ soup2 = pdbatoms.Soup(pdb2)
200
+ return rmsd_of_soups(
201
+ soup1, soup2, segments1, segments2,
202
+ atom_types, transform_pdb1, standard)
203
+