Select atoms
************

The ChemicalSystem keeps track of a set of selected atoms. In the GUI,
an atom is selected by simply clicking on it, and the current
selection is highlighted by a cyan outline and shading.

The following methods allow you to inspect the current selection:

ChemicalSystem.num_selected_atoms() -> int

   The number of currently selected atoms.

ChemicalSystem.is_atom_selected(atom: int | Atom) -> bool

   Checks if an atom is currently selected.

ChemicalSystem.get_selected_atoms() -> ndarray[Any, dtype[int64]]

   Returns an array of indices of all selected atoms.

You can also use the "$" symbol to refer to the set of currently
selected atoms in region expressions. The following bit of code loops
over all selected atoms in the region named "myregion":

   for atidx in mol.get_atoms_in_region("$ & myregion"):
        ...

There are many methods to change the current selection. Almost all of
them work by adding or removing atoms from the current selection, e.g.
the "select_atom" method adds an atom to the current selection and is
equivalent to clicking it in the GUI. The exception to this is the
"set_selected_atoms" method, which completely replaces the current
selection.

Note that the order in which atoms are selected is tracked for small
selections. Small selections of up to 4 atoms are used in the GUI for
interactive manipulation in internal coordinates using the sliders at
the bottom of the molecule view. The selection order is relevant for
manipulations of e.g. dihedral angles, as the dihedral angle between
atoms "(3,1,2,4)" is different from between atoms "(1,2,3,4)". For
large selections (>10 atoms) there are no use cases in which the
selection order is relevant and, for performance reasons
"get_selected_atoms" always returns the indices of the selected atoms
in ascending order.

Basic methods to change the current selection:

ChemicalSystem.select_atom(atom: int | Atom) -> None

   Selects an atom, i.e. adds it to the current selection.

ChemicalSystem.deselect_atom(atom: int | Atom) -> None

   Deselects an atom, i.e. removes it from the current selection.

ChemicalSystem.select_atoms(atom_indices: ArrayLike) -> None

   Selects multiple atoms at once, given their atom indices.

ChemicalSystem.deselect_atoms(atom_indices: ArrayLike) -> None

   Deselects multiple atoms at once, given their atom indices.

ChemicalSystem.set_selected_atoms(atom_indices: ArrayLike) -> None

   Sets the selection to the given atom indices. Any previous
   selection is cleared.

GUI style methods from AMSinput:

ChemicalSystem.select_all() -> None

   Selects all atoms.

ChemicalSystem.deselect_all() -> None

   Deselects all atoms, or in other words: clears the current
   selection.

ChemicalSystem.invert_selection() -> None

   Inverts the set of selected atoms.

   All previously unselected atoms will become selected. All
   previously selected atoms will become unselected.

ChemicalSystem.select_connected() -> None

   Selects all atoms bonded to the currently selected atoms.

ChemicalSystem.select_molecule() -> None

   Using the bonds, selects entire molecules that include any
   currently selected atom.

   This is equivalent to repeatedly calling "select_connected" until
   the selection stops growing.

ChemicalSystem.select_region(region: str) -> None

   Selects atoms in a region or region expression.

ChemicalSystem.select_atom_close_to_origin() -> None

   Selects the atom that is closest to the origin of the coordinate
   system.

ChemicalSystem.select_within_radius(radius: float, unit: str = 'angstrom') -> None

   Selects all atoms within a given radius of any of the currently
   selected atoms.

ChemicalSystem.make_selection_cappable() -> None

   Extends the current selection but does not cross single bonds,
   unless they are to hydrogen atoms.

   The intended use of this method is to select a suitable QM region
   for QM/MM calculations where one wants the QM region to be
   separated by single bonds from the rest of the molecule.

ChemicalSystem.select_atoms_of_same_type() -> None

   Selects all atoms whose element is the same as of a currently
   selected atom.

Methods taking predicate functions:

ChemicalSystem.select_atoms_if(pred: Callable[[Atom], bool]) -> None

   Selects atoms based on a predicate function.

ChemicalSystem.deselect_atoms_if(pred: Callable[[Atom], bool]) -> None

   Deselects atoms based on a predicate function.

ChemicalSystem.select_connected_if(pred: Callable[[Atom, Atom, Bond], bool]) -> None

   Selects atoms bonded to the currently selected atoms based on a
   predicate function.

   The predicate function is called on a pair of atoms and their
   connecting bond. The atom passed as the first argument into the
   predicate function is the already selected atom. The second
   argument is the unselected atom attached to the bond, which only
   becomes selected if the predicate function returns "True".

ChemicalSystem.select_molecule_if(pred: Callable[[Atom, Atom, Bond], bool]) -> None

   Using the bonds and a predicate function, selects all molecules
   that include a currently selected atom.

   This is equivalent to repeatedly calling "select_connected_if" with
   the same predicate until the selection stops growing.
