1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23  """Module for selecting and deselecting spins.""" 
 24   
 25   
 26  from warnings import warn 
 27   
 28   
 29  from lib.errors import RelaxError, RelaxNoDomainError, RelaxNoSequenceError 
 30  from lib.selection import Selection, spin_id_to_data_list 
 31  from lib.sequence import read_spin_data 
 32  from lib.warnings import RelaxNoSpinWarning 
 33  from pipe_control import pipes 
 34  from pipe_control.interatomic import interatomic_loop 
 35  from pipe_control.mol_res_spin import exists_mol_res_spin_data, generate_spin_id_unique, return_spin, spin_loop 
 36  from user_functions.data import Uf_tables; uf_tables = Uf_tables() 
 37  from user_functions.objects import Desc_container 
 38   
 39   
 40  boolean_doc = Desc_container("Boolean operators") 
 41  boolean_doc.add_paragraph("The boolean operator can be used to change how spin systems or interatomic data containers are selected.  The allowed values are: 'OR', 'NOR', 'AND', 'NAND', 'XOR', 'XNOR'.  The following table details how the selections will occur for the different boolean operators.") 
 42  table = uf_tables.add_table(label="table: bool operators", caption="Boolean operators and their effects on selections") 
 43  table.add_headings(["Spin system or interatomic data container", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) 
 44  table.add_row(["Original selection", "0", "1", "1", "1", "1", "0", "1", "0", "1"]) 
 45  table.add_row(["New selection", "0", "1", "1", "1", "1", "1", "0", "0", "0"]) 
 46  table.add_row(["OR", "0", "1", "1", "1", "1", "1", "1", "0", "1"]) 
 47  table.add_row(["NOR", "1", "0", "0", "0", "0", "0", "0", "1", "0"]) 
 48  table.add_row(["AND", "0", "1", "1", "1", "1", "0", "0", "0", "0"]) 
 49  table.add_row(["NAND", "1", "0", "0", "0", "0", "1", "1", "1", "1"]) 
 50  table.add_row(["XOR", "0", "0", "0", "0", "0", "1", "1", "0", "1"]) 
 51  table.add_row(["XNOR", "1", "1", "1", "1", "1", "0", "0", "1", "0"]) 
 52  boolean_doc.add_table(table.label) 
 53   
 54   
 56      """Return the new boolean deselection result using the current selection. 
 57   
 58      @keyword current:   The current selection state. 
 59      @type current:      bool 
 60      @keyword boolean:   The boolean operator used to select with.  It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. 
 61      @type boolean:      str 
 62      @return:            The new selection state. 
 63      @rtype:             bool 
 64      """ 
 65   
 66       
 67      if boolean == 'OR': 
 68          state = current or False 
 69      elif boolean == 'NOR': 
 70          state = not (current or False) 
 71      elif boolean == 'AND': 
 72          state = current and False 
 73      elif boolean == 'NAND': 
 74          state = not (current and False) 
 75      elif boolean == 'XOR': 
 76          state = not (current and False) and (current or False) 
 77      elif boolean == 'XNOR': 
 78          state = (current and False) or not (current or False) 
 79      else: 
 80          raise RelaxError("Unknown boolean operator " + repr(boolean)) 
 81   
 82       
 83      return state 
  84   
 85   
 87      """Return the new boolean selection result using the current selection. 
 88   
 89      @keyword current:   The current selection state. 
 90      @type current:      bool 
 91      @keyword boolean:   The boolean operator used to select with.  It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. 
 92      @type boolean:      str 
 93      @return:            The new selection state. 
 94      @rtype:             bool 
 95      """ 
 96   
 97       
 98      if boolean == 'OR': 
 99          state = current or True 
100      elif boolean == 'NOR': 
101          state = not (current or True) 
102      elif boolean == 'AND': 
103          state = current and True 
104      elif boolean == 'NAND': 
105          state = not (current and True) 
106      elif boolean == 'XOR': 
107          state = not (current and True) and (current or True) 
108      elif boolean == 'XNOR': 
109          state = (current and True) or not (current or True) 
110      else: 
111          raise RelaxError("Unknown boolean operator " + repr(boolean)) 
112   
113       
114      return state 
 115   
116   
133   
134   
135 -def desel_interatom(spin_id1=None, spin_id2=None, boolean='AND', change_all=False): 
 136      """Deselect specific interatomic data containers. 
137   
138      @keyword spin_id1:              The spin ID string of the first spin of the pair. 
139      @type spin_id1:                 str or None 
140      @keyword spin_id2:              The spin ID string of the second spin of the pair. 
141      @type spin_id2:                 str or None 
142      @param boolean:                 The boolean operator used to deselect the spin systems with.  It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. This will be ignored if the change_all flag is set. 
143      @type boolean:                  str 
144      @keyword change_all:            A flag which if True will cause all spins not specified in the file to be selected.  Only the boolean operator 'AND' is compatible with this flag set to True (all others will be ignored). 
145      @type change_all:               bool 
146      @raises RelaxNoSequenceError:   If no molecule/residue/spins sequence data exists. 
147      @raises RelaxError:             If the boolean operator is unknown. 
148      """ 
149   
150       
151      pipes.test() 
152   
153       
154      if not exists_mol_res_spin_data(): 
155          raise RelaxNoSequenceError 
156   
157       
158      if change_all: 
159           
160          for interatom in interatomic_loop(skip_desel=False): 
161              interatom.select = True 
162   
163       
164      for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2, skip_desel=False): 
165           
166          if change_all: 
167              interatom.select = False 
168   
169           
170          else: 
171              interatom.select = boolean_deselect(current=interatom.select, boolean=boolean) 
 172   
