parameters: (*, atoms_data: abins.AtomsData, selection: list)
return_statement: return atom_numbers, atom_symbols
docstring: Interpret the user 'Atoms' input as a set of elements and atom indices
  
          (These atom indices match the user-facing convention and begin at 1.)
docstring_summary: Interpret the user 'Atoms' input as a set of elements and atom indices
docstring_tokens: Interpret the user Atoms input as a set of elements and atom indices
function: def get_atom_selection(*, atoms_data: abins.AtomsData, selection: list) -> Tuple[list, list]:
          """Interpret the user 'Atoms' input as a set of elements and atom indices
  
          (These atom indices match the user-facing convention and begin at 1.)"""
  
          num_atoms = len(atoms_data)
          all_atms_smbls = list(set([atoms_data[atom_index]["symbol"]
                                     for atom_index in range(num_atoms)]))
          all_atms_smbls.sort()
  
          if len(selection) == 0:  # case: all atoms
              atom_symbols = all_atms_smbls
              atom_numbers = []
          else:  # case selected atoms
              # Specific atoms are identified with prefix and integer index, e.g 'atom_5'. Other items are element symbols
              # A regular expression match is used to make the underscore separator optional and check the index format
              atom_symbols = [item for item in selection if item[:len(ATOM_PREFIX)] != ATOM_PREFIX]
              if len(atom_symbols) != len(set(atom_symbols)):  # only different types
                  raise ValueError("User atom selection (by symbol) contains repeated species. This is not permitted as "
                                   "Abins cannot create multiple workspaces with the same name.")
  
              numbered_atom_test = re.compile('^' + ATOM_PREFIX + r'_?(\d+)$')
              atom_numbers = [numbered_atom_test.findall(item) for item in selection]  # Matches will be lists of str
              atom_numbers = [int(match[0]) for match in atom_numbers if match]  # Remove empty matches, cast rest to int
  
              if len(atom_numbers) != len(set(atom_numbers)):
                  raise ValueError("User atom selection (by number) contains repeated atom. This is not permitted as Abins"
                                   " cannot create multiple workspaces with the same name.")
  
              for atom_symbol in atom_symbols:
                  if atom_symbol not in all_atms_smbls:
                      raise ValueError("User defined atom selection (by element) '%s': not present in the system." %
                                       atom_symbol)
  
              for atom_number in atom_numbers:
                  if atom_number < 1 or atom_number > num_atoms:
                      raise ValueError("Invalid user atom selection (by number) '%s%s': out of range (%s - %s)" %
                                       (ATOM_PREFIX, atom_number, 1, num_atoms))
  
              # Final sanity check that everything in "atoms" field was understood
              if len(atom_symbols) + len(atom_numbers) < len(selection):
                  elements_report = " Symbols: " + ", ".join(atom_symbols) if len(atom_symbols) else ""
                  numbers_report = " Numbers: " + ", ".join(atom_numbers) if len(atom_numbers) else ""
                  raise ValueError("Not all user atom selections ('atoms' option) were understood."
                                   + elements_report + numbers_report)
  
          return atom_numbers, atom_symbols
function_tokens: def get_atom_selection ( * , atoms_data : abins . AtomsData , selection : list ) -> Tuple [ list , list ] : num_atoms = len ( atoms_data ) all_atms_smbls = list ( set ( [ atoms_data [ atom_index ] [ "symbol" ] for atom_index in range ( num_atoms ) ] ) ) all_atms_smbls . sort ( ) if len ( selection ) == 0 : # case: all atoms atom_symbols = all_atms_smbls atom_numbers = [ ] else : # case selected atoms # Specific atoms are identified with prefix and integer index, e.g 'atom_5'. Other items are element symbols # A regular expression match is used to make the underscore separator optional and check the index format atom_symbols = [ item for item in selection if item [ : len ( ATOM_PREFIX ) ] != ATOM_PREFIX ] if len ( atom_symbols ) != len ( set ( atom_symbols ) ) : # only different types raise ValueError ( "User atom selection (by symbol) contains repeated species. This is not permitted as " "Abins cannot create multiple workspaces with the same name." ) numbered_atom_test = re . compile ( '^' + ATOM_PREFIX + r'_?(\d+)$' ) atom_numbers = [ numbered_atom_test . findall ( item ) for item in selection ] # Matches will be lists of str atom_numbers = [ int ( match [ 0 ] ) for match in atom_numbers if match ] # Remove empty matches, cast rest to int if len ( atom_numbers ) != len ( set ( atom_numbers ) ) : raise ValueError ( "User atom selection (by number) contains repeated atom. This is not permitted as Abins" " cannot create multiple workspaces with the same name." ) for atom_symbol in atom_symbols : if atom_symbol not in all_atms_smbls : raise ValueError ( "User defined atom selection (by element) '%s': not present in the system." % atom_symbol ) for atom_number in atom_numbers : if atom_number < 1 or atom_number > num_atoms : raise ValueError ( "Invalid user atom selection (by number) '%s%s': out of range (%s - %s)" % ( ATOM_PREFIX , atom_number , 1 , num_atoms ) ) # Final sanity check that everything in "atoms" field was understood if len ( atom_symbols ) + len ( atom_numbers ) < len ( selection ) : elements_report = " Symbols: " + ", " . join ( atom_symbols ) if len ( atom_symbols ) else "" numbers_report = " Numbers: " + ", " . join ( atom_numbers ) if len ( atom_numbers ) else "" raise ValueError ( "Not all user atom selections ('atoms' option) were understood." + elements_report + numbers_report ) return atom_numbers , atom_symbols