1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """The optimisation methods of the specific API for model-free analysis."""
24
25
26 from copy import deepcopy
27 from math import pi
28 from minfx.grid import grid_split
29 from numpy import array, dot, float64, int8, zeros
30 from numpy.linalg import inv
31 from re import match, search
32 import sys
33 from warnings import warn
34
35
36 import arg_check
37 from float import isNaN, isInf
38 from generic_fns import diffusion_tensor, pipes
39 from generic_fns.diffusion_tensor import diff_data_exists
40 from generic_fns.interatomic import interatomic_loop, return_interatom_list
41 from generic_fns.mol_res_spin import count_spins, exists_mol_res_spin_data, return_spin, return_spin_from_index, spin_loop
42 from maths_fns.mf import Mf
43 from multi import Processor_box
44 from physical_constants import h_bar, mu0, return_gyromagnetic_ratio
45 from relax_errors import RelaxError, RelaxInfError, RelaxLenError, RelaxMultiVectorError, RelaxNaNError, RelaxNoModelError, RelaxNoPdbError, RelaxNoResError, RelaxNoSequenceError, RelaxNoTensorError, RelaxNoValueError, RelaxNoVectorsError, RelaxNucleusError, RelaxSpinTypeError
46 from relax_warnings import RelaxWarning
47 from specific_fns.model_free.multi_processor_commands import MF_grid_command, MF_memo, MF_minimise_command
48
49
50
52 """Empty class to be used for data storage."""
53
54
56 """Class containing functions specific to model-free optimisation."""
57
59 """Disassemble the model-free parameter vector.
60
61 @param model_type: The model-free model type. This must be one of 'mf', 'local_tm',
62 'diff', or 'all'.
63 @type model_type: str
64 @keyword param_vector: The model-free parameter vector.
65 @type param_vector: numpy array
66 @keyword spin: The spin data container. If this argument is supplied, then the spin_id
67 argument will be ignored.
68 @type spin: SpinContainer instance
69 @keyword spin_id: The spin identification string.
70 @type spin_id: str
71 @keyword sim_index: The optional MC simulation index.
72 @type sim_index: int
73 """
74
75
76 param_index = 0
77
78
79 if sim_index != None and (model_type == 'diff' or model_type == 'all'):
80
81 if cdp.diff_tensor.type == 'sphere':
82
83 cdp.diff_tensor.set(param='tm', value=param_vector[0], category='sim', sim_index=sim_index)
84
85
86 param_index = param_index + 1
87
88
89 elif cdp.diff_tensor.type == 'spheroid':
90
91 cdp.diff_tensor.set(param='tm', value=param_vector[0], category='sim', sim_index=sim_index)
92 cdp.diff_tensor.set(param='Da', value=param_vector[1], category='sim', sim_index=sim_index)
93 cdp.diff_tensor.set(param='theta', value=param_vector[2], category='sim', sim_index=sim_index)
94 cdp.diff_tensor.set(param='phi', value=param_vector[3], category='sim', sim_index=sim_index)
95 diffusion_tensor.fold_angles(sim_index=sim_index)
96
97
98 param_index = param_index + 4
99
100
101 elif cdp.diff_tensor.type == 'ellipsoid':
102
103 cdp.diff_tensor.set(param='tm', value=param_vector[0], category='sim', sim_index=sim_index)
104 cdp.diff_tensor.set(param='Da', value=param_vector[1], category='sim', sim_index=sim_index)
105 cdp.diff_tensor.set(param='Dr', value=param_vector[2], category='sim', sim_index=sim_index)
106 cdp.diff_tensor.set(param='alpha', value=param_vector[3], category='sim', sim_index=sim_index)
107 cdp.diff_tensor.set(param='beta', value=param_vector[4], category='sim', sim_index=sim_index)
108 cdp.diff_tensor.set(param='gamma', value=param_vector[5], category='sim', sim_index=sim_index)
109 diffusion_tensor.fold_angles(sim_index=sim_index)
110
111
112 param_index = param_index + 6
113
114
115 elif model_type == 'diff' or model_type == 'all':
116
117 if cdp.diff_tensor.type == 'sphere':
118
119 cdp.diff_tensor.set(param='tm', value=param_vector[0])
120
121
122 param_index = param_index + 1
123
124
125 elif cdp.diff_tensor.type == 'spheroid':
126
127 cdp.diff_tensor.set(param='tm', value=param_vector[0])
128 cdp.diff_tensor.set(param='Da', value=param_vector[1])
129 cdp.diff_tensor.set(param='theta', value=param_vector[2])
130 cdp.diff_tensor.set(param='phi', value=param_vector[3])
131 diffusion_tensor.fold_angles()
132
133
134 param_index = param_index + 4
135
136
137 elif cdp.diff_tensor.type == 'ellipsoid':
138
139 cdp.diff_tensor.set(param='tm', value=param_vector[0])
140 cdp.diff_tensor.set(param='Da', value=param_vector[1])
141 cdp.diff_tensor.set(param='Dr', value=param_vector[2])
142 cdp.diff_tensor.set(param='alpha', value=param_vector[3])
143 cdp.diff_tensor.set(param='beta', value=param_vector[4])
144 cdp.diff_tensor.set(param='gamma', value=param_vector[5])
145 diffusion_tensor.fold_angles()
146
147
148 param_index = param_index + 6
149
150
151 if model_type != 'diff':
152
153 if spin:
154 loop = [spin]
155 else:
156 loop = spin_loop(spin_id)
157
158
159 for spin in loop:
160
161 if not spin.select:
162 continue
163
164
165 for j in range(len(spin.params)):
166
167 if spin.params[j] == 'local_tm':
168 if sim_index == None:
169 spin.local_tm = param_vector[param_index]
170 else:
171 spin.local_tm_sim[sim_index] = param_vector[param_index]
172
173
174 elif spin.params[j] == 's2':
175 if sim_index == None:
176 spin.s2 = param_vector[param_index]
177 else:
178 spin.s2_sim[sim_index] = param_vector[param_index]
179
180
181 elif spin.params[j] == 's2f':
182 if sim_index == None:
183 spin.s2f = param_vector[param_index]
184 else:
185 spin.s2f_sim[sim_index] = param_vector[param_index]
186
187
188 elif spin.params[j] == 's2s':
189 if sim_index == None:
190 spin.s2s = param_vector[param_index]
191 else:
192 spin.s2s_sim[sim_index] = param_vector[param_index]
193
194
195 elif spin.params[j] == 'te':
196 if sim_index == None:
197 spin.te = param_vector[param_index]
198 else:
199 spin.te_sim[sim_index] = param_vector[param_index]
200
201
202 elif spin.params[j] == 'tf':
203 if sim_index == None:
204 spin.tf = param_vector[param_index]
205 else:
206 spin.tf_sim[sim_index] = param_vector[param_index]
207
208
209 elif spin.params[j] == 'ts':
210 if sim_index == None:
211 spin.ts = param_vector[param_index]
212 else:
213 spin.ts_sim[sim_index] = param_vector[param_index]
214
215
216 elif spin.params[j] == 'rex':
217 if sim_index == None:
218 spin.rex = param_vector[param_index]
219 else:
220 spin.rex_sim[sim_index] = param_vector[param_index]
221
222
223 elif spin.params[j] == 'r':
224 if sim_index == None:
225 spin.r = param_vector[param_index]
226 else:
227 spin.r_sim[sim_index] = param_vector[param_index]
228
229
230 elif spin.params[j] == 'csa':
231 if sim_index == None:
232 spin.csa = param_vector[param_index]
233 else:
234 spin.csa_sim[sim_index] = param_vector[param_index]
235
236
237 else:
238 raise RelaxError("Unknown parameter.")
239
240
241 param_index = param_index + 1
242
243
244 if model_type != 'diff':
245
246 if spin:
247 loop = [spin]
248 else:
249 loop = spin_loop(spin_id)
250
251
252 for spin in loop:
253
254 if not spin.select:
255 continue
256
257
258 if sim_index == None:
259
260 if 's2' not in spin.params and 's2f' in spin.params and 's2s' in spin.params:
261 spin.s2 = spin.s2f * spin.s2s
262
263
264 if 's2f' not in spin.params and 's2' in spin.params and 's2s' in spin.params:
265 if spin.s2s == 0.0:
266 spin.s2f = 1e99
267 else:
268 spin.s2f = spin.s2 / spin.s2s
269
270
271 if 's2s' not in spin.params and 's2' in spin.params and 's2f' in spin.params:
272 if spin.s2f == 0.0:
273 spin.s2s = 1e99
274 else:
275 spin.s2s = spin.s2 / spin.s2f
276
277
278 else:
279
280 if 's2' not in spin.params and 's2f' in spin.params and 's2s' in spin.params:
281 spin.s2_sim[sim_index] = spin.s2f_sim[sim_index] * spin.s2s_sim[sim_index]
282
283
284 if 's2f' not in spin.params and 's2' in spin.params and 's2s' in spin.params:
285 if spin.s2s_sim[sim_index] == 0.0:
286 spin.s2f_sim[sim_index] = 1e99
287 else:
288 spin.s2f_sim[sim_index] = spin.s2_sim[sim_index] / spin.s2s_sim[sim_index]
289
290
291 if 's2s' not in spin.params and 's2' in spin.params and 's2f' in spin.params:
292 if spin.s2f_sim[sim_index] == 0.0:
293 spin.s2s_sim[sim_index] = 1e99
294 else:
295 spin.s2s_sim[sim_index] = spin.s2_sim[sim_index] / spin.s2f_sim[sim_index]
296
297
298 - def _disassemble_result(self, param_vector=None, func=None, iter=None, fc=None, gc=None, hc=None, warning=None, spin=None, sim_index=None, model_type=None, scaling=None, scaling_matrix=None):
299 """Disassemble the optimisation results.
300
301 @keyword param_vector: The model-free parameter vector.
302 @type param_vector: numpy array
303 @keyword func: The optimised chi-squared value.
304 @type func: float
305 @keyword iter: The number of optimisation steps required to find the minimum.
306 @type iter: int
307 @keyword fc: The function count.
308 @type fc: int
309 @keyword gc: The gradient count.
310 @type gc: int
311 @keyword hc: The Hessian count.
312 @type hc: int
313 @keyword warning: Any optimisation warnings.
314 @type warning: str or None
315 @keyword spin: The spin container.
316 @type spin: SpinContainer instance or None
317 @keyword sim_index: The Monte Carlo simulation index.
318 @type sim_index: int or None
319 @keyword model_type: The model-free model type, one of 'mf', 'local_tm', 'diff', or
320 'all'.
321 @type model_type: str
322 @keyword scaling: If True, diagonal scaling is enabled during optimisation to
323 allow the problem to be better conditioned.
324 @type scaling: bool
325 @keyword scaling_matrix: The diagonal, square scaling matrix.
326 @type scaling_matrix: numpy diagonal matrix
327 """
328
329
330 cdp = pipes.get_pipe()
331
332
333 if isInf(func):
334 raise RelaxInfError('chi-squared')
335
336
337 if isNaN(func):
338 raise RelaxNaNError('chi-squared')
339
340
341 if scaling:
342 param_vector = dot(scaling_matrix, param_vector)
343
344
345 if sim_index == None:
346
347 chi2 = None
348 if (model_type == 'mf' or model_type == 'local_tm') and hasattr(cdp, 'chi2'):
349 chi2 = spin.chi2
350 if (model_type == 'diff' or model_type == 'all') and hasattr(cdp, 'chi2'):
351 chi2 = cdp.chi2
352
353
354 spin_text = ''
355 if spin != None and hasattr(spin, '_spin_ids') and len(spin._spin_ids):
356 spin_text = " for the spin '%s'" % spin._spin_ids[0]
357
358
359 if chi2 != None and func >= chi2:
360 print("Discarding the optimisation results%s, the optimised chi-squared value is higher than the current value (%s >= %s)." % (spin_text, func, chi2))
361
362
363 return
364
365
366 else:
367 print("Storing the optimisation results%s, the optimised chi-squared value is lower than the current value (%s < %s)." % (spin_text, func, chi2))
368
369
370 self._disassemble_param_vector(model_type, param_vector=param_vector, spin=spin, sim_index=sim_index)
371
372
373 if sim_index != None:
374
375 if model_type == 'mf' or model_type == 'local_tm':
376
377
378 spin.chi2_sim[sim_index] = func
379
380
381 spin.iter_sim[sim_index] = iter
382
383
384 spin.f_count_sim[sim_index] = fc
385
386
387 spin.g_count_sim[sim_index] = gc
388
389
390 spin.h_count_sim[sim_index] = hc
391
392
393 spin.warning_sim[sim_index] = warning
394
395
396 elif model_type == 'diff' or model_type == 'all':
397
398 cdp.chi2_sim[sim_index] = func
399
400
401 cdp.iter_sim[sim_index] = iter
402
403
404 cdp.f_count_sim[sim_index] = fc
405
406
407 cdp.g_count_sim[sim_index] = gc
408
409
410 cdp.h_count_sim[sim_index] = hc
411
412
413 cdp.warning_sim[sim_index] = warning
414
415
416 else:
417
418 if model_type == 'mf' or model_type == 'local_tm':
419
420 spin.chi2 = func
421
422
423 spin.iter = iter
424
425
426 spin.f_count = fc
427
428
429 spin.g_count = gc
430
431
432 spin.h_count = hc
433
434
435 spin.warning = warning
436
437
438 elif model_type == 'diff' or model_type == 'all':
439
440 cdp.chi2 = func
441
442
443 cdp.iter = iter
444
445
446 cdp.f_count = fc
447
448
449 cdp.g_count = gc
450
451
452 cdp.h_count = hc
453
454
455 cdp.warning = warning
456
457
458 - def _grid_search_config(self, num_params, spin=None, spin_id=None, lower=None, upper=None, inc=None, scaling_matrix=None, verbosity=1):
459 """Configure the grid search.
460
461 @param num_params: The number of parameters in the model.
462 @type num_params: int
463 @keyword spin: The spin data container.
464 @type spin: SpinContainer instance
465 @keyword spin_id: The spin identification string.
466 @type spin_id: str
467 @keyword lower: The lower bounds of the grid search which must be equal to the
468 number of parameters in the model.
469 @type lower: array of numbers
470 @keyword upper: The upper bounds of the grid search which must be equal to the
471 number of parameters in the model.
472 @type upper: array of numbers
473 @keyword inc: The increments for each dimension of the space for the grid
474 search. The number of elements in the array must equal to the
475 number of parameters in the model.
476 @type inc: array of int
477 @keyword scaling_matrix: The diagonal, square scaling matrix.
478 @type scaling_matrix: numpy diagonal matrix
479 @keyword verbosity: A flag specifying the amount of information to print. The
480 higher the value, the greater the verbosity.
481 @type verbosity: int
482 """
483
484
485 self.test_grid_ops(lower=lower, upper=upper, inc=inc, n=num_params)
486
487
488 if isinstance(inc, int):
489 inc = [inc]*num_params
490
491
492 if not lower:
493
494 lower = []
495 upper = []
496
497
498 model_type = self._determine_model_type()
499
500
501 if model_type == 'diff' or model_type == 'all':
502
503 self._grid_search_diff_bounds(lower, upper)
504
505
506 if model_type != 'diff':
507
508 if spin:
509 loop = [spin]
510 else:
511 loop = spin_loop(spin_id)
512
513
514 for spin in loop:
515
516 if not spin.select:
517 continue
518
519
520 self._grid_search_spin_bounds(spin, lower, upper)
521
522
523 lower_new = []
524 upper_new = []
525 for i in range(num_params):
526 lower_new.append(lower[i] / scaling_matrix[i, i])
527 upper_new.append(upper[i] / scaling_matrix[i, i])
528
529
530 return inc, lower_new, upper_new
531
532
534 """Set up the default grid search bounds the diffusion tensor.
535
536 This method appends the default bounds to the lower and upper lists.
537
538 @param lower: The lower bound list to append to.
539 @type lower: list
540 @param upper: The upper bound list to append to.
541 @type upper: list
542 """
543
544
545 if cdp.diff_tensor.type == 'sphere':
546 lower.append(1.0 * 1e-9)
547 upper.append(12.0 * 1e-9)
548
549
550 if cdp.diff_tensor.type == 'spheroid':
551
552 lower.append(1.0 * 1e-9)
553 upper.append(12.0 * 1e-9)
554
555
556 if cdp.diff_tensor.spheroid_type == 'prolate':
557 lower.append(0.0)
558 upper.append(1e7)
559 elif cdp.diff_tensor.spheroid_type == 'oblate':
560 lower.append(-1e7)
561 upper.append(0.0)
562 else:
563 lower.append(-1e7)
564 upper.append(1e7)
565
566
567 lower.append(0.0)
568 upper.append(pi)
569
570
571 lower.append(0.0)
572 upper.append(pi)
573
574
575 elif cdp.diff_tensor.type == 'ellipsoid':
576
577 lower.append(1.0 * 1e-9)
578 upper.append(12.0 * 1e-9)
579
580
581 lower.append(0.0)
582 upper.append(1e7)
583
584
585 lower.append(0.0)
586 upper.append(1.0)
587
588
589 lower.append(0.0)
590 upper.append(pi)
591
592
593 lower.append(0.0)
594 upper.append(pi)
595
596
597 lower.append(0.0)
598 upper.append(pi)
599
600
602 """Set up the default grid search bounds for a single spin.
603
604 This method appends the default bounds to the lower and upper lists. The ordering of the
605 lists in min_options matches that of the params list in the spin container.
606
607 @param spin: A SpinContainer object.
608 @type spin: class instance
609 @param lower: The lower bound list to append to.
610 @type lower: list
611 @param upper: The upper bound list to append to.
612 @type upper: list
613 """
614
615
616 for i in range(len(spin.params)):
617
618 if spin.params[i] == 'local_tm':
619 lower.append(1.0 * 1e-9)
620 upper.append(12.0 * 1e-9)
621
622
623 elif match('s2', spin.params[i]):
624 lower.append(0.0)
625 upper.append(1.0)
626
627
628 elif match('t', spin.params[i]):
629 lower.append(0.0)
630 upper.append(500.0 * 1e-12)
631
632
633 elif spin.params[i] == 'rex':
634 lower.append(0.0)
635 upper.append(5.0 / (2.0 * pi * cdp.frq[cdp.ri_ids[0]])**2)
636
637
638 elif spin.params[i] == 'r':
639 lower.append(1.0 * 1e-10)
640 upper.append(1.05 * 1e-10)
641
642
643 elif spin.params[i] == 'csa':
644 lower.append(-120 * 1e-6)
645 upper.append(-200 * 1e-6)
646
647
648 else:
649 raise RelaxError("Unknown model-free parameter.")
650
651
652 - def _linear_constraints(self, num_params, model_type=None, spin=None, spin_id=None, scaling_matrix=None):
653 """Set up the model-free linear constraint matrices A and b.
654
655 Standard notation
656 =================
657
658 The order parameter constraints are::
659
660 0 <= S2 <= 1
661 0 <= S2f <= 1
662 0 <= S2s <= 1
663
664 By substituting the formula S2 = S2f.S2s into the above inequalities, the additional two
665 inequalities can be derived::
666
667 S2 <= S2f
668 S2 <= S2s
669
670 Correlation time constraints are::
671
672 te >= 0
673 tf >= 0
674 ts >= 0
675
676 tf <= ts
677
678 te, tf, ts <= 2 * tm
679
680 Additional constraints used include::
681
682 Rex >= 0
683 0.9e-10 <= r <= 2e-10
684 -300e-6 <= CSA <= 0
685
686
687 Rearranged notation
688 ===================
689
690 The above inequality constraints can be rearranged into::
691
692 S2 >= 0
693 -S2 >= -1
694 S2f >= 0
695 -S2f >= -1
696 S2s >= 0
697 -S2s >= -1
698 S2f - S2 >= 0
699 S2s - S2 >= 0
700 te >= 0
701 tf >= 0
702 ts >= 0
703 ts - tf >= 0
704 Rex >= 0
705 r >= 0.9e-10
706 -r >= -2e-10
707 CSA >= -300e-6
708 -CSA >= 0
709
710
711 Matrix notation
712 ===============
713
714 In the notation A.x >= b, where A is an matrix of coefficients, x is an array of parameter
715 values, and b is a vector of scalars, these inequality constraints are::
716
717 | 1 0 0 0 0 0 0 0 0 | | 0 |
718 | | | |
719 |-1 0 0 0 0 0 0 0 0 | | -1 |
720 | | | |
721 | 0 1 0 0 0 0 0 0 0 | | 0 |
722 | | | |
723 | 0 -1 0 0 0 0 0 0 0 | | -1 |
724 | | | |
725 | 0 0 1 0 0 0 0 0 0 | | S2 | | 0 |
726 | | | | | |
727 | 0 0 -1 0 0 0 0 0 0 | | S2f | | -1 |
728 | | | | | |
729 |-1 1 0 0 0 0 0 0 0 | | S2s | | 0 |
730 | | | | | |
731 |-1 0 1 0 0 0 0 0 0 | | te | | 0 |
732 | | | | | |
733 | 0 0 0 1 0 0 0 0 0 | . | tf | >= | 0 |
734 | | | | | |
735 | 0 0 0 0 1 0 0 0 0 | | ts | | 0 |
736 | | | | | |
737 | 0 0 0 0 0 1 0 0 0 | | Rex | | 0 |
738 | | | | | |
739 | 0 0 0 0 -1 1 0 0 0 | | r | | 0 |
740 | | | | | |
741 | 0 0 0 0 0 0 1 0 0 | | CSA | | 0 |
742 | | | |
743 | 0 0 0 0 0 0 0 1 0 | | 0.9e-10 |
744 | | | |
745 | 0 0 0 0 0 0 0 -1 0 | | -2e-10 |
746 | | | |
747 | 0 0 0 0 0 0 0 0 1 | | -300e-6 |
748 | | | |
749 | 0 0 0 0 0 0 0 0 -1 | | 0 |
750
751
752 @param num_params: The number of parameters in the model.
753 @type num_params: int
754 @keyword model_type: The model type, one of 'all', 'diff', 'mf', or 'local_tm'.
755 @type model_type: str
756 @keyword spin: The spin data container. If this argument is supplied, then the
757 spin_id argument will be ignored.
758 @type spin: SpinContainer instance
759 @keyword spin_id: The spin identification string.
760 @type spin_id: str
761 @keyword scaling_matrix: The diagonal, square scaling matrix.
762 @type scaling_matrix: numpy diagonal matrix
763 """
764
765
766 upper_time_limit = 1
767
768
769 A = []
770 b = []
771 zero_array = zeros(num_params, float64)
772 i = 0
773 j = 0
774
775
776 if model_type != 'mf' and diffusion_tensor.diff_data_exists():
777
778 if cdp.diff_tensor.type == 'sphere':
779
780 A.append(zero_array * 0.0)
781 A.append(zero_array * 0.0)
782 A[j][i] = 1.0
783 A[j+1][i] = -1.0
784 b.append(0.0 / scaling_matrix[i, i])
785 b.append(-200.0 * 1e-9 / scaling_matrix[i, i])
786 i = i + 1
787 j = j + 2
788
789
790 elif cdp.diff_tensor.type == 'spheroid':
791
792 A.append(zero_array * 0.0)
793 A.append(zero_array * 0.0)
794 A[j][i] = 1.0
795 A[j+1][i] = -1.0
796 b.append(0.0 / scaling_matrix[i, i])
797 b.append(-200.0 * 1e-9 / scaling_matrix[i, i])
798 i = i + 1
799 j = j + 2
800
801
802 if cdp.diff_tensor.spheroid_type == 'prolate':
803 A.append(zero_array * 0.0)
804 A[j][i] = 1.0
805 b.append(0.0 / scaling_matrix[i, i])
806 i = i + 1
807 j = j + 1
808
809
810 i = i + 2
811
812
813 elif cdp.diff_tensor.spheroid_type == 'oblate':
814 A.append(zero_array * 0.0)
815 A[j][i] = -1.0
816 b.append(0.0 / scaling_matrix[i, i])
817 i = i + 1
818 j = j + 1
819
820
821 i = i + 2
822
823 else:
824
825 i = i + 3
826
827
828 elif cdp.diff_tensor.type == 'ellipsoid':
829
830 A.append(zero_array * 0.0)
831 A.append(zero_array * 0.0)
832 A[j][i] = 1.0
833 A[j+1][i] = -1.0
834 b.append(0.0 / scaling_matrix[i, i])
835 b.append(-200.0 * 1e-9 / scaling_matrix[i, i])
836 i = i + 1
837 j = j + 2
838
839
840 A.append(zero_array * 0.0)
841 A[j][i] = 1.0
842 b.append(0.0 / scaling_matrix[i, i])
843 i = i + 1
844 j = j + 1
845
846
847 A.append(zero_array * 0.0)
848 A.append(zero_array * 0.0)
849 A[j][i] = 1.0
850 A[j+1][i] = -1.0
851 b.append(0.0 / scaling_matrix[i, i])
852 b.append(-1.0 / scaling_matrix[i, i])
853 i = i + 1
854 j = j + 2
855
856
857 i = i + 3
858
859
860 if model_type != 'diff':
861
862 if spin:
863 loop = [spin]
864 else:
865 loop = spin_loop(spin_id)
866
867
868 for spin in loop:
869
870 if not spin.select:
871 continue
872
873
874 old_i = i
875
876
877 for l in range(len(spin.params)):
878
879 if spin.params[l] == 'local_tm':
880 if upper_time_limit:
881
882 A.append(zero_array * 0.0)
883 A.append(zero_array * 0.0)
884 A[j][i] = 1.0
885 A[j+1][i] = -1.0
886 b.append(0.0 / scaling_matrix[i, i])
887 b.append(-200.0 * 1e-9 / scaling_matrix[i, i])
888 j = j + 2
889 else:
890
891 A.append(zero_array * 0.0)
892 A[j][i] = 1.0
893 b.append(0.0 / scaling_matrix[i, i])
894 j = j + 1
895
896
897 elif match('s2', spin.params[l]):
898
899 A.append(zero_array * 0.0)
900 A.append(zero_array * 0.0)
901 A[j][i] = 1.0
902 A[j+1][i] = -1.0
903 b.append(0.0 / scaling_matrix[i, i])
904 b.append(-1.0 / scaling_matrix[i, i])
905 j = j + 2
906
907
908 if spin.params[l] == 's2':
909 for m in range(len(spin.params)):
910 if spin.params[m] == 's2f' or spin.params[m] == 's2s':
911 A.append(zero_array * 0.0)
912 A[j][i] = -1.0
913 A[j][old_i+m] = 1.0
914 b.append(0.0)
915 j = j + 1
916
917
918 elif match('t[efs]', spin.params[l]):
919
920 A.append(zero_array * 0.0)
921 A[j][i] = 1.0
922 b.append(0.0 / scaling_matrix[i, i])
923 j = j + 1
924
925
926 if spin.params[l] == 'ts':
927 for m in range(len(spin.params)):
928 if spin.params[m] == 'tf':
929 A.append(zero_array * 0.0)
930 A[j][i] = 1.0
931 A[j][old_i+m] = -1.0
932 b.append(0.0)
933 j = j + 1
934
935
936 if upper_time_limit:
937 if not spin.params[l] == 'tf':
938 if model_type == 'mf':
939 A.append(zero_array * 0.0)
940 A[j][i] = -1.0
941 b.append(-2.0 * cdp.diff_tensor.tm / scaling_matrix[i, i])
942 else:
943 A.append(zero_array * 0.0)
944 A[j][0] = 2.0
945 A[j][i] = -1.0
946 b.append(0.0)
947
948 j = j + 1
949
950
951 elif spin.params[l] == 'rex':
952 A.append(zero_array * 0.0)
953 A[j][i] = 1.0
954 b.append(0.0 / scaling_matrix[i, i])
955 j = j + 1
956
957
958 elif spin.params[l] == 'r':
959
960 A.append(zero_array * 0.0)
961 A.append(zero_array * 0.0)
962 A[j][i] = 1.0
963 A[j+1][i] = -1.0
964 b.append(0.9e-10 / scaling_matrix[i, i])
965 b.append(-2e-10 / scaling_matrix[i, i])
966 j = j + 2
967
968
969 elif spin.params[l] == 'csa':
970
971 A.append(zero_array * 0.0)
972 A.append(zero_array * 0.0)
973 A[j][i] = 1.0
974 A[j+1][i] = -1.0
975 b.append(-300e-6 / scaling_matrix[i, i])
976 b.append(0.0 / scaling_matrix[i, i])
977 j = j + 2
978
979
980 i = i + 1
981
982
983 A = array(A, int8)
984 b = array(b, float64)
985
986 return A, b
987
988
989 - def _minimise_data_setup(self, data_store, min_algor, num_data_sets, min_options, spin=None, sim_index=None):
990 """Set up all the data required for minimisation.
991
992 @param data_store: A data storage container.
993 @type data_store: class instance
994 @param min_algor: The minimisation algorithm to use.
995 @type min_algor: str
996 @param num_data_sets: The number of data sets.
997 @type num_data_sets: int
998 @param min_options: The minimisation options array.
999 @type min_options: list
1000 @keyword spin: The spin data container.
1001 @type spin: SpinContainer instance
1002 @keyword sim_index: The optional MC simulation index.
1003 @type sim_index: int
1004 @return: An insane tuple. The full tuple is (ri_data, ri_data_err, equations, param_types, param_values, r, csa, num_frq, frq, num_ri, remap_table, noe_r1_table, ri_types, num_params, xh_unit_vectors, diff_type, diff_params)
1005 @rtype: tuple
1006 """
1007
1008
1009 data_store.ri_data = []
1010 data_store.ri_data_err = []
1011 data_store.equations = []
1012 data_store.param_types = []
1013 data_store.param_values = None
1014 data_store.r = []
1015 data_store.csa = []
1016 data_store.num_frq = []
1017 data_store.frq = []
1018 data_store.num_ri = []
1019 data_store.remap_table = []
1020 data_store.noe_r1_table = []
1021 data_store.ri_types = []
1022 data_store.gx = []
1023 data_store.gh = []
1024 data_store.num_params = []
1025 data_store.xh_unit_vectors = []
1026 if data_store.model_type == 'local_tm':
1027 data_store.mf_params = []
1028 elif data_store.model_type == 'diff':
1029 data_store.param_values = []
1030
1031
1032 if min_algor == 'back_calc':
1033
1034 data_store.ri_data = [0.0]
1035 data_store.ri_data_err = [0.000001]
1036 data_store.equations = [spin.equation]
1037 data_store.param_types = [spin.params]
1038 data_store.csa = [spin.csa]
1039 data_store.num_frq = [1]
1040 data_store.frq = [[min_options[3]]]
1041 data_store.num_ri = [1]
1042 data_store.remap_table = [[0]]
1043 data_store.noe_r1_table = [[None]]
1044 data_store.ri_types = [[min_options[2]]]
1045 data_store.gx = [return_gyromagnetic_ratio(spin.isotope)]
1046
1047
1048 interatoms = return_interatom_list(data_store.spin_id)
1049 for i in range(len(interatoms)):
1050
1051 if not interatoms[i].dipole_pair:
1052 continue
1053
1054
1055 if data_store.spin_id != interatoms[i].spin_id1:
1056 spin_id2 = interatoms[i].spin_id1
1057 else:
1058 spin_id2 = interatoms[i].spin_id2
1059 spin2 = return_spin(spin_id2)
1060
1061
1062 data_store.r = [interatoms[i].r]
1063 data_store.gh = [return_gyromagnetic_ratio(spin2.isotope)]
1064 if data_store.model_type != 'local_tm' and cdp.diff_tensor.type != 'sphere':
1065 data_store.xh_unit_vectors = [interatoms[i].vector]
1066 else:
1067 data_store.xh_unit_vectors = [None]
1068
1069
1070 data_store.num_params = [len(spin.params)]
1071
1072
1073 for j in range(num_data_sets):
1074
1075 if data_store.model_type == 'diff' or data_store.model_type == 'all':
1076 spin_index = j
1077 spin, data_store.spin_id = return_spin_from_index(global_index=spin_index, return_spin_id=True)
1078
1079
1080 if not spin.select:
1081 continue
1082
1083
1084 if not hasattr(spin, 'ri_data') or not hasattr(spin, 'ri_data_err'):
1085 continue
1086
1087
1088 for ri_id in cdp.ri_ids:
1089
1090 if not ri_id in spin.ri_data_err:
1091 continue
1092
1093
1094 err = spin.ri_data_err[ri_id]
1095
1096
1097 if err != None and err == 0.0:
1098 raise RelaxError("Zero error for spin '%s' for the relaxation data ID '%s', minimisation not possible." % (data_store.spin_id, ri_id))
1099 elif err != None and err < 0.0:
1100 raise RelaxError("Negative error of %s for spin '%s' for the relaxation data ID '%s', minimisation not possible." % (err, data_store.spin_id, ri_id))
1101
1102
1103 data = self._relax_data_opt_structs(spin, sim_index=sim_index)
1104
1105
1106 data_store.ri_data.append(data[0])
1107 data_store.ri_data_err.append(data[1])
1108 data_store.num_frq.append(data[2])
1109 data_store.num_ri.append(data[3])
1110 data_store.ri_types.append(data[4])
1111 data_store.frq.append(data[5])
1112 data_store.remap_table.append(data[6])
1113 data_store.noe_r1_table.append(data[7])
1114 if sim_index == None or data_store.model_type == 'diff':
1115 data_store.csa.append(spin.csa)
1116 else:
1117 data_store.csa.append(spin.csa_sim[sim_index])
1118
1119
1120 data_store.equations.append(spin.equation)
1121 data_store.param_types.append(spin.params)
1122 data_store.gx.append(return_gyromagnetic_ratio(spin.isotope))
1123
1124
1125 interatoms = return_interatom_list(data_store.spin_id)
1126 for i in range(len(interatoms)):
1127
1128 if not interatoms[i].dipole_pair:
1129 continue
1130
1131
1132 if data_store.spin_id != interatoms[i].spin_id1:
1133 spin_id2 = interatoms[i].spin_id1
1134 else:
1135 spin_id2 = interatoms[i].spin_id2
1136 spin2 = return_spin(spin_id2)
1137
1138
1139 data_store.gh.append(return_gyromagnetic_ratio(spin2.isotope))
1140 if sim_index == None or data_store.model_type == 'diff' or not hasattr(interatoms[i], 'r_sim'):
1141 data_store.r.append(interatoms[i].r)
1142 else:
1143 data_store.r.append(interatoms[i].r_sim[sim_index])
1144
1145
1146 if data_store.model_type != 'local_tm' and cdp.diff_tensor.type != 'sphere':
1147
1148 if arg_check.is_num_list(interatoms[i].vector[0], raise_error=False):
1149 raise RelaxMultiVectorError(data_store.spin_id)
1150
1151
1152 data_store.xh_unit_vectors.append(interatoms[i].vector)
1153
1154
1155 else:
1156 data_store.xh_unit_vectors.append(None)
1157
1158
1159 break
1160
1161
1162 if data_store.model_type == 'local_tm':
1163 pass
1164
1165
1166 data_store.num_params.append(len(spin.params))
1167
1168
1169 if data_store.model_type == 'diff':
1170 data_store.param_values.append(self._assemble_param_vector(model_type='mf'))
1171
1172
1173 for k in range(len(data_store.ri_data)):
1174 data_store.ri_data[k] = array(data_store.ri_data[k], float64)
1175 data_store.ri_data_err[k] = array(data_store.ri_data_err[k], float64)
1176
1177
1178 if data_store.model_type == 'local_tm':
1179 data_store.diff_type = 'sphere'
1180 else:
1181 data_store.diff_type = cdp.diff_tensor.type
1182
1183
1184 data_store.diff_params = None
1185 if data_store.model_type == 'mf':
1186
1187 if data_store.diff_type == 'sphere':
1188 data_store.diff_params = [cdp.diff_tensor.tm]
1189
1190
1191 elif data_store.diff_type == 'spheroid':
1192 data_store.diff_params = [cdp.diff_tensor.tm, cdp.diff_tensor.Da, cdp.diff_tensor.theta, cdp.diff_tensor.phi]
1193
1194
1195 elif data_store.diff_type == 'ellipsoid':
1196 data_store.diff_params = [cdp.diff_tensor.tm, cdp.diff_tensor.Da, cdp.diff_tensor.Dr, cdp.diff_tensor.alpha, cdp.diff_tensor.beta, cdp.diff_tensor.gamma]
1197 elif min_algor == 'back_calc' and data_store.model_type == 'local_tm':
1198
1199 data_store.diff_params = [spin.local_tm]
1200
1201
1203 """Package the relaxation data into the data structures used for optimisation.
1204
1205 @param spin: The spin container to extract the data from.
1206 @type spin: SpinContainer instance
1207 @keyword sim_index: The optional MC simulation index.
1208 @type sim_index: int
1209 @return: The structures ri_data, ri_data_err, num_frq, num_ri, ri_ids, frq, remap_table, noe_r1_table.
1210 @rtype: tuple
1211 """
1212
1213
1214 ri_data = []
1215 ri_data_err = []
1216 ri_labels = []
1217 frq = []
1218 remap_table = []
1219 noe_r1_table = []
1220
1221
1222 for ri_id in cdp.ri_ids:
1223
1224 if ri_id not in spin.ri_data:
1225 continue
1226
1227
1228 if sim_index == None:
1229 data = spin.ri_data[ri_id]
1230 else:
1231 data = spin.ri_data_sim[ri_id][sim_index]
1232
1233
1234 err = spin.ri_data_err[ri_id]
1235
1236
1237 if data == None or err == None:
1238 continue
1239
1240
1241 ri_data.append(data)
1242 ri_data_err.append(err)
1243
1244
1245 ri_labels.append(cdp.ri_type[ri_id])
1246
1247
1248 if cdp.frq[ri_id] not in frq:
1249 frq.append(cdp.frq[ri_id])
1250
1251
1252 remap_table.append(frq.index(cdp.frq[ri_id]))
1253
1254
1255 noe_r1_table.append(None)
1256
1257
1258 num_ri = len(ri_data)
1259
1260
1261 for i in range(num_ri):
1262
1263 if cdp.ri_type[cdp.ri_ids[i]] == 'NOE':
1264 for j in range(num_ri):
1265 if cdp.ri_type[cdp.ri_ids[j]] == 'R1' and cdp.frq[cdp.ri_ids[i]] == cdp.frq[cdp.ri_ids[j]]:
1266 noe_r1_table[i] = j
1267
1268
1269 return ri_data, ri_data_err, len(frq), num_ri, ri_labels, frq, remap_table, noe_r1_table
1270
1271
1273 """Reset all the minimisation statistics.
1274
1275 All global and spin specific values will be set to None.
1276 """
1277
1278
1279 if hasattr(cdp, 'chi2'):
1280 cdp.chi2 = None
1281 cdp.iter = None
1282 cdp.f_count = None
1283 cdp.g_count = None
1284 cdp.h_count = None
1285 cdp.warning = None
1286
1287
1288 for spin in spin_loop():
1289 if hasattr(spin, 'chi2'):
1290 spin.chi2 = None
1291 spin.iter = None
1292 spin.f_count = None
1293 spin.g_count = None
1294 spin.h_count = None
1295 spin.warning = None
1296
1297
1298 - def calculate(self, spin_id=None, verbosity=1, sim_index=None):
1299 """Calculation of the model-free chi-squared value.
1300
1301 @keyword spin_id: The spin identification string.
1302 @type spin_id: str
1303 @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity.
1304 @type verbosity: int
1305 @keyword sim_index: The optional MC simulation index.
1306 @type sim_index: int
1307 """
1308
1309
1310 if not exists_mol_res_spin_data():
1311 raise RelaxNoSequenceError
1312
1313
1314 model_type = self._determine_model_type()
1315
1316
1317 if model_type != 'local_tm' and not diff_data_exists():
1318 raise RelaxNoTensorError('diffusion')
1319
1320
1321 if model_type != 'local_tm' and cdp.diff_tensor.type != 'sphere' and not hasattr(cdp, 'structure'):
1322 raise RelaxNoPdbError
1323
1324
1325 for spin, id in spin_loop(spin_id, return_id=True):
1326
1327 if not spin.select:
1328 continue
1329
1330
1331 if not spin.model:
1332 raise RelaxNoModelError
1333
1334
1335 if not hasattr(spin, 'isotope'):
1336 raise RelaxSpinTypeError
1337
1338
1339 unset_param = self._are_mf_params_set(spin)
1340 if unset_param != None:
1341 raise RelaxNoValueError(unset_param)
1342
1343
1344 if not hasattr(spin, 'csa') or spin.csa == None:
1345 raise RelaxNoValueError("CSA")
1346
1347
1348 interatoms = return_interatom_list(spin_id)
1349 for interatom in interatoms:
1350
1351 if not interatom.dipole_pair:
1352 continue
1353
1354
1355 if model_type != 'local_tm' and cdp.diff_tensor.type != 'sphere' and not hasattr(interatom, 'vector'):
1356 raise RelaxNoVectorsError
1357
1358
1359 if model_type != 'local_tm' and cdp.diff_tensor.type != 'sphere' and hasattr(interatom, 'vector') and arg_check.is_num_list(interatom.vector[0], raise_error=False):
1360 raise RelaxMultiVectorError
1361
1362
1363 if spin_id != interatom.spin_id1:
1364 spin_id2 = interatom.spin_id1
1365 else:
1366 spin_id2 = interatom.spin_id2
1367 spin2 = return_spin(spin_id2)
1368
1369
1370 if not hasattr(spin2, 'isotope'):
1371 raise RelaxSpinTypeError
1372
1373
1374 if not hasattr(interatom, 'r') or interatom.r == None:
1375 raise RelaxNoValueError("interatomic distance", spin_id=spin_id, spin_id2=spin_id2)
1376
1377
1378 if not hasattr(spin, 'ri_data') or not hasattr(spin, 'ri_data_err'):
1379 continue
1380
1381
1382 for ri_id in cdp.ri_ids:
1383
1384 err = spin.ri_data_err[ri_id]
1385
1386
1387 if err != None and err == 0.0:
1388 raise RelaxError("Zero error for spin '%s' for the relaxation data ID '%s', minimisation not possible." % (id, ri_id))
1389 elif err != None and err < 0.0:
1390 raise RelaxError("Negative error of %s for spin '%s' for the relaxation data ID '%s', minimisation not possible." % (err, id, ri_id))
1391
1392
1393 param_vector = self._assemble_param_vector(spin=spin, sim_index=sim_index)
1394
1395
1396 data = self._relax_data_opt_structs(spin, sim_index=sim_index)
1397
1398
1399 ri_data = [array(data[0])]
1400 ri_data_err = [array(data[1])]
1401 num_frq = [data[2]]
1402 num_ri = [data[3]]
1403 ri_labels = [data[4]]
1404 frq = [data[5]]
1405 remap_table = [data[6]]
1406 noe_r1_table = [data[7]]
1407 gx = [return_gyromagnetic_ratio(spin.isotope)]
1408 if sim_index == None:
1409 csa = [spin.csa]
1410 else:
1411 csa = [spin.csa_sim[sim_index]]
1412
1413
1414 interatoms = return_interatom_list(spin_id)
1415 for i in range(len(interatoms)):
1416
1417 if not interatoms[i].dipole_pair:
1418 continue
1419
1420
1421 if spin_id != interatoms[i].spin_id1:
1422 spin_id2 = interatoms[i].spin_id1
1423 else:
1424 spin_id2 = interatoms[i].spin_id2
1425 spin2 = return_spin(spin_id2)
1426
1427
1428 if sim_index == None:
1429 r = [interatoms[i].r]
1430 else:
1431 r = [interatoms[i].r_sim[sim_index]]
1432
1433
1434 if model_type != 'local_tm' and cdp.diff_tensor.type != 'sphere':
1435 xh_unit_vectors = [interatoms[i].vector]
1436 else:
1437 xh_unit_vectors = [None]
1438
1439
1440 gh = [return_gyromagnetic_ratio(spin2.isotope)]
1441
1442
1443 num_params = [len(spin.params)]
1444
1445
1446 param_values = [self._assemble_param_vector(model_type='mf')]
1447
1448
1449 if model_type == 'local_tm':
1450 diff_params = [spin.local_tm]
1451 diff_type = 'sphere'
1452 else:
1453
1454 diff_type = cdp.diff_tensor.type
1455
1456
1457 if diff_type == 'sphere':
1458 diff_params = [cdp.diff_tensor.tm]
1459
1460
1461 elif diff_type == 'spheroid':
1462 diff_params = [cdp.diff_tensor.tm, cdp.diff_tensor.Da, cdp.diff_tensor.theta, cdp.diff_tensor.phi]
1463
1464
1465 elif diff_type == 'ellipsoid':
1466 diff_params = [cdp.diff_tensor.tm, cdp.diff_tensor.Da, cdp.diff_tensor.Dr, cdp.diff_tensor.alpha, cdp.diff_tensor.beta, cdp.diff_tensor.gamma]
1467
1468
1469 mf = Mf(init_params=param_vector, model_type='mf', diff_type=diff_type, diff_params=diff_params, num_spins=1, equations=[spin.equation], param_types=[spin.params], param_values=param_values, relax_data=ri_data, errors=ri_data_err, bond_length=r, csa=csa, num_frq=num_frq, frq=frq, num_ri=num_ri, remap_table=remap_table, noe_r1_table=noe_r1_table, ri_labels=ri_labels, gx=gx, gh=gh, h_bar=h_bar, mu0=mu0, num_params=num_params, vectors=xh_unit_vectors)
1470
1471
1472 try:
1473 chi2 = mf.func(param_vector)
1474 except OverflowError:
1475 chi2 = 1e200
1476
1477
1478 if model_type == 'all' or model_type == 'diff':
1479 cdp.chi2 = cdp.chi2 + chi2
1480 else:
1481 spin.chi2 = chi2
1482
1483
1484 - def grid_search(self, lower=None, upper=None, inc=None, constraints=True, verbosity=1, sim_index=None):
1485 """The model-free grid search function.
1486
1487 @keyword lower: The lower bounds of the grid search which must be equal to the
1488 number of parameters in the model.
1489 @type lower: array of numbers
1490 @keyword upper: The upper bounds of the grid search which must be equal to the
1491 number of parameters in the model.
1492 @type upper: array of numbers
1493 @keyword inc: The increments for each dimension of the space for the grid search.
1494 The number of elements in the array must equal to the number of
1495 parameters in the model.
1496 @type inc: array of int
1497 @keyword constraints: If True, constraints are applied during the grid search (eliminating
1498 parts of the grid). If False, no constraints are used.
1499 @type constraints: bool
1500 @keyword verbosity: A flag specifying the amount of information to print. The higher
1501 the value, the greater the verbosity.
1502 @type verbosity: int
1503 @keyword sim_index: The index of the simulation to apply the grid search to. If None,
1504 the normal model is optimised.
1505 @type sim_index: int
1506 """
1507
1508
1509 self.minimise(min_algor='grid', lower=lower, upper=upper, inc=inc, constraints=constraints, verbosity=verbosity, sim_index=sim_index)
1510
1511
1512 - 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):
1513 """Model-free minimisation function.
1514
1515 Three categories of models exist for which the approach to minimisation is different. These
1516 are:
1517
1518 Single spin optimisations: The 'mf' and 'local_tm' model types which are the
1519 model-free parameters for single spins, optionally with a local tm parameter. These
1520 models have no global parameters.
1521
1522 Diffusion tensor optimisations: The 'diff' diffusion tensor model type. No spin
1523 specific parameters exist.
1524
1525 Optimisation of everything: The 'all' model type consisting of all model-free and all
1526 diffusion tensor parameters.
1527
1528
1529 @keyword min_algor: The minimisation algorithm to use.
1530 @type min_algor: str
1531 @keyword min_options: An array of options to be used by the minimisation algorithm.
1532 @type min_options: array of str
1533 @keyword func_tol: The function tolerance which, when reached, terminates optimisation.
1534 Setting this to None turns of the check.
1535 @type func_tol: None or float
1536 @keyword grad_tol: The gradient tolerance which, when reached, terminates optimisation.
1537 Setting this to None turns of the check.
1538 @type grad_tol: None or float
1539 @keyword max_iterations: The maximum number of iterations for the algorithm.
1540 @type max_iterations: int
1541 @keyword constraints: If True, constraints are used during optimisation.
1542 @type constraints: bool
1543 @keyword scaling: If True, diagonal scaling is enabled during optimisation to allow
1544 the problem to be better conditioned.
1545 @type scaling: bool
1546 @keyword verbosity: The amount of information to print. The higher the value, the
1547 greater the verbosity.
1548 @type verbosity: int
1549 @keyword sim_index: The index of the simulation to optimise. This should be None if
1550 normal optimisation is desired.
1551 @type sim_index: None or int
1552 @keyword lower: The lower bounds of the grid search which must be equal to the
1553 number of parameters in the model. This optional argument is only
1554 used when doing a grid search.
1555 @type lower: array of numbers
1556 @keyword upper: The upper bounds of the grid search which must be equal to the
1557 number of parameters in the model. This optional argument is only
1558 used when doing a grid search.
1559 @type upper: array of numbers
1560 @keyword inc: The increments for each dimension of the space for the grid search.
1561 The number of elements in the array must equal to the number of
1562 parameters in the model. This argument is only used when doing a
1563 grid search.
1564 @type inc: array of int
1565 """
1566
1567
1568 if not exists_mol_res_spin_data():
1569 raise RelaxNoSequenceError
1570
1571
1572 for spin in spin_loop():
1573
1574 if not spin.select:
1575 continue
1576
1577
1578 if not spin.model:
1579 raise RelaxNoModelError
1580
1581
1582 if not hasattr(spin, 'isotope'):
1583 raise RelaxSpinTypeError
1584
1585
1586 if sim_index == None and min_algor != 'back_calc':
1587 self._reset_min_stats()
1588
1589
1590 data_store = Data_container()
1591 opt_params = Data_container()
1592
1593
1594 data_store.h_bar = h_bar
1595 data_store.mu0 = mu0
1596 opt_params.min_algor = min_algor
1597 opt_params.min_options = min_options
1598 opt_params.func_tol = func_tol
1599 opt_params.grad_tol = grad_tol
1600 opt_params.max_iterations = max_iterations
1601
1602
1603 opt_params.verbosity = verbosity
1604
1605
1606 data_store.model_type = self._determine_model_type()
1607 if not data_store.model_type:
1608 return
1609
1610
1611 if min_algor == 'back_calc' and data_store.model_type != 'local_tm':
1612 data_store.model_type = 'mf'
1613
1614
1615 if data_store.model_type != 'local_tm' and not diffusion_tensor.diff_data_exists():
1616 raise RelaxNoTensorError('diffusion')
1617
1618
1619 if data_store.model_type != 'local_tm' and cdp.diff_tensor.type != 'sphere':
1620
1621 if not hasattr(cdp, 'structure'):
1622 raise RelaxNoPdbError
1623
1624
1625 for spin, spin_id in spin_loop(return_id=True):
1626
1627 if not spin.select:
1628 continue
1629
1630
1631 interatoms = return_interatom_list(spin_id)
1632
1633
1634 for i in range(len(interatoms)):
1635
1636 if not interatoms[i].dipole_pair:
1637 continue
1638
1639
1640 if not hasattr(interatoms[i], 'vector'):
1641 raise RelaxNoVectorsError
1642
1643
1644 if data_store.model_type == 'diff':
1645
1646 for spin in spin_loop():
1647 unset_param = self._are_mf_params_set(spin)
1648 if unset_param != None:
1649 raise RelaxNoValueError(unset_param)
1650
1651
1652 if verbosity >= 1:
1653 if data_store.model_type == 'mf':
1654 print("Only the model-free parameters for single spins will be used.")
1655 elif data_store.model_type == 'local_mf':
1656 print("Only a local tm value together with the model-free parameters for single spins will be used.")
1657 elif data_store.model_type == 'diff':
1658 print("Only diffusion tensor parameters will be used.")
1659 elif data_store.model_type == 'all':
1660 print("The diffusion tensor parameters together with the model-free parameters for all spins will be used.")
1661
1662
1663 for spin, spin_id in spin_loop(return_id=True):
1664
1665 if not spin.select:
1666 continue
1667
1668
1669 if not hasattr(spin, 'csa') or spin.csa == None:
1670 raise RelaxNoValueError("CSA")
1671
1672
1673 interatoms = return_interatom_list(spin_id)
1674
1675
1676 count = 0
1677 for i in range(len(interatoms)):
1678
1679 if not interatoms[i].dipole_pair:
1680 continue
1681
1682
1683 if not hasattr(interatoms[i], 'r') or interatoms[i].r == None:
1684 raise RelaxNoValueError("interatomic distance", spin_id=interatoms[i].spin_id1, spin_id2=interatoms[i].spin_id2)
1685
1686
1687 count += 1
1688
1689
1690 if count > 1:
1691 raise RelaxError("The spin '%s' has %s dipolar relaxation interactions defined, but only a maximum of one is currently supported." % (spin_id, count))
1692
1693
1694 if data_store.model_type == 'mf' or data_store.model_type == 'local_tm':
1695 num_instances = count_spins(skip_desel=False)
1696 num_data_sets = 1
1697 data_store.num_spins = 1
1698 elif data_store.model_type == 'diff' or data_store.model_type == 'all':
1699 num_instances = 1
1700 num_data_sets = count_spins(skip_desel=False)
1701 data_store.num_spins = count_spins()
1702
1703
1704 if min_algor == 'back_calc':
1705 num_instances = 1
1706 num_data_sets = 0
1707 data_store.num_spins = 1
1708
1709
1710 processor_box = Processor_box()
1711 processor = processor_box.processor
1712
1713
1714
1715
1716 for i in range(num_instances):
1717
1718 if data_store.model_type == 'diff' or data_store.model_type == 'all':
1719 spin_index = None
1720 spin, data_store.spin_id = None, None
1721 elif min_algor == 'back_calc':
1722 spin_index = opt_params.min_options[0]
1723 spin, data_store.spin_id = return_spin_from_index(global_index=spin_index, return_spin_id=True)
1724 else:
1725 spin_index = i
1726 spin, data_store.spin_id = return_spin_from_index(global_index=spin_index, return_spin_id=True)
1727
1728
1729 if spin and (data_store.model_type == 'mf' or data_store.model_type == 'local_tm') and not min_algor == 'back_calc':
1730
1731 if not spin.select:
1732 continue
1733
1734
1735 if not hasattr(spin, 'ri_data') or not hasattr(spin, 'ri_data_err'):
1736 continue
1737
1738
1739 if spin and (data_store.model_type == 'mf' or data_store.model_type == 'local_tm'):
1740 interatoms = return_interatom_list(data_store.spin_id)
1741 if not len(interatoms):
1742 continue
1743
1744
1745 if min_algor == 'back_calc':
1746
1747 opt_params.param_vector = self._assemble_param_vector(spin=spin, model_type=data_store.model_type)
1748
1749
1750 data_store.scaling_matrix = None
1751
1752 else:
1753
1754 opt_params.param_vector = self._assemble_param_vector(spin=spin, sim_index=sim_index)
1755
1756
1757 num_params = len(opt_params.param_vector)
1758
1759
1760 data_store.scaling_matrix = self._assemble_scaling_matrix(num_params, model_type=data_store.model_type, spin=spin, scaling=scaling)
1761 if len(data_store.scaling_matrix):
1762 opt_params.param_vector = dot(inv(data_store.scaling_matrix), opt_params.param_vector)
1763
1764
1765 opt_params.inc, opt_params.lower, opt_params.upper = None, None, None
1766 if match('^[Gg]rid', min_algor):
1767 opt_params.inc, opt_params.lower, opt_params.upper = self._grid_search_config(num_params, spin=spin, lower=lower, upper=upper, inc=inc, scaling_matrix=data_store.scaling_matrix)
1768
1769
1770 if match('^[Ss]et', min_algor):
1771 opt_params.min_options = dot(inv(data_store.scaling_matrix), opt_params.min_options)
1772
1773
1774 if constraints:
1775 opt_params.A, opt_params.b = self._linear_constraints(num_params, model_type=data_store.model_type, spin=spin, scaling_matrix=data_store.scaling_matrix)
1776 else:
1777 opt_params.A, opt_params.b = None, None
1778
1779
1780 self._minimise_data_setup(data_store, min_algor, num_data_sets, opt_params.min_options, spin=spin, sim_index=sim_index)
1781
1782
1783 if constraints and not match('^[Gg]rid', min_algor):
1784 algor = opt_params.min_options[0]
1785 else:
1786 algor = min_algor
1787
1788
1789 if min_algor == 'back_calc' or match('[Ll][Mm]$', algor) or match('[Ll]evenburg-[Mm]arquardt$', algor):
1790 self.mf = Mf(init_params=opt_params.param_vector, model_type=data_store.model_type, diff_type=data_store.diff_type, diff_params=data_store.diff_params, scaling_matrix=data_store.scaling_matrix, num_spins=data_store.num_spins, equations=data_store.equations, param_types=data_store.param_types, param_values=data_store.param_values, relax_data=data_store.ri_data, errors=data_store.ri_data_err, bond_length=data_store.r, csa=data_store.csa, num_frq=data_store.num_frq, frq=data_store.frq, num_ri=data_store.num_ri, remap_table=data_store.remap_table, noe_r1_table=data_store.noe_r1_table, ri_labels=data_store.ri_types, gx=data_store.gx, gh=data_store.gh, h_bar=data_store.h_bar, mu0=data_store.mu0, num_params=data_store.num_params, vectors=data_store.xh_unit_vectors)
1791
1792
1793 if match('[Ll][Mm]$', algor) or match('[Ll]evenburg-[Mm]arquardt$', algor):
1794
1795 number_ri = 0
1796 for k in range(len(ri_data_err)):
1797 number_ri = number_ri + len(ri_data_err[k])
1798
1799
1800 lm_error = zeros(number_ri, float64)
1801 index = 0
1802 for k in range(len(ri_data_err)):
1803 lm_error[index:index+len(ri_data_err[k])] = ri_data_err[k]
1804 index = index + len(ri_data_err[k])
1805
1806 opt_params.min_options = opt_params.min_options + (self.mf.lm_dri, lm_error)
1807
1808
1809 if min_algor == 'back_calc':
1810 return self.mf.calc_ri()
1811
1812
1813 if match('^[Gg]rid', min_algor) and data_store.model_type == 'diff':
1814
1815 print("Parallelised diffusion tensor grid search.")
1816
1817
1818 for subdivision in grid_split(divisions=processor.processor_size(), lower=opt_params.lower, upper=opt_params.upper, inc=opt_params.inc):
1819
1820 opt_params.subdivision = subdivision
1821
1822
1823 command = MF_grid_command()
1824
1825
1826 command.store_data(deepcopy(data_store), deepcopy(opt_params))
1827
1828
1829 memo = MF_memo(model_free=self, model_type=data_store.model_type, spin=spin, sim_index=sim_index, scaling=scaling, scaling_matrix=data_store.scaling_matrix)
1830 processor.add_to_queue(command, memo)
1831
1832
1833 processor.run_queue()
1834
1835
1836 return
1837
1838
1839 if search('^[Gg]rid', min_algor):
1840 command = MF_grid_command()
1841
1842
1843 else:
1844 command = MF_minimise_command()
1845
1846
1847 command.store_data(deepcopy(data_store), deepcopy(opt_params))
1848
1849
1850 memo = MF_memo(model_free=self, model_type=data_store.model_type, spin=spin, sim_index=sim_index, scaling=scaling, scaling_matrix=data_store.scaling_matrix)
1851 processor.add_to_queue(command, memo)
1852
1853
1854 processor.run_queue()
1855