173   
174 -def desel_read(file=None, dir=None, file_data=None, spin_id_col=None, mol_name_col=None, res_num_col=None, res_name_col=None, spin_num_col=None, spin_name_col=None, sep=None, spin_id=None, boolean='AND', change_all=False): 
 175      """Deselect the spins contained in the given file. 
176   
177      @keyword file:                  The name of the file to open. 
178      @type file:                     str 
179      @keyword dir:                   The directory containing the file (defaults to the current 
180                                      directory if None). 
181      @type dir:                      str or None 
182      @keyword file_data:             An alternative opening a file, if the data already exists in the 
183                                      correct format.  The format is a list of lists where the first 
184                                      index corresponds to the row and the second the column. 
185      @type file_data:                list of lists 
186      @keyword spin_id_col:           The column containing the spin ID strings.  If supplied, the 
187                                      mol_name_col, res_name_col, res_num_col, spin_name_col, and 
188                                      spin_num_col arguments must be none. 
189      @type spin_id_col:              int or None 
190      @keyword mol_name_col:          The column containing the molecule name information.  If 
191                                      supplied, spin_id_col must be None. 
192      @type mol_name_col:             int or None 
193      @keyword res_name_col:          The column containing the residue name information.  If 
194                                      supplied, spin_id_col must be None. 
195      @type res_name_col:             int or None 
196      @keyword res_num_col:           The column containing the residue number information.  If 
197                                      supplied, spin_id_col must be None. 
198      @type res_num_col:              int or None 
199      @keyword spin_name_col:         The column containing the spin name information.  If supplied, 
200                                      spin_id_col must be None. 
201      @type spin_name_col:            int or None 
202      @keyword spin_num_col:          The column containing the spin number information.  If supplied, 
203                                      spin_id_col must be None. 
204      @type spin_num_col:             int or None 
205      @keyword sep:                   The column separator which, if None, defaults to whitespace. 
206      @type sep:                      str or None 
207      @keyword spin_id:               The spin ID string used to restrict data loading to a subset of 
208                                      all spins. 
209      @type spin_id:                  None or str 
210      @param boolean:                 The boolean operator used to deselect the spin systems with.  It 
211                                      can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. 
212                                      This will be ignored if the change_all flag is set. 
213      @type boolean:                  str 
214      @keyword change_all:            A flag which if True will cause all spins not specified in the 
215                                      file to be selected.  Only the boolean operator 'AND' is 
216                                      compatible with this flag set to True (all others will be 
217                                      ignored). 
218      @type change_all:               bool 
219      @raises RelaxNoSequenceError:   If no molecule/residue/spins sequence data exists. 
220      @raises RelaxError:             If the boolean operator is unknown. 
221      """ 
222   
223       
224      pipes.test() 
225   
226       
227      if not exists_mol_res_spin_data(): 
228          raise RelaxNoSequenceError 
229   
230       
231      if change_all: 
232          for spin in spin_loop(): 
233              spin.select = True 
234   
235       
236      ids = [] 
237      for mol_name, res_num, res_name, spin_num, spin_name in read_spin_data(file=file, dir=dir, file_data=file_data, spin_id_col=spin_id_col, mol_name_col=mol_name_col, res_num_col=res_num_col, res_name_col=res_name_col, spin_num_col=spin_num_col, spin_name_col=spin_name_col, sep=sep, spin_id=spin_id): 
238           
239          id = generate_spin_id_unique(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name) 
240          spin = return_spin(id) 
241   
242           
243          if spin == None: 
244              warn(RelaxNoSpinWarning(id)) 
245              continue 
246   
247           
248          if change_all: 
249              spin.select = False 
250   
251           
252          else: 
253              spin.select = boolean_deselect(current=spin.select, boolean=boolean) 
254   
255           
256          if not spin.select: 
257              ids.append(id) 
258   
259       
260      if not len(ids): 
261          print("No spins deselected.") 
262      else: 
263          print("The following spins were deselected:") 
264          for id in ids: 
265              print(id) 
 266   
