def run(self, processor, completed): """Set up and perform the optimisation.""" # Print out. if self.verbosity >= 1: # Individual spin block section. top = 2 if self.verbosity >= 2: top += 2 subsection(file=sys.stdout, text="Fitting to the spin block %s"%self.spin_ids, prespace=top) # Grid search printout. if search('^[Gg]rid', self.min_algor): result = 1 for x in self.inc: result = mul(result, x) print("Unconstrained grid search size: %s (constraints may decrease this size).\n" % result) # Initialise the function to minimise. 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) # Grid search. if search('^[Gg]rid', self.min_algor): 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) # Unpack the results. param_vector, chi2, iter_count, warning = results f_count = iter_count g_count = 0.0 h_count = 0.0 # Minimisation. else: 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) # Unpack the results. if results == None: return param_vector, chi2, iter_count, f_count, g_count, h_count, warning = results # Optimisation printout. if self.verbosity: print("\nOptimised parameter values:") for i in range(len(param_vector)): print("%-20s %25.15f" % (self.param_names[i], param_vector[i]*self.scaling_matrix[i, i])) # Create the result command object to send back to the master. 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))
def __init__(self, exp_type=None, num_spins=1, model=None, r2=None, r2a=None, r2b=None, phi_ex=None, phi_ex_B=None, phi_ex_C=None, dw=None, dw_AB=None, dw_BC=None, dwH=None, dwH_AB=None, dwH_BC=None, pA=None, pB=None, kex=None, kex_AB=None, kex_BC=None, kex_AC=None, kB=None, kC=None, k_AB=None, tex=None, spins_params=None): """Special method __init__() is called first (acts as Constructor). It brings in data from outside the class like the variable num_spins (in this case num_spins is also set to a default value of 1). The first parameter of any method/function in the class is always self, the name self is used by convention. Assigning num_spins to self.num_spins allows it to be passed to all methods within the class. Think of self as a carrier, or if you want impress folks call it target instance object. @keyword exp_type: The list of experiment types. @type exp_type: list of str @keyword num_spins: Number of spins in the cluster. @type num_spins: integer @keyword model: The dispersion model to instantiate the Dispersion class with. @type model: string @keyword r2: The transversal relaxation rate. @type r2: float @keyword r2a: The transversal relaxation rate for state A in the absence of exchange. @type r2a: float @keyword r2b: The transversal relaxation rate for state B in the absence of exchange. @type r2b: float @keyword phi_ex: The phi_ex = pA.pB.dw**2 value (ppm^2) @type phi_ex: float @keyword phi_ex_B: The fast exchange factor between sites A and B (ppm^2) @type phi_ex_B: float @keyword phi_ex_C: The fast exchange factor between sites A and C (ppm^2) @type phi_ex_C: float @keyword dw: The chemical exchange difference between states A and B in ppm. @type dw: float @keyword pA: The population of state A. @type pA: float @keyword kex: The rate of exchange. @type kex: float @keyword kB : The rate of exchange. @type kB: float @keyword kC: The rate of exchange. @type kC: float @keyword k_AB: The exchange rate from state A to state B @type k_AB: float @keyword tex: The exchange time. @type tex: float @keyword spins_params: List of parameter strings used in dispersion model. @type spins_params: array of strings """ # Define parameters self.exp_type = exp_type self.model = model self.num_spins = num_spins #self.fields = array([800. * 1E6]) #self.fields = array([600. * 1E6, 800. * 1E6]) self.fields = array([600. * 1E6, 800. * 1E6, 900. * 1E6]) # Set The spin-lock field strength, nu1, in Hz self.spin_lock_fields = [431.0, 651.2, 800.5, 984.0, 1341.11] # Required data structures. self.relax_times = self.fields / (100 * 100. * 1E6) self.ncycs = [] self.points = [] self.value = [] self.error = [] for i in range(len(self.fields)): ncyc = arange(2, 1000. * self.relax_times[i], 4) #ncyc = arange(2, 42, 2) self.ncycs.append(ncyc) print("sfrq: ", self.fields[i], "number of cpmg frq", len(ncyc), ncyc) # CPMG data. if EXP_TYPE_CPMG_SQ in self.exp_type or EXP_TYPE_CPMG_MQ in self.exp_type: cpmg_point = ncyc / self.relax_times[i] self.points.append(list(cpmg_point)) self.value.append([2.0] * len(cpmg_point)) self.error.append([1.0] * len(cpmg_point)) # R1rho data. else: points = self.spin_lock_fields self.points.append(list(points)) self.value.append([2.0] * len(self.spin_lock_fields)) self.error.append([1.0] * len(self.spin_lock_fields)) # Spin lock offsets in ppm. if EXP_TYPE_CPMG_SQ in self.exp_type or EXP_TYPE_CPMG_MQ in self.exp_type: self.offsets = [0] else: self.offsets = list(range(10)) # Chemical shift in ppm. self.chemical_shift = 1.0 # Assemble param vector. self.params = self.assemble_param_vector(r2=r2, r2a=r2a, r2b=r2b, phi_ex=phi_ex, phi_ex_B=phi_ex_B, phi_ex_C=phi_ex_C, dw=dw, dw_AB=dw_AB, dw_BC=dw_BC, dwH=dwH, dwH_AB=dwH_AB, dwH_BC=dwH_BC, pA=pA, pB=pB, kex=kex, kex_AB=kex_AB, kex_BC=kex_BC, kex_AC=kex_AC, kB=kB, kC=kC, k_AB=k_AB, tex=tex, spins_params=spins_params) # Make nested list arrays of data. And return them. values, errors, cpmg_frqs, missing, frqs, frqs_H, exp_types, relax_times, offsets, spin_lock_nu1 = self.return_r2eff_arrays( ) # The offset and R1 data. chemical_shifts, offsets, tilt_angles, Delta_omega, w_eff = self.return_offset_data( ) r1 = ones([self.num_spins, self.fields.shape[0]]) # relax version compatibility. self.relax_times_compat = relax_times if version == 'repository checkout' or version_comparison( version, '3.2.3') == 1: self.relax_times_compat = [] for ei in range(len(self.exp_type)): self.relax_times_compat.append([]) for mi in range(len(self.fields)): self.relax_times_compat[ei].append([]) for oi in range(len(self.offsets)): self.relax_times_compat[ei][mi].append([]) for di in range(len(self.points[mi])): self.relax_times_compat[ei][mi][oi].append( self.relax_times.tolist()) # Init the Dispersion class. self.model = Dispersion(model=self.model, num_params=None, num_spins=self.num_spins, num_frq=len(self.fields), 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=self.relax_times_compat, scaling_matrix=None)
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): """Back-calculation of R2eff/R1rho values for the given spin. @keyword spins: The list of specific spin data container for cluster. @type spins: List of SpinContainer instances @keyword spin_ids: The list of spin ID strings for the spin containers in cluster. @type spin_ids: list of str @keyword cpmg_frqs: The CPMG frequencies to use instead of the user loaded values - to enable interpolation. @type cpmg_frqs: list of lists of numpy rank-1 float arrays @keyword spin_lock_offset: The spin-lock offsets to use instead of the user loaded values - to enable interpolation. @type spin_lock_offset: list of lists of numpy rank-1 float arrays @keyword spin_lock_nu1: The spin-lock field strengths to use instead of the user loaded values - to enable interpolation. @type spin_lock_nu1: list of lists of numpy rank-1 float arrays @keyword relax_times_new: The interpolated experiment specific fixed time period for relaxation (in seconds). The dimensions are {Ei, Mi, Oi, Di, Ti}. @type relax_times_new: rank-4 list of floats @keyword store_chi2: A flag which if True will cause the spin specific chi-squared value to be stored in the spin container. @type store_chi2: bool @return: The back-calculated R2eff/R1rho value for the given spin. @rtype: numpy rank-1 float array """ # Create the initial parameter vector. param_vector = assemble_param_vector(spins=spins) # Number of spectrometer fields. fields = [None] field_count = 1 if hasattr(cdp, 'spectrometer_frq_count'): fields = cdp.spectrometer_frq_list field_count = cdp.spectrometer_frq_count # Initialise the data structures for the target function. 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) # The offset and R1 data. r1_setup() 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) r1 = return_r1_data(spins=spins, spin_ids=spin_ids, field_count=field_count) r1_fit = is_r1_optimised(spins[0].model) # The relaxation times. if relax_times_new != None: relax_times = relax_times_new # The dispersion data. recalc_tau = True if cpmg_frqs == None and spin_lock_nu1 == None and spin_lock_offset == None: cpmg_frqs = return_cpmg_frqs(ref_flag=False) spin_lock_nu1 = return_spin_lock_nu1(ref_flag=False) # Reset the cpmg_frqs if interpolating R1rho models. elif cpmg_frqs == None and spin_lock_offset != None: cpmg_frqs = None spin_lock_nu1 = spin_lock_fields_inter recalc_tau = False values = [] errors = [] missing = [] for exp_type, ei in loop_exp(return_indices=True): values.append([]) errors.append([]) missing.append([]) for si in range(len(spins)): values[ei].append([]) errors[ei].append([]) missing[ei].append([]) for frq, mi in loop_frq(return_indices=True): values[ei][si].append([]) errors[ei][si].append([]) missing[ei][si].append([]) for oi, offset in enumerate(offsets[ei][si][mi]): num = len(spin_lock_nu1[ei][mi][oi]) values[ei][si][mi].append(zeros(num, float64)) errors[ei][si][mi].append(ones(num, float64)) missing[ei][si][mi].append(zeros(num, int32)) # Reconstruct the structures for interpolation. else: recalc_tau = False values = [] errors = [] missing = [] for exp_type, ei in loop_exp(return_indices=True): values.append([]) errors.append([]) missing.append([]) for si in range(len(spins)): values[ei].append([]) errors[ei].append([]) missing[ei].append([]) for frq, mi in loop_frq(return_indices=True): values[ei][si].append([]) errors[ei][si].append([]) missing[ei][si].append([]) for offset, oi in loop_offset(exp_type=exp_type, frq=frq, return_indices=True): if exp_type in EXP_TYPE_LIST_CPMG: num = len(cpmg_frqs[ei][mi][oi]) else: num = len(spin_lock_nu1[ei][mi][oi]) values[ei][si][mi].append(zeros(num, float64)) errors[ei][si][mi].append(ones(num, float64)) missing[ei][si][mi].append(zeros(num, int32)) # Initialise the relaxation dispersion fit functions. 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) # Make a single function call. This will cause back calculation and the data will be stored in the class instance. chi2 = model.func(param_vector) # Store the chi-squared value. if store_chi2: for spin in spins: spin.chi2 = chi2 # Return the structure. return model.get_back_calc()