1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23  """Analysis specific code for the reduced spectral density mapping of relaxation data.""" 
 24   
 25   
 26  from re import search 
 27  from warnings import warn 
 28   
 29   
 30  from generic_fns.interatomic import return_interatom_list 
 31  from generic_fns.mol_res_spin import exists_mol_res_spin_data, return_spin, spin_loop 
 32  from generic_fns import pipes 
 33  from maths_fns.jw_mapping import Mapping 
 34  from physical_constants import N15_CSA, NH_BOND_LENGTH, h_bar, mu0, return_gyromagnetic_ratio 
 35  from relax_errors import RelaxError, RelaxFuncSetupError, RelaxNoSequenceError, RelaxNoValueError, RelaxSpinTypeError 
 36  from relax_warnings import RelaxDeselectWarning 
 37  import specific_fns 
 38  from specific_fns.api_base import API_base 
 39  from specific_fns.api_common import API_common 
 40  from user_functions.data import Uf_tables; uf_tables = Uf_tables() 
 41  from user_functions.objects import Desc_container 
 42   
 43   
 45      """Class containing functions specific to reduced spectral density mapping.""" 
 46   
 48          """Initialise the class by placing API_common methods into the API.""" 
 49   
 50           
 51          super(Jw_mapping, self).__init__() 
 52   
 53           
 54          self.base_data_loop = self._base_data_loop_spin 
 55          self.create_mc_data = self._create_mc_relax_data 
 56          self.model_loop = self._model_loop_spin 
 57          self.return_conversion_factor = self._return_no_conversion_factor 
 58          self.return_error = self._return_error_relax_data 
 59          self.return_value = self._return_value_general 
 60          self.set_param_values = self._set_param_values_spin 
 61          self.set_selected_sim = self._set_selected_sim_spin 
 62          self.sim_pack_data = self._sim_pack_relax_data 
 63   
 64           
 65          self.PARAMS.add('j0', scope='spin', string='J(0)', desc='Spectral density value at 0 MHz', py_type=float, set='params', grace_string='\\qJ(0)\\Q', err=True, sim=True) 
 66          self.PARAMS.add('jwx', scope='spin', string='J(wX)', desc='Spectral density value at the frequency of the heteronucleus', py_type=float, set='params', grace_string='\\qJ(\\xw\\f{}\\sX\\N)\\Q', err=True, sim=True) 
 67          self.PARAMS.add('jwh', scope='spin', string='J(wH)', desc='Spectral density value at the frequency of the proton', py_type=float, set='params', grace_string='\\qJ(\\xw\\f{}\\sH\\N)\\Q', err=True, sim=True) 
 68          self.PARAMS.add('csa', scope='spin', default=N15_CSA, units='ppm', desc='CSA value', py_type=float, grace_string='\\qCSA\\Q') 
  69   
 70   
 72          """Function for selecting which relaxation data to use in the J(w) mapping.""" 
 73   
 74           
 75          pipes.test() 
 76   
 77           
 78          function_type = cdp.pipe_type 
 79          if function_type != 'jw': 
 80              raise RelaxFuncSetupError(specific_fns.setup.get_string(function_type)) 
 81   
 82           
 83          if hasattr(cdp, 'jw_frq'): 
 84              raise RelaxError("The frequency has already been set.") 
 85   
 86           
 87          if not hasattr(cdp, 'jw_frq'): 
 88              cdp.jw_frq = {} 
 89   
 90           
 91          cdp.jw_frq = frq 
  92   
 93   
 94 -    def calculate(self, spin_id=None, verbosity=1, sim_index=None): 
  95          """Calculation of the spectral density values. 
 96   
 97          @keyword spin_id:   The spin identification string. 
 98          @type spin_id:      None or str 
 99          @keyword verbosity: The amount of information to print.  The higher the value, the greater the verbosity. 
100          @type verbosity:    int 
101          @keyword sim_index: The optional MC simulation index. 
102          @type sim_index:    None or int 
103          """ 
104   
105           
106          if not hasattr(cdp, 'jw_frq') or not isinstance(cdp.jw_frq, float): 
107              raise RelaxError("The frequency has not been set up.") 
108   
109           
110          if not exists_mol_res_spin_data(): 
111              raise RelaxNoSequenceError 
112   
113           
114          for spin, id in spin_loop(spin_id, return_id=True): 
115               
116              if not spin.select: 
117                  continue 
118   
119               
120              if not hasattr(spin, 'isotope'): 
121                  raise RelaxSpinTypeError 
122   
123               
124              if not hasattr(spin, 'csa') or spin.csa == None: 
125                  raise RelaxNoValueError("CSA") 
126   
127               
128              interatoms = return_interatom_list(id) 
129              for interatom in interatoms: 
130                   
131                  if not interatom.dipole_pair: 
132                      continue 
133   
134                   
135                  if id != interatom.spin_id1: 
136                      spin_id2 = interatom.spin_id1 
137                  else: 
138                      spin_id2 = interatom.spin_id2 
139                  spin2 = return_spin(spin_id2) 
140   
141                   
142                  if not hasattr(spin2, 'isotope'): 
143                      raise RelaxSpinTypeError 
144   
145                   
146                  if not hasattr(interatom, 'r') or interatom.r == None: 
147                      raise RelaxNoValueError("interatomic distance", spin_id=spin_id, spin_id2=spin_id2) 
148   
149           
150          if cdp.jw_frq not in cdp.frq.values(): 
151              raise RelaxError("No relaxation data corresponding to the frequency " + repr(cdp.jw_frq) + " has been loaded.") 
152   
153           
154          for spin, id in spin_loop(spin_id, return_id=True): 
155               
156              if not spin.select: 
157                  continue 
158   
159               
160              r1 = None 
161              r2 = None 
162              noe = None 
163   
164               
165              for ri_id in cdp.ri_ids: 
166                   
167                  if cdp.frq[ri_id] != cdp.jw_frq: 
168                      continue 
169   
170                   
171                  if cdp.ri_type[ri_id] == 'R1': 
172                      if sim_index == None: 
173                          r1 = spin.ri_data[ri_id] 
174                      else: 
175                          r1 = spin.ri_data_sim[ri_id][sim_index] 
176   
177                   
178                  if cdp.ri_type[ri_id] == 'R2': 
179                      if sim_index == None: 
180                          r2 = spin.ri_data[ri_id] 
181                      else: 
182                          r2 = spin.ri_data_sim[ri_id][sim_index] 
183   
184                   
185                  if cdp.ri_type[ri_id] == 'NOE': 
186                      if sim_index == None: 
187                          noe = spin.ri_data[ri_id] 
188                      else: 
189                          noe = spin.ri_data_sim[ri_id][sim_index] 
190   
191               
192              if r1 == None or r2 == None or noe == None: 
193                  continue 
194   
195               
196              interatoms = return_interatom_list(id) 
197              for i in range(len(interatoms)): 
198                   
199                  if not interatoms[i].dipole_pair: 
200                      continue 
201   
202                   
203                  if id != interatoms[i].spin_id1: 
204                      spin_id2 = interatoms[i].spin_id1 
205                  else: 
206                      spin_id2 = interatoms[i].spin_id2 
207                  spin2 = return_spin(spin_id2) 
208   
209                   
210                  gx = return_gyromagnetic_ratio(spin.isotope) 
211                  gh = return_gyromagnetic_ratio(spin2.isotope) 
212   
213                   
214                  r = interatoms[i].r 
215   
216               
217              self.jw = Mapping(frq=cdp.jw_frq, gx=gx, gh=gh, mu0=mu0, h_bar=h_bar) 
218   
219               
220              j0, jwx, jwh = self.jw.func(r=r, csa=spin.csa, r1=r1, r2=r2, noe=noe) 
221   
222               
223              if sim_index == None: 
224                  spin.j0 = j0 
225                  spin.jwx = jwx 
226                  spin.jwh = jwh 
227   
228               
229              else: 
230                   
231                  self.data_init(spin, sim=1) 
232                  if spin.j0_sim == None: 
233                      spin.j0_sim = [] 
234                      spin.jwx_sim = [] 
235                      spin.jwh_sim = [] 
236   
237                   
238                  spin.j0_sim.append(j0) 
239                  spin.jwx_sim.append(jwx) 
240                  spin.jwh_sim.append(jwh) 
 241   
