1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """Module for the optimisation of the relaxation dispersion models."""
25
26
27 from minfx.generic import generic_minimise
28 from minfx.grid import grid
29 from numpy import dot, float64, int32, ones, zeros
30 from numpy.linalg import inv
31 from operator import mul
32 from re import match, search
33 import sys
34 from warnings import warn
35
36
37 from dep_check import C_module_exp_fn
38 from lib.dispersion.two_point import calc_two_point_r2eff, calc_two_point_r2eff_err
39 from lib.dispersion.variables import EXP_TYPE_LIST_CPMG, MODEL_CR72, MODEL_CR72_FULL, MODEL_LM63, MODEL_M61, MODEL_MP05, MODEL_TAP03, MODEL_TP02
40 from lib.errors import RelaxError
41 from lib.text.sectioning import subsection
42 from lib.warnings import RelaxWarning
43 from multi import Memo, Result_command, Slave_command
44 from pipe_control.mol_res_spin import generate_spin_string, spin_loop
45 from specific_analyses.relax_disp.checks import check_disp_points, check_exp_type, check_exp_type_fixed_time
46 from specific_analyses.relax_disp.data import average_intensity, count_spins, find_intensity_keys, has_exponential_exp_type, has_proton_mmq_cpmg, is_r1_optimised, loop_exp, loop_exp_frq_offset_point, loop_exp_frq_offset_point_time, loop_frq, loop_offset, loop_time, pack_back_calc_r2eff, return_cpmg_frqs, return_offset_data, return_param_key_from_data, return_r1_data, return_r2eff_arrays, return_spin_lock_nu1
47 from specific_analyses.relax_disp.parameters import assemble_param_vector, disassemble_param_vector, linear_constraints, param_conversion, param_num, r1_setup
48 from target_functions.relax_disp import Dispersion
49 from target_functions.relax_fit_wrapper import Relax_fit_opt
50
51
53 """Back-calculation of peak intensity for the given relaxation time.
54
55 @keyword spin: The specific spin data container.
56 @type spin: SpinContainer instance
57 @keyword spin_id: The optional spin ID string for use in warning messages.
58 @type spin_id: str or None
59 @keyword exp_type: The experiment type.
60 @type exp_type: str
61 @keyword frq: The spectrometer frequency.
62 @type frq: float
63 @keyword offset: For R1rho-type data, the spin-lock offset value in ppm.
64 @type offset: None or float
65 @keyword point: The dispersion point data (either the spin-lock field strength in Hz or the nu_CPMG frequency in Hz).
66 @type point: float
67 @return: The back-calculated peak intensities for the given exponential curve.
68 @rtype: numpy rank-1 float array
69 """
70
71
72 if not has_exponential_exp_type():
73 raise RelaxError("Back-calculation is not allowed for the fixed time experiment types.")
74
75
76 param_key = return_param_key_from_data(exp_type=exp_type, frq=frq, offset=offset, point=point)
77
78
79 param_vector = assemble_param_vector(spins=[spin], key=param_key)
80
81
82 values = []
83 errors = []
84 times = []
85 for time in loop_time(exp_type=exp_type, frq=frq, offset=offset, point=point):
86
87 int_keys = find_intensity_keys(exp_type=exp_type, frq=frq, offset=offset, point=point, time=time)
88 for i in range(len(int_keys)):
89 if int_keys[i] not in spin.peak_intensity:
90 if spin_id:
91 warn(RelaxWarning("The spin %s peak intensity key '%s' is not present, skipping the back-calculation." % (spin_id, int_keys[i])))
92 else:
93 warn(RelaxWarning("The peak intensity key '%s' is not present, skipping the back-calculation." % int_keys[i]))
94 return
95
96
97 values.append(average_intensity(spin=spin, exp_type=exp_type, frq=frq, offset=offset, point=point, time=time))
98 errors.append(average_intensity(spin=spin, exp_type=exp_type, frq=frq, offset=offset, point=point, time=time, error=True))
99 times.append(time)
100
101
102 scaling_list = []
103 for i in range(len(param_vector)):
104 scaling_list.append(1.0)
105
106
107 model = Relax_fit_opt(model='exp', num_params=len(spin.params), values=values, errors=errors, relax_times=times, scaling_matrix=scaling_list)
108
109
110 model.func(param_vector)
111
112
113 results = model.back_calc_data()
114
115
116 return results
117
118
119 -def back_calc_r2eff(spins=None, spin_ids=None, cpmg_frqs=None, spin_lock_offset=None, spin_lock_nu1=None, relax_times_new=None, store_chi2=False):
120 """Back-calculation of R2eff/R1rho values for the given spin.
121
122 @keyword spins: The list of specific spin data container for cluster.
123 @type spins: List of SpinContainer instances
124 @keyword spin_ids: The list of spin ID strings for the spin containers in cluster.
125 @type spin_ids: list of str
126 @keyword cpmg_frqs: The CPMG frequencies to use instead of the user loaded values - to enable interpolation.
127 @type cpmg_frqs: list of lists of numpy rank-1 float arrays
128 @keyword spin_lock_offset: The spin-lock offsets to use instead of the user loaded values - to enable interpolation.
129 @type spin_lock_offset: list of lists of numpy rank-1 float arrays
130 @keyword spin_lock_nu1: The spin-lock field strengths to use instead of the user loaded values - to enable interpolation.
131 @type spin_lock_nu1: list of lists of numpy rank-1 float arrays
132 @keyword relax_times_new: The interpolated experiment specific fixed time period for relaxation (in seconds). The dimensions are {Ei, Mi, Oi, Di, Ti}.
133 @type relax_times_new: rank-4 list of floats
134 @keyword store_chi2: A flag which if True will cause the spin specific chi-squared value to be stored in the spin container.
135 @type store_chi2: bool
136 @return: The back-calculated R2eff/R1rho value for the given spin.
137 @rtype: numpy rank-1 float array
138 """
139
140
141 param_vector = assemble_param_vector(spins=spins)
142
143
144 fields = [None]
145 field_count = 1
146 if hasattr(cdp, 'spectrometer_frq_count'):
147 fields = cdp.spectrometer_frq_list
148 field_count = cdp.spectrometer_frq_count
149
150
151 values, errors, missing, frqs, frqs_H, exp_types, relax_times = return_r2eff_arrays(spins=spins, spin_ids=spin_ids, fields=fields, field_count=field_count)
152
153
154 r1_setup()
155 offsets, spin_lock_fields_inter, chemical_shifts, tilt_angles, Delta_omega, w_eff = return_offset_data(spins=spins, spin_ids=spin_ids, field_count=field_count, spin_lock_offset=spin_lock_offset, fields=spin_lock_nu1)
156 r1 = return_r1_data(spins=spins, spin_ids=spin_ids, field_count=field_count)
157 r1_fit = is_r1_optimised(spins[0].model)
158
159
160 if relax_times_new != None:
161 relax_times = relax_times_new
162
163
164 recalc_tau = True
165 if cpmg_frqs == None and spin_lock_nu1 == None and spin_lock_offset == None:
166 cpmg_frqs = return_cpmg_frqs(ref_flag=False)
167 spin_lock_nu1 = return_spin_lock_nu1(ref_flag=False)
168
169
170 elif cpmg_frqs == None and spin_lock_offset != None:
171 cpmg_frqs = None
172 spin_lock_nu1 = spin_lock_fields_inter
173
174 recalc_tau = False
175 values = []
176 errors = []
177 missing = []
178 for exp_type, ei in loop_exp(return_indices=True):
179 values.append([])
180 errors.append([])
181 missing.append([])
182 for si in range(len(spins)):
183 values[ei].append([])
184 errors[ei].append([])
185 missing[ei].append([])
186 for frq, mi in loop_frq(return_indices=True):
187 values[ei][si].append([])
188 errors[ei][si].append([])
189 missing[ei][si].append([])
190 for oi, offset in enumerate(offsets[ei][si][mi]):
191 num = len(spin_lock_nu1[ei][mi][oi])
192
193 values[ei][si][mi].append(zeros(num, float64))
194 errors[ei][si][mi].append(ones(num, float64))
195 missing[ei][si][mi].append(zeros(num, int32))
196
197
198 else:
199 recalc_tau = False
200 values = []
201 errors = []
202 missing = []
203 for exp_type, ei in loop_exp(return_indices=True):
204 values.append([])
205 errors.append([])
206 missing.append([])
207 for si in range(len(spins)):
208 values[ei].append([])
209 errors[ei].append([])
210 missing[ei].append([])
211 for frq, mi in loop_frq(return_indices=True):
212 values[ei][si].append([])
213 errors[ei][si].append([])
214 missing[ei][si].append([])
215 for offset, oi in loop_offset(exp_type=exp_type, frq=frq, return_indices=True):
216 if exp_type in EXP_TYPE_LIST_CPMG:
217 num = len(cpmg_frqs[ei][mi][oi])
218 else:
219 num = len(spin_lock_nu1[ei][mi][oi])
220 values[ei][si][mi].append(zeros(num, float64))
221 errors[ei][si][mi].append(ones(num, float64))
222 missing[ei][si][mi].append(zeros(num, int32))
223
224
225 model = Dispersion(model=spins[0].model, num_params=param_num(spins=spins), num_spins=len(spins), num_frq=field_count, exp_types=exp_types, values=values, errors=errors, missing=missing, frqs=frqs, frqs_H=frqs_H, cpmg_frqs=cpmg_frqs, spin_lock_nu1=spin_lock_nu1, chemical_shifts=chemical_shifts, offset=offsets, tilt_angles=tilt_angles, r1=r1, relax_times=relax_times, recalc_tau=recalc_tau, r1_fit=r1_fit)
226
227
228 chi2 = model.func(param_vector)
229
230
231 if store_chi2:
232 for spin in spins:
233 spin.chi2 = chi2
234
235
236 return model.get_back_calc()
237
238
240 """Calculate the R2eff values for fixed relaxation time period data."""
241
242
243 check_exp_type()
244 check_disp_points()
245 check_exp_type_fixed_time()
246
247
248 print("Calculating the R2eff/R1rho values for fixed relaxation time period data.")
249
250
251 for spin, mol_name, resi, resn, spin_id in spin_loop(full_info=True, return_id=True, skip_desel=True):
252
253 print("Spin '%s'." % spin_id)
254
255
256 if not hasattr(spin, 'peak_intensity'):
257 continue
258
259
260 if not hasattr(spin, 'r2eff'):
261 spin.r2eff = {}
262 if not hasattr(spin, 'r2eff_err'):
263 spin.r2eff_err = {}
264
265
266 for exp_type, frq, offset, point, time in loop_exp_frq_offset_point_time():
267
268 ref_keys = find_intensity_keys(exp_type=exp_type, frq=frq, offset=offset, point=None, time=time)
269 int_keys = find_intensity_keys(exp_type=exp_type, frq=frq, offset=offset, point=point, time=time)
270 param_key = return_param_key_from_data(exp_type=exp_type, frq=frq, offset=offset, point=point)
271
272
273 missing = False
274 for i in range(len(ref_keys)):
275 if ref_keys[i] not in spin.peak_intensity:
276 missing = True
277 for i in range(len(int_keys)):
278 if int_keys[i] not in spin.peak_intensity:
279 missing = True
280 if missing:
281 continue
282
283
284 ref_intensity = average_intensity(spin=spin, exp_type=exp_type, frq=frq, offset=offset, point=None, time=time)
285 ref_intensity_err = average_intensity(spin=spin, exp_type=exp_type, frq=frq, offset=offset, point=None, time=time, error=True)
286
287
288 intensity = average_intensity(spin=spin, exp_type=exp_type, frq=frq, offset=offset, point=point, time=time)
289 intensity_err = average_intensity(spin=spin, exp_type=exp_type, frq=frq, offset=offset, point=point, time=time, error=True)
290
291
292 if ref_intensity == 0.0:
293 skip_data = True
294 elif float(intensity) / ref_intensity <= 0.0:
295 skip_data = True
296 else:
297 skip_data = False
298
299 if skip_data:
300 spin_string = generate_spin_string(spin=spin, mol_name=mol_name, res_num=resi, res_name=resn)
301 msg = "Math log(I / I_ref) domain error for spin '%s' in R2eff value calculation for fixed relaxation time period data. I=%3.3f, I_ref=%3.3f. The point is skipped." % (spin_string, intensity, ref_intensity)
302 warn(RelaxWarning("%s" % msg))
303 point_info = "This happened for '%s' at %3.1f MHz, for offset=%3.1f ppm and dispersion point %3.1f Hz and time %1.2f s.\n" % (exp_type, frq/1E6, offset, point, time)
304 print(point_info)
305 else:
306
307 spin.r2eff[param_key] = calc_two_point_r2eff(relax_time=time, I_ref=ref_intensity, I=intensity)
308
309
310 spin.r2eff_err[param_key] = calc_two_point_r2eff_err(relax_time=time, I_ref=ref_intensity, I=intensity, I_ref_err=ref_intensity_err, I_err=intensity_err)
311
312
313 -def minimise_r2eff(spins=None, spin_ids=None, min_algor=None, min_options=None, func_tol=None, grad_tol=None, max_iterations=None, constraints=False, scaling_matrix=None, verbosity=0, sim_index=None, lower=None, upper=None, inc=None):
314 """Optimise the R2eff model by fitting the 2-parameter exponential curves.
315
316 This mimics the R1 and R2 relax_fit analysis.
317
318
319 @keyword spins: The list of spins for the cluster.
320 @type spins: list of SpinContainer instances
321 @keyword spin_ids: The list of spin IDs for the cluster.
322 @type spin_ids: list of str
323 @keyword min_algor: The minimisation algorithm to use.
324 @type min_algor: str
325 @keyword min_options: An array of options to be used by the minimisation algorithm.
326 @type min_options: array of str
327 @keyword func_tol: The function tolerance which, when reached, terminates optimisation. Setting this to None turns of the check.
328 @type func_tol: None or float
329 @keyword grad_tol: The gradient tolerance which, when reached, terminates optimisation. Setting this to None turns of the check.
330 @type grad_tol: None or float
331 @keyword max_iterations: The maximum number of iterations for the algorithm.
332 @type max_iterations: int
333 @keyword constraints: If True, constraints are used during optimisation.
334 @type constraints: bool
335 @keyword scaling_matrix: The diagonal and square scaling matrix.
336 @type scaling_matrix: numpy rank-2, float64 array or None
337 @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity.
338 @type verbosity: int
339 @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
340 @type sim_index: None or int
341 @keyword lower: The model specific 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.
342 @type lower: list of numbers
343 @keyword upper: The model specific 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.
344 @type upper: list of numbers
345 @keyword inc: The model specific 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.
346 @type inc: list of int
347 """
348
349
350 if not C_module_exp_fn:
351 raise RelaxError("Relaxation curve fitting is not available. Try compiling the C modules on your platform.")
352
353
354 for si in range(len(spins)):
355
356 if not spins[si].select:
357 continue
358
359
360 for exp_type, frq, offset, point in loop_exp_frq_offset_point():
361
362 param_key = return_param_key_from_data(exp_type=exp_type, frq=frq, offset=offset, point=point)
363
364
365 param_vector = assemble_param_vector(spins=[spins[si]], key=param_key, sim_index=sim_index)
366
367
368 if scaling_matrix is not None:
369 param_vector = dot(inv(scaling_matrix), param_vector)
370
371
372 A, b = None, None
373 if constraints:
374 A, b = linear_constraints(spins=[spins[si]], scaling_matrix=scaling_matrix)
375
376
377 if verbosity >= 1:
378
379 top = 2
380 if verbosity >= 2:
381 top += 2
382 text = "Fitting to spin %s, frequency %s and dispersion point %s" % (spin_ids[si], frq, point)
383 subsection(file=sys.stdout, text=text, prespace=top)
384
385
386 if match('^[Gg]rid', min_algor):
387 result = 1
388 for x in inc:
389 result = mul(result, x)
390 print("Unconstrained grid search size: %s (constraints may decrease this size).\n" % result)
391
392
393 values = []
394 errors = []
395 times = []
396 data_flag = True
397 for time in loop_time(exp_type=exp_type, frq=frq, offset=offset, point=point):
398
399 int_keys = find_intensity_keys(exp_type=exp_type, frq=frq, offset=offset, point=point, time=time)
400 peak_intensities = spins[si].peak_intensity
401 if sim_index != None:
402 peak_intensities = spins[si].peak_intensity_sim
403 for i in range(len(int_keys)):
404 if int_keys[i] not in peak_intensities:
405 if verbosity:
406 warn(RelaxWarning("The spin %s peak intensity key '%s' is not present, skipping the optimisation." % (spin_ids[si], int_keys[i])))
407 data_flag = False
408 break
409
410 if data_flag:
411 values.append(average_intensity(spin=spins[si], exp_type=exp_type, frq=frq, offset=offset, point=point, time=time, sim_index=sim_index))
412 errors.append(average_intensity(spin=spins[si], exp_type=exp_type, frq=frq, offset=offset, point=point, time=time, error=True))
413 times.append(time)
414 if not data_flag:
415 continue
416
417
418 if len(times) < 3:
419 subsection(file=sys.stdout, text="Exponential curve fitting error for point:", prespace=2)
420 point_info = "%s at %3.1f MHz, for offset=%3.3f ppm and dispersion point %-5.1f, with %i time points." % (exp_type, frq/1E6, offset, point, len(times))
421 raise RelaxError("The data setup points to exponential curve fitting, but only %i time points was found, where 3 time points is minimum. If calculating R2eff values for fixed relaxation time period data, check that a reference intensity has been specified for each offset value."%(len(times)))
422
423
424 scaling_list = []
425 if scaling_matrix is None:
426 for i in range(len(param_vector)):
427 scaling_list.append(1.0)
428 else:
429 for i in range(len(scaling_matrix)):
430 scaling_list.append(scaling_matrix[i, i])
431
432
433 model = Relax_fit_opt(model='exp', num_params=len(param_vector), values=values, errors=errors, relax_times=times, scaling_matrix=scaling_list)
434
435
436 if search('^[Gg]rid', min_algor):
437 results = grid(func=model.func, args=(), num_incs=inc, lower=lower, upper=upper, A=A, b=b, verbosity=verbosity)
438
439
440 param_vector, chi2, iter_count, warning = results
441 f_count = iter_count
442 g_count = 0.0
443 h_count = 0.0
444
445
446 else:
447 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=True, print_flag=verbosity)
448
449
450 if results == None:
451 return
452 param_vector, chi2, iter_count, f_count, g_count, h_count, warning = results
453
454
455 if scaling_matrix is not None:
456 param_vector = dot(scaling_matrix, param_vector)
457
458
459 disassemble_param_vector(param_vector=param_vector, spins=[spins[si]], key=param_key, sim_index=sim_index)
460
461
462 if sim_index != None:
463
464 spins[si].chi2_sim[sim_index] = chi2
465
466
467 spins[si].iter_sim[sim_index] = iter_count
468
469
470 spins[si].f_count_sim[sim_index] = f_count
471
472
473 spins[si].g_count_sim[sim_index] = g_count
474
475
476 spins[si].h_count_sim[sim_index] = h_count
477
478
479 spins[si].warning_sim[sim_index] = warning
480
481
482 else:
483
484 spins[si].chi2 = chi2
485
486
487 spins[si].iter = iter_count
488
489
490 spins[si].f_count = f_count
491
492
493 spins[si].g_count = g_count
494
495
496 spins[si].h_count = h_count
497
498
499 spins[si].warning = warning
500
501
502
504 """The relaxation dispersion memo class."""
505
506 - def __init__(self, spins=None, spin_ids=None, sim_index=None, scaling_matrix=None, verbosity=None):
507 """Initialise the relaxation dispersion memo class.
508
509 This is used for handling the optimisation results returned from a slave processor. It runs on the master processor and is used to store data which is passed to the slave processor and then passed back to the master via the results command.
510
511
512 @keyword spins: The list of spin data container for the cluster. If this argument is supplied, then the spin_id argument will be ignored.
513 @type spins: list of SpinContainer instances
514 @keyword spin_ids: The spin ID strings for the cluster.
515 @type spin_ids: list of str
516 @keyword sim_index: The optional MC simulation index.
517 @type sim_index: int
518 @keyword scaling_matrix: The diagonal, square scaling matrix.
519 @type scaling_matrix: numpy diagonal matrix
520 @keyword verbosity: The verbosity level. This is used by the result command returned to the master for printouts.
521 @type verbosity: int
522 """
523
524
525 super(Disp_memo, self).__init__()
526
527
528 self.spins = spins
529 self.spin_ids = spin_ids
530 self.sim_index = sim_index
531 self.scaling_matrix = scaling_matrix
532 self.verbosity = verbosity
533
534
535
537 """Command class for relaxation dispersion optimisation on the slave processor."""
538
539 - def __init__(self, spins=None, spin_ids=None, sim_index=None, scaling_matrix=None, min_algor=None, min_options=None, func_tol=None, grad_tol=None, max_iterations=None, constraints=False, verbosity=0, lower=None, upper=None, inc=None, fields=None, param_names=None):
540 """Initialise the base class, storing all the master data to be sent to the slave processor.
541
542 This method is run on the master processor whereas the run() method is run on the slave processor.
543
544
545 @keyword spins: The list of spin data container for the cluster. If this argument is supplied, then the spin_id argument will be ignored.
546 @type spins: list of SpinContainer instances
547 @keyword spin_ids: The list of spin ID strings corresponding to the spins argument.
548 @type spin_ids: list of str
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 @keyword scaling_matrix: The diagonal, square scaling matrix.
552 @type scaling_matrix: numpy diagonal matrix
553 @keyword min_algor: The minimisation algorithm to use.
554 @type min_algor: str
555 @keyword min_options: An array of options to be used by the minimisation algorithm.
556 @type min_options: array of str
557 @keyword func_tol: The function tolerance which, when reached, terminates optimisation. Setting this to None turns of the check.
558 @type func_tol: None or float
559 @keyword grad_tol: The gradient tolerance which, when reached, terminates optimisation. Setting this to None turns of the check.
560 @type grad_tol: None or float
561 @keyword max_iterations: The maximum number of iterations for the algorithm.
562 @type max_iterations: int
563 @keyword constraints: If True, constraints are used during optimisation.
564 @type constraints: bool
565 @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity.
566 @type verbosity: int
567 @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.
568 @type lower: array of numbers
569 @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.
570 @type upper: array of numbers
571 @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.
572 @type inc: array of int
573 @keyword fields: The list of unique of spectrometer field strengths.
574 @type fields: int
575 @keyword param_names: The list of parameter names to use in printouts.
576 @type param_names: str
577 """
578
579
580 super(Disp_minimise_command, self).__init__()
581
582
583 self.spins = spins
584 self.spin_ids = spin_ids
585 self.sim_index = sim_index
586 self.scaling_matrix = scaling_matrix
587 self.verbosity = verbosity
588 self.min_algor = min_algor
589 self.min_options = min_options
590 self.func_tol = func_tol
591 self.grad_tol = grad_tol
592 self.max_iterations = max_iterations
593 self.lower = lower
594 self.upper = upper
595 self.inc = inc
596 self.fields = fields
597 self.param_names = param_names
598
599
600 self.param_vector = assemble_param_vector(spins=self.spins)
601 if len(scaling_matrix):
602 self.param_vector = dot(inv(scaling_matrix), self.param_vector)
603
604
605 self.A, self.b = None, None
606 if constraints:
607 self.A, self.b = linear_constraints(spins=spins, scaling_matrix=scaling_matrix)
608
609
610 if spins[0].model in [MODEL_LM63, MODEL_CR72, MODEL_CR72_FULL, MODEL_M61, MODEL_TP02, MODEL_TAP03, MODEL_MP05] and not hasattr(cdp, 'spectrometer_frq'):
611 raise RelaxError("The spectrometer frequency information has not been specified.")
612
613
614 self.values, self.errors, self.missing, self.frqs, self.frqs_H, self.exp_types, self.relax_times = return_r2eff_arrays(spins=spins, spin_ids=spin_ids, fields=fields, field_count=len(fields), sim_index=sim_index)
615
616
617 r1_setup()
618 self.offsets, spin_lock_fields_inter, self.chemical_shifts, self.tilt_angles, self.Delta_omega, self.w_eff = return_offset_data(spins=spins, spin_ids=spin_ids, field_count=len(fields))
619 self.r1 = return_r1_data(spins=spins, spin_ids=spin_ids, field_count=len(fields), sim_index=sim_index)
620 self.r1_fit = is_r1_optimised(spins[0].model)
621
622
623 self.param_num = param_num(spins=spins)
624
625
626 self.dispersion_points = cdp.dispersion_points
627 self.cpmg_frqs = return_cpmg_frqs(ref_flag=False)
628 self.spin_lock_nu1 = return_spin_lock_nu1(ref_flag=False)
629
630
631 - def run(self, processor, completed):
632 """Set up and perform the optimisation."""
633
634
635 if self.verbosity >= 1:
636
637 top = 2
638 if self.verbosity >= 2:
639 top += 2
640 subsection(file=sys.stdout, text="Fitting to the spin block %s"%self.spin_ids, prespace=top)
641
642
643 if search('^[Gg]rid', self.min_algor):
644 result = 1
645 for x in self.inc:
646 result = mul(result, x)
647 print("Unconstrained grid search size: %s (constraints may decrease this size).\n" % result)
648
649
650 model = Dispersion(model=self.spins[0].model, num_params=self.param_num, num_spins=count_spins(self.spins), num_frq=len(self.fields), exp_types=self.exp_types, values=self.values, errors=self.errors, missing=self.missing, frqs=self.frqs, frqs_H=self.frqs_H, cpmg_frqs=self.cpmg_frqs, spin_lock_nu1=self.spin_lock_nu1, chemical_shifts=self.chemical_shifts, offset=self.offsets, tilt_angles=self.tilt_angles, r1=self.r1, relax_times=self.relax_times, scaling_matrix=self.scaling_matrix, r1_fit=self.r1_fit)
651
652
653 if search('^[Gg]rid', self.min_algor):
654 results = grid(func=model.func, args=(), num_incs=self.inc, lower=self.lower, upper=self.upper, A=self.A, b=self.b, verbosity=self.verbosity)
655
656
657 param_vector, chi2, iter_count, warning = results
658 f_count = iter_count
659 g_count = 0.0
660 h_count = 0.0
661
662
663 else:
664 results = generic_minimise(func=model.func, args=(), x0=self.param_vector, min_algor=self.min_algor, min_options=self.min_options, func_tol=self.func_tol, grad_tol=self.grad_tol, maxiter=self.max_iterations, A=self.A, b=self.b, full_output=True, print_flag=self.verbosity)
665
666
667 if results == None:
668 return
669 param_vector, chi2, iter_count, f_count, g_count, h_count, warning = results
670
671
672 if self.verbosity:
673 print("\nOptimised parameter values:")
674 for i in range(len(param_vector)):
675 print("%-20s %25.15f" % (self.param_names[i], param_vector[i]*self.scaling_matrix[i, i]))
676
677
678 processor.return_object(Disp_result_command(processor=processor, memo_id=self.memo_id, param_vector=param_vector, chi2=chi2, iter_count=iter_count, f_count=f_count, g_count=g_count, h_count=h_count, warning=warning, missing=self.missing, back_calc=model.get_back_calc(), completed=False))
679
680
681
683 """Class for processing the dispersion optimisation results.
684
685 This object will be sent from the slave back to the master to have its run() method executed.
686 """
687
688 - def __init__(self, processor=None, memo_id=None, param_vector=None, chi2=None, iter_count=None, f_count=None, g_count=None, h_count=None, warning=None, missing=None, back_calc=None, completed=True):
689 """Set up this class object on the slave, placing the minimisation results here.
690
691 @keyword processor: The processor object.
692 @type processor: multi.processor.Processor instance
693 @keyword memo_id: The memo identification string.
694 @type memo_id: str
695 @keyword param_vector: The optimised parameter vector.
696 @type param_vector: numpy rank-1 array
697 @keyword chi2: The final target function value.
698 @type chi2: float
699 @keyword iter_count: The number of optimisation iterations.
700 @type iter_count: int
701 @keyword f_count: The total function call count.
702 @type f_count: int
703 @keyword g_count: The total gradient call count.
704 @type g_count: int
705 @keyword h_count: The total Hessian call count.
706 @type h_count: int
707 @keyword warning: Any optimisation warnings.
708 @type warning: str or None
709 @keyword missing: The data structure indicating which R2eff/R1rho' base data is missing.
710 @type missing: numpy rank-3 array
711 @keyword back_calc: The back-calculated R2eff/R1rho' data structure from the target function class. This is will be transfered to the master to be stored in the r2eff_bc data structure.
712 @type back_calc: numpy rank-3 array
713 @keyword completed: A flag which if True signals that the optimisation successfully completed.
714 @type completed: bool
715 """
716
717
718 super(Disp_result_command, self).__init__(processor=processor, completed=completed)
719
720
721 self.memo_id = memo_id
722 self.param_vector = param_vector
723 self.chi2 = chi2
724 self.iter_count = iter_count
725 self.f_count = f_count
726 self.g_count = g_count
727 self.h_count = h_count
728 self.warning = warning
729 self.missing = missing
730 self.back_calc = back_calc
731 self.completed = completed
732
733
734 - def run(self, processor=None, memo=None):
735 """Disassemble the model-free optimisation results (on the master).
736
737 @param processor: Unused!
738 @type processor: None
739 @param memo: The dispersion memo. This holds a lot of the data and objects needed for processing the results from the slave.
740 @type memo: memo
741 """
742
743
744 if memo.sim_index != None:
745 print("Simulation %s, cluster %s" % (memo.sim_index+1, memo.spin_ids))
746
747
748 if memo.scaling_matrix is not None:
749 param_vector = dot(memo.scaling_matrix, self.param_vector)
750
751
752 disassemble_param_vector(param_vector=param_vector, spins=memo.spins, sim_index=memo.sim_index)
753 param_conversion(spins=memo.spins, sim_index=memo.sim_index)
754
755
756 if memo.sim_index != None:
757 for spin in memo.spins:
758
759 if not spin.select:
760 continue
761
762
763 spin.chi2_sim[memo.sim_index] = self.chi2
764
765
766 spin.iter_sim[memo.sim_index] = self.iter_count
767
768
769 spin.f_count_sim[memo.sim_index] = self.f_count
770
771
772 spin.g_count_sim[memo.sim_index] = self.g_count
773
774
775 spin.h_count_sim[memo.sim_index] = self.h_count
776
777
778 spin.warning_sim[memo.sim_index] = self.warning
779
780
781 else:
782 for spin in memo.spins:
783
784 if not spin.select:
785 continue
786
787
788 spin.chi2 = self.chi2
789
790
791 spin.iter = self.iter_count
792
793
794 spin.f_count = self.f_count
795
796
797 spin.g_count = self.g_count
798
799
800 spin.h_count = self.h_count
801
802
803 spin.warning = self.warning
804
805
806 if memo.sim_index == None:
807
808 proton_mmq_flag = has_proton_mmq_cpmg()
809
810
811 si = 0
812 for spin_index in range(len(memo.spins)):
813
814 if not memo.spins[spin_index].select:
815 continue
816
817
818 pack_back_calc_r2eff(spin=memo.spins[spin_index], spin_id=memo.spin_ids[spin_index], si=si, back_calc=self.back_calc, proton_mmq_flag=proton_mmq_flag)
819
820
821 si += 1
822