1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from math import sqrt
24 from minfx.generic import generic_minimise
25 from numpy import array, dot, float64, ndarray, zeros
26 from numpy.linalg import norm
27 from os import F_OK, access
28 from re import search
29 import sys
30 from warnings import warn
31
32
33 from generic_fns import molmol, relax_re
34 from generic_fns.interatomic import interatomic_loop
35 from generic_fns.mol_res_spin import create_spin, exists_mol_res_spin_data, generate_spin_id_unique, linear_ave, return_molecule, return_residue, return_spin, spin_loop
36 from generic_fns import pipes
37 from generic_fns.structure.api_base import Displacements
38 from generic_fns.structure.internal import Internal
39 from generic_fns.structure.scientific import Scientific_data
40 from generic_fns.structure.statistics import atomic_rmsd
41 from generic_fns.structure.superimpose import fit_to_first, fit_to_mean
42 from maths_fns.ens_pivot_finder import Pivot_finder
43 from relax_errors import RelaxError, RelaxFileError, RelaxNoPdbError, RelaxNoSequenceError
44 from relax_io import get_file_path, open_write_file, write_data, write_spin_data
45 from relax_warnings import RelaxWarning, RelaxNoPDBFileWarning, RelaxZeroVectorWarning
46
47
48 -def add_atom(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):
49 """Add a new atom to the structural data object.
50
51 @keyword mol_name: The name of the molecule.
52 @type mol_name: str
53 @keyword atom_name: The atom name, e.g. 'H1'.
54 @type atom_name: str or None
55 @keyword res_name: The residue name.
56 @type res_name: str or None
57 @keyword res_num: The residue number.
58 @type res_num: int or None
59 @keyword pos: The position vector of coordinates. If a rank-2 array is supplied, the length of the first dimension must match the number of models.
60 @type pos: rank-1 or rank-2 array or list of float
61 @keyword element: The element symbol.
62 @type element: str or None
63 @keyword atom_num: The atom number.
64 @type atom_num: int or None
65 @keyword chain_id: The chain identifier.
66 @type chain_id: str or None
67 @keyword segment_id: The segment identifier.
68 @type segment_id: str or None
69 @keyword pdb_record: The optional PDB record name, e.g. 'ATOM' or 'HETATM'.
70 @type pdb_record: str or None
71 """
72
73
74 pipes.test()
75
76
77 if not hasattr(cdp, 'structure'):
78 cdp.structure = Internal()
79
80
81 cdp.structure.add_atom(mol_name=mol_name, atom_name=atom_name, res_name=res_name, res_num=res_num, pos=pos, element=element, atom_num=atom_num, chain_id=chain_id, segment_id=segment_id, pdb_record=pdb_record)
82
83
85 """Add a new model to the empty structural data object."""
86
87
88 pipes.test()
89
90
91 if not hasattr(cdp, 'structure'):
92 cdp.structure = Internal()
93
94
95 if cdp.structure.id != 'internal':
96 raise RelaxError("Models can only be added to the internal structural object.")
97
98
99 if cdp.structure.num_molecules() != 0:
100 raise RelaxError("The internal structural object is not empty.")
101
102
103 cdp.structure.structural_data.add_item(model_num=model_num)
104 print("Created the empty model number %s." % model_num)
105
106
108 """Connect two atoms.
109
110 @keyword index1: The global index of the first atom.
111 @type index1: str
112 @keyword index2: The global index of the first atom.
113 @type index2: str
114 """
115
116
117 pipes.test()
118
119
120 if not hasattr(cdp, 'structure'):
121 cdp.structure = Internal()
122
123
124 cdp.structure.connect_atom(index1=index1, index2=index2)
125
126
128 """Delete structural data.
129
130 @keyword atom_id: The molecule, residue, and atom identifier string. This matches the spin ID string format. If not given, then all structural data will be deleted.
131 @type atom_id: str or None
132 """
133
134
135 pipes.test()
136
137
138 if hasattr(cdp, 'structure'):
139 print("Deleting structural data from the current pipe.")
140 cdp.structure.delete(atom_id=atom_id)
141 else:
142 print("No structures are present.")
143
144
145 print("Deleting all spin specific structural info.")
146 for spin in spin_loop(selection=atom_id):
147
148 if hasattr(spin, 'pos'):
149 del spin.pos
150
151
152 print("Deleting all interatomic vectors.")
153 for interatom in interatomic_loop(selection1=atom_id):
154
155 if hasattr(interatom, 'vector'):
156 del interatom.vector
157
158
159 -def displacement(model_from=None, model_to=None, atom_id=None, centroid=None):
160 """Calculate the rotational and translational displacement between two structural models.
161
162 @keyword model_from: The optional model number for the starting position of the displacement.
163 @type model_from: int or None
164 @keyword model_to: The optional model number for the ending position of the displacement.
165 @type model_to: int or None
166 @keyword atom_id: The molecule, residue, and atom identifier string. This matches the spin ID string format.
167 @type atom_id: str or None
168 @keyword centroid: An alternative position of the centroid, used for studying pivoted systems.
169 @type centroid: list of float or numpy rank-1, 3D array
170 """
171
172
173 pipes.test()
174
175
176 if model_from != None:
177 model_from = [model_from]
178 if model_to != None:
179 model_to = [model_to]
180
181
182 models = []
183 for model in cdp.structure.model_loop():
184 models.append(model.num)
185
186
187 if model_from == None:
188 model_from = models
189 if model_to == None:
190 model_to = models
191
192
193 if not hasattr(cdp.structure, 'displacements'):
194 cdp.structure.displacements = Displacements()
195
196
197 for i in range(len(model_from)):
198
199 coord_from = []
200 for pos in cdp.structure.atom_loop(atom_id=atom_id, model_num=model_from[i], pos_flag=True):
201 coord_from.append(pos)
202
203
204 for j in range(len(model_to)):
205
206 coord_to = []
207 for pos in cdp.structure.atom_loop(atom_id=atom_id, model_num=model_to[j], pos_flag=True):
208 coord_to.append(pos)
209
210
211 cdp.structure.displacements._calculate(model_from=model_from[i], model_to=model_to[j], coord_from=array(coord_from), coord_to=array(coord_to), centroid=centroid)
212
213
214 -def find_pivot(models=None, atom_id=None, init_pos=None, func_tol=1e-5, box_limit=200):
215 """Superimpose a set of structural models.
216
217 @keyword models: The list of models to use. If set to None, then all models will be used.
218 @type models: list of int or None
219 @keyword atom_id: The molecule, residue, and atom identifier string. This matches the spin ID string format.
220 @type atom_id: str or None
221 @keyword init_pos: The starting pivot position for the pivot point optimisation.
222 @type init_pos: list of float or numpy rank-1, 3D array
223 @keyword func_tol: The function tolerance which, when reached, terminates optimisation. Setting this to None turns of the check.
224 @type func_tol: None or float
225 @keyword box_limit: The simplex optimisation used in this function is constrained withing a box of +/- x Angstrom containing the pivot point using the logarithmic barrier function. This argument is the value of x.
226 @type box_limit: int
227 """
228
229
230 pipes.test()
231
232
233 if init_pos == None:
234 init_pos = zeros(3, float64)
235 init_pos = array(init_pos)
236
237
238 cdp.structure.validate_models()
239
240
241 if models == None:
242 models = []
243 for model in cdp.structure.model_loop():
244 models.append(model.num)
245
246
247 coord = []
248 for model in models:
249 coord.append([])
250 for pos in cdp.structure.atom_loop(atom_id=atom_id, model_num=model, pos_flag=True):
251 coord[-1].append(pos)
252 coord[-1] = array(coord[-1])
253 coord = array(coord)
254
255
256 A = zeros((6, 3), float64)
257 b = zeros(6, float64)
258 for i in range(3):
259 A[2*i, i] = 1
260 A[2*i+1, i] = -1
261 b[2*i] = -box_limit
262 b[2*i+1] = -box_limit
263
264
265 finder = Pivot_finder(models, coord)
266 results = generic_minimise(func=finder.func, x0=init_pos, min_algor='Log barrier', min_options=('simplex',), A=A, b=b, func_tol=func_tol, print_flag=1)
267
268
269 if results == None:
270 return
271
272
273 cdp.structure.pivot = results
274
275
276 print("Motional pivot found at: %s" % results)
277
278
279 -def get_pos(spin_id=None, str_id=None, ave_pos=False):
280 """Load the spins from the structural object into the relax data store.
281
282 @keyword spin_id: The molecule, residue, and spin identifier string.
283 @type spin_id: str
284 @keyword str_id: The structure identifier. This can be the file name, model number, or structure number.
285 @type str_id: int or str
286 @keyword ave_pos: A flag specifying if the average atom position or the atom position from all loaded structures is loaded into the SpinContainer.
287 @type ave_pos: bool
288 """
289
290
291 pipes.test()
292
293
294 if not hasattr(cdp, 'structure') or not cdp.structure.num_models() or not cdp.structure.num_molecules():
295 raise RelaxNoPdbError
296
297
298 model_index = -1
299 last_model = None
300 data = []
301 for model_num, mol_name, res_num, res_name, atom_num, atom_name, element, pos in cdp.structure.atom_loop(atom_id=spin_id, str_id=str_id, model_num_flag=True, mol_name_flag=True, res_num_flag=True, res_name_flag=True, atom_num_flag=True, atom_name_flag=True, element_flag=True, pos_flag=True, ave=ave_pos):
302
303 if last_model != model_num:
304 model_index = model_index + 1
305 last_model = model_num
306
307
308 if mol_name and search('\+', mol_name):
309 mol_name = mol_name.replace('+', '')
310 if res_name and search('\+', res_name):
311 res_name = res_name.replace('+', '')
312 if atom_name and search('\+', atom_name):
313 atom_name = atom_name.replace('+', '')
314
315
316 id = generate_spin_id_unique(res_num=res_num, res_name=None, spin_num=atom_num, spin_name=atom_name)
317
318
319 spin_cont = return_spin(id)
320
321
322 if spin_cont == None:
323 continue
324
325
326 if ave_pos:
327 spin_cont.pos = pos
328 else:
329 if not hasattr(spin_cont, 'pos'):
330 spin_cont.pos = []
331 spin_cont.pos.append(pos)
332
333
334 data.append([id, repr(pos)])
335
336
337 if not len(data):
338 raise RelaxError("No positional information matching the spin ID '%s' could be found." % spin_id)
339
340
341 for spin in spin_loop():
342 if hasattr(spin, 'members'):
343
344 positions = []
345 for atom in spin.members:
346
347 subspin = return_spin(atom)
348
349
350 if subspin == None:
351 raise RelaxNoSpinError(atom)
352
353
354 if not hasattr(subspin, 'pos') or not subspin.pos:
355 raise RelaxError("Positional information is not available for the atom '%s'." % atom)
356
357
358 pos = subspin.pos
359
360
361 multi_model = True
362 if type(pos[0]) in [float, float64]:
363 multi_model = False
364 pos = [pos]
365
366
367 positions.append([])
368 for i in range(len(pos)):
369 positions[-1].append(pos[i].tolist())
370
371
372 if spin.averaging == 'linear':
373
374 ave = linear_ave(positions)
375
376
377 if multi_model:
378 spin.pos = ave
379 else:
380 spin.pos = ave[0]
381
382
383 write_data(out=sys.stdout, headings=["Spin_ID", "Position"], data=data)
384
385
386 -def load_spins(spin_id=None, str_id=None, mol_name_target=None, ave_pos=False):
387 """Load the spins from the structural object into the relax data store.
388
389 @keyword spin_id: The molecule, residue, and spin identifier string.
390 @type spin_id: str
391 @keyword str_id: The structure identifier. This can be the file name, model number, or structure number.
392 @type str_id: int or str
393 @keyword mol_name: The name of target molecule container, overriding the name of the loaded structures
394 @type mol_name: str or None
395 @keyword ave_pos: A flag specifying if the average atom position or the atom position from all loaded structures is loaded into the SpinContainer.
396 @type ave_pos: bool
397 """
398
399
400 pipes.test()
401
402
403 if not hasattr(cdp, 'structure') or not cdp.structure.num_models() or not cdp.structure.num_molecules():
404 raise RelaxNoPdbError
405
406
407 print("Adding the following spins to the relax data store.\n")
408
409
410 mol_names = []
411 res_nums = []
412 res_names = []
413 spin_nums = []
414 spin_names = []
415
416
417 model_index = -1
418 last_model = 1000000
419
420
421 for model_num, mol_name, res_num, res_name, atom_num, atom_name, element, pos in cdp.structure.atom_loop(atom_id=spin_id, str_id=str_id, model_num_flag=True, mol_name_flag=True, res_num_flag=True, res_name_flag=True, atom_num_flag=True, atom_name_flag=True, element_flag=True, pos_flag=True, ave=ave_pos):
422
423 if mol_name_target:
424 mol_name = mol_name_target
425
426
427 if last_model != model_num:
428 model_index = model_index + 1
429 last_model = model_num
430
431
432 if mol_name and search('\+', mol_name):
433 mol_name = mol_name.replace('+', '')
434 if res_name and search('\+', res_name):
435 res_name = res_name.replace('+', '')
436 if atom_name and search('\+', atom_name):
437 atom_name = atom_name.replace('+', '')
438
439
440 id = generate_spin_id_unique(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=atom_num, spin_name=atom_name)
441
442
443 try:
444 spin_cont = create_spin(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=atom_num, spin_name=atom_name)
445 except RelaxError:
446
447 if not model_index:
448 warn(RelaxWarning("The spin '%s' already exists." % id))
449 continue
450
451
452 spin_cont = return_spin(id)
453
454
455 if model_index == 0:
456 if mol_name_target:
457 mol_names.append(mol_name_target)
458 else:
459 mol_names.append(mol_name)
460 res_nums.append(res_num)
461 res_names.append(res_name)
462 spin_nums.append(atom_num)
463 spin_names.append(atom_name)
464
465
466 pos = array(pos, float64)
467
468
469 if ave_pos:
470 spin_cont.pos = pos
471
472
473 else:
474
475 if not hasattr(spin_cont, 'pos'):
476 spin_cont.pos = []
477
478
479 spin_cont.pos.append(pos)
480
481
482 if not model_index:
483 spin_cont.element = element
484
485
486 if len(mol_names) == 0:
487 warn(RelaxWarning("No spins matching the '%s' ID string could be found." % spin_id))
488 return
489
490
491 write_spin_data(file=sys.stdout, mol_names=mol_names, res_nums=res_nums, res_names=res_names, spin_nums=spin_nums, spin_names=spin_names)
492
493
494 -def read_pdb(file=None, dir=None, read_mol=None, set_mol_name=None, read_model=None, set_model_num=None, parser='internal', alt_loc=None, verbosity=1, merge=False, fail=True):
495 """The PDB loading function.
496
497 Parsers
498 =======
499
500 A number of parsers are available for reading PDB files. These include:
501
502 - 'scientific', the Scientific Python PDB parser.
503 - 'internal', a low quality yet fast PDB parser built into relax.
504
505
506 @keyword file: The name of the PDB file to read.
507 @type file: str
508 @keyword dir: The directory where the PDB file is located. If set to None, then the file will be searched for in the current directory.
509 @type dir: str or None
510 @keyword read_mol: The molecule(s) to read from the file, independent of model. The molecules are determined differently by the different parsers, but are numbered consecutively from 1. If set to None, then all molecules will be loaded.
511 @type read_mol: None, int, or list of int
512 @keyword set_mol_name: Set the names of the molecules which are loaded. If set to None, then the molecules will be automatically labelled based on the file name or other information.
513 @type set_mol_name: None, str, or list of str
514 @keyword read_model: The PDB model to extract from the file. If set to None, then all models will be loaded.
515 @type read_model: None, int, or list of int
516 @keyword set_model_num: Set the model number of the loaded molecule. If set to None, then the PDB model numbers will be preserved, if they exist.
517 @type set_model_num: None, int, or list of int
518 @keyword parser: The parser to be used to read the PDB file.
519 @type parser: str
520 @keyword alt_loc: The PDB ATOM record 'Alternate location indicator' field value to select which coordinates to use.
521 @type alt_loc: str or None
522 @keyword verbosity: The amount of information to print to screen. Zero corresponds to minimal output while higher values increase the amount of output. The default value is 1.
523 @type verbosity: int
524 @keyword merge: A flag which if set to True will try to merge the PDB structure into the currently loaded structures.
525 @type merge: bool
526 @keyword fail: A flag which, if True, will cause a RelaxError to be raised if the PDB file does not exist. If False, then a RelaxWarning will be trown instead.
527 @type fail: bool
528 @raise RelaxFileError: If the fail flag is set, then a RelaxError is raised if the PDB file does not exist.
529 """
530
531
532 pipes.test()
533
534
535 file_path = get_file_path(file, dir)
536
537
538 file_path_orig = file_path
539 if not access(file_path, F_OK):
540
541 for ext in ['.pdb', '.gz', '.pdb.gz', '.bz2', '.pdb.bz2']:
542
543 if access(file_path+ext, F_OK):
544 file_path = file_path + ext
545
546
547 if not access(file_path, F_OK):
548 if fail:
549 raise RelaxFileError('PDB', file_path_orig)
550 else:
551 warn(RelaxNoPDBFileWarning(file_path))
552 return
553
554
555 if hasattr(cdp, 'structure') and cdp.structure.id != parser:
556 raise RelaxError("The " + repr(parser) + " parser does not match the " + repr(cdp.structure.id) + " parser of the PDB loaded into the current pipe.")
557
558
559 if not hasattr(cdp, 'structure'):
560 if parser == 'scientific':
561 cdp.structure = Scientific_data()
562 elif parser == 'internal':
563 cdp.structure = Internal()
564
565
566 cdp.structure.load_pdb(file_path, read_mol=read_mol, set_mol_name=set_mol_name, read_model=read_model, set_model_num=set_model_num, alt_loc=alt_loc, verbosity=verbosity, merge=merge)
567
568
569 molmol.molmol_obj.open_pdb()
570
571
572 -def read_xyz(file=None, dir=None, read_mol=None, set_mol_name=None, read_model=None, set_model_num=None, verbosity=1, fail=True):
573 """The XYZ loading function.
574
575
576 @keyword file: The name of the XYZ file to read.
577 @type file: str
578 @keyword dir: The directory where the XYZ file is located. If set to None, then the
579 file will be searched for in the current directory.
580 @type dir: str or None
581 @keyword read_mol: The molecule(s) to read from the file, independent of model.
582 If set to None, then all molecules will be loaded.
583 @type read_mol: None, int, or list of int
584 @keyword set_mol_name: Set the names of the molecules which are loaded. If set to None, then
585 the molecules will be automatically labelled based on the file name or
586 other information.
587 @type set_mol_name: None, str, or list of str
588 @keyword read_model: The XYZ model to extract from the file. If set to None, then all models
589 will be loaded.
590 @type read_model: None, int, or list of int
591 @keyword set_model_num: Set the model number of the loaded molecule. If set to None, then the
592 XYZ model numbers will be preserved, if they exist.
593 @type set_model_num: None, int, or list of int
594 @keyword fail: A flag which, if True, will cause a RelaxError to be raised if the XYZ
595 file does not exist. If False, then a RelaxWarning will be trown
596 instead.
597 @type fail: bool
598 @keyword verbosity: The amount of information to print to screen. Zero corresponds to
599 minimal output while higher values increase the amount of output. The
600 default value is 1.
601 @type verbosity: int
602 @raise RelaxFileError: If the fail flag is set, then a RelaxError is raised if the XYZ file
603 does not exist.
604 """
605
606
607 pipes.test()
608
609
610 file_path = get_file_path(file, dir)
611
612
613 if not access(file_path, F_OK):
614 file_path_orig = file_path
615 file_path = file_path + '.xyz'
616
617
618 if not access(file_path, F_OK):
619 if fail:
620 raise RelaxFileError('XYZ', file_path_orig)
621 else:
622 warn(RelaxNoPDBFileWarning(file_path))
623 return
624
625
626 if not hasattr(cdp, 'structure'):
627 cdp.structure = Internal()
628
629
630 cdp.structure.load_xyz(file_path, read_mol=read_mol, set_mol_name=set_mol_name, read_model=read_model, set_model_num=set_model_num, verbosity=verbosity)
631
632
633 -def rmsd(atom_id=None, models=None):
634 """Calculate the RMSD between the loaded models.
635
636 @keyword atom_id: The molecule, residue, and atom identifier string. Only atoms matching this selection will be used.
637 @type atom_id: str or None
638 @keyword models: The list of models to calculate the RMDS of. If set to None, then all models will be used.
639 @type models: list of int or None
640 @return: The RMSD value.
641 @rtype: float
642 """
643
644
645 pipes.test()
646
647
648 if models == None:
649 models = []
650 for model in cdp.structure.model_loop():
651 models.append(model.num)
652
653
654 coord = []
655 for model in models:
656 coord.append([])
657 for pos in cdp.structure.atom_loop(atom_id=atom_id, model_num=model, pos_flag=True):
658 coord[-1].append(pos)
659 coord[-1] = array(coord[-1])
660
661
662 cdp.structure.rmsd = atomic_rmsd(coord, verbosity=1)
663
664
665 return cdp.structure.rmsd
666
667
668 -def rotate(R=None, origin=None, model=None, atom_id=None):
669 """Rotate the structural data about the origin by the specified forwards rotation.
670
671 @keyword R: The forwards rotation matrix.
672 @type R: numpy 3D, rank-2 array or a 3x3 list of floats
673 @keyword origin: The origin of the rotation. If not supplied, the origin will be set to [0, 0, 0].
674 @type origin: numpy 3D, rank-1 array or list of len 3 or None
675 @keyword model: The model to rotate. If None, all models will be rotated.
676 @type model: int
677 @keyword atom_id: The molecule, residue, and atom identifier string. Only atoms matching this selection will be used.
678 @type atom_id: str or None
679 """
680
681
682 pipes.test()
683
684
685 if not hasattr(cdp, 'structure') or not cdp.structure.num_models() or not cdp.structure.num_molecules():
686 raise RelaxNoPdbError
687
688
689 if origin == None:
690 origin = [0, 0, 0]
691
692
693 R = array(R, float64)
694 origin = array(origin, float64)
695
696
697 cdp.structure.rotate(R=R, origin=origin, model=model, atom_id=atom_id)
698
699
701 """Place the XH unit vector into the spin container object.
702
703 @keyword spin: The spin container object.
704 @type spin: SpinContainer instance
705 @keyword xh_vect: The unit vector parallel to the XH bond.
706 @type xh_vect: array of len 3
707 """
708
709
710 spin.xh_vect = xh_vect
711
712
713 -def superimpose(models=None, method='fit to mean', atom_id=None, centroid=None):
714 """Superimpose a set of structural models.
715
716 @keyword models: The list of models to superimpose. If set to None, then all models will be used.
717 @type models: list of int or None
718 @keyword method: The superimposition method. It must be one of 'fit to mean' or 'fit to first'.
719 @type method: str
720 @keyword atom_id: The molecule, residue, and atom identifier string. This matches the spin ID string format.
721 @type atom_id: str or None
722 @keyword centroid: An alternative position of the centroid to allow for different superpositions, for example of pivot point motions.
723 @type centroid: list of float or numpy rank-1, 3D array
724 """
725
726
727 allowed = ['fit to mean', 'fit to first']
728 if method not in allowed:
729 raise RelaxError("The superimposition method '%s' is unknown. It must be one of %s." % (method, allowed))
730
731
732 pipes.test()
733
734
735 cdp.structure.validate_models()
736
737
738 if models == None:
739 models = []
740 for model in cdp.structure.model_loop():
741 models.append(model.num)
742
743
744 coord = []
745 for model in models:
746 coord.append([])
747 for pos in cdp.structure.atom_loop(atom_id=atom_id, model_num=model, pos_flag=True):
748 coord[-1].append(pos)
749 coord[-1] = array(coord[-1])
750
751
752 if method == 'fit to mean':
753 T, R, pivot = fit_to_mean(models=models, coord=coord, centroid=centroid)
754 elif method == 'fit to first':
755 T, R, pivot = fit_to_first(models=models, coord=coord, centroid=centroid)
756
757
758
759 for i in range(len(models)):
760
761 translate(T=T[i], model=models[i])
762
763
764 rotate(R=R[i], origin=pivot[i], model=models[i])
765
766
767 -def translate(T=None, model=None, atom_id=None):
768 """Shift the structural data by the specified translation vector.
769
770 @keyword T: The translation vector.
771 @type T: numpy rank-1, 3D array or list of float
772 @keyword model: The model to translate. If None, all models will be rotated.
773 @type model: int or None
774 @keyword atom_id: The molecule, residue, and atom identifier string. Only atoms matching this selection will be used.
775 @type atom_id: str or None
776 """
777
778
779 pipes.test()
780
781
782 if not hasattr(cdp, 'structure') or not cdp.structure.num_models() or not cdp.structure.num_molecules():
783 raise RelaxNoPdbError
784
785
786 T = array(T, float64)
787
788
789 cdp.structure.translate(T=T, model=model, atom_id=atom_id)
790
791
792 -def vectors(spin_id1=None, spin_id2=None, model=None, verbosity=1, ave=True, unit=True):
793 """Extract the bond vectors from the loaded structures and store them in the spin container.
794
795 @keyword spin_id1: The spin identifier string of the first spin of the pair.
796 @type spin_id1: str
797 @keyword spin_id2: The spin identifier string of the second spin of the pair.
798 @type spin_id2: str
799 @keyword model: The model to extract the vector from. If None, all vectors will be extracted.
800 @type model: str
801 @keyword verbosity: The higher the value, the more information is printed to screen.
802 @type verbosity: int
803 @keyword ave: A flag which if True will cause the average of all vectors to be extracted.
804 @type ave: bool
805 @keyword unit: A flag which if True will cause the function to calculate the unit vectors.
806 @type unit: bool
807 """
808
809
810 pipes.test()
811
812
813 if not hasattr(cdp, 'structure'):
814 raise RelaxNoPdbError
815
816
817 if not exists_mol_res_spin_data():
818 raise RelaxNoSequenceError
819
820
821 if verbosity:
822
823 num_models = cdp.structure.num_models()
824
825
826 if num_models > 1:
827 if model:
828 print("Extracting vectors for model '%s'." % model)
829 else:
830 print("Extracting vectors for all %s models." % num_models)
831 if ave:
832 print("Averaging all vectors.")
833
834
835 else:
836 print("Extracting vectors from the single model.")
837
838
839 if unit:
840 print("Calculating the unit vectors.")
841
842
843 no_vectors = True
844 for spin, mol_name, res_num, res_name in spin_loop(selection=spin_id, full_info=True):
845
846 if not spin.select:
847 continue
848
849
850 id = generate_spin_id_unique(res_num=res_num, res_name=None, spin_name=spin.name, spin_num=spin.num)
851
852
853 if spin.num == None and spin.name == None:
854 warn(RelaxWarning("Either the spin number or name must be set for the spin " + repr(id) + " to identify the corresponding atom in the molecule."))
855 continue
856
857
858 if hasattr(spin, 'vector'):
859 obj = getattr(spin, 'vector')
860 if obj != None:
861 warn(RelaxWarning("The bond vector for the spin " + repr(id) + " already exists."))
862 continue
863
864
865 bond_vectors, attached_name, warnings = cdp.structure.bond_vectors(attached_atom=attached, model_num=model, res_num=res_num, spin_name=spin.name, spin_num=spin.num, return_name=True, return_warnings=True)
866
867
868 if not bond_vectors:
869
870 if warnings:
871 warn(RelaxWarning(warnings + " (atom ID " + repr(id) + ")."))
872
873
874 continue
875
876
877 if not hasattr(spin, 'attached_atom'):
878 spin.attached_atom = attached_name
879 elif spin.attached_atom != attached_name:
880 raise RelaxError("The " + repr(spin.attached_atom) + " atom already attached to the spin does not match the attached atom " + repr(attached_name) + ".")
881
882
883 if ave:
884 ave_vector = zeros(3, float64)
885
886
887 for i in range(len(bond_vectors)):
888
889 if unit:
890
891 norm_factor = norm(bond_vectors[i])
892
893
894 if norm_factor == 0.0:
895 warn(RelaxZeroVectorWarning(id))
896
897
898 else:
899 bond_vectors[i] = bond_vectors[i] / norm_factor
900
901
902 if ave:
903 ave_vector = ave_vector + bond_vectors[i]
904
905
906 if ave:
907 vector = ave_vector / float(len(bond_vectors))
908 else:
909 vector = bond_vectors
910
911
912 if len(vector) == 1:
913 vector = vector[0]
914
915
916 setattr(spin, 'vector', vector)
917
918
919 no_vectors = False
920
921
922 if verbosity:
923
924 num = len(bond_vectors)
925 plural = 's'
926 if num == 1:
927 plural = ''
928
929 if spin.name:
930 print("Extracted %s %s-%s vector%s for the spin '%s'." % (num, spin.name, attached_name, plural, id))
931 else:
932 print("Extracted %s %s-%s vector%s for the spin '%s'." % (num, spin.num, attached_name, plural, id))
933
934
935 if no_vectors:
936 raise RelaxError("No vectors could be extracted.")
937
938
939 -def web_of_motion(file=None, dir=None, models=None, force=False):
940 """Create a PDB representation of the motion between a set of models.
941
942 This will create a PDB file containing the atoms of all models, with identical atoms links using CONECT records. This function only supports the internal structural object.
943
944 @keyword file: The name of the PDB file to write.
945 @type file: str
946 @keyword dir: The directory where the PDB file will be placed. If set to None, then the file will be placed in the current directory.
947 @type dir: str or None
948 @keyword models: The optional list of models to restrict this to.
949 @type models: list of int or None
950 @keyword force: The force flag which if True will cause the file to be overwritten.
951 @type force: bool
952 """
953
954
955 pipes.test()
956
957
958 if not hasattr(cdp, 'structure') or not cdp.structure.num_models() or not cdp.structure.num_molecules():
959 raise RelaxNoPdbError
960
961
962 cdp.structure.validate_models()
963
964
965 if cdp.structure.id != 'internal':
966 raise RelaxError("The %s structure type is not supported." % cdp.structure.id)
967
968
969 web = Internal()
970
971
972 if models == None:
973 models = []
974 for k in range(len(cdp.structure.structural_data)):
975 models.append(cdp.structure.structural_data[k].num)
976
977
978 for i in range(len(cdp.structure.structural_data[0].mol)):
979
980 mol1 = cdp.structure.structural_data[0].mol[i]
981
982
983 for j in range(len(mol1.atom_name)):
984
985 for k in range(len(cdp.structure.structural_data)):
986
987 if cdp.structure.structural_data[k].num not in models:
988 continue
989
990
991 mol = cdp.structure.structural_data[k].mol[i]
992
993
994 web.add_atom(mol_name=mol1.mol_name, atom_name=mol.atom_name[j], res_name=mol.res_name[j], res_num=mol.res_num[j], pos=[mol.x[j], mol.y[j], mol.z[j]], element=mol.element[j], chain_id=mol.chain_id[j], segment_id=mol.seg_id[j], pdb_record=mol.pdb_record[j])
995
996
997 for k in range(len(models)):
998 for l in range(len(models)):
999
1000 if k == l:
1001 continue
1002
1003
1004 index1 = j*len(models) + k
1005 index2 = j*len(models) + l
1006
1007
1008 web.connect_atom(mol_name=mol1.mol_name, index1=index1, index2=index2)
1009
1010
1011 if isinstance(file, str):
1012
1013 file = get_file_path(file, dir)
1014
1015
1016 if not search(".pdb$", file):
1017 file += '.pdb'
1018
1019
1020 file = open_write_file(file, force=force)
1021
1022
1023 web.write_pdb(file)
1024
1025
1026 -def write_pdb(file=None, dir=None, model_num=None, compress_type=0, force=False):
1027 """The PDB writing function.
1028
1029 @keyword file: The name of the PDB file to write.
1030 @type file: str
1031 @keyword dir: The directory where the PDB file will be placed. If set to None, then the file will be placed in the current directory.
1032 @type dir: str or None
1033 @keyword model_num: The model to place into the PDB file. If not supplied, then all models will be placed into the file.
1034 @type model_num: None or int
1035 @keyword compress_type: The compression type. The integer values correspond to the compression type: 0, no compression; 1, Bzip2 compression; 2, Gzip compression.
1036 @type compress_type: int
1037 @keyword force: The force flag which if True will cause the file to be overwritten.
1038 @type force: bool
1039 """
1040
1041
1042 pipes.test()
1043
1044
1045 if not hasattr(cdp, 'structure'):
1046 raise RelaxError("No structural data is present in the current data pipe.")
1047
1048
1049 if cdp.structure.id in ['scientific']:
1050 raise RelaxError("The structures from the " + cdp.structure.id + " parser are not writable.")
1051
1052
1053 file_path = get_file_path(file, dir)
1054
1055
1056 if not search(".pdb$", file_path):
1057 file_path = file_path + '.pdb'
1058
1059
1060 file = open_write_file(file_path, compress_type=compress_type, force=force)
1061
1062
1063 cdp.structure.write_pdb(file, model_num=model_num)
1064