242   
244          """Initialise the data structures. 
245   
246          @param data_cont:   The data container. 
247          @type data_cont:    instance 
248          @keyword sim:       The Monte Carlo simulation flag, which if true will initialise the simulation data structure. 
249          @type sim:          bool 
250          """ 
251   
252           
253          data_names = self.data_names() 
254   
255           
256          for name in data_names: 
257               
258              if sim: 
259                   
260                  name = name + '_sim' 
261   
262               
263              if not hasattr(data_cont, name): 
264                   
265                  setattr(data_cont, name, None) 
 266   
267   
268      default_value_doc = Desc_container("Reduced spectral density mapping default values") 
269      default_value_doc.add_paragraph("These default values are found in the file 'physical_constants.py'.") 
270      _table = uf_tables.add_table(label="table: J(w) default values", caption="Reduced spectral density mapping default values.") 
271      _table.add_headings(["Data type", "Object name", "Value"]) 
272      _table.add_row(["CSA", "'csa'", "-172 * 1e-6"]) 
273      default_value_doc.add_table(_table.label) 
274   
275   
277          """Deselect spins which _have insufficient data to support calculation. 
278   
279          @keyword data_check:    A flag to signal if the presence of base data is to be checked for. 
280          @type data_check:       bool 
281          @keyword verbose:       A flag which if True will allow printouts. 
282          @type verbose:          bool 
283          """ 
284   
285           
286          if verbose: 
287              print("\nOver-fit spin deselection:") 
288   
289           
290          if not exists_mol_res_spin_data(): 
291              raise RelaxNoSequenceError 
292   
293           
294          deselect_flag = False 
295          for spin, spin_id in spin_loop(return_id=True): 
296               
297              if not spin.select: 
298                  continue 
299   
300               
301              if not hasattr(spin, 'ri_data'): 
302                  warn(RelaxDeselectWarning(spin_id, 'missing relaxation data')) 
303                  spin.select = False 
304                  deselect_flag = True 
305                  continue 
306   
307               
308              else: 
309                   
310                  data_points = 0 
311                  for id in cdp.ri_ids: 
312                      if id in spin.ri_data and spin.ri_data[id] != None: 
313                          data_points += 1 
314   
315                   
316                  if data_points < 3: 
317                      warn(RelaxDeselectWarning(spin_id, 'insufficient relaxation data, 3 or more data points are required')) 
318                      spin.select = False 
319                      deselect_flag = True 
320                      continue 
321   
322           
323          if verbose and not deselect_flag: 
324              print("No spins have been deselected.") 
 325   
