1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """The API for accessing, creating, and modifying structural information.
24
25 The full API is documented within this base class object. Each available API call is given as a
26 prototype method stub (or functional method) with all arguments, raised errors, and return values
27 documented.
28 """
29
30
31 from numpy import float64
32 from os import sep
33 from re import match
34 from types import MethodType
35 from warnings import warn
36
37
38 from data.relax_xml import fill_object_contents, object_to_xml, xml_to_object
39 from float import floatAsByteArray, packBytesAsPyFloat
40 from generic_fns.structure.superimpose import kabsch
41 from relax_errors import RelaxError, RelaxFileError, RelaxFromXMLNotEmptyError, RelaxImplementError
42 from relax_io import file_root
43 from relax_warnings import RelaxWarning
44
45
47 """The structural object base class.
48
49 All API methods are prototyped here as stub methods.
50 """
51
52
53 id = 'API'
54
55
57 """Initialise the structural object."""
58
59
60 self.structural_data = ModelList()
61
62
63 - def add_atom(self, mol_name=None, atom_name=None, res_name=None, res_num=None, pos=[None, None, None], element=None, atom_num=None, chain_id=None, segment_id=None, pdb_record=None):
64 """Add a new atom to the structural data object.
65
66 @keyword mol_name: The name of the molecule.
67 @type mol_name: str
68 @keyword atom_name: The atom name, e.g. 'H1'.
69 @type atom_name: str or None
70 @keyword res_name: The residue name.
71 @type res_name: str or None
72 @keyword res_num: The residue number.
73 @type res_num: int or None
74 @keyword pos: The position vector of coordinates.
75 @type pos: list (length = 3)
76 @keyword element: The element symbol.
77 @type element: str or None
78 @keyword atom_num: The atom number.
79 @type atom_num: int or None
80 @keyword chain_id: The chain identifier.
81 @type chain_id: str or None
82 @keyword segment_id: The segment identifier.
83 @type segment_id: str or None
84 @keyword pdb_record: The optional PDB record name, e.g. 'ATOM' or 'HETATM'.
85 @type pdb_record: str or None
86 """
87
88
89 raise RelaxImplementError
90
91
92 - def add_model(self, model=None, coords_from=None):
93 """Add a new model to the store.
94
95 The new model will be constructured with the structural information from the other models currently present. The coords_from argument allows the atomic positions to be taken from a certain model. If this argument is not set, then the atomic positions from the first model will be used.
96
97 @keyword model: The number of the model to create.
98 @type model: int or None
99 @keyword coords_from: The model number to take the coordinates from.
100 @type coords_from: int or None
101 @return: The model container.
102 @rtype: ModelContainer instance
103 """
104
105
106 raise RelaxImplementError
107
108
110 """Prototype method stub for adding the given molecule to the store.
111
112 @keyword name: The molecule identification string.
113 @type name: str
114 """
115
116
117 raise RelaxImplementError
118
119
120 - def are_bonded(self, atom_id1=None, atom_id2=None):
121 """Prototype method stub for determining if two atoms are directly bonded to each other.
122
123 @keyword atom_id1: The molecule, residue, and atom identifier string of the first atom.
124 @type atom_id1: str
125 @keyword atom_id2: The molecule, residue, and atom identifier string of the second atom.
126 @type atom_id2: str
127 @return: True if the atoms are directly bonded.
128 @rtype: bool
129 """
130
131
132 raise RelaxImplementError('are_bonded')
133
134
135 - def atom_loop(self, atom_id=None, str_id=None, model_num=None, model_num_flag=False, mol_name_flag=False, res_num_flag=False, res_name_flag=False, atom_num_flag=False, atom_name_flag=False, element_flag=False, pos_flag=False, ave=False):
136 """Prototype generator method stub for looping over all atoms in the structural data object.
137
138 This method should be designed as a generator (http://www.python.org/dev/peps/pep-0255/).
139 It should loop over all atoms of the system yielding the following atomic information, if
140 the corresponding flag is True, in tuple form:
141
142 1. Model number.
143 2. Molecule name.
144 3. Residue number.
145 4. Residue name.
146 5. Atom number.
147 6. Atom name.
148 7. The element name (its atomic symbol and optionally the isotope, e.g. 'N', 'Mg',
149 '17O', '13C', etc).
150 8. The position of the atom in Euclidean space.
151
152
153 @keyword atom_id: The molecule, residue, and atom identifier string. Only atoms matching this selection will be yielded.
154 @type atom_id: str
155 @keyword str_id: The structure identifier. This can be the file name, model number, or structure number. If None, then all structures will be looped over.
156 @type str_id: str, int, or None
157 @keyword model_num: Only loop over a specific model.
158 @type model_num: int or None
159 @keyword model_num_flag: A flag which if True will cause the model number to be yielded.
160 @type model_num_flag: bool
161 @keyword mol_name_flag: A flag which if True will cause the molecule name to be yielded.
162 @type mol_name_flag: bool
163 @keyword res_num_flag: A flag which if True will cause the residue number to be yielded.
164 @type res_num_flag: bool
165 @keyword res_name_flag: A flag which if True will cause the residue name to be yielded.
166 @type res_name_flag: bool
167 @keyword atom_num_flag: A flag which if True will cause the atom number to be yielded.
168 @type atom_num_flag: bool
169 @keyword atom_name_flag: A flag which if True will cause the atom name to be yielded.
170 @type atom_name_flag: bool
171 @keyword element_flag: A flag which if True will cause the element name to be yielded.
172 @type element_flag: bool
173 @keyword pos_flag: A flag which if True will cause the atomic position to be yielded.
174 @type pos_flag: bool
175 @keyword ave: A flag which if True will result in this method returning the average atom properties across all loaded structures.
176 @type ave: bool
177 @return: A tuple of atomic information, as described in the docstring.
178 @rtype: tuple consisting of optional molecule name (str), residue number (int), residue name (str), atom number (int), atom name(str), element name (str), and atomic position (array of len 3).
179 """
180
181
182 raise RelaxImplementError
183
184
185 - def attached_atom(self, atom_id=None, attached_atom=None, model=None):
186 """Prototype method stub for finding the atom 'attached_atom' bonded to the atom 'atom_id'.
187
188 @keyword atom_id: The molecule, residue, and atom identifier string. This must
189 correspond to a single atom in the system.
190 @type atom_id: str
191 @keyword attached_atom: The name of the attached atom to return.
192 @type attached_atom: str
193 @keyword model: The model to return the positional information from. If not
194 supplied and multiple models exist, then the returned atomic
195 position will be a list of the positions in each model.
196 @type model: None or int
197 @return: A tuple of information about the bonded atom.
198 @rtype: tuple consisting of the atom number (int), atom name (str), element
199 name (str), and atomic positions for each model (list of numpy
200 arrays)
201 """
202
203
204 raise RelaxImplementError
205
206
207 - def bond_vectors(self, attached_atom=None, model_num=None, mol_name=None, res_num=None, res_name=None, spin_num=None, spin_name=None, return_name=False, return_warnings=False):
208 """Prototype method stub for finding the bond vectors between 'attached_atom' and 'atom_id'.
209
210 @keyword attached_atom: The name of the bonded atom.
211 @type attached_atom: str
212 @keyword model_num: The model of which to return the vectors from. If not supplied
213 and multiple models exist, then vectors from all models will be
214 returned.
215 @type model_num: None or int
216 @keyword mol_name: The name of the molecule that attached_atom belongs to.
217 @type mol_name: str
218 @keyword res_num: The number of the residue that attached_atom belongs to.
219 @type res_num: str
220 @keyword res_name: The name of the residue that attached_atom belongs to.
221 @type res_name: str
222 @keyword spin_num: The number of the spin that attached_atom is attached to.
223 @type spin_num: str
224 @keyword spin_name: The name of the spin that attached_atom is attached to.
225 @type spin_name: str
226 @keyword return_name: A flag which if True will cause the name of the attached atom to
227 be returned together with the bond vectors.
228 @type return_name: bool
229 @keyword return_warnings: A flag which if True will cause warning messages to be returned.
230 @type return_warnings: bool
231 @return: The list of bond vectors for each model.
232 @rtype: list of numpy arrays
233 """
234
235
236 raise RelaxImplementError
237
238
239 - def connect_atom(self, mol_name=None, index1=None, index2=None):
240 """Connect two atoms in the structural data object.
241
242 @keyword mol_name: The name of the molecule.
243 @type mol_name: str
244 @keyword index1: The global index of the first atom.
245 @type index1: str
246 @keyword index2: The global index of the first atom.
247 @type index2: str
248 """
249
250
251 raise RelaxImplementError
252
253
255 """Prototype method stub for deleting all structural data from the current data pipe."""
256
257
258 raise RelaxImplementError
259
260
262 """Report if the structural data structure is empty or not.
263
264 @return: True if empty, False otherwise.
265 @rtype: bool
266 """
267
268
269 if len(self.structural_data) == 0:
270 return True
271 else:
272 return False
273
274
275 - def from_xml(self, str_node, dir=None, id=None, file_version=1):
276 """Recreate the structural object from the XML structural object node.
277
278 @param str_node: The structural object XML node.
279 @type str_node: xml.dom.minicompat.Element instance
280 @keyword dir: The name of the directory containing the results file.
281 @type dir: str
282 @keyword id: The specific structural object ID string. This can be 'scientific', 'internal', etc.
283 @type id: str
284 @keyword file_version: The relax XML version of the XML file.
285 @type file_version: int
286 """
287
288
289 model_nodes = str_node.getElementsByTagName('model')
290 self.structural_data.from_xml(model_nodes, id=id, file_version=file_version)
291
292
293 disp_nodes = str_node.getElementsByTagName('displacements')
294 if len(disp_nodes):
295
296 self.displacements = Displacements()
297
298
299 self.displacements.from_xml(disp_nodes[0], file_version=file_version)
300
301
303 """Return or create the model.
304
305 @param model: The model number.
306 @type model: int or None
307 @return: The ModelContainer corresponding to the model number or that newly created.
308 @rtype: ModelContainer instance
309 """
310
311
312 if model == None and self.num_models() > 1:
313 raise RelaxError("The target model cannot be determined as there are %s models already present." % self.num_modes())
314
315
316 if model == None:
317
318 if self.num_models():
319 self.structural_data.add_item()
320
321
322 model_cont = self.structural_data[0]
323
324
325 else:
326
327 found = False
328 for model_cont in self.structural_data:
329 if model_cont.num == model:
330 found = True
331 break
332
333
334 if not found:
335 self.structural_data.add_item(model)
336 model_cont = self.structural_data[-1]
337
338
340 """Return the molecule.
341
342 @param molecule: The molecule name.
343 @type molecule: int or None
344 @keyword model: The model number.
345 @type model: int or None
346 @return: The MolContainer corresponding to the molecule name and model number.
347 @rtype: MolContainer instance or None
348 """
349
350
351 raise RelaxImplementError
352
353
354 - def load_pdb(self, file_path, read_mol=None, set_mol_name=None, read_model=None, set_model_num=None, verbosity=False):
355 """Prototype method stub for loading structures from a PDB file.
356
357 This inherited prototype method is a stub which, if the functionality is desired, should be
358 overwritten by the derived class.
359
360
361 @param file_path: The full path of the PDB file.
362 @type file_path: str
363 @keyword read_mol: The molecule(s) to read from the file, independent of model. The
364 molecules are determined differently by the different parsers, but
365 are numbered consecutively from 1. If set to None, then all
366 molecules will be loaded.
367 @type read_mol: None, int, or list of int
368 @keyword set_mol_name: Set the names of the molecules which are loaded. If set to None,
369 then the molecules will be automatically labelled based on the file
370 name or other information.
371 @type set_mol_name: None, str, or list of str
372 @keyword read_model: The PDB model to extract from the file. If set to None, then all
373 models will be loaded.
374 @type read_model: None, int, or list of int
375 @keyword set_model_num: Set the model number of the loaded molecule. If set to None, then
376 the PDB model numbers will be preserved, if they exist.
377 @type set_model_num: None, int, or list of int
378 @keyword verbosity: A flag which if True will cause messages to be printed.
379 @type verbosity: bool
380 @return: The status of the loading of the PDB file.
381 @rtype: bool
382 """
383
384
385 raise RelaxImplementError
386
387
388 - def load_xyz(self, file_path, read_mol=None, set_mol_name=None, read_model=None, set_model_num=None, verbosity=False):
389 """Method for loading structures from a XYZ file.
390
391 @param file_path: The full path of the XYZ file.
392 @type file_path: str
393 @keyword read_mol: The molecule(s) to read from the file, independent of model. The
394 molecules are determined differently by the different parsers, but
395 are numbered consecutively from 1. If set to None, then all
396 molecules will be loaded.
397 @type read_mol: None, int, or list of int
398 @keyword set_mol_name: Set the names of the molecules which are loaded. If set to None,
399 then the molecules will be automatically labelled based on the file
400 name or other information.
401 @type set_mol_name: None, str, or list of str
402 @keyword read_model: The XYZ model to extract from the file. If set to None, then all
403 models will be loaded.
404 @type read_model: None, int, or list of int
405 @keyword set_model_num: Set the model number of the loaded molecule. If set to None, then
406 the XYZ model numbers will be preserved, if they exist.
407 @type set_model_num: None, int, or list of int
408 @keyword verbosity: A flag which if True will cause messages to be printed.
409 @type verbosity: bool
410 @return: The status of the loading of the XYZ file.
411 @rtype: bool
412 """
413
414
415 raise RelaxImplementError
416
417
419 """Generator method for looping over the models in numerical order.
420
421 @keyword model: Limit the loop to a single number.
422 @type model: int
423 @return: The model structural object.
424 @rtype: ModelContainer container
425 """
426
427
428 if model:
429 for i in range(len(self.structural_data)):
430 if self.structural_data[i].num == model:
431 yield self.structural_data[i]
432
433
434 else:
435
436 model_nums = []
437 for i in range(len(self.structural_data)):
438 if self.structural_data[i].num != None:
439 model_nums.append(self.structural_data[i].num)
440
441
442 if model_nums:
443 model_nums.sort()
444
445
446 for model_num in model_nums:
447
448 for i in range(len(self.structural_data)):
449
450 if self.structural_data[i].num == model_num:
451 yield self.structural_data[i]
452
453
454 if not model_nums:
455 yield self.structural_data[0]
456
457
459 """Method for returning the number of models.
460
461 @return: The number of models in the structural object.
462 @rtype: int
463 """
464
465 return len(self.structural_data)
466
467
469 """Method for returning the number of molecules.
470
471 @return: The number of molecules in the structural object.
472 @rtype: int
473 """
474
475
476 self.validate()
477
478
479 return len(self.structural_data[0].mol)
480
481
482 - def pack_structs(self, data_matrix, orig_model_num=None, set_model_num=None, orig_mol_num=None, set_mol_name=None, file_name=None, file_path=None):
483 """From the given structural data, expand the structural data data structure.
484
485 @param data_matrix: A matrix of structural objects.
486 @type data_matrix: list of lists of structural objects
487 @keyword orig_model_num: The original model numbers (for storage).
488 @type orig_model_num: list of int
489 @keyword set_model_num: The new model numbers (for model renumbering).
490 @type set_model_num: list of int
491 @keyword orig_mol_num: The original molecule numbers (for storage).
492 @type orig_mol_num: list of int
493 @keyword set_mol_name: The new molecule names.
494 @type set_mol_name: list of str
495 @keyword file_name: The name of the file from which the molecular data has been
496 extracted.
497 @type file_name: None or str
498 @keyword file_path: The full path to the file specified by 'file_name'.
499 @type file_path: None or str
500 """
501
502
503 if len(orig_model_num) != len(data_matrix):
504 raise RelaxError("Structural data mismatch, %s original models verses %s in the structural data." % (len(orig_model_num), len(data_matrix)))
505
506
507 if len(orig_mol_num) != len(data_matrix[0]):
508 raise RelaxError("Structural data mismatch, %s original molecules verses %s in the structural data." % (len(orig_mol_num), len(data_matrix[0])))
509
510
511 if not set_model_num:
512 set_model_num = orig_model_num
513
514
515 if len(set_model_num) != len(data_matrix):
516 raise RelaxError("Failure of the mapping of new model numbers, %s new model numbers verses %s models in the structural data." % (len(set_model_num), len(data_matrix)))
517
518
519 if len(set_mol_name) != len(data_matrix[0]):
520 raise RelaxError("Failure of the mapping of new molecule names, %s new molecule names verses %s molecules in the structural data." % (len(set_mol_name), len(data_matrix[0])))
521
522
523 current_models = []
524 for i in range(len(self.structural_data)):
525
526 current_models.append(self.structural_data[i].num)
527
528
529 for j in range(len(self.structural_data[i].mol)):
530 if self.structural_data[i].num in set_model_num and self.structural_data[i].mol[j].mol_name in set_mol_name:
531 raise RelaxError("The molecule '%s' of model %s already exists." % (self.structural_data[i].mol[j].mol_name, self.structural_data[i].num))
532
533
534 for i in range(len(set_model_num)):
535
536 if set_model_num[i] not in current_models:
537
538 self.structural_data.add_item(set_model_num[i])
539
540
541 current_models.append(set_model_num[i])
542
543
544 model = self.structural_data[-1]
545
546
547 else:
548 model = self.structural_data[current_models.index(set_model_num[i])]
549
550
551 for j in range(len(set_mol_name)):
552
553 print("Adding molecule '%s' to model %s (from the original molecule number %s of model %s)" % (set_mol_name[j], set_model_num[i], orig_mol_num[j], orig_model_num[i]))
554
555
556 index = len(model.mol)
557 if model.num != self.structural_data[0].num and self.structural_data[0].mol[index].mol_name != set_mol_name[j]:
558 raise RelaxError("The new molecule name of '%s' in model %s does not match the corresponding molecule's name of '%s' in model %s." % (set_mol_name[j], set_model_num[i], self.structural_data[0].mol[index].mol_name, self.structural_data[0].num))
559
560
561 model.mol.add_item(mol_name=set_mol_name[j], mol_cont=data_matrix[i][j])
562
563
564 model.mol[-1].mol_name = set_mol_name[j]
565 model.mol[-1].file_name = file_name
566 model.mol[-1].file_path = file_path
567 model.mol[-1].file_mol_num = orig_mol_num[j]
568 model.mol[-1].file_model = orig_model_num[i]
569
570
571 - def rotate(self, R=None, origin=None, model=None, atom_id=None):
572 """Method stub for rotating a structure.
573
574 @keyword R: The forwards rotation matrix.
575 @type R: numpy 3D, rank-2 array
576 @keyword origin: The origin of the rotation.
577 @type origin: numpy 3D, rank-1 array
578 @keyword model: The model to rotate. If None, all models will be rotated.
579 @type model: int
580 @keyword atom_id: The molecule, residue, and atom identifier string. Only atoms matching this selection will be used.
581 @type atom_id: str or None
582 """
583
584
585 raise RelaxImplementError
586
587
588 - def target_mol_name(self, set=None, target=None, index=None, mol_num=None, file=None):
589 """Add the new molecule name to the target data structure.
590
591 @keyword set: The list of new molecule names. If not supplied, the names will be
592 generated from the file name.
593 @type set: None or list of str
594 @keyword target: The target molecule name data structure to which the new name will be
595 appended.
596 @type target: list
597 @keyword index: The molecule index, matching the set argument.
598 @type index: int
599 @keyword mol_num: The molecule number.
600 @type mol_num: int
601 @keyword file: The name of the file, excluding all directories.
602 @type file: str
603 """
604
605
606 if set:
607 target.append(set[index])
608 else:
609
610 target.append(file_root(file) + '_mol' + repr(mol_num))
611
612
613 - def translate(self, T=None, model=None, atom_id=None):
614 """Method stub for displacing the structural information by the given translation vector.
615
616 @keyword T: The translation vector.
617 @type T: numpy 3D, rank-1 array
618 @keyword model: The model to rotate. If None, all models will be rotated.
619 @type model: int
620 @keyword atom_id: The molecule, residue, and atom identifier string. Only atoms matching this selection will be used.
621 @type atom_id: str or None
622 """
623
624
625 raise RelaxImplementError
626
627
628 - def to_xml(self, doc, element):
629 """Prototype method for converting the structural object to an XML representation.
630
631 @param doc: The XML document object.
632 @type doc: xml.dom.minidom.Document instance
633 @param element: The element to add the alignment tensors XML element to.
634 @type element: XML element object
635 """
636
637
638 str_element = doc.createElement('structure')
639 element.appendChild(str_element)
640
641
642 str_element.setAttribute('desc', 'Structural information')
643 str_element.setAttribute('id', self.id)
644
645
646 if not self.structural_data.is_empty():
647 self.structural_data.to_xml(doc, str_element)
648
649
650 if hasattr(self, 'displacements'):
651
652 disp_element = doc.createElement('displacements')
653 str_element.appendChild(disp_element)
654
655
656 disp_element.setAttribute('desc', 'The rotational and translational displacements between models')
657
658
659 self.displacements.to_xml(doc, disp_element)
660
661
663 """Check that the models are consistent with each other.
664
665 This checks that the primary structure is identical between the models.
666 """
667
668
669 raise RelaxImplementError
670
671
673 """Prototype method stub for the creation of a PDB file from the structural data.
674
675 The PDB records
676 ===============
677
678 The following information about the PDB records has been taken from the "Protein Data Bank
679 Contents Guide: Atomic Coordinate Entry Format Description" version 3.1, February 11, 2008.
680
681 HET record
682 ----------
683
684 The HET record describes non-standard residues. The format of the record is::
685 __________________________________________________________________________________________
686 | | | | |
687 | Columns | Data type | Field | Definition |
688 |_________|______________|______________|________________________________________________|
689 | | | | |
690 | 1 - 6 | Record name | "HET " | |
691 | 8 - 10 | LString(3) | hetID | Het identifier, right-justified. |
692 | 13 | Character | ChainID | Chain identifier. |
693 | 14 - 17 | Integer | seqNum | Sequence number. |
694 | 18 | AChar | iCode | Insertion code. |
695 | 21 - 25 | Integer | numHetAtoms | Number of HETATM records for the group present |
696 | | | | in the entry. |
697 | 31 - 70 | String | text | Text describing Het group. |
698 |_________|______________|______________|________________________________________________|
699
700
701 HETNAM record
702 -------------
703
704 The HETNAM associates a chemical name with the hetID from the HET record. The format is of
705 the record is::
706 __________________________________________________________________________________________
707 | | | | |
708 | Columns | Data type | Field | Definition |
709 |_________|______________|______________|________________________________________________|
710 | | | | |
711 | 1 - 6 | Record name | "HETNAM" | |
712 | 9 - 10 | Continuation | continuation | Allows concatenation of multiple records. |
713 | 12 - 14 | LString(3) | hetID | Het identifier, right-justified. |
714 | 16 - 70 | String | text | Chemical name. |
715 |_________|______________|______________|________________________________________________|
716
717
718 FORMUL record
719 -------------
720
721 The chemical formula for non-standard groups. The format of the record is::
722 __________________________________________________________________________________________
723 | | | | |
724 | Columns | Data type | Field | Definition |
725 |_________|______________|______________|________________________________________________|
726 | | | | |
727 | 1 - 6 | Record name | "FORMUL" | |
728 | 9 - 10 | Integer | compNum | Component number. |
729 | 13 - 15 | LString(3) | hetID | Het identifier. |
730 | 17 - 18 | Integer | continuation | Continuation number. |
731 | 19 | Character | asterisk | "*" for water. |
732 | 20 - 70 | String | text | Chemical formula. |
733 |_________|______________|______________|________________________________________________|
734
735
736 MODEL record
737 ------------
738
739 The model number, for multiple structures. The format of the record is::
740 __________________________________________________________________________________________
741 | | | | |
742 | Columns | Data type | Field | Definition |
743 |_________|______________|______________|________________________________________________|
744 | | | | |
745 | 1 - 6 | Record name | "MODEL " | |
746 | 11 - 14 | Integer | serial | Model serial number. |
747 |_________|______________|______________|________________________________________________|
748
749
750 ATOM record
751 -----------
752
753 The ATOM record contains the atomic coordinates for atoms belonging to standard residues.
754 The format of the record is::
755 __________________________________________________________________________________________
756 | | | | |
757 | Columns | Data type | Field | Definition |
758 |_________|______________|______________|________________________________________________|
759 | | | | |
760 | 1 - 6 | Record name | "ATOM" | |
761 | 7 - 11 | Integer | serial | Atom serial number. |
762 | 13 - 16 | Atom | name | Atom name. |
763 | 17 | Character | altLoc | Alternate location indicator. |
764 | 18 - 20 | Residue name | resName | Residue name. |
765 | 22 | Character | chainID | Chain identifier. |
766 | 23 - 26 | Integer | resSeq | Residue sequence number. |
767 | 27 | AChar | iCode | Code for insertion of residues. |
768 | 31 - 38 | Real(8.3) | x | Orthogonal coordinates for X in Angstroms. |
769 | 39 - 46 | Real(8.3) | y | Orthogonal coordinates for Y in Angstroms. |
770 | 47 - 54 | Real(8.3) | z | Orthogonal coordinates for Z in Angstroms. |
771 | 55 - 60 | Real(6.2) | occupancy | Occupancy. |
772 | 61 - 66 | Real(6.2) | tempFactor | Temperature factor. |
773 | 73 - 76 | LString(4) | segID | Segment identifier, left-justified. |
774 | 77 - 78 | LString(2) | element | Element symbol, right-justified. |
775 | 79 - 80 | LString(2) | charge | Charge on the atom. |
776 |_________|______________|______________|________________________________________________|
777
778
779 HETATM record
780 -------------
781
782 The HETATM record contains the atomic coordinates for atoms belonging to non-standard
783 groups. The format of the record is::
784 __________________________________________________________________________________________
785 | | | | |
786 | Columns | Data type | Field | Definition |
787 |_________|______________|______________|________________________________________________|
788 | | | | |
789 | 1 - 6 | Record name | "HETATM" | |
790 | 7 - 11 | Integer | serial | Atom serial number. |
791 | 13 - 16 | Atom | name | Atom name. |
792 | 17 | Character | altLoc | Alternate location indicator. |
793 | 18 - 20 | Residue name | resName | Residue name. |
794 | 22 | Character | chainID | Chain identifier. |
795 | 23 - 26 | Integer | resSeq | Residue sequence number. |
796 | 27 | AChar | iCode | Code for insertion of residues. |
797 | 31 - 38 | Real(8.3) | x | Orthogonal coordinates for X. |
798 | 39 - 46 | Real(8.3) | y | Orthogonal coordinates for Y. |
799 | 47 - 54 | Real(8.3) | z | Orthogonal coordinates for Z. |
800 | 55 - 60 | Real(6.2) | occupancy | Occupancy. |
801 | 61 - 66 | Real(6.2) | tempFactor | Temperature factor. |
802 | 73 - 76 | LString(4) | segID | Segment identifier; left-justified. |
803 | 77 - 78 | LString(2) | element | Element symbol; right-justified. |
804 | 79 - 80 | LString(2) | charge | Charge on the atom. |
805 |_________|______________|______________|________________________________________________|
806
807
808 TER record
809 ----------
810
811 The end of the ATOM and HETATM records for a chain. According to the draft atomic
812 coordinate entry format description:
813
814 I{"The TER record has the same residue name, chain identifier, sequence number and insertion
815 code as the terminal residue. The serial number of the TER record is one number greater than
816 the serial number of the ATOM/HETATM preceding the TER."}
817
818 The format of the record is::
819 __________________________________________________________________________________________
820 | | | | |
821 | Columns | Data type | Field | Definition |
822 |_________|______________|______________|________________________________________________|
823 | | | | |
824 | 1 - 6 | Record name | "TER " | |
825 | 7 - 11 | Integer | serial | Serial number. |
826 | 18 - 20 | Residue name | resName | Residue name. |
827 | 22 | Character | chainID | Chain identifier. |
828 | 23 - 26 | Integer | resSeq | Residue sequence number. |
829 | 27 | AChar | iCode | Insertion code. |
830 |_________|______________|______________|________________________________________________|
831
832
833 CONECT record
834 -------------
835
836 The connectivity between atoms. This is required for all HET groups and for non-standard
837 bonds. The format of the record is::
838 __________________________________________________________________________________________
839 | | | | |
840 | Columns | Data type | Field | Definition |
841 |_________|______________|______________|________________________________________________|
842 | | | | |
843 | 1 - 6 | Record name | "CONECT" | |
844 | 7 - 11 | Integer | serial | Atom serial number |
845 | 12 - 16 | Integer | serial | Serial number of bonded atom |
846 | 17 - 21 | Integer | serial | Serial number of bonded atom |
847 | 22 - 26 | Integer | serial | Serial number of bonded atom |
848 | 27 - 31 | Integer | serial | Serial number of bonded atom |
849 | 32 - 36 | Integer | serial | Serial number of hydrogen bonded atom |
850 | 37 - 41 | Integer | serial | Serial number of hydrogen bonded atom |
851 | 42 - 46 | Integer | serial | Serial number of salt bridged atom |
852 | 47 - 51 | Integer | serial | Serial number of hydrogen bonded atom |
853 | 52 - 56 | Integer | serial | Serial number of hydrogen bonded atom |
854 | 57 - 61 | Integer | serial | Serial number of salt bridged atom |
855 |_________|______________|______________|________________________________________________|
856
857
858 ENDMDL record
859 -------------
860
861 The end of model record, for multiple structures. The format of the record is::
862 __________________________________________________________________________________________
863 | | | | |
864 | Columns | Data type | Field | Definition |
865 |_________|______________|______________|________________________________________________|
866 | | | | |
867 | 1 - 6 | Record name | "ENDMDL" | |
868 |_________|______________|______________|________________________________________________|
869
870
871
872 MASTER record
873 -------------
874
875 The control record for bookkeeping. The format of the record is::
876 __________________________________________________________________________________________
877 | | | | |
878 | Columns | Data type | Field | Definition |
879 |_________|______________|______________|________________________________________________|
880 | | | | |
881 | 1 - 6 | Record name | "MASTER" | |
882 | 11 - 15 | Integer | numRemark | Number of REMARK records |
883 | 16 - 20 | Integer | "0" | |
884 | 21 - 25 | Integer | numHet | Number of HET records |
885 | 26 - 30 | Integer | numHelix | Number of HELIX records |
886 | 31 - 35 | Integer | numSheet | Number of SHEET records |
887 | 36 - 40 | Integer | numTurn | Number of TURN records |
888 | 41 - 45 | Integer | numSite | Number of SITE records |
889 | 46 - 50 | Integer | numXform | Number of coordinate transformation records |
890 | | | | (ORIGX+SCALE+MTRIX) |
891 | 51 - 55 | Integer | numCoord | Number of atomic coordinate records |
892 | | | | (ATOM+HETATM) |
893 | 56 - 60 | Integer | numTer | Number of TER records |
894 | 61 - 65 | Integer | numConect | Number of CONECT records |
895 | 66 - 70 | Integer | numSeq | Number of SEQRES records |
896 |_________|______________|______________|________________________________________________|
897
898
899 END record
900 ----------
901
902 The end of the PDB file. The format of the record is::
903 __________________________________________________________________________________________
904 | | | | |
905 | Columns | Data type | Field | Definition |
906 |_________|______________|______________|________________________________________________|
907 | | | | |
908 | 1 - 6 | Record name | "END " | |
909 |_________|______________|______________|________________________________________________|
910
911
912 @param file: The PDB file object. This object must be writable.
913 @type file: file object
914 @keyword model_num: The model to place into the PDB file. If not supplied, then all
915 models will be placed into the file.
916 @type model_num: None or int
917 """
918
919
920 raise RelaxImplementError
921
922
924 """Check the integrity of the structural data.
925
926 The number of molecules must be the same in all models.
927 """
928
929
930 num_mols = len(self.structural_data[0].mol)
931
932
933 for i in range(1, len(self.structural_data)):
934
935 model_i = self.structural_data[i]
936
937
938 if num_mols != len(model_i.mol):
939 raise RelaxError("The structural object is not valid - the number of molecules is not the same for all models.")
940
941
942 for j in range(len(model_i.mol)):
943 if model_i.mol[j].mol_name != self.structural_data[0].mol[j].mol_name:
944 raise RelaxError("The molecule name '%s' of model %s does not match the corresponding molecule '%s' of model %s." % (model_i.mol[j].mol_name, model_i.num, self.structural_data[0].mol[j].mol_name, self.structural_data[0].num))
945
946
947
949 """A special object for representing rotational and translational displacements between models."""
950
952 """Initialise the storage objects."""
953
954
955 self._translation_vector = {}
956 self._translation_distance = {}
957 self._rotation_matrix = {}
958 self._rotation_axis = {}
959 self._rotation_angle = {}
960
961
962 - def _calculate(self, model_from=None, model_to=None, coord_from=None, coord_to=None, centroid=None):
963 """Calculate the rotational and translational displacements using the given coordinate sets.
964
965 This uses the Kabsch algorithm (http://en.wikipedia.org/wiki/Kabsch_algorithm).
966
967
968 @keyword model_from: The model number of the starting structure.
969 @type model_from: int
970 @keyword model_to: The model number of the ending structure.
971 @type model_to: int
972 @keyword coord_from: The list of atomic coordinates for the starting structure.
973 @type coord_from: numpy rank-2, Nx3 array
974 @keyword coord_to: The list of atomic coordinates for the ending structure.
975 @type coord_to: numpy rank-2, Nx3 array
976 @keyword centroid: An alternative position of the centroid, used for studying pivoted systems.
977 @type centroid: list of float or numpy rank-1, 3D array
978 """
979
980
981 if not model_from in self._translation_vector:
982 self._translation_vector[model_from] = {}
983 if not model_from in self._translation_distance:
984 self._translation_distance[model_from] = {}
985 if not model_from in self._rotation_matrix:
986 self._rotation_matrix[model_from] = {}
987 if not model_from in self._rotation_axis:
988 self._rotation_axis[model_from] = {}
989 if not model_from in self._rotation_angle:
990 self._rotation_angle[model_from] = {}
991
992
993 trans_vect, trans_dist, R, axis, angle, pivot = kabsch(name_from='model %s'%model_from, name_to='model %s'%model_to, coord_from=coord_from, coord_to=coord_to, centroid=centroid)
994
995
996 self._translation_vector[model_from][model_to] = trans_vect
997 self._translation_distance[model_from][model_to] = trans_dist
998 self._rotation_matrix[model_from][model_to] = R
999 self._rotation_axis[model_from][model_to] = axis
1000 self._rotation_angle[model_from][model_to] = angle
1001
1002
1003 - def from_xml(self, str_node, dir=None, id=None, file_version=1):
1004 """Recreate the structural object from the XML structural object node.
1005
1006 @param str_node: The structural object XML node.
1007 @type str_node: xml.dom.minicompat.Element instance
1008 @keyword dir: The name of the directory containing the results file.
1009 @type dir: str
1010 @keyword id: The specific structural object ID string. This can be 'scientific', 'internal', etc.
1011 @type id: str
1012 @keyword file_version: The relax XML version of the XML file.
1013 @type file_version: int
1014 """
1015
1016
1017 pair_nodes = str_node.getElementsByTagName('pair')
1018
1019
1020 for pair_node in pair_nodes:
1021
1022 model_from = int(pair_node.getAttribute('model_from'))
1023 model_to = int(pair_node.getAttribute('model_to'))
1024
1025
1026 if not model_from in self._translation_vector:
1027 self._translation_vector[model_from] = {}
1028 if not model_from in self._translation_distance:
1029 self._translation_distance[model_from] = {}
1030 if not model_from in self._rotation_matrix:
1031 self._rotation_matrix[model_from] = {}
1032 if not model_from in self._rotation_axis:
1033 self._rotation_axis[model_from] = {}
1034 if not model_from in self._rotation_angle:
1035 self._rotation_angle[model_from] = {}
1036
1037
1038 cont = ModelContainer()
1039
1040
1041 xml_to_object(pair_node, cont, file_version=file_version)
1042
1043
1044 for name in ['translation_vector', 'translation_distance', 'rotation_matrix', 'rotation_axis', 'rotation_angle']:
1045
1046 obj = getattr(self, '_'+name)
1047 obj_temp = getattr(cont, name)
1048
1049
1050 obj[model_from][model_to] = obj_temp
1051
1052
1053 - def to_xml(self, doc, element):
1054 """Create XML elements for each model.
1055
1056 @param doc: The XML document object.
1057 @type doc: xml.dom.minidom.Document instance
1058 @param element: The element to add the displacement XML elements to.
1059 @type element: XML element object
1060 """
1061
1062
1063 start_models = sorted(self._translation_vector.keys())
1064 for model_from in start_models:
1065
1066 end_models = sorted(self._translation_vector[model_from].keys())
1067 for model_to in end_models:
1068
1069 pair_element = doc.createElement('pair')
1070 element.appendChild(pair_element)
1071
1072
1073 pair_element.setAttribute('desc', 'The displacement from model %s to model %s' % (model_from, model_to))
1074 pair_element.setAttribute('model_from', str(model_from))
1075 pair_element.setAttribute('model_to', str(model_to))
1076
1077
1078 obj_names = [
1079 '_translation_vector',
1080 '_translation_distance',
1081 '_rotation_matrix',
1082 '_rotation_axis',
1083 '_rotation_angle'
1084 ]
1085
1086
1087 for i in range(len(obj_names)):
1088
1089 sub_elem = doc.createElement(obj_names[i][1:])
1090 pair_element.appendChild(sub_elem)
1091
1092
1093 subobj = getattr(self, obj_names[i])[model_from][model_to]
1094
1095
1096 object_to_xml(doc, sub_elem, value=subobj)
1097
1098
1099
1101 """List type data container for the different structural models.
1102
1103 Here different models are defined as the same molecule but with different conformations.
1104 """
1105
1107 """The string representation of the object.
1108
1109 Rather than using the standard Python conventions (either the string representation of the
1110 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
1111 """
1112
1113 text = "Models.\n\n"
1114 text = text + "%-8s%-8s" % ("Index", "Model number") + "\n"
1115 for i in range(len(self)):
1116 text = text + "%-8i%-8s" % (i, self[i].num) + "\n"
1117 return text
1118
1119
1121 """Append an empty ModelContainer to the ModelList.
1122
1123 @keyword model_num: The model number.
1124 @type model_num: int
1125 """
1126
1127
1128 if len(self) and self.is_empty():
1129 self[0].num = model_num
1130
1131
1132 else:
1133
1134 for i in range(len(self)):
1135 if self[i].num == model_num:
1136 raise RelaxError("The model '" + repr(model_num) + "' already exists.")
1137
1138
1139 self.append(ModelContainer(model_num))
1140
1141
1143 """Method for testing if this ModelList object is empty.
1144
1145 @return: True if this list only has one ModelContainer and the model name has not
1146 been set, False otherwise.
1147 @rtype: bool
1148 """
1149
1150
1151 if len(self) == 0:
1152 return True
1153
1154
1155 if len(self) == 1 and self[0].is_empty():
1156 return True
1157
1158
1159 return False
1160
1161
1162 - def from_xml(self, model_nodes, id=None, file_version=1):
1163 """Recreate a model list data structure from the XML model nodes.
1164
1165 @param model_nodes: The model XML nodes.
1166 @type model_nodes: xml.dom.minicompat.NodeList instance
1167 @keyword id: The specific structural object ID string. This can be 'scientific', 'internal', etc.
1168 @type id: str
1169 @keyword file_version: The relax XML version of the XML file.
1170 @type file_version: int
1171 """
1172
1173
1174 if not self.is_empty():
1175 raise RelaxFromXMLNotEmptyError(self.__class__.__name__)
1176
1177
1178 for model_node in model_nodes:
1179
1180 num = eval(model_node.getAttribute('num'))
1181 if num == 'None':
1182 num = None
1183 self.add_item(model_num=num)
1184
1185
1186 mol_nodes = model_node.getElementsByTagName('mol_cont')
1187
1188
1189 self[-1].mol.from_xml(mol_nodes, id=id, file_version=file_version)
1190
1191
1192 - def to_xml(self, doc, element):
1193 """Create XML elements for each model.
1194
1195 @param doc: The XML document object.
1196 @type doc: xml.dom.minidom.Document instance
1197 @param element: The element to add the model XML elements to.
1198 @type element: XML element object
1199 """
1200
1201
1202 for i in range(len(self)):
1203
1204 model_element = doc.createElement('model')
1205 element.appendChild(model_element)
1206
1207
1208 model_element.setAttribute('desc', 'Model container')
1209 model_element.setAttribute('num', str(self[i].num))
1210
1211
1212 fill_object_contents(doc, model_element, object=self[i], blacklist=['num', 'mol'] + list(self[i].__class__.__dict__.keys()))
1213
1214
1215 self[i].mol.to_xml(doc, model_element)
1216
1217
1218
1220 """Class containing all the model specific data."""
1221
1223 """Set up the default objects of the model data container."""
1224
1225
1226 self.num = model_num
1227
1228
1229 self.mol = MolList()
1230
1231
1233 """The string representation of the object.
1234
1235 Rather than using the standard Python conventions (either the string representation of the
1236 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
1237 """
1238
1239
1240 text = "Class containing the data for model %s.\n" % self.num
1241
1242
1243 text = text + "\n"
1244 text = text + "Objects:\n"
1245 for name in dir(self):
1246
1247 if name == 'mol':
1248 text = text + " mol: The list of %s molecules within the model.\n" % len(self.mol)
1249 continue
1250
1251
1252 if name == 'is_empty':
1253 continue
1254
1255
1256 if match("^__", name):
1257 continue
1258
1259
1260 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n"
1261
1262 return text
1263
1264
1266 """Method for testing if this ModelContainer object is empty.
1267
1268 @return: True if this container is empty and the model number has not been set, False
1269 otherwise.
1270 @rtype: bool
1271 """
1272
1273
1274 if self.num != None:
1275 return False
1276
1277
1278 for name in dir(self):
1279
1280 if name == 'num' or name == 'mol':
1281 continue
1282
1283
1284 if name == 'is_empty':
1285 continue
1286
1287
1288 if match("^__", name):
1289 continue
1290
1291
1292 return False
1293
1294
1295 if not self.mol.is_empty():
1296 return False
1297
1298
1299 return True
1300
1301
1302
1304 """List type data container for holding the different molecules of one model."""
1305
1307 """The string representation of the object.
1308
1309 Rather than using the standard Python conventions (either the string representation of the
1310 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
1311 """
1312
1313 text = "Molecules.\n\n"
1314 text = text + "%-8s%-8s" % ("Index", "Name") + "\n"
1315 for i in range(len(self)):
1316 text = text + "%-8i%-8s" % (i, self[i].mol_name) + "\n"
1317 return text
1318
1319
1320 - def add_item(self, mol_name=None, mol_cont=None):
1321 """Append the given MolContainer instance to the MolList.
1322
1323 @keyword mol_name: The molecule number.
1324 @type mol_name: int
1325 @keyword mol_cont: The data structure for the molecule.
1326 @type mol_cont: MolContainer instance
1327 """
1328
1329
1330 if len(self) and self.is_empty():
1331 self[0].mol_name = mol_name
1332
1333
1334 else:
1335
1336 for i in range(len(self)):
1337 if self[i].mol_name == mol_name:
1338 raise RelaxError("The molecule '%s' already exists." % mol_name)
1339
1340
1341 self.append(mol_cont)
1342
1343
1344 self[-1].mol_name = mol_name
1345
1346
1348 """Method for testing if this MolList object is empty.
1349
1350 @return: True if this list only has one MolContainer and the molecule name has not
1351 been set, False otherwise.
1352 @rtype: bool
1353 """
1354
1355
1356 if len(self) == 0:
1357 return True
1358
1359
1360 if len(self) == 1 and hasattr(self[0], 'is_empty') and self[0].is_empty():
1361 return True
1362
1363
1364 return False
1365
1366
1367 - def from_xml(self, mol_nodes, id=None, file_version=1):
1368 """Recreate a molecule list data structure from the XML molecule nodes.
1369
1370 @param mol_nodes: The molecule XML nodes.
1371 @type mol_nodes: xml.dom.minicompat.NodeList instance
1372 @keyword id: The specific structural object ID string. This can be 'scientific', 'internal', etc.
1373 @type id: str
1374 @keyword file_version: The relax XML version of the XML file.
1375 @type file_version: int
1376 """
1377
1378
1379 if not self.is_empty():
1380 raise RelaxFromXMLNotEmptyError(self.__class__.__name__)
1381
1382
1383 for mol_node in mol_nodes:
1384
1385 if id == 'internal':
1386 from generic_fns.structure.internal import MolContainer
1387 elif id == 'scientific':
1388 from generic_fns.structure.scientific import MolContainer
1389
1390
1391 mol_cont = MolContainer()
1392
1393
1394 name = mol_node.getAttribute('name')
1395 if name == 'None':
1396 name = None
1397
1398
1399 self.add_item(mol_name=name, mol_cont=mol_cont)
1400
1401
1402 self[-1].from_xml(mol_node, file_version=file_version)
1403
1404
1405 - def to_xml(self, doc, element):
1406 """Create XML elements for each molecule.
1407
1408 @param doc: The XML document object.
1409 @type doc: xml.dom.minidom.Document instance
1410 @param element: The element to add the molecule XML elements to.
1411 @type element: XML element object
1412 """
1413
1414
1415 for i in range(len(self)):
1416
1417 self[i].to_xml(doc, element)
1418