267   
268 -def desel_spin(spin_id=None, boolean='AND', change_all=False): 
 269      """Deselect specific spins. 
270   
271      @keyword spin_id:               The spin identification string. 
272      @type spin_id:                  str or None 
273      @param boolean:                 The boolean operator used to deselect the spin systems with.  It 
274                                      can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. 
275                                      This will be ignored if the change_all flag is set. 
276      @type boolean:                  str 
277      @keyword change_all:            A flag which if True will cause all spins not specified in the 
278                                      file to be selected.  Only the boolean operator 'AND' is 
279                                      compatible with this flag set to True (all others will be 
280                                      ignored). 
281      @type change_all:               bool 
282      @raises RelaxNoSequenceError:   If no molecule/residue/spins sequence data exists. 
283      @raises RelaxError:             If the boolean operator is unknown. 
284      """ 
285   
286       
287      pipes.test() 
288   
289       
290      if not exists_mol_res_spin_data(): 
291          raise RelaxNoSequenceError 
292   
293       
294      if change_all: 
295          for spin in spin_loop(): 
296              spin.select = True 
297   
298       
299      for spin in spin_loop(spin_id): 
300           
301          if change_all: 
302              spin.select = False 
303   
304           
305          else: 
306              spin.select = boolean_deselect(current=spin.select, boolean=boolean) 
 307   
308   
310      """Query if the molecule is selected. 
311   
312      @keyword selection:     The molecule ID string. 
313      @type selection:        str 
314      """ 
315   
316       
317      select = False 
318      for spin in spin_loop(selection): 
319          if spin.select: 
320              select = True 
321              break 
322   
323       
324      return select 
 325   
326   
328      """Query if the residue is selected. 
329   
330      @keyword selection:     The residue ID string. 
331      @type selection:        str 
332      """ 
333   
334       
335      select = False 
336      for spin in spin_loop(selection): 
337          if spin.select: 
338              select = True 
339              break 
340   
341       
342      return select 
 343   
344   
346      """Query if the spin is selected. 
347   
348      @keyword selection:     The molecule ID string. 
349      @type selection:        str 
350      """ 
351   
352       
353      spin = return_spin(selection) 
354   
355       
356      return spin.select 
 357   