326   
327      return_data_name_doc = Desc_container("Reduced spectral density mapping data type string matching patterns") 
328      _table = uf_tables.add_table(label="table: J(w) data types", caption="Reduced spectral density mapping data type string matching patterns.") 
329      _table.add_headings(["Data type", "Object name"]) 
330      _table.add_row(["J(0)", "'j0'"]) 
331      _table.add_row(["J(wX)", "'jwx'"]) 
332      _table.add_row(["J(wH)", "'jwh'"]) 
333      _table.add_row(["CSA", "'csa'"]) 
334      return_data_name_doc.add_table(_table.label) 
335   
336   
337      set_doc = Desc_container("Reduced spectral density mapping set details") 
338      set_doc.add_paragraph("In reduced spectral density mapping, three values must be set prior to the calculation of spectral density values:  the bond length, CSA, and heteronucleus type.") 
339   
340   
341 -    def set_error(self, model_info, index, error): 
 342          """Set the parameter errors. 
343   
344          @param model_info:  The spin container originating from model_loop(). 
345          @type model_info:   SpinContainer instance 
346          @param index:       The index of the parameter to set the errors for. 
347          @type index:        int 
348          @param error:       The error value. 
349          @type error:        float 
350          """ 
351   
352           
353          spin = model_info 
354   
355           
356          if index == 0: 
357              spin.j0_err = error 
358   
359           
360          if index == 1: 
361              spin.jwx_err = error 
362   
363           
364          if index == 2: 
365              spin.jwh_err = error 
 366   
367   
369          """Return the array of simulation parameter values. 
370   
371          @param model_info:  The spin container originating from model_loop(). 
372          @type model_info:   SpinContainer instance 
373          @param index:       The index of the parameter to return the array of values for. 
374          @type index:        int 
375          @return:            The array of simulation parameter values. 
376          @rtype:             list of float 
377          """ 
378   
379           
380          spin = model_info 
381   
382           
383          if not spin.select: 
384              return 
385   
386           
387          if index == 0: 
388              return spin.j0_sim 
389   
390           
391          if index == 1: 
392              return spin.jwx_sim 
393   
394           
395          if index == 2: 
396              return spin.jwh_sim 
 397   
398   
400          """Return the array of selected simulation flags. 
401   
402          @param model_info:  The spin container originating from model_loop(). 
403          @type model_info:   SpinContainer instance 
404          @return:            The array of selected simulation flags. 
405          @rtype:             list of int 
406          """ 
407   
408           
409          spin = model_info 
410   
411           
412          return spin.select_sim 
  413