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,543 @@
1
+ # encoding: utf-8
2
+
3
+ __doc__ = """
4
+
5
+ Provides the Soup object to manipulate protein structures.
6
+
7
+ The Soup object contains a list of Atom objects, which are also
8
+ grouped into a list of Residues. The Residues provide a
9
+ convenient way to search and access Atoms.
10
+
11
+ Specifically, chain_ids are not used to organize the data
12
+ structures. In the author's experience, for the amount of work to
13
+ maintain chain structure, not much utility is gained. As well,
14
+ chain_id has only loose semantics that are not strictly
15
+ hierchical to residues. By sticking to a Soup as a group of
16
+ residues, the resultant data structure is much cleaner. Chain
17
+ analysis can easily be done on a case-by-case basis.
18
+ """
19
+
20
+
21
+ from . import v3
22
+ import copy
23
+ import string
24
+
25
+ from . import data
26
+
27
+
28
+ class Atom:
29
+ """
30
+ This is the basic object to hold Atom information.
31
+
32
+ The attributes are basically those of a PDB atom field.
33
+ However, pos and vel are proper vectors that can be manipulated
34
+ with the v3 3d-vector geometry library.
35
+ """
36
+
37
+ def __init__(self, pos=None, atom_type="", res_num=None):
38
+ """
39
+ Normally initialized as an empty container, and filled
40
+ up progressively as fields are read by parsers.
41
+ """
42
+ self.is_hetatm = False
43
+ self.pos = v3.vector() if pos is None else pos
44
+ self.vel = v3.vector()
45
+ self.mass = 0.0
46
+ self.charge = 0.0
47
+ self.type = ""
48
+ self.element = ""
49
+ self.chain_id = " "
50
+ self.res_type = ""
51
+ self.res_num = ""
52
+ self.res_insert = ""
53
+ self.bfactor = 0.0
54
+ self.occupancy = 0.0
55
+ self.num = 0
56
+ self.alt_conform = " "
57
+
58
+ def copy(self):
59
+ return copy.deepcopy(self)
60
+
61
+ def type_str(self):
62
+ """
63
+ Format atom_type to write to a PDB file's atom line.
64
+ """
65
+ atom_type = self.type.strip()
66
+ if len(atom_type) == 1:
67
+ atom_type = " %s " % atom_type
68
+ elif len(atom_type) == 2:
69
+ if atom_type[0].isdigit():
70
+ atom_type = "%s " % atom_type
71
+ else:
72
+ atom_type = " %s " % atom_type
73
+ elif len(atom_type) == 3:
74
+ if atom_type[0].isdigit():
75
+ atom_type = "%s " % atom_type
76
+ else:
77
+ atom_type = " %s" % atom_type
78
+ return atom_type
79
+
80
+ def pdb_str(self):
81
+ """
82
+ Returns a string for output to an PDB file.
83
+ """
84
+ if self.is_hetatm:
85
+ field = "HETATM"
86
+ else:
87
+ field = "ATOM "
88
+ x, y, z = self.pos
89
+ s = "%6s%5s %4s %-4s%1s%4s%1s %8.3f%8.3f%8.3f%6.2f%6.2f" % \
90
+ (field,
91
+ str(self.num)[-5:],
92
+ self.type_str(),
93
+ self.res_type,
94
+ self.chain_id,
95
+ str(self.res_num)[-4:],
96
+ self.res_insert,
97
+ x, y, z,
98
+ self.occupancy,
99
+ self.bfactor)
100
+ return s
101
+
102
+ def res_tag(self):
103
+ tag = ""
104
+ if self.chain_id != " " and self.chain_id != "":
105
+ tag += self.chain_id + ":"
106
+ tag += str(self.res_num)
107
+ if self.res_insert:
108
+ tag += self.res_insert
109
+ return tag
110
+
111
+ def __str__(self):
112
+ x, y, z = self.pos
113
+ return "%s:%s-%s" % \
114
+ (self.res_tag(), self.res_type, self.type)
115
+
116
+ def transform(self, matrix):
117
+ """
118
+ Transforms the pos vector by a v3.transform matrix.
119
+ """
120
+ new_pos = v3.transform(matrix, self.pos)
121
+ v3.set_vector(self.pos, new_pos)
122
+
123
+
124
+ def AtomFromPdbLine(line):
125
+ """
126
+ Returns an Atom object from an atom line in a pdb file.
127
+ """
128
+ atom = Atom()
129
+ if line.startswith('HETATM'):
130
+ atom.is_hetatm = True
131
+ else:
132
+ atom.is_hetatm = False
133
+ atom.num = int(line[6:11])
134
+ atom.type = line[12:16].strip(" ")
135
+ atom.alt_conform = line[16]
136
+ atom.res_type = line[17:21].strip()
137
+ atom.element = data.guess_element(atom.res_type, atom.type)
138
+ atom.chain_id = line[21]
139
+ atom.res_num = int(line[22:26])
140
+ atom.res_insert = line[26]
141
+ if atom.res_insert == " ":
142
+ atom.res_insert = ""
143
+ x = float(line[30:38])
144
+ y = float(line[38:46])
145
+ z = float(line[46:54])
146
+ v3.set_vector(atom.pos, x, y, z)
147
+ try:
148
+ atom.occupancy = float(line[54:60])
149
+ except:
150
+ atom.occupancy = 100.0
151
+ try:
152
+ atom.bfactor = float(line[60:66])
153
+ except:
154
+ atom.bfactor = 0.0
155
+ return atom
156
+
157
+
158
+ # The following functions is for handling lists of atoms
159
+
160
+ def cmp_atom(a1):
161
+ """
162
+ Sorting operator for atoms
163
+ """
164
+ return a1.num
165
+
166
+
167
+ def add_radii(atoms):
168
+ """
169
+ Lookup and assign atom.radius for atoms.
170
+ """
171
+ for atom in atoms:
172
+ if atom.element in data.radii:
173
+ atom.radius = data.radii[atom.element]
174
+ else:
175
+ atom.radius = data.radii['.']
176
+
177
+
178
+ def get_center(atoms):
179
+ """
180
+ Returns the geometric center position vector of atoms.
181
+ """
182
+ center = v3.vector()
183
+ for atom in atoms:
184
+ center += atom.pos
185
+ result = v3.scale(center, 1.0/float(len(atoms)))
186
+ return result
187
+
188
+
189
+ def get_width(atoms, center=None):
190
+ """
191
+ Returns twice the longest distance from the center.
192
+ """
193
+ max_diff = 0
194
+ if center is None:
195
+ center = get_center(atoms)
196
+ for atom in atoms:
197
+ diff = v3.distance(atom.pos, center)
198
+ if diff > max_diff:
199
+ max_diff = diff
200
+ return 2*max_diff
201
+
202
+
203
+ def read_pdb(fname):
204
+ """
205
+ Reads a list of Atoms from a PDB file.
206
+ """
207
+ atoms = []
208
+ for line in open(fname, 'r'):
209
+ if line.startswith(("ENDMDL", "END")):
210
+ break
211
+ if line.startswith(("ATOM", "HETATM")):
212
+ atoms.append(AtomFromPdbLine(line))
213
+ return atoms
214
+
215
+
216
+ def write_pdb(atoms, pdb):
217
+ """
218
+ Writes a list of atoms to a PDB file.
219
+ """
220
+ with open(pdb, 'w') as f:
221
+ for atom in sorted(atoms, key=cmp_atom):
222
+ f.write(atom.pdb_str() + '\n')
223
+
224
+
225
+ # Introducing the Residue structure for organizing atoms
226
+
227
+ def split_tag(tag):
228
+ """
229
+ Returns (chain_id, res_num, insert). Empty chain_id=" " and
230
+ empty insert="".
231
+ """
232
+ words = tag.split(":")
233
+ if len(words) > 2:
234
+ raise Exception("Too many : in res tag %s" % tag)
235
+ res_num = words[-1]
236
+ insert = ""
237
+ while not res_num[-1].isdigit():
238
+ insert += res_num[-1]
239
+ res_num = res_num[:-1]
240
+ res_num = int(res_num)
241
+ if len(words) == 1:
242
+ chain_id = " "
243
+ else:
244
+ chain_id = words[0]
245
+ if len(chain_id) > 1:
246
+ raise Exception("chain_id in res tag %s too long" % tag)
247
+ return (chain_id, res_num, insert)
248
+
249
+
250
+ class Residue:
251
+ """
252
+ Class to collect atoms in a residue together. Allows group
253
+ searching where each atom in a residue must have a unique
254
+ atom_type.
255
+ """
256
+
257
+ def __init__(self, in_type, in_chain_id, in_num, in_insert=''):
258
+ self.type = in_type
259
+ self.chain_id = in_chain_id
260
+ self.num = in_num
261
+ self.insert = in_insert
262
+ self._atom_dict = {}
263
+
264
+ def tag(self):
265
+ """
266
+ Returns a name e.g. "A:12" that combines the chain_id and
267
+ residue number. This is a unique tag that can be used to
268
+ identify a residue in a Soup through get_i_residue().
269
+ """
270
+ tag = ""
271
+ if self.chain_id != " " and self.chain_id != "":
272
+ tag += self.chain_id + ":"
273
+ tag += str(self.num)
274
+ if self.insert:
275
+ tag += self.insert
276
+ return tag
277
+
278
+ def __str__(self):
279
+ atom_name_list = [a.type for a in self.atoms()]
280
+ atom_name = " ".join(atom_name_list)
281
+ return "%s-%s { %s }" % (self.type, self.num, atom_name)
282
+
283
+ def copy(self):
284
+ return copy.deepcopy(self)
285
+
286
+ def n_atom(self):
287
+ return len(self._atom_dict)
288
+
289
+ def atom(self, atom_type):
290
+ return self._atom_dict[atom_type]
291
+
292
+ def has_atom(self, atom_type):
293
+ return atom_type in list(self._atom_dict.keys())
294
+
295
+ def change_atom_type(self, atom_type1, atom_type2):
296
+ if not self.has_atom(atom_type1):
297
+ return
298
+ atom = self._atom_dict[atom_type1]
299
+ atom.type = atom_type2
300
+ del self._atom_dict[atom_type1]
301
+ self._atom_dict[atom_type2] = atom
302
+
303
+ def atoms(self):
304
+ return list(self._atom_dict.values())
305
+
306
+ def atom_name(self, atom_type):
307
+ return self.type + self.num + ":" + atom_type
308
+
309
+ def insert_atom(self, atom):
310
+ self._atom_dict[atom.type] = atom
311
+ atom.chain_id = self.chain_id
312
+ atom.res_num = self.num
313
+ atom.res_type = self.type
314
+
315
+ def erase_atom(self, atom_type):
316
+ del self._atom_dict[atom_type]
317
+
318
+ def set_num(self, i, insert=""):
319
+ self.num = i
320
+ self.insert = insert
321
+ for atom in self.atoms():
322
+ atom.res_num = self.num
323
+ atom.res_insert = insert
324
+
325
+ def inc_num(self):
326
+ self.set_num(self.num+1, self.insert)
327
+
328
+ def dec_num(self):
329
+ self.set_num(self.num-1, self.insert)
330
+
331
+ def dec_insert(self):
332
+ l = self.insert;
333
+ if l == "A" or l == "a":
334
+ self.insert = ''
335
+ else:
336
+ i = string.ascii_letters.find(l)
337
+ self.insert = string.ascii_letters[i-1]
338
+
339
+ def transform(self, matrix):
340
+ for atom in self.atoms():
341
+ atom.transform(matrix)
342
+
343
+ def set_chain_id(self, chain_id):
344
+ self.chain_id = chain_id
345
+ for a in self.atoms():
346
+ a.chain_id = chain_id
347
+
348
+ def set_type(self, res_type):
349
+ self.type = res_type
350
+ for a in self.atoms():
351
+ a.res_type = res_type
352
+
353
+ def load_bfactor(self, bfactor):
354
+ for atom in self.atoms():
355
+ atom.bfactor = bfactor
356
+
357
+
358
+ class Soup():
359
+ """
360
+ The major class that holds a list of atoms and references them
361
+ to a list of residues.
362
+
363
+ The methods residues() and atoms() provide access to the
364
+ data structures.
365
+
366
+ Inserting of residues should be done here, as Soup will
367
+ administer both atom and residue lists.
368
+ """
369
+
370
+ def __init__(self, fname=""):
371
+ self._residues = []
372
+ self._atoms = []
373
+ if fname:
374
+ self.read_pdb(fname)
375
+
376
+ def clear(self):
377
+ del self._residues[:]
378
+ for atom in self._atoms:
379
+ del atom
380
+ del self._atoms[:]
381
+
382
+ def copy(self):
383
+ return copy.deepcopy(self)
384
+
385
+ def n_atom(self):
386
+ return len(self._atoms)
387
+
388
+ def atoms(self):
389
+ return self._atoms
390
+
391
+ def atom(self, i):
392
+ return _atoms[i]
393
+
394
+ def insert_atom(self, i, atom):
395
+ self._atoms.append(atom)
396
+ self.residue(i).insert_atom(atom)
397
+
398
+ def erase_atom(self, i, atom_type):
399
+ atom = self.residue(i).atom(atom_type)
400
+ self.residue(i).erase_atom(atom_type)
401
+ for _atom in self._atoms:
402
+ if _atom == atom:
403
+ self._atoms.remove(atom)
404
+ del atom
405
+ break
406
+
407
+ def transform(self, matrix):
408
+ for atom in self._atoms:
409
+ atom.transform(matrix)
410
+
411
+ def residues(self):
412
+ return self._residues
413
+
414
+ def residue(self, i):
415
+ return self._residues[i]
416
+
417
+ def get_i_residue(self, tag):
418
+ """
419
+ Returns the index of residue with tag, or -1 on failure.
420
+ """
421
+ for i, residue in enumerate(self.residues()):
422
+ if split_tag(tag) == (residue.chain_id, residue.num, residue.insert):
423
+ return i
424
+ raise -1
425
+
426
+ def residue_by_tag(self, tag):
427
+ i = self.get_i_residue(tag)
428
+ if i >= 0:
429
+ return self.residue(i)
430
+ else:
431
+ raise None
432
+
433
+ def n_residue(self):
434
+ return len(self._residues)
435
+
436
+ def insert_residue(self, i, res):
437
+ is_insertion = False
438
+ if i < self.n_residue()-1:
439
+ save_res_num = self.residue(i).num
440
+ if self.residue(i+1).num == save_res_num:
441
+ is_insertion = True
442
+
443
+ if self.n_residue() == 0:
444
+ res.set_num(res.num, res.insert)
445
+ elif i < self.n_residue():
446
+ res.set_num(self.residue(i).num, self.residue(i).insert)
447
+ else:
448
+ res.set_num(self.residue(i-1).num, "")
449
+ res.inc_num()
450
+
451
+ self._residues.insert(i, res)
452
+ for atom in res.atoms():
453
+ self.insert_atom(i, atom)
454
+
455
+ for j in range(i+1, self.n_residue()):
456
+ self.residue(j).inc_num()
457
+
458
+ if is_insertion:
459
+ while self.residue(i+1).insert:
460
+ for j in range(i+1, self.n_residue()):
461
+ if self.residue(j).res_num == save_res_num:
462
+ self.residue(k).dec_insert()
463
+
464
+ def append_residue(self, res):
465
+ self._residues.append(res)
466
+ for atom in res.atoms():
467
+ self.insert_atom(self.n_residue()-1, atom)
468
+
469
+ def erase_residue(self, i):
470
+ save_res_num = self.residue(i).num
471
+
472
+ for atom in self.residue(i).atoms():
473
+ self._atoms.remove(atom)
474
+ del atom
475
+ self._residues.pop(i)
476
+
477
+ if i < self.n_residue():
478
+ if self.residue(i).num == save_res_num:
479
+ # erasing residue in an insertion
480
+ for j in range(i, self.n_residue()):
481
+ if self.residue(j).num == erase_res_num_int:
482
+ self.residue(j).dec_insert()
483
+ else:
484
+ for j in range(i, self.n_residue()):
485
+ self.residue(j).dec_num()
486
+
487
+ def extract_soup(self, i, j):
488
+ extract = Soup()
489
+ for res in self.residues()[i:j]:
490
+ extract.append_residue(res.copy())
491
+ return extract
492
+
493
+ def insert_soup(self, i, insert):
494
+ for res in reversed(insert.residues()):
495
+ self.insert_residue(i, res.copy())
496
+
497
+ def chain_ids(self):
498
+ chain_id = [r.chain_id for r in self.residues()]
499
+ return list(set(chain_id))
500
+
501
+ def extract_chain(self, chain_id):
502
+ extract = Soup()
503
+ for res in self.residues():
504
+ if res.chain_id == chain_id:
505
+ extract.append_residue(res.copy())
506
+ return extract
507
+
508
+ def load_residue_bfactors(self, res_bfactors):
509
+ for r, b in zip(self.residues(), res_bfactors):
510
+ r.load_bfactor(b)
511
+
512
+ def __str__(self):
513
+ res_name_list = [str(res) for res in self._residues]
514
+ return "\n".join(res_name_list)
515
+
516
+ def read_pdb(self, fname):
517
+ self.clear()
518
+ res_num = -1
519
+ res_insert = " "
520
+ for line in open(fname, 'r').readlines():
521
+ if line.startswith("ATOM") or line.startswith("HETATM"):
522
+ atom = AtomFromPdbLine(line);
523
+ if (res_num != atom.res_num) or \
524
+ (res_insert != atom.res_insert):
525
+ residue = Residue(
526
+ atom.res_type, atom.chain_id,
527
+ atom.res_num, atom.res_insert)
528
+ self.append_residue(residue)
529
+ res_num = atom.res_num
530
+ res_insert = atom.res_insert
531
+ self.insert_atom(-1, atom)
532
+ if line.startswith(("END", "ENDMDL")):
533
+ return
534
+
535
+ def write_pdb(self, pdb):
536
+ f = open(pdb, 'w')
537
+ n_atom = 0
538
+ for res in self.residues():
539
+ res_atoms = res.atoms()
540
+ res_atoms.sort(key=cmp_atom)
541
+ for atom in res_atoms:
542
+ f.write(atom.pdb_str() + '\n')
543
+ f.close()
@@ -0,0 +1,120 @@
1
+ # encoding: utf-8
2
+
3
+ __doc__ = """
4
+
5
+ Text manipulation of PDB protein structure files.
6
+
7
+ This is a utility function providing common operations
8
+ applied to PDB files that can easily be done with text
9
+ processing.
10
+ """
11
+
12
+
13
+ from . import data
14
+
15
+
16
+ def strip_lines(pdb_txt, tag_func):
17
+ new_lines = []
18
+ for line in pdb_txt.splitlines():
19
+ if tag_func(line):
20
+ continue
21
+ new_lines.append(line)
22
+ return '\n'.join(new_lines)
23
+
24
+
25
+ def strip_hydrogens(pdb_txt):
26
+
27
+ def strip_space_and_digits(s):
28
+ result = ""
29
+ for c in s:
30
+ if not (c.isdigit() or c is " "):
31
+ result += c
32
+ return result
33
+
34
+ new_lines = []
35
+ for line in pdb_txt.splitlines():
36
+ if line.startswith("ATOM"):
37
+ raw_atom_type = line[12:16]
38
+ element = strip_space_and_digits(raw_atom_type)[0]
39
+ if element == "H":
40
+ continue
41
+ new_lines.append(line)
42
+ return '\n'.join(new_lines)
43
+
44
+
45
+ def strip_solvent(pdb_txt):
46
+ new_lines = []
47
+ for line in pdb_txt.splitlines():
48
+ res_type = line[17:20].strip().upper()
49
+ if not res_type in data.solvent_res_types:
50
+ new_lines.append(line)
51
+ return '\n'.join(new_lines)
52
+
53
+
54
+ def renumber_residues(pdb_txt):
55
+ get_res_tag = lambda line: line[17:27]
56
+
57
+ sorted_res_tags = []
58
+ lines = pdb_txt.splitlines()
59
+ for line in lines:
60
+ if line.startswith('ATOM') or line.startswith('HETATM'):
61
+ tag = get_res_tag(line)
62
+ if tag not in sorted_res_tags:
63
+ sorted_res_tags.append(tag)
64
+
65
+ res_tag_to_new_resnum = {}
66
+ for i, tag in enumerate(sorted_res_tags):
67
+ res_tag_to_new_resnum[tag] = "%4d" % (i+1)
68
+
69
+ new_lines = []
70
+ for line in lines:
71
+ new_line = line
72
+ for start_tag in ['ATOM', 'ANISOU', 'HETATM']:
73
+ if line.startswith(start_tag):
74
+ tag = get_res_tag(line)
75
+ resnum = res_tag_to_new_resnum[tag]
76
+ resnum = '%4d ' % (int(resnum) % 10000)
77
+ new_line = line[:22] + resnum + line[27:]
78
+ new_lines.append(new_line)
79
+ txt = ''.join(l + '\n' for l in new_lines)
80
+ return txt
81
+
82
+
83
+ def strip_other_nmr_models(pdb_txt):
84
+ new_lines = []
85
+ for line in pdb_txt.splitlines():
86
+ new_lines.append(line)
87
+ if line.startswith("ENDMDL"):
88
+ break
89
+ return '\n'.join(new_lines)
90
+
91
+
92
+ def strip_alternative_atoms(pdb_txt):
93
+ new_lines = []
94
+ for line in pdb_txt.splitlines():
95
+ new_line = line
96
+ if line.startswith('ATOM'):
97
+ alt_loc = line[16]
98
+ if not alt_loc in [' ']:
99
+ if alt_loc in ['A', 'a']:
100
+ new_line = line[:16] + ' ' + line[17:]
101
+ else:
102
+ continue
103
+ new_lines.append(new_line)
104
+ return '\n'.join(new_lines)
105
+
106
+
107
+ def clean_pdb(in_pdb, out_pdb):
108
+ txt = open(in_pdb, 'r').read()
109
+ txt = strip_other_nmr_models(txt)
110
+ txt = strip_lines(txt, lambda l: l.startswith('HETATM'))
111
+ txt = strip_lines(txt, lambda l: l.startswith('ANISOU'))
112
+ txt = strip_lines(txt, lambda l: l.startswith('CONECT'))
113
+ txt = strip_lines(txt, lambda l: l.startswith('MASTER'))
114
+ txt = strip_solvent(txt)
115
+ txt = strip_alternative_atoms(txt)
116
+ txt = strip_hydrogens(txt)
117
+ txt = renumber_residues(txt)
118
+ open(out_pdb, 'w').write(txt)
119
+
120
+