358   
381   
382   
399   
400   
401 -def sel_domain(domain_id=None, boolean='OR', change_all=False): 
 402      """Select all spins and interatomic data containers of the given domain. 
403   
404      @keyword domain_id:     The domain ID string. 
405      @type domain_id:        str or None 
406      @param boolean:         The boolean operator used to select the spin systems with.  It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. This will be ignored if the change_all flag is set. 
407      @type boolean:          str 
408      @keyword change_all:    A flag which if True will cause all spins and interatomic data containers outside of the domain to be deselected. 
409      @type change_all:       bool 
410      """ 
411   
412       
413      pipes.test() 
414   
415       
416      if not hasattr(cdp, 'domain') or domain_id not in cdp.domain: 
417          raise RelaxNoDomainError(domain_id) 
418   
419       
420      domain = Selection(cdp.domain[domain_id]) 
421   
422       
423      for spin, mol_name, res_num, res_name in spin_loop(full_info=True): 
424           
425          if domain.contains_spin(spin_name=spin.name, spin_num=spin.num, res_name=res_name, res_num=res_num, mol=mol_name): 
426              spin.select = boolean_select(current=spin.select, boolean=boolean) 
427   
428           
429          elif change_all: 
430              spin.select = False 
431   
432       
433      for interatom in interatomic_loop(): 
434           
435          mol_name1, res_num1, res_name1, spin_num1, spin_name1 = spin_id_to_data_list(interatom.spin_id1) 
436          mol_name2, res_num2, res_name2, spin_num2, spin_name2 = spin_id_to_data_list(interatom.spin_id2) 
437   
438           
439          if domain.contains_spin(spin_name=spin_name1, spin_num=spin_num1, res_name=res_name1, res_num=res_num1, mol=mol_name1) or domain.contains_spin(spin_name=spin_name2, spin_num=spin_num2, res_name=res_name2, res_num=res_num2, mol=mol_name2): 
440              interatom.select = boolean_select(current=interatom.select, boolean=boolean) 
441   
442           
443          elif change_all: 
444              interatom.select = False 
 445   
446   
447 -def sel_interatom(spin_id1=None, spin_id2=None, boolean='OR', change_all=False): 
 448      """Select specific interatomic data containers. 
449   
450      @keyword spin_id1:              The spin ID string of the first spin of the pair. 
451      @type spin_id1:                 str or None 
452      @keyword spin_id2:              The spin ID string of the second spin of the pair. 
453      @type spin_id2:                 str or None 
454      @param boolean:                 The boolean operator used to select the spin systems with.  It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'.  This will be ignored if the change_all flag is set. 
455      @type boolean:                  str 
456      @keyword change_all:            A flag which if True will cause all spins not specified in the file to be deselected.  Only the boolean operator 'OR' is compatible with this flag set to True (all others will be ignored). 
457      @type change_all:               bool 
458      @raises RelaxNoSequenceError:   If no molecule/residue/spins sequence data exists. 
459      @raises RelaxError:             If the boolean operator is unknown. 
460      """ 
461   
462       
463      pipes.test() 
464   
465       
466      if not exists_mol_res_spin_data(): 
467          raise RelaxNoSequenceError 
468   
469       
470      if change_all: 
471           
472          for interatom in interatomic_loop(skip_desel=False): 
473              interatom.select = False 
474   
475       
476      for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2, skip_desel=False): 
477           
478          if change_all: 
479              interatom.select = True 
480   
481           
482          else: 
483              interatom.select = boolean_select(current=interatom.select, boolean=boolean) 
 484   
