1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for the manipulation of the interatomic data structures in the relax data store."""
24
25
26 from copy import deepcopy
27 from numpy import float64, zeros
28 from numpy.linalg import norm
29 from re import search
30 import sys
31 from warnings import warn
32
33
34 from lib.arg_check import is_float
35 from lib.errors import RelaxError, RelaxInteratomInconsistentError, RelaxNoInteratomError, RelaxNoSpinError
36 from lib.io import extract_data, strip, write_data
37 from lib.warnings import RelaxWarning, RelaxZeroVectorWarning
38 from pipe_control import pipes
39 from pipe_control.mol_res_spin import Selection, count_spins, exists_mol_res_spin_data, generate_spin_id_unique, return_spin, spin_loop
40 from pipe_control.pipes import check_pipe
41
42
43 -def copy(pipe_from=None, pipe_to=None, spin_id1=None, spin_id2=None, verbose=True):
44 """Copy the interatomic data from one data pipe to another.
45
46 @keyword pipe_from: The data pipe to copy the interatomic data from. This defaults to the current data pipe.
47 @type pipe_from: str
48 @keyword pipe_to: The data pipe to copy the interatomic data to. This defaults to the current data pipe.
49 @type pipe_to: str
50 @keyword spin_id1: The spin ID string of the first atom.
51 @type spin_id1: str
52 @keyword spin_id2: The spin ID string of the second atom.
53 @type spin_id2: str
54 @keyword verbose: A flag which if True will cause info about each spin pair to be printed out.
55 @type verbose: bool
56 """
57
58
59 if pipe_from == None and pipe_to == None:
60 raise RelaxError("The pipe_from and pipe_to arguments cannot both be set to None.")
61 elif pipe_from == None:
62 pipe_from = pipes.cdp_name()
63 elif pipe_to == None:
64 pipe_to = pipes.cdp_name()
65
66
67 check_pipe(pipe_from)
68 check_pipe(pipe_to)
69
70
71 if spin_id1:
72 if count_spins(selection=spin_id1, pipe=pipe_from, skip_desel=False) == 0:
73 raise RelaxNoSpinError(spin_id1, pipe_from)
74 if count_spins(selection=spin_id1, pipe=pipe_to, skip_desel=False) == 0:
75 raise RelaxNoSpinError(spin_id1, pipe_to)
76 if spin_id2:
77 if count_spins(selection=spin_id2, pipe=pipe_from, skip_desel=False) == 0:
78 raise RelaxNoSpinError(spin_id2, pipe_from)
79 if count_spins(selection=spin_id2, pipe=pipe_to, skip_desel=False) == 0:
80 raise RelaxNoSpinError(spin_id2, pipe_to)
81
82
83 if not spin_id1 and not spin_id2:
84 for spin, spin_id in spin_loop(pipe=pipe_from, return_id=True):
85 if not return_spin(spin_id, pipe=pipe_to):
86 raise RelaxNoSpinError(spin_id, pipe_to)
87
88
89 if not exists_data(pipe_from):
90 return
91
92
93 ids = []
94 for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2, pipe=pipe_from):
95
96 new_interatom = create_interatom(spin_id1=interatom.spin_id1, spin_id2=interatom.spin_id2, pipe=pipe_to)
97
98
99 for name in dir(interatom):
100
101 if search('^_', name):
102 continue
103
104
105 if name in ['spin_id1', 'spin_id2']:
106 continue
107
108
109 if name in interatom.__class__.__dict__:
110 continue
111
112
113 obj = deepcopy(getattr(interatom, name))
114 setattr(new_interatom, name, obj)
115
116
117 ids.append([repr(interatom.spin_id1), repr(interatom.spin_id2)])
118
119
120 if verbose:
121 write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2"], data=ids)
122
123
153
154
156 """Create and return the interatomic data container for the two spins.
157
158 @keyword spin_id1: The spin ID string of the first atom.
159 @type spin_id1: str
160 @keyword spin_id2: The spin ID string of the second atom.
161 @type spin_id2: str
162 @keyword pipe: The data pipe to create the interatomic data container for. This defaults to the current data pipe if not supplied.
163 @type pipe: str or None
164 @keyword verbose: A flag which if True will result printouts.
165 @type verbose: bool
166 @return: The newly created interatomic data container.
167 @rtype: data.interatomic.InteratomContainer instance
168 """
169
170
171 if verbose:
172 print("Creating an interatomic data container between the spins '%s' and '%s'." % (spin_id1, spin_id2))
173
174
175 if pipe == None:
176 pipe = pipes.cdp_name()
177
178
179 dp = pipes.get_pipe(pipe)
180
181
182 spin = return_spin(spin_id1, pipe)
183 if spin == None:
184 raise RelaxNoSpinError(spin_id1)
185 spin = return_spin(spin_id2, pipe)
186 if spin == None:
187 raise RelaxNoSpinError(spin_id2)
188
189
190 for i in range(len(dp.interatomic)):
191 if id_match(spin_id=spin_id1, interatom=dp.interatomic[i], pipe=pipe) and id_match(spin_id=spin_id2, interatom=dp.interatomic[i], pipe=pipe):
192 raise RelaxError("The spin pair %s and %s have already been added." % (spin_id1, spin_id2))
193
194
195 return dp.interatomic.add_item(spin_id1=spin_id1, spin_id2=spin_id2)
196
197
198 -def define(spin_id1=None, spin_id2=None, pipe=None, direct_bond=False, spin_selection=False, verbose=True):
199 """Set up the magnetic dipole-dipole interaction.
200
201 @keyword spin_id1: The spin identifier string of the first spin of the pair.
202 @type spin_id1: str
203 @keyword spin_id2: The spin identifier string of the second spin of the pair.
204 @type spin_id2: str
205 @param pipe: The data pipe to operate on. Defaults to the current data pipe.
206 @type pipe: str
207 @keyword direct_bond: A flag specifying if the two spins are directly bonded.
208 @type direct_bond: bool
209 @keyword spin_selection: Define the interatomic data container selection based on the spin selection. If either spin is deselected, the interatomic container will also be deselected. Otherwise the container will be selected.
210 @type spin_selection: bool
211 @keyword verbose: A flag which if True will result in printouts of the created interatomoic data containers.
212 @type verbose: bool
213 """
214
215
216 if pipe == None:
217 pipe = pipes.cdp_name()
218
219
220 dp = pipes.get_pipe(pipe)
221
222
223 ids = []
224 spin_selections = []
225
226
227 if hasattr(dp, 'structure'):
228
229 selection1 = cdp.structure.selection(atom_id=spin_id1)
230 selection2 = cdp.structure.selection(atom_id=spin_id2)
231
232
233 for mol_name1, res_num1, res_name1, atom_num1, atom_name1, mol_index1, atom_index1 in dp.structure.atom_loop(selection=selection1, model_num=1, mol_name_flag=True, res_num_flag=True, res_name_flag=True, atom_num_flag=True, atom_name_flag=True, mol_index_flag=True, index_flag=True):
234
235 id1 = generate_spin_id_unique(pipe_cont=dp, mol_name=mol_name1, res_num=res_num1, res_name=res_name1, spin_num=atom_num1, spin_name=atom_name1)
236
237
238 spin1 = return_spin(id1)
239 if not spin1:
240 continue
241
242
243 for mol_name2, res_num2, res_name2, atom_num2, atom_name2, mol_index2, atom_index2 in dp.structure.atom_loop(selection=selection2, model_num=1, mol_name_flag=True, res_num_flag=True, res_name_flag=True, atom_num_flag=True, atom_name_flag=True, mol_index_flag=True, index_flag=True):
244
245 if direct_bond:
246
247 if mol_name1 != mol_name2:
248 continue
249
250
251 if not dp.structure.are_bonded_index(mol_index1=mol_index1, atom_index1=atom_index1, mol_index2=mol_index2, atom_index2=atom_index2):
252 continue
253
254
255 id2 = generate_spin_id_unique(pipe_cont=dp, mol_name=mol_name2, res_num=res_num2, res_name=res_name2, spin_num=atom_num2, spin_name=atom_name2)
256
257
258 spin2 = return_spin(id2)
259 if not spin2:
260 continue
261
262
263 ids.append([id1, id2])
264 spin_selections.append([spin1.select, spin2.select])
265
266
267 if ids == []:
268 for spin1, mol_name1, res_num1, res_name1, id1 in spin_loop(spin_id1, pipe=pipe, full_info=True, return_id=True):
269 for spin2, mol_name2, res_num2, res_name2, id2 in spin_loop(spin_id2, pipe=pipe, full_info=True, return_id=True):
270
271 if direct_bond:
272
273 if mol_name1 != mol_name2:
274 continue
275
276
277 if not hasattr(spin1, 'element'):
278 raise RelaxError("The spin '%s' does not have the element type set." % id1)
279 if not hasattr(spin2, 'element'):
280 raise RelaxError("The spin '%s' does not have the element type set." % id2)
281
282
283 pair = False
284 if (spin1.element == 'N' and spin2.element == 'H') or (spin2.element == 'N' and spin1.element == 'H'):
285 pair = True
286 elif (spin1.element == 'C' and spin2.element == 'H') or (spin2.element == 'C' and spin1.element == 'H'):
287 pair = True
288
289
290 if pair and res_num1 != None and res_num1 != res_num2:
291 continue
292 elif pair and res_num1 == None and res_name1 != res_name2:
293 continue
294
295
296 ids.append([id1, id2])
297 spin_selections.append([spin1.select, spin2.select])
298
299
300 if not len(ids):
301
302 count1 = 0
303 count2 = 0
304 for spin in spin_loop(spin_id1):
305 count1 += 1
306 for spin in spin_loop(spin_id2):
307 count2 += 1
308
309
310 if count1 == 0 and count2 == 0:
311 raise RelaxError("Neither spin IDs '%s' and '%s' match any spins." % (spin_id1, spin_id2))
312 elif count1 == 0:
313 raise RelaxError("The spin ID '%s' matches no spins." % spin_id1)
314 elif count2 == 0:
315 raise RelaxError("The spin ID '%s' matches no spins." % spin_id2)
316 else:
317 raise RelaxError("Unknown error.")
318
319
320 for i in range(len(ids)):
321
322 id1, id2 = ids[i]
323
324 interatom = return_interatom(id1, id2, pipe=pipe)
325
326
327 if interatom == None:
328 interatom = create_interatom(spin_id1=id1, spin_id2=id2, pipe=pipe)
329
330
331 if interatom.dipole_pair:
332 raise RelaxError("The magnetic dipole-dipole interaction already exists between the spins '%s' and '%s'." % (id1, id2))
333
334
335 interatom.dipole_pair = True
336
337
338 if spin_selection:
339 interatom.select = False
340 if spin_selections[i][0] and spin_selections[i][1]:
341 interatom.select = True
342
343
344 if verbose:
345
346 for i in range(len(ids)):
347 ids[i][0] = repr(ids[i][0])
348 ids[i][1] = repr(ids[i][1])
349
350
351 print("Interatomic interactions are now defined for the following spins:\n")
352 write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2"], data=ids)
353
354
356 """Determine if any interatomic data exists.
357
358 @keyword pipe: The data pipe in which the interatomic data will be checked for.
359 @type pipe: str
360 @return: The answer to the question about the existence of data.
361 @rtype: bool
362 """
363
364
365 if pipe == None:
366 pipe = pipes.cdp_name()
367
368
369 check_pipe(pipe)
370
371
372 dp = pipes.get_pipe(pipe)
373
374
375 if dp.interatomic.is_empty():
376 return False
377
378
379 return True
380
381
382 -def id_match(spin_id=None, interatom=None, pipe=None):
383 """Test if the spin ID matches one of the two spins of the given container.
384
385 @keyword spin_id: The spin ID string of the first atom.
386 @type spin_id: str
387 @keyword interatom: The interatomic data container.
388 @type interatom: InteratomContainer instance
389 @keyword pipe: The data pipe containing the interatomic data container. Defaults to the current data pipe.
390 @type pipe: str or None
391 @return: True if the spin ID matches one of the two spins, False otherwise.
392 @rtype: bool
393 """
394
395
396 spin1 = return_spin(interatom.spin_id1, pipe=pipe)
397 spin2 = return_spin(interatom.spin_id2, pipe=pipe)
398
399
400 if spin1 == None or spin2 == None:
401 return False
402
403
404 if spin_id in spin1._spin_ids or spin_id in spin2._spin_ids:
405 return True
406
407
408 return False
409
410
411 -def interatomic_loop(selection1=None, selection2=None, pipe=None, skip_desel=True):
412 """Generator function for looping over all the interatomic data containers.
413
414 @keyword selection1: The optional spin ID selection of the first atom.
415 @type selection1: str
416 @keyword selection2: The optional spin ID selection of the second atom.
417 @type selection2: str
418 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
419 @type pipe: str
420 @keyword skip_desel: A flag which if True will cause only selected interatomic data containers to be returned.
421 @type skip_desel: bool
422 """
423
424
425 if pipe == None:
426 pipe = pipes.cdp_name()
427
428
429 dp = pipes.get_pipe(pipe)
430
431
432 select_obj = None
433 select_obj1 = None
434 select_obj2 = None
435 if selection1 and selection2:
436 select_obj1 = Selection(selection1)
437 select_obj2 = Selection(selection2)
438 elif selection1:
439 select_obj = Selection(selection1)
440 elif selection2:
441 select_obj = Selection(selection2)
442
443
444 for i in range(len(dp.interatomic)):
445
446 if skip_desel and not dp.interatomic[i].select:
447 continue
448
449
450 interatom = dp.interatomic[i]
451 mol_index1, res_index1, spin_index1 = dp.mol._spin_id_lookup[interatom.spin_id1]
452 mol_index2, res_index2, spin_index2 = dp.mol._spin_id_lookup[interatom.spin_id2]
453 mol1 = dp.mol[mol_index1]
454 res1 = dp.mol[mol_index1].res[res_index1]
455 spin1 = dp.mol[mol_index1].res[res_index1].spin[spin_index1]
456 mol2 = dp.mol[mol_index2]
457 res2 = dp.mol[mol_index2].res[res_index2]
458 spin2 = dp.mol[mol_index2].res[res_index2].spin[spin_index2]
459
460
461 if select_obj:
462 sel1 = select_obj.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
463 sel2 = select_obj.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)
464 if select_obj1:
465 sel11 = select_obj1.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
466 sel12 = select_obj1.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)
467 if select_obj2:
468 sel21 = select_obj2.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
469 sel22 = select_obj2.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)
470
471
472 if select_obj:
473 if not sel1 and not sel2:
474 continue
475 if select_obj1:
476 if not (sel11 or sel12):
477 continue
478 if select_obj2:
479 if not (sel21 or sel22):
480 continue
481
482
483 yield interatom
484
485
486 -def read_dist(file=None, dir=None, unit='meter', spin_id1_col=None, spin_id2_col=None, data_col=None, sep=None):
487 """Set up the magnetic dipole-dipole interaction.
488
489 @keyword file: The name of the file to open.
490 @type file: str
491 @keyword dir: The directory containing the file (defaults to the current directory if None).
492 @type dir: str or None
493 @keyword unit: The measurement unit. This can be either 'meter' or 'Angstrom'.
494 @type unit: str
495 @keyword spin_id1_col: The column containing the spin ID strings of the first spin.
496 @type spin_id1_col: int
497 @keyword spin_id2_col: The column containing the spin ID strings of the second spin.
498 @type spin_id2_col: int
499 @keyword data_col: The column containing the averaged distances in meters.
500 @type data_col: int or None
501 @keyword sep: The column separator which, if None, defaults to whitespace.
502 @type sep: str or None
503 """
504
505
506 if unit not in ['meter', 'Angstrom']:
507 raise RelaxError("The measurement unit of '%s' must be one of 'meter' or 'Angstrom'." % unit)
508
509
510 check_pipe()
511
512
513 if not exists_mol_res_spin_data():
514 raise RelaxNoSequenceError
515
516
517 file_data = extract_data(file, dir, sep=sep)
518 file_data = strip(file_data, comments=True)
519
520
521 data = []
522 for line in file_data:
523
524 if spin_id1_col > len(line):
525 warn(RelaxWarning("The data %s is invalid, no first spin ID column can be found." % line))
526 continue
527 if spin_id2_col > len(line):
528 warn(RelaxWarning("The data %s is invalid, no second spin ID column can be found." % line))
529 continue
530 if data_col and data_col > len(line):
531 warn(RelaxWarning("The data %s is invalid, no data column can be found." % line))
532 continue
533
534
535 spin_id1 = line[spin_id1_col-1]
536 spin_id2 = line[spin_id2_col-1]
537 ave_dist = None
538 if data_col:
539 ave_dist = line[data_col-1]
540
541
542 if ave_dist != None:
543 try:
544 ave_dist = float(ave_dist)
545 except ValueError:
546 warn(RelaxWarning("The averaged distance of '%s' from the line %s is invalid." % (ave_dist, line)))
547 continue
548
549
550 if unit == 'Angstrom':
551 ave_dist = ave_dist * 1e-10
552
553
554 interatom = return_interatom(spin_id1, spin_id2)
555
556
557 if interatom == None:
558 interatom = create_interatom(spin_id1=spin_id1, spin_id2=spin_id2, verbose=True)
559
560
561 interatom.r = ave_dist
562
563
564 data.append([repr(interatom.spin_id1), repr(interatom.spin_id2), repr(ave_dist)])
565
566
567 if not len(data):
568 raise RelaxError("No data could be extracted from the file.")
569
570
571 print("The following averaged distances have been read:\n")
572 write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2", "Ave_distance(meters)"], data=data)
573
574
576 """Return the list of interatomic data containers for the two spins.
577
578 @keyword spin_id1: The spin ID string of the first atom.
579 @type spin_id1: str
580 @keyword spin_id2: The spin ID string of the second atom.
581 @type spin_id2: str
582 @keyword pipe: The data pipe holding the container. Defaults to the current data pipe.
583 @type pipe: str or None
584 @return: The matching interatomic data container, if it exists.
585 @rtype: data.interatomic.InteratomContainer instance or None
586 """
587
588
589 if spin_id1 == None:
590 raise RelaxError("The first spin ID must be supplied.")
591 if spin_id2 == None:
592 raise RelaxError("The second spin ID must be supplied.")
593
594
595 if pipe == None:
596 pipe = pipes.cdp_name()
597
598
599 dp = pipes.get_pipe(pipe)
600
601
602 for i in range(len(dp.interatomic)):
603 if id_match(spin_id=spin_id1, interatom=dp.interatomic[i], pipe=pipe) and id_match(spin_id=spin_id2, interatom=dp.interatomic[i], pipe=pipe):
604 return dp.interatomic[i]
605
606
607 return None
608
609
642
643
644 -def set_dist(spin_id1=None, spin_id2=None, ave_dist=None, unit='meter'):
645 """Set up the magnetic dipole-dipole interaction.
646
647 @keyword spin_id1: The spin identifier string of the first spin of the pair.
648 @type spin_id1: str
649 @keyword spin_id2: The spin identifier string of the second spin of the pair.
650 @type spin_id2: str
651 @keyword ave_dist: The r^-3 averaged interatomic distance.
652 @type ave_dist: float
653 @keyword unit: The measurement unit. This can be either 'meter' or 'Angstrom'.
654 @type unit: str
655 """
656
657
658 if unit not in ['meter', 'Angstrom']:
659 raise RelaxError("The measurement unit of '%s' must be one of 'meter' or 'Angstrom'." % unit)
660
661
662 if unit == 'Angstrom':
663 ave_dist = ave_dist * 1e-10
664
665
666 sel_obj1 = Selection(spin_id1)
667 sel_obj2 = Selection(spin_id2)
668
669
670 data = []
671 for interatom in interatomic_loop():
672
673 mol_name1, res_num1, res_name1, spin1 = return_spin(interatom.spin_id1, full_info=True)
674 mol_name2, res_num2, res_name2, spin2 = return_spin(interatom.spin_id2, full_info=True)
675
676
677 if not (sel_obj1.contains_spin(spin_num=spin1.num, spin_name=spin1.name, res_num=res_num1, res_name=res_name1, mol=mol_name1) and sel_obj2.contains_spin(spin_num=spin2.num, spin_name=spin2.name, res_num=res_num2, res_name=res_name2, mol=mol_name2)) and not (sel_obj2.contains_spin(spin_num=spin1.num, spin_name=spin1.name, res_num=res_num1, res_name=res_name1, mol=mol_name1) and sel_obj1.contains_spin(spin_num=spin2.num, spin_name=spin2.name, res_num=res_num2, res_name=res_name2, mol=mol_name2)):
678 continue
679
680
681 interatom.r = ave_dist
682
683
684 data.append([repr(interatom.spin_id1), repr(interatom.spin_id2), repr(ave_dist)])
685
686
687 if not len(data):
688 raise RelaxError("No data could be set.")
689
690
691 print("The following averaged distances have been set:\n")
692 write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2", "Ave_distance(meters)"], data=data)
693
694
696 """Extract the bond vectors from the loaded structures and store them in the spin container.
697
698 @keyword ave: A flag which if True will cause the average of all vectors to be calculated.
699 @type ave: bool
700 """
701
702
703 check_pipe()
704
705
706 if not exists_data():
707 raise RelaxNoInteratomError
708
709
710 if ave:
711 print("Averaging all vectors.")
712 else:
713 print("No averaging of the vectors.")
714
715
716 no_vectors = True
717 pos_info = False
718 for interatom in interatomic_loop(skip_desel=False):
719
720 spin1 = return_spin(interatom.spin_id1)
721 spin2 = return_spin(interatom.spin_id2)
722
723
724 if not hasattr(spin1, 'pos'):
725 continue
726 if not hasattr(spin2, 'pos'):
727 continue
728
729
730 pos_info = True
731
732
733 if is_float(spin1.pos[0], raise_error=False) and is_float(spin2.pos[0], raise_error=False):
734
735 vector_list = [spin2.pos - spin1.pos]
736
737
738 elif is_float(spin1.pos[0], raise_error=False) or is_float(spin2.pos[0], raise_error=False):
739
740 if is_float(spin2.pos[0], raise_error=False):
741 vector_list = []
742 for i in range(len(spin1.pos)):
743 vector_list.append(spin2.pos - spin1.pos[i])
744
745
746 else:
747 vector_list = []
748 for i in range(len(spin2.pos)):
749 vector_list.append(spin2.pos[i] - spin1.pos)
750
751
752 else:
753
754 if len(spin1.pos) != len(spin2.pos):
755 raise RelaxError("The spin '%s' consists of %s positions whereas the spin '%s' consists of %s - these numbers must match." % (interatom.spin_id1, len(spin1.pos), interatom.spin_id1, len(spin1.pos)))
756
757
758 vector_list = []
759 for i in range(len(spin1.pos)):
760
761 if spin1.pos[i] == None or spin2.pos[i] == None:
762 warn(RelaxWarning("No structural information for state %i can be found between spins '%s' and '%s'." % (i, interatom.spin_id1, interatom.spin_id2)))
763 vector_list.append(None)
764
765
766 else:
767 vector_list.append(spin2.pos[i] - spin1.pos[i])
768
769
770 for i in range(len(vector_list)):
771
772 if vector_list[i] == None:
773 continue
774
775
776 norm_factor = norm(vector_list[i])
777
778
779 if norm_factor == 0.0:
780 warn(RelaxZeroVectorWarning(spin_id1=interatom.spin_id1, spin_id2=interatom.spin_id2))
781
782
783 else:
784 vector_list[i] = vector_list[i] / norm_factor
785
786
787 if ave:
788 ave_vector = zeros(3, float64)
789 count = 0
790 for i in range(len(vector_list)):
791 if vector_list[i] != None:
792 ave_vector = ave_vector + vector_list[i]
793 count += 1
794 vector_list = [ave_vector / count]
795
796
797 if len(vector_list) == 1:
798 vector_list = vector_list[0]
799
800
801 setattr(interatom, 'vector', vector_list)
802
803
804 no_vectors = False
805
806
807 num = 1
808 if not is_float(vector_list[0], raise_error=False):
809 num = len(vector_list)
810 plural = 's'
811 if num == 1:
812 plural = ''
813 if spin1.name:
814 spin1_str = spin1.name
815 else:
816 spin1_str = spin1.num
817 if spin2.name:
818 spin2_str = spin2.name
819 else:
820 spin2_str = spin2.num
821 print("Calculated %s %s-%s unit vector%s between the spins '%s' and '%s'." % (num, spin1_str, spin2_str, plural, interatom.spin_id1, interatom.spin_id2))
822
823
824 if not pos_info:
825 raise RelaxError("Positional information could not be found for any spins.")
826
827
828 if no_vectors:
829 raise RelaxError("No vectors could be extracted.")
830