1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Analysis specific code for the N-state model or structure ensemble analysis."""
24
25
26 from copy import deepcopy
27 from math import acos, cos, pi
28 from minfx.generic import generic_minimise
29 from minfx.grid import grid
30 from numpy import array, dot, float64, identity, ones, zeros
31 from numpy.linalg import inv, norm
32 from re import search
33 from warnings import warn
34
35
36 import arg_check
37 from float import isNaN, isInf
38 from generic_fns import align_tensor, pcs, pipes, rdc
39 from generic_fns.interatomic import interatomic_loop
40 from generic_fns.mol_res_spin import return_spin, spin_loop
41 from generic_fns.structure import geometric
42 from generic_fns.structure.cones import Iso_cone
43 from generic_fns.structure.internal import Internal
44 from generic_fns.structure.mass import centre_of_mass
45 from maths_fns.n_state_model import N_state_opt
46 from maths_fns.potential import quad_pot
47 from maths_fns.rotation_matrix import euler_to_R_zyz, two_vect_to_R
48 from physical_constants import dipolar_constant, g1H, return_gyromagnetic_ratio
49 from relax_errors import RelaxError, RelaxInfError, RelaxNaNError, RelaxNoModelError, RelaxNoValueError, RelaxSpinTypeError
50 from relax_io import open_write_file
51 from relax_warnings import RelaxWarning
52 from specific_fns.api_base import API_base
53 from specific_fns.api_common import API_common
54 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
55 from user_functions.objects import Desc_container
56
57
59 """Class containing functions for the N-state model."""
60
80
81
83 """Assemble all the parameters of the model into a single array.
84
85 @param sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
86 @type sim_index: None or int
87 @return: The parameter vector used for optimisation.
88 @rtype: numpy array
89 """
90
91
92 if not hasattr(cdp, 'model') or not isinstance(cdp.model, str):
93 raise RelaxNoModelError
94
95
96 data_types = self._base_data_types()
97
98
99 param_vector = []
100
101
102 if self._opt_uses_align_data():
103 for i in range(len(cdp.align_tensors)):
104
105 if not self._opt_tensor(cdp.align_tensors[i]):
106 continue
107
108
109 param_vector = param_vector + list(cdp.align_tensors[i].A_5D)
110
111
112 if sim_index != None:
113
114 if cdp.model in ['2-domain', 'population']:
115 probs = cdp.probs_sim[sim_index]
116
117
118 if cdp.model == '2-domain':
119 alpha = cdp.alpha_sim[sim_index]
120 beta = cdp.beta_sim[sim_index]
121 gamma = cdp.gamma_sim[sim_index]
122
123
124 else:
125
126 if cdp.model in ['2-domain', 'population']:
127 probs = cdp.probs
128
129
130 if cdp.model == '2-domain':
131 alpha = cdp.alpha
132 beta = cdp.beta
133 gamma = cdp.gamma
134
135
136 if cdp.model in ['2-domain', 'population']:
137 param_vector = param_vector + probs[0:-1]
138
139
140 if cdp.model == '2-domain':
141 for i in range(cdp.N):
142 param_vector.append(alpha[i])
143 param_vector.append(beta[i])
144 param_vector.append(gamma[i])
145
146
147 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
148 if not hasattr(cdp, 'paramagnetic_centre'):
149 for i in range(3):
150 param_vector.append(0.0)
151 elif sim_index != None:
152 if cdp.paramagnetic_centre_sim[sim_index] == None:
153 for i in range(3):
154 param_vector.append(0.0)
155 else:
156 for i in range(3):
157 param_vector.append(cdp.paramagnetic_centre_sim[sim_index][i])
158 else:
159 for i in range(3):
160 param_vector.append(cdp.paramagnetic_centre[i])
161
162
163 for i in range(len(param_vector)):
164 if param_vector[i] == None:
165 param_vector[i] = 0.0
166
167
168 return array(param_vector, float64)
169
170
172 """Create and return the scaling matrix.
173
174 @keyword data_types: The base data types used in the optimisation. This list can contain
175 the elements 'rdc', 'pcs' or 'tensor'.
176 @type data_types: list of str
177 @keyword scaling: If False, then the identity matrix will be returned.
178 @type scaling: bool
179 @return: The square and diagonal scaling matrix.
180 @rtype: numpy rank-2 array
181 """
182
183
184 scaling_matrix = identity(self._param_num(), float64)
185
186
187 if not scaling:
188 return scaling_matrix
189
190
191 pop_start = 0
192
193
194 tensor_num = 0
195 for i in range(len(cdp.align_tensors)):
196
197 if not self._opt_tensor(cdp.align_tensors[i]):
198 continue
199
200
201 pop_start = pop_start + 5
202
203
204 for j in range(5):
205 scaling_matrix[5*tensor_num + j, 5*tensor_num + j] = 1.0
206
207
208 tensor_num += 1
209
210
211 if cdp.model in ['2-domain', 'population']:
212 factor = 0.1
213 for i in range(pop_start, pop_start + (cdp.N-1)):
214 scaling_matrix[i, i] = factor
215
216
217 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
218 for i in range(-3, 0):
219 scaling_matrix[i, i] = 1e2
220
221
222 return scaling_matrix
223
224
226 """Determine all the base data types.
227
228 The base data types can include::
229 - 'rdc', residual dipolar couplings.
230 - 'pcs', pseudo-contact shifts.
231 - 'noesy', NOE restraints.
232 - 'tensor', alignment tensors.
233
234 @return: A list of all the base data types.
235 @rtype: list of str
236 """
237
238
239 list = []
240
241
242 for interatom in interatomic_loop():
243 if hasattr(interatom, 'rdc'):
244 list.append('rdc')
245 break
246
247
248 for spin in spin_loop():
249 if hasattr(spin, 'pcs'):
250 list.append('pcs')
251 break
252
253
254 if not ('rdc' in list or 'pcs' in list) and hasattr(cdp, 'align_tensors'):
255 list.append('tensor')
256
257
258 if hasattr(cdp, 'noe_restraints'):
259 list.append('noesy')
260
261
262 if not list:
263 raise RelaxError("Neither RDC, PCS, NOESY nor alignment tensor data is present.")
264
265
266 return list
267
268
270 """Calculate the average distances.
271
272 The formula used is::
273
274 _N_
275 / 1 \ \ 1/exp
276 <r> = | - > |p1i - p2i|^exp |
277 \ N /__ /
278 i
279
280 where i are the members of the ensemble, N is the total number of structural models, and p1
281 and p2 at the two atom positions.
282
283
284 @param atom1: The atom identification string of the first atom.
285 @type atom1: str
286 @param atom2: The atom identification string of the second atom.
287 @type atom2: str
288 @keyword exp: The exponent used for the averaging, e.g. 1 for linear averaging and -6 for
289 r^-6 NOE averaging.
290 @type exp: int
291 @return: The average distance between the two atoms.
292 @rtype: float
293 """
294
295
296 spin1 = return_spin(atom1)
297 spin2 = return_spin(atom2)
298
299
300 num_models = len(spin1.pos)
301 ave_dist = 0.0
302 for i in range(num_models):
303
304 dist = norm(spin1.pos[i] - spin2.pos[i])
305 ave_dist = ave_dist + dist**(exp)
306
307
308 ave_dist = ave_dist / num_models
309
310
311 ave_dist = ave_dist**(1.0/exp)
312
313
314 return ave_dist
315
316
401
402
404 """Check if the RDCs for the given interatomic data container should be used.
405
406 @param interatom: The interatomic data container.
407 @type interatom: InteratomContainer instance
408 @param spin1: The first spin container.
409 @type spin1: SpinContainer instance
410 @param spin2: The second spin container.
411 @type spin2: SpinContainer instance
412 @return: True if the RDCs should be used, False otherwise.
413 """
414
415
416 if not interatom.select:
417 return False
418
419
420
421 if not spin1.select or not spin2.select:
422 return False
423
424
425 if not hasattr(interatom, 'rdc'):
426 return False
427
428
429 if not hasattr(interatom, 'vector'):
430
431 warn(RelaxWarning("RDC data exists but the interatomic vectors are missing, skipping the spin pair '%s' and '%s'." % (interatom.spin_id1, interatom.spin_id2)))
432
433
434 return False
435
436
437 if hasattr(spin1, 'members') and len(spin1.members) != 3:
438 warn(RelaxWarning("Only methyl group pseudo atoms are supported due to their fast rotation, skipping the spin pair '%s' and '%s'." % (interatom.spin_id1, interatom.spin_id2)))
439 return False
440
441
442 if hasattr(spin2, 'members') and len(spin2.members) != 3:
443 warn(RelaxWarning("Only methyl group pseudo atoms are supported due to their fast rotation, skipping the spin pair '%s' and '%s'." % (interatom.spin_id1, interatom.spin_id2)))
444 return False
445
446
447 if not hasattr(spin1, 'isotope'):
448 raise RelaxSpinTypeError(interatom.spin_id1)
449 if not hasattr(spin2, 'isotope'):
450 raise RelaxSpinTypeError(interatom.spin_id2)
451 if not hasattr(interatom, 'r'):
452 raise RelaxNoValueError("averaged interatomic distance")
453
454
455 return True
456
457
458 - def _cone_pdb(self, cone_type=None, scale=1.0, file=None, dir=None, force=False):
459 """Create a PDB file containing a geometric object representing the various cone models.
460
461 Currently the only cone types supported are 'diff in cone' and 'diff on cone'.
462
463
464 @param cone_type: The type of cone model to represent.
465 @type cone_type: str
466 @param scale: The size of the geometric object is eqaul to the average pivot-CoM
467 vector length multiplied by this scaling factor.
468 @type scale: float
469 @param file: The name of the PDB file to create.
470 @type file: str
471 @param dir: The name of the directory to place the PDB file into.
472 @type dir: str
473 @param force: Flag which if set to True will cause any pre-existing file to be
474 overwritten.
475 @type force: int
476 """
477
478
479 if cone_type == 'diff in cone':
480 if not hasattr(cdp, 'S_diff_in_cone'):
481 raise RelaxError("The diffusion in a cone model has not yet been determined.")
482 elif cone_type == 'diff on cone':
483 if not hasattr(cdp, 'S_diff_on_cone'):
484 raise RelaxError("The diffusion on a cone model has not yet been determined.")
485 else:
486 raise RelaxError("The cone type " + repr(cone_type) + " is unknown.")
487
488
489 inc = 20
490
491
492 R = zeros((3, 3), float64)
493 two_vect_to_R(array([0, 0, 1], float64), cdp.ave_pivot_CoM/norm(cdp.ave_pivot_CoM), R)
494
495
496 if cone_type == 'diff in cone':
497 angle = cdp.theta_diff_in_cone
498 elif cone_type == 'diff on cone':
499 angle = cdp.theta_diff_on_cone
500 cone = Iso_cone(angle)
501
502
503 structure = Internal()
504
505
506 structure.add_molecule(name='cone')
507
508
509 mol = structure.structural_data[0].mol[0]
510
511
512 mol.atom_add(pdb_record='HETATM', atom_num=1, atom_name='R', res_name='PIV', res_num=1, pos=cdp.pivot_point, element='C')
513
514
515 print("\nGenerating the average pivot-CoM vectors.")
516 sim_vectors = None
517 if hasattr(cdp, 'ave_pivot_CoM_sim'):
518 sim_vectors = cdp.ave_pivot_CoM_sim
519 res_num = geometric.generate_vector_residues(mol=mol, vector=cdp.ave_pivot_CoM, atom_name='Ave', res_name_vect='AVE', sim_vectors=sim_vectors, res_num=2, origin=cdp.pivot_point, scale=scale)
520
521
522 print("\nGenerating the cone outer edge.")
523 cap_start_atom = mol.atom_num[-1]+1
524 geometric.cone_edge(mol=mol, cone=cone, res_name='CON', res_num=3, apex=cdp.pivot_point, R=R, scale=norm(cdp.pivot_CoM), inc=inc)
525
526
527 if cone_type == 'diff in cone':
528 print("\nGenerating the cone cap.")
529 cone_start_atom = mol.atom_num[-1]+1
530 geometric.generate_vector_dist(mol=mol, res_name='CON', res_num=3, centre=cdp.pivot_point, R=R, limit_check=cone.limit_check, scale=norm(cdp.pivot_CoM), inc=inc)
531 geometric.stitch_cone_to_edge(mol=mol, cone=cone, dome_start=cone_start_atom, edge_start=cap_start_atom+1, inc=inc)
532
533
534 print("\nGenerating the PDB file.")
535 pdb_file = open_write_file(file, dir, force=force)
536 structure.write_pdb(pdb_file)
537 pdb_file.close()
538
539
541 """Disassemble the parameter vector and place the values into the relevant variables.
542
543 For the 2-domain N-state model, the parameters are stored in the probability and Euler angle data structures. For the population N-state model, only the probabilities are stored. If RDCs are present and alignment tensors are optimised, then these are stored as well.
544
545 @keyword data_types: The base data types used in the optimisation. This list can contain the elements 'rdc', 'pcs' or 'tensor'.
546 @type data_types: list of str
547 @keyword param_vector: The parameter vector returned from optimisation.
548 @type param_vector: numpy array
549 @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
550 @type sim_index: None or int
551 """
552
553
554 if not hasattr(cdp, 'model') or not isinstance(cdp.model, str):
555 raise RelaxNoModelError
556
557
558 if ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
559
560 tensor_num = 0
561 for i in range(len(cdp.align_tensors)):
562
563 if not self._opt_tensor(cdp.align_tensors[i]):
564 continue
565
566
567 if sim_index == None:
568 cdp.align_tensors[i].set(param='Axx', value=param_vector[5*tensor_num])
569 cdp.align_tensors[i].set(param='Ayy', value=param_vector[5*tensor_num+1])
570 cdp.align_tensors[i].set(param='Axy', value=param_vector[5*tensor_num+2])
571 cdp.align_tensors[i].set(param='Axz', value=param_vector[5*tensor_num+3])
572 cdp.align_tensors[i].set(param='Ayz', value=param_vector[5*tensor_num+4])
573
574
575 else:
576 cdp.align_tensors[i].set(param='Axx', value=param_vector[5*tensor_num], category='sim', sim_index=sim_index)
577 cdp.align_tensors[i].set(param='Ayy', value=param_vector[5*tensor_num+1], category='sim', sim_index=sim_index)
578 cdp.align_tensors[i].set(param='Axy', value=param_vector[5*tensor_num+2], category='sim', sim_index=sim_index)
579 cdp.align_tensors[i].set(param='Axz', value=param_vector[5*tensor_num+3], category='sim', sim_index=sim_index)
580 cdp.align_tensors[i].set(param='Ayz', value=param_vector[5*tensor_num+4], category='sim', sim_index=sim_index)
581
582
583 tensor_num += 1
584
585
586 param_vector = param_vector[5*tensor_num:]
587
588
589 if sim_index != None:
590
591 if cdp.model in ['2-domain', 'population']:
592 probs = cdp.probs_sim[sim_index]
593
594
595 if cdp.model == '2-domain':
596 alpha = cdp.alpha_sim[sim_index]
597 beta = cdp.beta_sim[sim_index]
598 gamma = cdp.gamma_sim[sim_index]
599
600
601 else:
602
603 if cdp.model in ['2-domain', 'population']:
604 probs = cdp.probs
605
606
607 if cdp.model == '2-domain':
608 alpha = cdp.alpha
609 beta = cdp.beta
610 gamma = cdp.gamma
611
612
613 if cdp.model in ['2-domain', 'population']:
614 for i in range(cdp.N-1):
615 probs[i] = param_vector[i]
616
617
618 probs[-1] = 1 - sum(probs[0:-1])
619
620
621 if cdp.model == '2-domain':
622 for i in range(cdp.N):
623 alpha[i] = param_vector[cdp.N-1 + 3*i]
624 beta[i] = param_vector[cdp.N-1 + 3*i + 1]
625 gamma[i] = param_vector[cdp.N-1 + 3*i + 2]
626
627
628 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
629
630 if not hasattr(cdp, 'paramagnetic_centre'):
631 cdp.paramagnetic_centre = zeros(3, float64)
632
633
634 if sim_index == None:
635 cdp.paramagnetic_centre[0] = param_vector[-3]
636 cdp.paramagnetic_centre[1] = param_vector[-2]
637 cdp.paramagnetic_centre[2] = param_vector[-1]
638
639
640 else:
641 if cdp.paramagnetic_centre_sim[sim_index] == None:
642 cdp.paramagnetic_centre_sim[sim_index] = [None, None, None]
643 cdp.paramagnetic_centre_sim[sim_index][0] = param_vector[-3]
644 cdp.paramagnetic_centre_sim[sim_index][1] = param_vector[-2]
645 cdp.paramagnetic_centre_sim[sim_index][2] = param_vector[-1]
646
647
649 """Remove all structures or states which have no probability."""
650
651
652 pipes.test()
653
654
655 if not hasattr(cdp, 'model'):
656 raise RelaxNoModelError('N-state')
657
658
659 if not hasattr(cdp, 'probs'):
660 raise RelaxError("The N-state model populations do not exist.")
661
662
663 if not hasattr(cdp, 'select_models'):
664 cdp.state_select = [True] * cdp.N
665
666
667 for i in range(len(cdp.N)):
668
669 if cdp.probs[i] < 1e-5:
670 cdp.state_select[i] = False
671
672
674 """Function for setting up the linear constraint matrices A and b.
675
676 Standard notation
677 =================
678
679 The N-state model constraints are::
680
681 0 <= pc <= 1,
682
683 where p is the probability and c corresponds to state c.
684
685
686 Matrix notation
687 ===============
688
689 In the notation A.x >= b, where A is an matrix of coefficients, x is an array of parameter
690 values, and b is a vector of scalars, these inequality constraints are::
691
692 | 1 0 0 | | 0 |
693 | | | |
694 |-1 0 0 | | -1 |
695 | | | |
696 | 0 1 0 | | 0 |
697 | | | p0 | | |
698 | 0 -1 0 | | | | -1 |
699 | | . | p1 | >= | |
700 | 0 0 1 | | | | 0 |
701 | | | p2 | | |
702 | 0 0 -1 | | -1 |
703 | | | |
704 |-1 -1 -1 | | -1 |
705 | | | |
706 | 1 1 1 | | 0 |
707
708 This example is for a 4-state model, the last probability pn is not included as this
709 parameter does not exist (because the sum of pc is equal to 1). The Euler angle parameters
710 have been excluded here but will be included in the returned A and b objects. These
711 parameters simply add columns of zero to the A matrix and have no effect on b. The last two
712 rows correspond to the inequality::
713
714 0 <= pN <= 1.
715
716 As::
717 N-1
718 \
719 pN = 1 - > pc,
720 /__
721 c=1
722
723 then::
724
725 -p1 - p2 - ... - p(N-1) >= -1,
726
727 p1 + p2 + ... + p(N-1) >= 0.
728
729
730 @keyword data_types: The base data types used in the optimisation. This list can
731 contain the elements 'rdc', 'pcs' or 'tensor'.
732 @type data_types: list of str
733 @keyword scaling_matrix: The diagonal scaling matrix.
734 @type scaling_matrix: numpy rank-2 square matrix
735 @return: The matrices A and b.
736 @rtype: tuple of len 2 of a numpy rank-2, size NxM matrix and numpy
737 rank-1, size N array
738 """
739
740
741 pop_start = 0
742 if ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
743
744 for i in range(len(cdp.align_tensors)):
745
746 if not self._opt_tensor(cdp.align_tensors[i]):
747 continue
748
749
750 pop_start += 5
751
752
753 A = []
754 b = []
755 zero_array = zeros(self._param_num(), float64)
756 i = pop_start
757 j = 0
758
759
760 if cdp.model in ['2-domain', 'population']:
761
762 for k in range(cdp.N - 1):
763
764 A.append(zero_array * 0.0)
765 A.append(zero_array * 0.0)
766 A[j][i] = 1.0
767 A[j+1][i] = -1.0
768 b.append(0.0)
769 b.append(-1.0 / scaling_matrix[i, i])
770 j = j + 2
771
772
773 i = i + 1
774
775
776 A.append(zero_array * 0.0)
777 A.append(zero_array * 0.0)
778 for i in range(pop_start, pop_start+cdp.N-1):
779 A[-2][i] = -1.0
780 A[-1][i] = 1.0
781 b.append(-1.0 / scaling_matrix[i, i])
782 b.append(0.0)
783
784
785 A = array(A, float64)
786 b = array(b, float64)
787
788
789 return A, b
790
791
793 """Extract and unpack the back calculated data.
794
795 @param model: The instantiated class containing the target function.
796 @type model: class instance
797 """
798
799
800 if not hasattr(cdp, 'align_tensors'):
801 return
802
803
804 align_index = 0
805 for i in range(len(cdp.align_ids)):
806
807 if not self._opt_tensor(cdp.align_tensors[i]):
808 continue
809
810
811 align_id = cdp.align_ids[i]
812
813
814 rdc_flag = False
815 if hasattr(cdp, 'rdc_ids') and align_id in cdp.rdc_ids:
816 rdc_flag = True
817 pcs_flag = False
818 if hasattr(cdp, 'pcs_ids') and align_id in cdp.pcs_ids:
819 pcs_flag = True
820
821
822 pcs_index = 0
823 for spin in spin_loop():
824
825 if not spin.select:
826 continue
827
828
829 if pcs_flag and hasattr(spin, 'pcs'):
830
831 if not hasattr(spin, 'pcs_bc'):
832 spin.pcs_bc = {}
833
834
835 spin.pcs_bc[align_id] = model.deltaij_theta[align_index, pcs_index] * 1e6
836
837
838 pcs_index = pcs_index + 1
839
840
841 rdc_index = 0
842 for interatom in interatomic_loop():
843
844 spin1 = return_spin(interatom.spin_id1)
845 spin2 = return_spin(interatom.spin_id2)
846
847
848 if not self._check_rdcs(interatom, spin1, spin2):
849 continue
850
851
852 if rdc_flag and hasattr(interatom, 'rdc'):
853
854 if not hasattr(interatom, 'rdc_bc'):
855 interatom.rdc_bc = {}
856
857
858 interatom.rdc_bc[align_id] = model.Dij_theta[align_index, rdc_index]
859
860
861 rdc_index = rdc_index + 1
862
863
864 align_index += 1
865
866
868 """Set up the atomic position data structures for optimisation using PCSs and PREs as base data sets.
869
870 @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
871 @type sim_index: None or int
872 @return: The atomic positions (the first index is the spins, the second is the structures, and the third is the atomic coordinates) and the paramagnetic centre.
873 @rtype: numpy rank-3 array, numpy rank-1 array.
874 """
875
876
877 atomic_pos = []
878
879
880 for spin in spin_loop():
881
882 if not spin.select:
883 continue
884
885
886 if not hasattr(spin, 'pcs') and not hasattr(spin, 'pre'):
887 continue
888
889
890 if type(spin.pos[0]) in [float, float64]:
891 atomic_pos.append([spin.pos])
892 else:
893 atomic_pos.append(spin.pos)
894
895
896 atomic_pos = array(atomic_pos, float64)
897
898
899 if not hasattr(cdp, 'paramagnetic_centre'):
900 paramag_centre = zeros(3, float64)
901 elif sim_index != None and not cdp.paramag_centre_fixed:
902 if not hasattr(cdp, 'paramagnetic_centre_sim') or cdp.paramagnetic_centre_sim[sim_index] == None:
903 paramag_centre = zeros(3, float64)
904 else:
905 paramag_centre = array(cdp.paramagnetic_centre_sim[sim_index])
906 else:
907 paramag_centre = array(cdp.paramagnetic_centre)
908
909
910 return atomic_pos, paramag_centre
911
912
914 """Set up the data structures for optimisation using PCSs as base data sets.
915
916 @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
917 @type sim_index: None or int
918 @return: The assembled data structures for using PCSs as the base data for optimisation. These include:
919 - the PCS values.
920 - the unit vectors connecting the paramagnetic centre (the electron spin) to
921 - the PCS weight.
922 - the nuclear spin.
923 - the pseudocontact shift constants.
924 @rtype: tuple of (numpy rank-2 array, numpy rank-2 array, numpy rank-2 array, numpy rank-1 array, numpy rank-1 array)
925 """
926
927
928 if not hasattr(cdp, 'paramagnetic_centre') and (hasattr(cdp, 'paramag_centre_fixed') and cdp.paramag_centre_fixed):
929 raise RelaxError("The paramagnetic centre has not yet been specified.")
930 if not hasattr(cdp, 'temperature'):
931 raise RelaxError("The experimental temperatures have not been set.")
932 if not hasattr(cdp, 'frq'):
933 raise RelaxError("The spectrometer frequencies of the experiments have not been set.")
934
935
936 pcs = []
937 pcs_err = []
938 pcs_weight = []
939 temp = []
940 frq = []
941
942
943 for i in range(len(cdp.align_ids)):
944
945 align_id = cdp.align_ids[i]
946
947
948 if not self._opt_uses_align_data(align_id):
949 continue
950
951
952 pcs.append([])
953 pcs_err.append([])
954 pcs_weight.append([])
955
956
957 if align_id in cdp.temperature:
958 temp.append(cdp.temperature[align_id])
959
960
961 else:
962 raise RelaxError("The experimental temperature for the alignment ID '%s' has not been set." % align_id)
963
964
965 if align_id in cdp.frq:
966 frq.append(cdp.frq[align_id] * 2.0 * pi / g1H)
967
968
969 else:
970 raise RelaxError("The spectrometer frequency for the alignment ID '%s' has not been set." % align_id)
971
972
973 j = 0
974 for spin in spin_loop():
975
976 if not spin.select:
977 continue
978
979
980 if not hasattr(spin, 'pcs'):
981 continue
982
983
984 if align_id in spin.pcs.keys():
985 if sim_index != None:
986 pcs[-1].append(spin.pcs_sim[align_id][sim_index])
987 else:
988 pcs[-1].append(spin.pcs[align_id])
989 else:
990 pcs[-1].append(None)
991
992
993 if hasattr(spin, 'pcs_err') and align_id in spin.pcs_err.keys():
994 pcs_err[-1].append(spin.pcs_err[align_id])
995 else:
996 pcs_err[-1].append(None)
997
998
999 if hasattr(spin, 'pcs_weight') and align_id in spin.pcs_weight.keys():
1000 pcs_weight[-1].append(spin.pcs_weight[align_id])
1001 else:
1002 pcs_weight[-1].append(1.0)
1003
1004
1005 j = j + 1
1006
1007
1008 pcs = array(pcs, float64)
1009 pcs_err = array(pcs_err, float64)
1010 pcs_weight = array(pcs_weight, float64)
1011
1012
1013 pcs = pcs * 1e-6
1014 pcs_err = pcs_err * 1e-6
1015
1016
1017 return pcs, pcs_err, pcs_weight, temp, frq
1018
1019
1021 """Set up the data structures for optimisation using RDCs as base data sets.
1022
1023 @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
1024 @type sim_index: None or int
1025 @return: The assembled data structures for using RDCs as the base data for optimisation. These include:
1026 - rdc, the RDC values.
1027 - rdc_err, the RDC errors.
1028 - rdc_weight, the RDC weights.
1029 - vectors, the interatomic vectors.
1030 - rdc_const, the dipolar constants.
1031 - absolute, the absolute value flags (as 1's and 0's).
1032 @rtype: tuple of (numpy rank-2 array, numpy rank-2 array, numpy rank-2 array, numpy rank-3 array, numpy rank-2 array, numpy rank-2 array)
1033 """
1034
1035
1036 rdc = []
1037 rdc_err = []
1038 rdc_weight = []
1039 unit_vect = []
1040 rdc_const = []
1041 absolute = []
1042
1043
1044 for interatom in interatomic_loop():
1045
1046 spin1 = return_spin(interatom.spin_id1)
1047 spin2 = return_spin(interatom.spin_id2)
1048
1049
1050 if not self._check_rdcs(interatom, spin1, spin2):
1051 continue
1052
1053
1054 if arg_check.is_float(interatom.vector[0], raise_error=False):
1055 unit_vect.append([interatom.vector])
1056 else:
1057 unit_vect.append(interatom.vector)
1058
1059
1060 g1 = return_gyromagnetic_ratio(spin1.isotope)
1061 g2 = return_gyromagnetic_ratio(spin2.isotope)
1062
1063
1064 rdc_const.append(3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r))
1065
1066
1067 num = None
1068 for rdc_index in range(len(unit_vect)):
1069
1070 if num == None:
1071 if unit_vect[rdc_index] != None:
1072 num = len(unit_vect[rdc_index])
1073 continue
1074
1075
1076 if unit_vect[rdc_index] != None and len(unit_vect[rdc_index]) != num:
1077 raise RelaxError("The number of interatomic vectors for all no match:\n%s" % unit_vect)
1078
1079
1080 if num == None:
1081 raise RelaxError("No interatomic vectors could be found.")
1082
1083
1084 for i in range(len(unit_vect)):
1085 if unit_vect[i] == None:
1086 unit_vect[i] = [[None, None, None]]*num
1087
1088
1089 for i in range(len(cdp.align_ids)):
1090
1091 align_id = cdp.align_ids[i]
1092
1093
1094 if not self._opt_uses_align_data(align_id):
1095 continue
1096
1097
1098 rdc.append([])
1099 rdc_err.append([])
1100 rdc_weight.append([])
1101 absolute.append([])
1102
1103
1104 for interatom in interatomic_loop():
1105
1106 spin1 = return_spin(interatom.spin_id1)
1107 spin2 = return_spin(interatom.spin_id2)
1108
1109
1110 if not spin1.select or not spin2.select:
1111 continue
1112
1113
1114 if not hasattr(interatom, 'rdc') or not hasattr(interatom, 'vector'):
1115 continue
1116
1117
1118 value = None
1119 error = None
1120
1121
1122 if (hasattr(spin1, 'members') or hasattr(spin2, 'members')) and align_id in interatom.rdc.keys():
1123
1124 if (hasattr(spin1, 'members') and len(spin1.members) != 3) or (hasattr(spin2, 'members') and len(spin2.members) != 3):
1125 continue
1126
1127
1128
1129
1130 if sim_index != None:
1131 value = -3.0 * interatom.rdc_sim[align_id][sim_index]
1132 else:
1133 value = -3.0 * interatom.rdc[align_id]
1134
1135
1136 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
1137 error = -3.0 * interatom.rdc_err[align_id]
1138
1139
1140 elif align_id in interatom.rdc.keys():
1141
1142 if sim_index != None:
1143 value = interatom.rdc_sim[align_id][sim_index]
1144 else:
1145 value = interatom.rdc[align_id]
1146
1147
1148 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
1149 error = interatom.rdc_err[align_id]
1150
1151
1152 rdc[-1].append(value)
1153
1154
1155 rdc_err[-1].append(error)
1156
1157
1158 if hasattr(interatom, 'rdc_weight') and align_id in interatom.rdc_weight.keys():
1159 rdc_weight[-1].append(interatom.rdc_weight[align_id])
1160 else:
1161 rdc_weight[-1].append(1.0)
1162
1163
1164 if hasattr(interatom, 'absolute_rdc') and align_id in interatom.absolute_rdc.keys():
1165 absolute[-1].append(interatom.absolute_rdc[align_id])
1166 else:
1167 absolute[-1].append(False)
1168
1169
1170 rdc = array(rdc, float64)
1171 rdc_err = array(rdc_err, float64)
1172 rdc_weight = array(rdc_weight, float64)
1173 unit_vect = array(unit_vect, float64)
1174 rdc_const = array(rdc_const, float64)
1175 absolute = array(absolute, float64)
1176
1177
1178 return rdc, rdc_err, rdc_weight, unit_vect, rdc_const, absolute
1179
1180
1182 """Set up the data structures for optimisation using alignment tensors as base data sets.
1183
1184 @keyword sim_index: The index of the simulation to optimise. This should be None if
1185 normal optimisation is desired.
1186 @type sim_index: None or int
1187 @return: The assembled data structures for using alignment tensors as the base
1188 data for optimisation. These include:
1189 - full_tensors, the data of the full alignment tensors.
1190 - red_tensor_elem, the tensors as concatenated rank-1 5D arrays.
1191 - red_tensor_err, the tensor errors as concatenated rank-1 5D
1192 arrays.
1193 - full_in_ref_frame, flags specifying if the tensor in the reference
1194 frame is the full or reduced tensor.
1195 @rtype: tuple of (list, numpy rank-1 array, numpy rank-1 array, numpy rank-1
1196 array)
1197 """
1198
1199
1200 n = len(cdp.align_tensors.reduction)
1201 full_tensors = zeros(n*5, float64)
1202 red_tensors = zeros(n*5, float64)
1203 red_err = ones(n*5, float64) * 1e-5
1204 full_in_ref_frame = zeros(n, float64)
1205
1206
1207 for i, tensor in self._tensor_loop(red=False):
1208
1209 full_tensors[5*i + 0] = tensor.Axx
1210 full_tensors[5*i + 1] = tensor.Ayy
1211 full_tensors[5*i + 2] = tensor.Axy
1212 full_tensors[5*i + 3] = tensor.Axz
1213 full_tensors[5*i + 4] = tensor.Ayz
1214
1215
1216 if cdp.ref_domain == tensor.domain:
1217 full_in_ref_frame[i] = 1
1218
1219
1220 for i, tensor in self._tensor_loop(red=True):
1221
1222 if sim_index != None:
1223 red_tensors[5*i + 0] = tensor.Axx_sim[sim_index]
1224 red_tensors[5*i + 1] = tensor.Ayy_sim[sim_index]
1225 red_tensors[5*i + 2] = tensor.Axy_sim[sim_index]
1226 red_tensors[5*i + 3] = tensor.Axz_sim[sim_index]
1227 red_tensors[5*i + 4] = tensor.Ayz_sim[sim_index]
1228
1229
1230 else:
1231 red_tensors[5*i + 0] = tensor.Axx
1232 red_tensors[5*i + 1] = tensor.Ayy
1233 red_tensors[5*i + 2] = tensor.Axy
1234 red_tensors[5*i + 3] = tensor.Axz
1235 red_tensors[5*i + 4] = tensor.Ayz
1236
1237
1238 if hasattr(tensor, 'Axx_err'):
1239 red_err[5*i + 0] = tensor.Axx_err
1240 red_err[5*i + 1] = tensor.Ayy_err
1241 red_err[5*i + 2] = tensor.Axy_err
1242 red_err[5*i + 3] = tensor.Axz_err
1243 red_err[5*i + 4] = tensor.Ayz_err
1244
1245
1246 return full_tensors, red_tensors, red_err, full_in_ref_frame
1247
1248
1250 """Set up the data structures for the fixed alignment tensors.
1251
1252 @return: The assembled data structures for the fixed alignment tensors.
1253 @rtype: numpy rank-1 array.
1254 """
1255
1256
1257 n = align_tensor.num_tensors(skip_fixed=False) - align_tensor.num_tensors(skip_fixed=True)
1258 tensors = zeros(n*5, float64)
1259
1260
1261 if n == 0:
1262 return None
1263
1264
1265 index = 0
1266 for i in range(len(cdp.align_tensors)):
1267
1268 if not self._opt_uses_align_data(cdp.align_tensors[i].name):
1269 continue
1270
1271
1272 tensors[5*index + 0] = cdp.align_tensors[i].Axx
1273 tensors[5*index + 1] = cdp.align_tensors[i].Ayy
1274 tensors[5*index + 2] = cdp.align_tensors[i].Axy
1275 tensors[5*index + 3] = cdp.align_tensors[i].Axz
1276 tensors[5*index + 4] = cdp.align_tensors[i].Ayz
1277
1278
1279 index += 1
1280
1281
1282 return tensors
1283
1284
1286 """Determine the number of data points used in the model.
1287
1288 @return: The number, n, of data points in the model.
1289 @rtype: int
1290 """
1291
1292
1293 data_types = self._base_data_types()
1294
1295
1296 n = 0
1297
1298
1299 for spin in spin_loop():
1300
1301 if not spin.select:
1302 continue
1303
1304
1305 if 'pcs' in data_types:
1306 if hasattr(spin, 'pcs'):
1307 for pcs in spin.pcs:
1308 if isinstance(pcs, float):
1309 n = n + 1
1310
1311
1312 for interatom in interatomic_loop():
1313
1314 if 'rdc' in data_types:
1315 if hasattr(interatom, 'rdc'):
1316 for rdc in interatom.rdc:
1317 if isinstance(rdc, float):
1318 n = n + 1
1319
1320
1321 if 'tensor' in data_types:
1322 n = n + 5*len(cdp.align_tensors)
1323
1324
1325 return n
1326
1327
1329 """Set the number of states in the N-state model.
1330
1331 @param N: The number of states.
1332 @type N: int
1333 """
1334
1335
1336 pipes.test()
1337
1338
1339 cdp.N = N
1340
1341
1342 if hasattr(cdp, 'model'):
1343 self._update_model()
1344
1345
1347 """Determine if the given tensor is to be optimised.
1348
1349 @param tensor: The alignment tensor to check.
1350 @type tensor: AlignmentTensor object.
1351 @return: True if the tensor is to be optimised, False otherwise.
1352 @rtype: bool
1353 """
1354
1355
1356 ids = []
1357 if hasattr(cdp, 'rdc_ids'):
1358 ids += cdp.rdc_ids
1359 if hasattr(cdp, 'pcs_ids'):
1360 ids += cdp.pcs_ids
1361
1362
1363 if tensor.name not in ids:
1364 return False
1365
1366
1367 if tensor.fixed:
1368 return False
1369
1370
1371 return True
1372
1373
1375 """Determine if the PCS or RDC data for the given alignment ID is needed for optimisation.
1376
1377 @keyword align_id: The optional alignment ID string.
1378 @type align_id: str
1379 @return: True if alignment data is to be used for optimisation, False otherwise.
1380 @rtype: bool
1381 """
1382
1383
1384 if not hasattr(cdp, 'align_ids'):
1385 return False
1386
1387
1388 if align_id:
1389 align_ids = [align_id]
1390 else:
1391 align_ids = cdp.align_ids
1392
1393
1394 for align_id in align_ids:
1395 if self._opt_uses_pcs(align_id) or self._opt_uses_rdc(align_id):
1396 return True
1397
1398
1399 return False
1400
1401
1403 """Determine if the PCS data for the given alignment ID is needed for optimisation.
1404
1405 @param align_id: The alignment ID string.
1406 @type align_id: str
1407 @return: True if the PCS data is to be used for optimisation, False otherwise.
1408 @rtype: bool
1409 """
1410
1411
1412 if not hasattr(cdp, 'pcs_ids'):
1413 return False
1414
1415
1416 if align_id not in cdp.pcs_ids:
1417 return False
1418
1419
1420 tensor_flag = self._opt_tensor(align_tensor.get_tensor_object(align_id))
1421
1422
1423 pos_flag = False
1424 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
1425 pos_flag = True
1426
1427
1428 prob_flag = False
1429 if cdp.model == 'population':
1430 prob_flag = True
1431
1432
1433 if not tensor_flag and not pos_flag and not prob_flag:
1434 return False
1435
1436
1437 return True
1438
1439
1441 """Determine if the RDC data for the given alignment ID is needed for optimisation.
1442
1443 @param align_id: The alignment ID string.
1444 @type align_id: str
1445 @return: True if the RDC data is to be used for optimisation, False otherwise.
1446 @rtype: bool
1447 """
1448
1449
1450 if not hasattr(cdp, 'rdc_ids'):
1451 return False
1452
1453
1454 if align_id not in cdp.rdc_ids:
1455 return False
1456
1457
1458 tensor_flag = self._opt_tensor(align_tensor.get_tensor_object(align_id))
1459
1460
1461 pos_flag = False
1462 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
1463 pos_flag = True
1464
1465
1466 prob_flag = False
1467 if cdp.model == 'population':
1468 prob_flag = True
1469
1470
1471 if not tensor_flag and not pos_flag and not prob_flag:
1472 return False
1473
1474
1475 return True
1476
1477
1479 """Return the N-state model index for the given parameter.
1480
1481 @param param: The N-state model parameter.
1482 @type param: str
1483 @return: The N-state model index.
1484 @rtype: str
1485 """
1486
1487
1488 if search('^p[0-9]*$', param):
1489 return int(param[1:])
1490
1491
1492 if search('^alpha', param):
1493 return int(param[5:])
1494
1495
1496 if search('^beta', param):
1497 return int(param[4:])
1498
1499
1500 if search('^gamma', param):
1501 return int(param[5:])
1502
1503
1504 return None
1505
1506
1508 """Determine the number of parameters in the model.
1509
1510 @return: The number of model parameters.
1511 @rtype: int
1512 """
1513
1514
1515 data_types = self._base_data_types()
1516
1517
1518 num = 0
1519
1520
1521 if ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
1522
1523 for i in range(len(cdp.align_tensors)):
1524
1525 if not self._opt_tensor(cdp.align_tensors[i]):
1526 continue
1527
1528
1529 num += 5
1530
1531
1532 if cdp.model in ['2-domain', 'population']:
1533 num = num + (cdp.N - 1)
1534
1535
1536 if cdp.model == '2-domain':
1537 num = num + 3*cdp.N
1538
1539
1540 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
1541 num = num + 3
1542
1543
1544 return num
1545
1546
1547 - def _ref_domain(self, ref=None):
1548 """Set the reference domain for the '2-domain' N-state model.
1549
1550 @param ref: The reference domain.
1551 @type ref: str
1552 """
1553
1554
1555 pipes.test()
1556
1557
1558 if not hasattr(cdp, 'model'):
1559 raise RelaxNoModelError('N-state')
1560
1561
1562 if cdp.model != '2-domain':
1563 raise RelaxError("Setting the reference domain is only possible for the '2-domain' N-state model.")
1564
1565
1566 exists = False
1567 for tensor_cont in cdp.align_tensors:
1568 if tensor_cont.domain == ref:
1569 exists = True
1570 if not exists:
1571 raise RelaxError("The reference domain cannot be found within any of the loaded tensors.")
1572
1573
1574 cdp.ref_domain = ref
1575
1576
1577 self._update_model()
1578
1579
1581 """Select the N-state model type.
1582
1583 @param model: The N-state model type. Can be one of '2-domain', 'population', or 'fixed'.
1584 @type model: str
1585 """
1586
1587
1588 pipes.test()
1589
1590
1591 if not model in ['2-domain', 'population', 'fixed']:
1592 raise RelaxError("The model name " + repr(model) + " is invalid.")
1593
1594
1595 if hasattr(cdp, 'model'):
1596 warn(RelaxWarning("The N-state model has already been set up. Switching from model '%s' to '%s'." % (cdp.model, model)))
1597
1598
1599 cdp.model = model
1600
1601
1602 cdp.params = []
1603
1604
1605 self._update_model()
1606
1607
1609 """Initialise the target function for optimisation or direct calculation.
1610
1611 @param sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
1612 @type sim_index: None or int
1613 @param scaling: If True, diagonal scaling is enabled during optimisation to allow the problem to be better conditioned.
1614 @type scaling: bool
1615 """
1616
1617
1618 if not hasattr(cdp, 'model'):
1619 raise RelaxNoModelError('N-state')
1620
1621
1622 if cdp.model == '2-domain':
1623
1624 if not hasattr(cdp, 'N'):
1625 raise RelaxError("The number of states has not been set.")
1626
1627
1628 if not hasattr(cdp, 'ref_domain'):
1629 raise RelaxError("The reference domain has not been set.")
1630
1631
1632 self._update_model()
1633
1634
1635 param_vector = self._assemble_param_vector(sim_index=sim_index)
1636
1637
1638 data_types = self._base_data_types()
1639
1640
1641 probs = None
1642 if hasattr(cdp, 'probs') and len(cdp.probs) and cdp.probs[0] != None:
1643 probs = cdp.probs
1644
1645
1646 scaling_matrix = None
1647 if len(param_vector):
1648 scaling_matrix = self._assemble_scaling_matrix(data_types=data_types, scaling=scaling)
1649 param_vector = dot(inv(scaling_matrix), param_vector)
1650
1651
1652 full_tensors, red_tensor_elem, red_tensor_err, full_in_ref_frame = None, None, None, None
1653 if 'tensor' in data_types:
1654 full_tensors, red_tensor_elem, red_tensor_err, full_in_ref_frame = self._minimise_setup_tensors(sim_index=sim_index)
1655
1656
1657 pcs, pcs_err, pcs_weight, temp, frq = None, None, None, None, None
1658 if 'pcs' in data_types:
1659 pcs, pcs_err, pcs_weight, temp, frq = self._minimise_setup_pcs(sim_index=sim_index)
1660
1661
1662 rdcs, rdc_err, rdc_weight, rdc_vector, rdc_dj, absolute_rdc = None, None, None, None, None, None
1663 if 'rdc' in data_types:
1664 rdcs, rdc_err, rdc_weight, rdc_vector, rdc_dj, absolute_rdc = self._minimise_setup_rdcs(sim_index=sim_index)
1665
1666
1667 fixed_tensors = None
1668 if 'rdc' in data_types or 'pcs' in data_types:
1669 full_tensors = self._minimise_setup_fixed_tensors()
1670
1671
1672 fixed_tensors = []
1673 for i in range(len(cdp.align_tensors)):
1674
1675 if not self._opt_uses_align_data(cdp.align_tensors[i].name):
1676 continue
1677
1678 if cdp.align_tensors[i].fixed:
1679 fixed_tensors.append(True)
1680 else:
1681 fixed_tensors.append(False)
1682
1683
1684 atomic_pos, paramag_centre, centre_fixed = None, None, True
1685 if 'pcs' in data_types or 'pre' in data_types:
1686 atomic_pos, paramag_centre = self._minimise_setup_atomic_pos(sim_index=sim_index)
1687
1688
1689 if hasattr(cdp, 'paramag_centre_fixed'):
1690 centre_fixed = cdp.paramag_centre_fixed
1691
1692
1693 model = N_state_opt(model=cdp.model, N=cdp.N, init_params=param_vector, probs=probs, full_tensors=full_tensors, red_data=red_tensor_elem, red_errors=red_tensor_err, full_in_ref_frame=full_in_ref_frame, fixed_tensors=fixed_tensors, pcs=pcs, rdcs=rdcs, pcs_errors=pcs_err, rdc_errors=rdc_err, pcs_weights=pcs_weight, rdc_weights=rdc_weight, rdc_vect=rdc_vector, temp=temp, frq=frq, dip_const=rdc_dj, absolute_rdc=absolute_rdc, atomic_pos=atomic_pos, paramag_centre=paramag_centre, scaling_matrix=scaling_matrix, centre_fixed=centre_fixed)
1694
1695
1696 return model, param_vector, data_types, scaling_matrix
1697
1698
1700 """Generator method for looping over the full or reduced tensors.
1701
1702 @keyword red: A flag which if True causes the reduced tensors to be returned, and if False
1703 the full tensors are returned.
1704 @type red: bool
1705 @return: The tensor index and the tensor.
1706 @rtype: (int, AlignTensorData instance)
1707 """
1708
1709
1710 n = len(cdp.align_tensors.reduction)
1711
1712
1713 data = cdp.align_tensors
1714 list = data.reduction
1715
1716
1717 if red:
1718 index = 1
1719 else:
1720 index = 0
1721
1722
1723 for i in range(n):
1724 yield i, data[list[i][index]]
1725
1726
1728 """Update the model parameters as necessary."""
1729
1730
1731 if not hasattr(cdp, 'params'):
1732 cdp.params = []
1733
1734
1735 if not hasattr(cdp, 'N'):
1736
1737 if hasattr(cdp, 'structure'):
1738 cdp.N = cdp.structure.num_models()
1739
1740
1741 else:
1742 return
1743
1744
1745 if not cdp.params:
1746
1747 if cdp.model in ['2-domain', 'population']:
1748 for i in range(cdp.N-1):
1749 cdp.params.append('p' + repr(i))
1750
1751
1752 if cdp.model == '2-domain':
1753 for i in range(cdp.N):
1754 cdp.params.append('alpha' + repr(i))
1755 cdp.params.append('beta' + repr(i))
1756 cdp.params.append('gamma' + repr(i))
1757
1758
1759 if cdp.model in ['2-domain', 'population']:
1760 if not hasattr(cdp, 'probs'):
1761 cdp.probs = [None] * cdp.N
1762 if cdp.model == '2-domain':
1763 if not hasattr(cdp, 'alpha'):
1764 cdp.alpha = [None] * cdp.N
1765 if not hasattr(cdp, 'beta'):
1766 cdp.beta = [None] * cdp.N
1767 if not hasattr(cdp, 'gamma'):
1768 cdp.gamma = [None] * cdp.N
1769
1770
1771 data_types = self._base_data_types()
1772
1773
1774 if hasattr(cdp, 'align_ids'):
1775 for id in cdp.align_ids:
1776
1777 if not hasattr(cdp, 'align_tensors'):
1778 align_tensor.init(tensor=id, params=[0.0, 0.0, 0.0, 0.0, 0.0])
1779
1780
1781 exists = False
1782 for tensor in cdp.align_tensors:
1783 if id == tensor.name:
1784 exists = True
1785
1786
1787 if not exists:
1788 align_tensor.init(tensor=id, params=[0.0, 0.0, 0.0, 0.0, 0.0])
1789
1790
1792 """Loop over the base data of the spins - RDCs, PCSs, and NOESY data.
1793
1794 This loop iterates for each data point (RDC, PCS, NOESY) for each spin or interatomic data container, returning the identification information.
1795
1796 @return: A list of the spin or interatomic data container, the data type ('rdc', 'pcs', 'noesy'), and the alignment ID if required.
1797 @rtype: list of [SpinContainer instance, str, str] or [InteratomContainer instance, str, str]
1798 """
1799
1800
1801 for interatom in interatomic_loop():
1802
1803 if not interatom.select:
1804 continue
1805
1806
1807 data = [interatom, None, None]
1808
1809
1810 if hasattr(interatom, 'rdc'):
1811 data[1] = 'rdc'
1812
1813
1814 for id in cdp.rdc_ids:
1815
1816 data[2] = id
1817
1818
1819 yield data
1820
1821
1822 if hasattr(interatom, 'noesy'):
1823 data[1] = 'noesy'
1824
1825
1826 for id in cdp.noesy_ids:
1827
1828 data[2] = id
1829
1830
1831 yield data
1832
1833
1834 for spin in spin_loop():
1835
1836 if not spin.select:
1837 continue
1838
1839
1840 data = [spin, None, None]
1841
1842
1843 if hasattr(spin, 'pcs'):
1844 data[1] = 'pcs'
1845
1846
1847 for id in cdp.pcs_ids:
1848
1849 data[2] = id
1850
1851
1852 yield data
1853
1854
1855 - def calculate(self, spin_id=None, verbosity=1, sim_index=None):
1856 """Calculation function.
1857
1858 Currently this function simply calculates the NOESY flat-bottom quadratic energy potential,
1859 if NOE restraints are available.
1860
1861 @keyword spin_id: The spin identification string (unused).
1862 @type spin_id: None or str
1863 @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity.
1864 @type verbosity: int
1865 @keyword sim_index: The MC simulation index (unused).
1866 @type sim_index: None
1867 """
1868
1869
1870 model, param_vector, data_types, scaling_matrix = self._target_fn_setup()
1871
1872
1873 if model:
1874
1875 chi2 = model.func(param_vector)
1876
1877
1878 cdp.chi2 = chi2
1879
1880
1881 self._minimise_bc_data(model)
1882
1883
1884 if 'rdc' in data_types:
1885 rdc.q_factors()
1886
1887
1888 if 'pcs' in data_types:
1889 pcs.q_factors()
1890
1891
1892 if hasattr(cdp, 'noe_restraints'):
1893
1894 num_restraints = len(cdp.noe_restraints)
1895 dist = zeros(num_restraints, float64)
1896 pot = zeros(num_restraints, float64)
1897 lower = zeros(num_restraints, float64)
1898 upper = zeros(num_restraints, float64)
1899
1900
1901 for i in range(num_restraints):
1902
1903 lower[i] = cdp.noe_restraints[i][2]
1904 upper[i] = cdp.noe_restraints[i][3]
1905
1906
1907 dist[i] = self._calc_ave_dist(cdp.noe_restraints[i][0], cdp.noe_restraints[i][1], exp=-6)
1908
1909
1910 quad_pot(dist, pot, lower, upper)
1911
1912
1913 cdp.ave_dist = []
1914 cdp.quad_pot = []
1915 for i in range(num_restraints):
1916 cdp.ave_dist.append([cdp.noe_restraints[i][0], cdp.noe_restraints[i][1], dist[i]])
1917 cdp.quad_pot.append([cdp.noe_restraints[i][0], cdp.noe_restraints[i][1], pot[i]])
1918
1919
1921 """Create the Monte Carlo data by back-calculation.
1922
1923 @keyword data_id: The list of spin ID, data type, and alignment ID, as yielded by the base_data_loop() generator method.
1924 @type data_id: str
1925 @return: The Monte Carlo Ri data.
1926 @rtype: list of floats
1927 """
1928
1929
1930 mc_data = []
1931
1932
1933 container = data_id[0]
1934
1935
1936 if data_id[1] == 'rdc' and hasattr(container, 'rdc'):
1937
1938 if not hasattr(container, 'rdc_bc'):
1939 self.calculate()
1940
1941
1942 if not hasattr(container, 'rdc_bc') or not data_id[2] in container.rdc_bc:
1943 data = None
1944 else:
1945 data = container.rdc_bc[data_id[2]]
1946
1947
1948 mc_data.append(data)
1949
1950
1951 elif data_id[1] == 'noesy' and hasattr(container, 'noesy'):
1952
1953 if not hasattr(container, 'noesy_bc'):
1954 self.calculate()
1955
1956
1957 mc_data.append(container.noesy_bc)
1958
1959
1960 elif data_id[1] == 'pcs' and hasattr(container, 'pcs'):
1961
1962 if not hasattr(container, 'pcs_bc'):
1963 self.calculate()
1964
1965
1966 if not hasattr(container, 'pcs_bc') or not data_id[2] in container.pcs_bc:
1967 data = None
1968 else:
1969 data = container.pcs_bc[data_id[2]]
1970
1971
1972 mc_data.append(data)
1973
1974
1975 return mc_data
1976
1977
1978 default_value_doc = Desc_container("N-state model default values")
1979 _table = uf_tables.add_table(label="table: N-state default values", caption="N-state model default values.")
1980 _table.add_headings(["Data type", "Object name", "Value"])
1981 _table.add_row(["Probabilities", "'p0', 'p1', 'p2', ..., 'pN'", "1/N"])
1982 _table.add_row(["Euler angle alpha", "'alpha0', 'alpha1', ...", "(c+1) * pi / (N+1)"])
1983 _table.add_row(["Euler angle beta", "'beta0', 'beta1', ...", "(c+1) * pi / (N+1)"])
1984 _table.add_row(["Euler angle gamma", "'gamma0', 'gamma1', ...", "(c+1) * pi / (N+1)"])
1985 default_value_doc.add_table(_table.label)
1986 default_value_doc.add_paragraph("In this table, N is the total number of states and c is the index of a given state ranging from 0 to N-1. The default probabilities are all set to be equal whereas the angles are given a range of values so that no 2 states are equal at the start of optimisation.")
1987 default_value_doc.add_paragraph("Note that setting the probability for state N will do nothing as it is equal to one minus all the other probabilities.")
1988
1990 """The default N-state model parameter values.
1991
1992 @param param: The N-state model parameter.
1993 @type param: str
1994 @return: The default value.
1995 @rtype: float
1996 """
1997
1998
1999 name = self.return_data_name(param)
2000 index = self._param_model_index(param)
2001
2002
2003 N = float(cdp.N)
2004
2005
2006 if name == 'probs':
2007 return 1.0 / N
2008
2009
2010 elif name == 'alpha' or name == 'beta' or name == 'gamma':
2011 return (float(index)+1) * pi / (N+1.0)
2012
2013
2014 - def grid_search(self, lower=None, upper=None, inc=None, constraints=False, verbosity=0, sim_index=None):
2015 """The grid search function.
2016
2017 @param lower: The lower bounds of the grid search which must be equal to the number of parameters in the model.
2018 @type lower: array of numbers
2019 @param upper: The upper bounds of the grid search which must be equal to the number of parameters in the model.
2020 @type upper: array of numbers
2021 @param inc: The increments for each dimension of the space for the grid search. The number of elements in the array must equal to the number of parameters in the model.
2022 @type inc: array of int
2023 @param constraints: If True, constraints are applied during the grid search (elinating parts of the grid). If False, no constraints are used.
2024 @type constraints: bool
2025 @param verbosity: A flag specifying the amount of information to print. The higher the value, the greater the verbosity.
2026 @type verbosity: int
2027 """
2028
2029
2030 if not hasattr(cdp, 'model'):
2031 raise RelaxNoModelError('N-state')
2032
2033
2034 n = self._param_num()
2035
2036
2037 if n == 0:
2038 print("Cannot run a grid search on a model with zero parameters, skipping the grid search.")
2039 return
2040
2041
2042 self.test_grid_ops(lower=lower, upper=upper, inc=inc, n=n)
2043
2044
2045 if isinstance(inc, int):
2046 inc = [inc]*n
2047
2048
2049 if not lower:
2050
2051 lower = []
2052 upper = []
2053
2054
2055 for i in range(n):
2056
2057 if i < len(cdp.params):
2058
2059 if search('^p', cdp.params[i]):
2060 lower.append(0.0)
2061 upper.append(1.0)
2062
2063
2064 if search('^alpha', cdp.params[i]) or search('^gamma', cdp.params[i]):
2065 lower.append(0.0)
2066 upper.append(2*pi)
2067 elif search('^beta', cdp.params[i]):
2068 lower.append(0.0)
2069 upper.append(pi)
2070
2071
2072 elif hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed and (n - i) <= 3:
2073 lower.append(-100)
2074 upper.append(100)
2075
2076
2077 else:
2078 lower.append(-1e-3)
2079 upper.append(1e-3)
2080
2081
2082 data_types = self._base_data_types()
2083
2084
2085 tensor_num = align_tensor.num_tensors(skip_fixed=True)
2086
2087
2088 if cdp.model == 'fixed' and tensor_num > 1 and ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed() and hasattr(cdp, 'paramag_centre_fixed') and cdp.paramag_centre_fixed:
2089
2090 print("Optimising each alignment tensor separately.")
2091
2092
2093 fixed_flags = []
2094 for i in range(len(cdp.align_ids)):
2095
2096 tensor = align_tensor.return_tensor(index=i, skip_fixed=False)
2097
2098
2099 fixed_flags.append(tensor.fixed)
2100
2101
2102 tensor.set('fixed', True)
2103
2104
2105 for i in range(len(cdp.align_ids)):
2106
2107 if fixed_flags[i]:
2108 continue
2109
2110
2111 tensor = align_tensor.return_tensor(index=i, skip_fixed=False)
2112
2113
2114 tensor.set('fixed', False)
2115
2116
2117 lower_sub = lower[i*5:i*5+5]
2118 upper_sub = upper[i*5:i*5+5]
2119 inc_sub = inc[i*5:i*5+5]
2120
2121
2122 self.minimise(min_algor='grid', lower=lower_sub, upper=upper_sub, inc=inc_sub, constraints=constraints, verbosity=verbosity, sim_index=sim_index)
2123
2124
2125 tensor.set('fixed', True)
2126
2127
2128 for i in range(len(cdp.align_ids)):
2129
2130 tensor = align_tensor.return_tensor(index=i, skip_fixed=False)
2131
2132
2133 tensor.set('fixed', fixed_flags[i])
2134
2135
2136 else:
2137 self.minimise(min_algor='grid', lower=lower, upper=upper, inc=inc, constraints=constraints, verbosity=verbosity, sim_index=sim_index)
2138
2139
2141 """Determine whether the given parameter is spin specific.
2142
2143 @param name: The name of the parameter.
2144 @type name: str
2145 @return: False
2146 @rtype: bool
2147 """
2148
2149
2150 if name in ['r', 'heteronuc_type', 'proton_type']:
2151 return True
2152
2153
2154 return False
2155
2156
2158 """Create bounds for the OpenDX mapping function.
2159
2160 @param param: The name of the parameter to return the lower and upper bounds of.
2161 @type param: str
2162 @param spin_id: The spin identification string (unused).
2163 @type spin_id: None
2164 @return: The upper and lower bounds of the parameter.
2165 @rtype: list of float
2166 """
2167
2168
2169 if search('^paramag_[xyz]$', param):
2170 return [-100.0, 100.0]
2171
2172
2173 - def minimise(self, min_algor=None, min_options=None, func_tol=None, grad_tol=None, max_iterations=None, constraints=False, scaling=True, verbosity=0, sim_index=None, lower=None, upper=None, inc=None):
2174 """Minimisation function.
2175
2176 @param min_algor: The minimisation algorithm to use.
2177 @type min_algor: str
2178 @param min_options: An array of options to be used by the minimisation algorithm.
2179 @type min_options: array of str
2180 @param func_tol: The function tolerance which, when reached, terminates optimisation. Setting this to None turns of the check.
2181 @type func_tol: None or float
2182 @param grad_tol: The gradient tolerance which, when reached, terminates optimisation. Setting this to None turns of the check.
2183 @type grad_tol: None or float
2184 @param max_iterations: The maximum number of iterations for the algorithm.
2185 @type max_iterations: int
2186 @param constraints: If True, constraints are used during optimisation.
2187 @type constraints: bool
2188 @param scaling: If True, diagonal scaling is enabled during optimisation to allow the problem to be better conditioned.
2189 @type scaling: bool
2190 @param verbosity: A flag specifying the amount of information to print. The higher the value, the greater the verbosity.
2191 @type verbosity: int
2192 @param sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
2193 @type sim_index: None or int
2194 @keyword lower: The lower bounds of the grid search which must be equal to the number of parameters in the model. This optional argument is only used when doing a grid search.
2195 @type lower: array of numbers
2196 @keyword upper: The upper bounds of the grid search which must be equal to the number of parameters in the model. This optional argument is only used when doing a grid search.
2197 @type upper: array of numbers
2198 @keyword inc: The increments for each dimension of the space for the grid search. The number of elements in the array must equal to the number of parameters in the model. This argument is only used when doing a grid search.
2199 @type inc: array of int
2200 """
2201
2202
2203 model, param_vector, data_types, scaling_matrix = self._target_fn_setup(sim_index=sim_index, scaling=scaling)
2204
2205
2206 if not len(param_vector):
2207 warn(RelaxWarning("The model has no parameters, minimisation cannot be performed."))
2208 return
2209
2210
2211 if constraints and cdp.model == 'fixed':
2212 warn(RelaxWarning("Turning constraints off. These cannot be used for the 'fixed' model."))
2213 constraints = False
2214
2215
2216 if min_algor == 'Method of Multipliers':
2217 min_algor = min_options[0]
2218 min_options = min_options[1:]
2219
2220
2221 if not constraints and cdp.model == 'population':
2222 warn(RelaxWarning("Turning constraints on. These absolutely must be used for the 'population' model."))
2223 constraints = True
2224
2225
2226 min_options = (min_algor,) + min_options
2227 min_algor = 'Method of Multipliers'
2228
2229
2230 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
2231 if min_algor in ['newton']:
2232 raise RelaxError("For the paramagnetic centre position, as the Hessians are not yet implemented Newton optimisation cannot be performed.")
2233
2234
2235 if constraints:
2236 A, b = self._linear_constraints(data_types=data_types, scaling_matrix=scaling_matrix)
2237 else:
2238 A, b = None, None
2239
2240
2241 if search('^[Gg]rid', min_algor):
2242
2243 if scaling:
2244 for i in range(len(param_vector)):
2245 lower[i] = lower[i] / scaling_matrix[i, i]
2246 upper[i] = upper[i] / scaling_matrix[i, i]
2247
2248
2249 results = grid(func=model.func, args=(), num_incs=inc, lower=lower, upper=upper, A=A, b=b, verbosity=verbosity)
2250
2251
2252 param_vector, func, iter_count, warning = results
2253 f_count = iter_count
2254 g_count = 0.0
2255 h_count = 0.0
2256
2257
2258 else:
2259 results = generic_minimise(func=model.func, dfunc=model.dfunc, d2func=model.d2func, args=(), x0=param_vector, min_algor=min_algor, min_options=min_options, func_tol=func_tol, grad_tol=grad_tol, maxiter=max_iterations, A=A, b=b, full_output=1, print_flag=verbosity)
2260
2261
2262 if results == None:
2263 return
2264 param_vector, func, iter_count, f_count, g_count, h_count, warning = results
2265
2266
2267 if isInf(func):
2268 raise RelaxInfError('chi-squared')
2269
2270
2271 if isNaN(func):
2272 raise RelaxNaNError('chi-squared')
2273
2274
2275 chi2 = model.func(param_vector)
2276
2277
2278 if scaling:
2279 param_vector = dot(scaling_matrix, param_vector)
2280
2281
2282 self._disassemble_param_vector(param_vector=param_vector, data_types=data_types, sim_index=sim_index)
2283
2284
2285 if sim_index != None:
2286
2287 cdp.chi2_sim[sim_index] = func
2288
2289
2290 cdp.iter_sim[sim_index] = iter_count
2291
2292
2293 cdp.f_count_sim[sim_index] = f_count
2294
2295
2296 cdp.g_count_sim[sim_index] = g_count
2297
2298
2299 cdp.h_count_sim[sim_index] = h_count
2300
2301
2302 cdp.warning_sim[sim_index] = warning
2303
2304
2305 else:
2306
2307 cdp.chi2 = func
2308
2309
2310 cdp.iter = iter_count
2311
2312
2313 cdp.f_count = f_count
2314
2315
2316 cdp.g_count = g_count
2317
2318
2319 cdp.h_count = h_count
2320
2321
2322 cdp.warning = warning
2323
2324
2325 if sim_index == None and ('rdc' in data_types or 'pcs' in data_types):
2326
2327 self._minimise_bc_data(model)
2328
2329
2330 if 'rdc' in data_types:
2331 rdc.q_factors()
2332
2333
2334 if 'pcs' in data_types:
2335 pcs.q_factors()
2336
2337
2339 """Return the k, n, and chi2 model statistics.
2340
2341 k - number of parameters.
2342 n - number of data points.
2343 chi2 - the chi-squared value.
2344
2345
2346 @keyword model_info: The data returned from model_loop() (unused).
2347 @type model_info: None
2348 @keyword spin_id: The spin identification string. This is ignored in the N-state model.
2349 @type spin_id: None or str
2350 @keyword global_stats: A parameter which determines if global or local statistics are returned. For the N-state model, this argument is ignored.
2351 @type global_stats: None or bool
2352 @return: The optimisation statistics, in tuple format, of the number of parameters (k), the number of data points (n), and the chi-squared value (chi2).
2353 @rtype: tuple of (int, int, float)
2354 """
2355
2356
2357 return self._param_num(), self._num_data_points(), cdp.chi2
2358
2359
2401
2402
2403 return_data_name_doc = Desc_container("N-state model data type string matching patterns")
2404 _table = uf_tables.add_table(label="table: N-state data type patterns", caption="N-state model data type string matching patterns.")
2405 _table.add_headings(["Data type", "Object name", "Patterns"])
2406 _table.add_row(["Probabilities", "'probs'", "'p0', 'p1', 'p2', ..., 'pN'"])
2407 _table.add_row(["Euler angle alpha", "'alpha'", "'alpha0', 'alpha1', ..."])
2408 _table.add_row(["Euler angle beta", "'beta'", "'beta0', 'beta1', ..."])
2409 _table.add_row(["Euler angle gamma", "'gamma'", "'gamma0', 'gamma1', ..."])
2410 _table.add_row(["Bond length", "'r'", "'^r$' or '[Bb]ond[ -_][Ll]ength'"])
2411 _table.add_row(["Heteronucleus type", "'heteronuc_type'", "'^[Hh]eteronucleus$'"])
2412 _table.add_row(["Proton type", "'proton_type'", "'^[Pp]roton$'"])
2413 return_data_name_doc.add_table(_table.label)
2414 return_data_name_doc.add_paragraph("The objects corresponding to the object names are lists (or arrays) with each element corrsponding to each state.")
2415
2417 """Return a unique identifying string for the N-state model parameter.
2418
2419 @param param: The N-state model parameter.
2420 @type param: str
2421 @return: The unique parameter identifying string.
2422 @rtype: str
2423 """
2424
2425
2426 if search('^p[0-9]*$', param):
2427 return 'probs'
2428
2429
2430 if search('^alpha', param):
2431 return 'alpha'
2432
2433
2434 if search('^beta', param):
2435 return 'beta'
2436
2437
2438 if search('^gamma', param):
2439 return 'gamma'
2440
2441
2442 if search('^r$', param) or search('[Bb]ond[ -_][Ll]ength', param):
2443 return 'r'
2444
2445
2446 if param == 'heteronuc_type':
2447 return 'heteronuc_type'
2448
2449
2450 if param == 'proton_type':
2451 return 'proton_type'
2452
2453
2454 if search('^paramag_[xyz]$', param):
2455 return param
2456
2457
2459 """Create and return the spin specific Monte Carlo Ri error structure.
2460
2461 @keyword data_id: The list of spin ID, data type, and alignment ID, as yielded by the base_data_loop() generator method.
2462 @type data_id: str
2463 @return: The Monte Carlo simulation data errors.
2464 @rtype: list of float
2465 """
2466
2467
2468 mc_errors = []
2469
2470
2471 container = data_id[0]
2472
2473
2474 if data_id[1] == 'pcs' and not container.select:
2475 return
2476
2477
2478 if data_id[1] == 'rdc' and hasattr(container, 'rdc'):
2479
2480 if not hasattr(container, 'rdc_err'):
2481 raise RelaxError("The RDC errors are missing for the spin pair '%s' and '%s'." % (container.spin_id1, container.spin_id2))
2482
2483
2484 if data_id[2] not in container.rdc_err:
2485 err = None
2486 else:
2487 err = container.rdc_err[data_id[2]]
2488
2489
2490 mc_errors.append(err)
2491
2492
2493 elif data_id[1] == 'noesy' and hasattr(container, 'noesy'):
2494
2495 if not hasattr(container, 'noesy_err'):
2496 raise RelaxError("The NOESY errors are missing for the spin pair '%s' and '%s'." % (container.spin_id1, container.spin_id2))
2497
2498
2499 mc_errors.append(container.noesy_err)
2500
2501
2502 elif data_id[1] == 'pcs' and hasattr(container, 'pcs'):
2503
2504 if not hasattr(container, 'pcs_err'):
2505 raise RelaxError("The PCS errors are missing for spin '%s'." % data_id[0])
2506
2507
2508 if data_id[2] not in container.pcs_err:
2509 err = None
2510 else:
2511 err = container.pcs_err[data_id[2]]
2512
2513
2514 mc_errors.append(err)
2515
2516
2517 return mc_errors
2518
2519
2521 """Return the Grace string representation of the parameter.
2522
2523 This is used for axis labelling.
2524
2525 @param param: The specific analysis parameter.
2526 @type param: str
2527 @return: The Grace string representation of the parameter.
2528 @rtype: str
2529 """
2530
2531
2532 if param == 'pcs':
2533 return "Measured PCS"
2534
2535
2536 if param == 'pcs_bc':
2537 return "Back-calculated PCS"
2538
2539
2540 if param == 'rdc':
2541 return "Measured RDC"
2542
2543
2544 if param == 'rdc_bc':
2545 return "Back-calculated RDC"
2546
2547
2549 """Return a string representing the parameters units.
2550
2551 @param param: The name of the parameter to return the units string for.
2552 @type param: str
2553 @return: The parameter units string.
2554 @rtype: str
2555 """
2556
2557
2558 if param == 'pcs' or param == 'pcs_bc':
2559 return 'ppm'
2560
2561
2562 if param == 'rdc' or param == 'rdc_bc':
2563 return 'Hz'
2564
2565
2566 set_doc = Desc_container("N-state model set details")
2567 set_doc.add_paragraph("Setting parameters for the N-state model is a little different from the other type of analyses as each state has a set of parameters with the same names as the other states. To set the parameters for a specific state c (ranging from 0 for the first to N-1 for the last, the number c should be added to the end of the parameter name. So the Euler angle gamma of the third state is specified using the string 'gamma2'.")
2568
2569
2570 - def set_error(self, model_info, index, error):
2571 """Set the parameter errors.
2572
2573 @param model_info: The global model index originating from model_loop().
2574 @type model_info: int
2575 @param index: The index of the parameter to set the errors for.
2576 @type index: int
2577 @param error: The error value.
2578 @type error: float
2579 """
2580
2581
2582 names = ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz']
2583
2584
2585 if index < len(cdp.align_ids)*5:
2586
2587 param_index = index % 5
2588 tensor_index = (index - index % 5) / 5
2589
2590
2591 tensor = align_tensor.return_tensor(index=tensor_index, skip_fixed=True)
2592 tensor.set(param=names[param_index], value=error, category='err')
2593
2594
2595 return getattr(tensor, names[param_index]+'_err')
2596
2597
2599 """Set the N-state model parameter values.
2600
2601 @keyword param: The parameter name list.
2602 @type param: list of str
2603 @keyword value: The parameter value list.
2604 @type value: list
2605 @keyword spin_id: The spin identification string (unused).
2606 @type spin_id: None
2607 @keyword force: A flag which if True will cause current values to be overwritten. If False, a RelaxError will raised if the parameter value is already set.
2608 @type force: bool
2609 """
2610
2611
2612 arg_check.is_str_list(param, 'parameter name')
2613 arg_check.is_list(value, 'parameter value')
2614
2615
2616 for i in range(len(param)):
2617
2618 obj_name = self.return_data_name(param[i])
2619
2620
2621 if not obj_name:
2622 raise RelaxError("The parameter '%s' is not valid for this data pipe type." % param[i])
2623
2624
2625 if obj_name in ['probs', 'alpha', 'beta', 'gamma']:
2626
2627 index = self._param_model_index(param[i])
2628
2629
2630 obj = getattr(cdp, obj_name)
2631 obj[index] = value[i]
2632
2633
2634 if search('^paramag_[xyz]$', obj_name):
2635
2636 if not hasattr(cdp, 'paramagnetic_centre'):
2637 cdp.paramagnetic_centre = zeros(3, float64)
2638
2639
2640 if obj_name == 'paramag_x':
2641 index = 0
2642 elif obj_name == 'paramag_y':
2643 index = 1
2644 else:
2645 index = 2
2646
2647
2648 cdp.paramagnetic_centre[index] = value[i]
2649
2650
2651 else:
2652 for spin in spin_loop(spin_id):
2653 setattr(spin, obj_name, value[i])
2654
2655
2657 """Initialise the Monte Carlo parameter values."""
2658
2659
2660 sim_names = self.data_names(set='min')
2661
2662
2663 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
2664 sim_names += ['paramagnetic_centre']
2665
2666
2667 if hasattr(cdp, 'align_tensors'):
2668
2669 names = ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz']
2670
2671
2672 for i in range(len(cdp.align_tensors)):
2673
2674 if not self._opt_tensor(cdp.align_tensors[i]):
2675 continue
2676
2677
2678 cdp.align_tensors[i].set_sim_num(cdp.sim_number)
2679
2680
2681 for object_name in names:
2682 for j in range(cdp.sim_number):
2683 cdp.align_tensors[i].set(param=object_name, value=deepcopy(getattr(cdp.align_tensors[i], object_name)), category='sim', sim_index=j)
2684
2685
2686 for object_name in sim_names:
2687
2688 sim_object_name = object_name + '_sim'
2689
2690
2691 setattr(cdp, sim_object_name, [])
2692
2693
2694 sim_object = getattr(cdp, sim_object_name)
2695
2696
2697 for j in range(cdp.sim_number):
2698
2699 sim_object.append(None)
2700
2701
2702 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
2703 for j in range(cdp.sim_number):
2704 cdp.paramagnetic_centre_sim[j] = deepcopy(cdp.paramagnetic_centre)
2705
2706
2708 """Pack the Monte Carlo simulation data.
2709
2710 @keyword data_id: The list of spin ID, data type, and alignment ID, as yielded by the base_data_loop() generator method.
2711 @type data_id: list of str
2712 @param sim_data: The Monte Carlo simulation data.
2713 @type sim_data: list of float
2714 """
2715
2716
2717 container = data_id[0]
2718
2719
2720 if data_id[1] == 'rdc' and hasattr(container, 'rdc'):
2721
2722 if not hasattr(container, 'rdc_sim'):
2723 container.rdc_sim = {}
2724
2725
2726 container.rdc_sim[data_id[2]] = []
2727 for i in range(cdp.sim_number):
2728 container.rdc_sim[data_id[2]].append(sim_data[i][0])
2729
2730
2731 elif data_id[1] == 'noesy' and hasattr(container, 'noesy'):
2732
2733 container.noesy_sim = []
2734 for i in range(cdp.sim_number):
2735 container.noesy_sim[data_id[2]].append(sim_data[i][0])
2736
2737
2738 elif data_id[1] == 'pcs' and hasattr(container, 'pcs'):
2739
2740 if not hasattr(container, 'pcs_sim'):
2741 container.pcs_sim = {}
2742
2743
2744 container.pcs_sim[data_id[2]] = []
2745 for i in range(cdp.sim_number):
2746 container.pcs_sim[data_id[2]].append(sim_data[i][0])
2747
2748
2750 """Return the array of simulation parameter values.
2751
2752 @param model_info: The global model index originating from model_loop().
2753 @type model_info: int
2754 @param index: The index of the parameter to return the array of values for.
2755 @type index: int
2756 @return: The array of simulation parameter values.
2757 @rtype: list of float
2758 """
2759
2760
2761 names = ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz']
2762
2763
2764 if index < align_tensor.num_tensors(skip_fixed=True)*5:
2765
2766 param_index = index % 5
2767 tensor_index = (index - index % 5) / 5
2768
2769
2770 tensor = align_tensor.return_tensor(index=tensor_index, skip_fixed=True)
2771 return getattr(tensor, names[param_index]+'_sim')
2772