485   
486 -def sel_read(file=None, dir=None, file_data=None, spin_id_col=None, mol_name_col=None, res_num_col=None, res_name_col=None, spin_num_col=None, spin_name_col=None, sep=None, spin_id=None, boolean='OR', change_all=False): 
 487      """Select the spins contained in the given file. 
488   
489      @keyword file:                  The name of the file to open. 
490      @type file:                     str 
491      @keyword dir:                   The directory containing the file (defaults to the current 
492                                      directory if None). 
493      @type dir:                      str or None 
494      @keyword file_data:             An alternative opening a file, if the data already exists in the 
495                                      correct format.  The format is a list of lists where the first 
496                                      index corresponds to the row and the second the column. 
497      @type file_data:                list of lists 
498      @keyword spin_id_col:           The column containing the spin ID strings.  If supplied, the 
499                                      mol_name_col, res_name_col, res_num_col, spin_name_col, and 
500                                      spin_num_col arguments must be none. 
501      @type spin_id_col:              int or None 
502      @keyword mol_name_col:          The column containing the molecule name information.  If 
503                                      supplied, spin_id_col must be None. 
504      @type mol_name_col:             int or None 
505      @keyword res_name_col:          The column containing the residue name information.  If 
506                                      supplied, spin_id_col must be None. 
507      @type res_name_col:             int or None 
508      @keyword res_num_col:           The column containing the residue number information.  If 
509                                      supplied, spin_id_col must be None. 
510      @type res_num_col:              int or None 
511      @keyword spin_name_col:         The column containing the spin name information.  If supplied, 
512                                      spin_id_col must be None. 
513      @type spin_name_col:            int or None 
514      @keyword spin_num_col:          The column containing the spin number information.  If supplied, 
515                                      spin_id_col must be None. 
516      @type spin_num_col:             int or None 
517      @keyword sep:                   The column separator which, if None, defaults to whitespace. 
518      @type sep:                      str or None 
519      @keyword spin_id:               The spin ID string used to restrict data loading to a subset of 
520                                      all spins. 
521      @type spin_id:                  None or str 
522      @param boolean:                 The boolean operator used to select the spin systems with.  It 
523                                      can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. 
524                                      This will be ignored if the change_all flag is set. 
525      @type boolean:                  str 
526      @keyword change_all:            A flag which if True will cause all spins not specified in the 
527                                      file to be deselected.  Only the boolean operator 'OR' is 
528                                      compatible with this flag set to True (all others will be 
529                                      ignored). 
530      @type change_all:               bool 
531      @raises RelaxNoSequenceError:   If no molecule/residue/spins sequence data exists. 
532      @raises RelaxError:             If the boolean operator is unknown. 
533      """ 
534   
535       
536      pipes.test() 
537   
538       
539      if not exists_mol_res_spin_data(): 
540          raise RelaxNoSequenceError 
541   
542       
543      if change_all: 
544           
545          for spin in spin_loop(): 
546              spin.select = False 
547   
548       
549      ids = [] 
550      for id in read_spin_data(file=file, dir=dir, file_data=file_data, spin_id_col=spin_id_col, mol_name_col=mol_name_col, res_num_col=res_num_col, res_name_col=res_name_col, spin_num_col=spin_num_col, spin_name_col=spin_name_col, sep=sep, spin_id=spin_id): 
551           
552          spin = return_spin(id) 
553   
554           
555          if spin == None: 
556              warn(RelaxNoSpinWarning(id)) 
557              continue 
558   
559           
560          if change_all: 
561              spin.select = True 
562   
563           
564          else: 
565              spin.select = boolean_select(current=spin.select, boolean=boolean) 
566   
567           
568          if spin.select: 
569              ids.append(id) 
570   
571       
572      if not len(ids): 
573          print("No spins selected.") 
574      else: 
575          print("The following spins were selected:") 
576          for id in ids: 
577              print(id) 
 578   
579   
580 -def sel_spin(spin_id=None, boolean='OR', change_all=False): 
 581      """Select specific spins. 
582   
583      @keyword spin_id:               The spin identification string. 
584      @type spin_id:                  str or None 
585      @param boolean:                 The boolean operator used to select the spin systems with.  It 
586                                      can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. 
587                                      This will be ignored if the change_all flag is set. 
588      @type boolean:                  str 
589      @keyword change_all:            A flag which if True will cause all spins not specified in the 
590                                      file to be deselected.  Only the boolean operator 'OR' is 
591                                      compatible with this flag set to True (all others will be 
592                                      ignored). 
593      @type change_all:               bool 
594      @raises RelaxNoSequenceError:   If no molecule/residue/spins sequence data exists. 
595      @raises RelaxError:             If the boolean operator is unknown. 
596      """ 
597   
598       
599      pipes.test() 
600   
601       
602      if not exists_mol_res_spin_data(): 
603          raise RelaxNoSequenceError 
604   
605       
606      if change_all: 
607           
608          for spin in spin_loop(): 
609              spin.select = False 
610   
611       
612      for spin in spin_loop(spin_id): 
613           
614          if change_all: 
615              spin.select = True 
616   
617           
618          else: 
619              spin.select = boolean_select(current=spin.select, boolean=boolean) 
 620