
     iF                        d Z ddlZddlZddlZddlmZ ddlmZ ddl	m
Z
 dZ e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             Z ej        d          Z ej        d          Z e
dd	e
          d             Z e
dd	e
          dd            Z e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             Z e
dd	e
          d             ZdS )aY
  
Guessing unknown Topology information --- :mod:`MDAnalysis.topology.guessers`
=============================================================================

.. deprecated:: 2.8.0
   The :mod:`MDAnalysis.topology.guessers` module will be removed in release 3.0.0.
   It is deprecated in favor of the new Guessers API. See 
   :mod:`MDAnalysis.guesser.default_guesser` for more details.

In general `guess_atom_X` returns the guessed value for a single value,
while `guess_Xs` will work on an array of many atoms.


Example uses of guessers
------------------------

Guessing elements from atom names
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Currently, it is possible to guess elements from atom names using
:func:`guess_atom_element` (or the synonymous :func:`guess_atom_type`). This can
be done in the following manner::

  import MDAnalysis as mda
  from MDAnalysis.topology.guessers import guess_atom_element
  from MDAnalysisTests.datafiles import PRM7

  u = mda.Universe(PRM7)

  print(u.atoms.names[1])  # returns the atom name H1

  element = guess_atom_element(u.atoms.names[1])

  print(element)  # returns element H

In the above example, we take an atom named H1 and use
:func:`guess_atom_element` to guess the element hydrogen (i.e. H). It is
important to note that element guessing is not always accurate. Indeed in cases
where the atom type is not recognised, we may end up with the wrong element.
For example::

  import MDAnalysis as mda
  from MDAnalysis.topology.guessers import guess_atom_element
  from MDAnalysisTests.datafiles import PRM19SBOPC

  u = mda.Universe(PRM19SBOPC)

  print(u.atoms.names[-1])  # returns the atom name EPW

  element = guess_atom_element(u.atoms.names[-1])

  print(element)  # returns element P

Here we find that virtual site atom 'EPW' was given the element P, which
would not be an expected result. We therefore always recommend that users
carefully check the outcomes of any guessers.

In some cases, one may want to guess elements for an entire universe and add
this guess as a topology attribute. This can be done using :func:`guess_types`
in the following manner::

  import MDAnalysis as mda
  from MDAnalysis.topology.guessers import guess_types
  from MDAnalysisTests.datafiles import PRM7

  u = mda.Universe(PRM7)

  guessed_elements = guess_types(u.atoms.names)

  u.add_TopologyAttr('elements', guessed_elements)

  print(u.atoms.elements)  # returns an array of guessed elements

More information on adding topology attributes can found in the `user guide`_.


.. Links

.. _user guide: https://www.mdanalysis.org/UserGuide/examples/constructing_universe.html#Adding-topology-attributes

    N   )	distances)tables)	deprecatezMDAnalysis.topology.guessers is deprecated in favour of the new Guessers API. See MDAnalysis.guesser.default_guesser for more details.z2.8.0z3.0.0)releaseremovemessagec                 x    t          |            t          j        d | D             t          j                  }|S )zGuess the mass of many atoms based upon their type

    Parameters
    ----------
    atom_types
      Type of each atom

    Returns
    -------
    atom_masses : np.ndarray dtype float64
    c                 ,    g | ]}t          |          S  )get_atom_mass).0atom_ts     f/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/topology/guessers.py
<listcomp>z guess_masses.<locals>.<listcomp>   s     8886v		888    dtype)validate_atom_typesnparrayfloat64)
atom_typesmassess     r   guess_massesr   x   sD     
###X88Z888
  F Mr   c                 4   t          j        |           D ]}	 t          j        |          # t          $ r` 	 t          j        |                                          n7# t          $ r* t          j        d                    |                     Y nw xY wY w xY wdS )a  Vaildates the atom types based on whether they are available in our tables

    Parameters
    ----------
    atom_types
      Type of each atom

    Returns
    -------
    None

    .. versionchanged:: 0.20.0
       Try uppercase atom type name as well
    z9Failed to guess the mass for the following atom types: {}N)	r   uniquer   r   KeyErrorupperwarningswarnformat)r   	atom_types     r   r   r      s      Yz**  	
	M)$$$ 	 	 	ioo//000   OVV!     	 s2   +
B$AB1BBBBBc                 L    t          j        d | D             t                    S )zGuess the atom type of many atoms based on atom name

    Parameters
    ----------
    atom_names
      Name of each atom

    Returns
    -------
    atom_types : np.ndarray dtype object
    c                 ,    g | ]}t          |          S r   guess_atom_element)r   names     r   r   zguess_types.<locals>.<listcomp>   s!    999d	D	!	!999r   r   )r   r   object)
atom_namess    r   guess_typesr+      s0     899j999   r   c                      t          |           S )zGuess atom type from the name.

    At the moment, this function simply returns the element, as
    guessed by :func:`guess_atom_element`.


    See Also
    --------
    :func:`guess_atom_element`
    :mod:`MDAnalysis.topology.tables`


    r&   atomnames    r   guess_atom_typer/      s     h'''r   z[0-9]z[*+-]c                    | dk    rdS 	 t           j        |                                          S # t          $ r t	          j        t          d|           }t	          j        t          |          }t          t          d|                    }|r|d                                         nd}|t           j        v rt           j        |         cY S |r|t           j        v r|cY S |dd         t           j        v r|dd         cY S |dd         t           j        v r|dd         cY S t          |          dk    r
|d         cY S |dd         }||cY S w xY w)a5  Guess the element of the atom from the name.

    Looks in dict to see if element is found, otherwise it uses the first
    character in the atomname. The table comes from CHARMM and AMBER atom
    types, where the first character is not sufficient to determine the atom
    type. Some GROMOS ions have also been added.

    .. Warning: The translation table is incomplete. This will probably result
                in some mistakes, but it still better than nothing!

    See Also
    --------
    :func:`guess_atom_type`
    :mod:`MDAnalysis.topology.tables`
     Nr      r   )r   atomelementsr   r   resubSYMBOLSsplitNUMBERSlistfilterelementslen)r.   
no_symbols
no_numbersr(   s       r   r'   r'      sx   " 2~~r"8>>#3#344   VGR22
 Xgz22
&z2233
(2:z!}""$$$ 6&&&&t,,,, 		v&&CRCyFO++CRCy   ABBx6?**ABBx4yyA~~Aw9D  		 5s.   #. BEE E E#E EEc           	         t          |           t          |          k    rt          d          |                    dd          }t          j                                        |                    dd          }|r                    |           | j        }t          fdt          |          D                       sDt          dd
                    fd	t          |          D                       z   d
z   dz             |                    dd          }|t          j        |          }t          fd|D                       }g }	t          j        |d|z  ||          \  }
}t!          |
          D ]a\  }\  }}||                  ||                  z   |z  }||         |k     r-|	                    | |         j        | |         j        f           bt'          |	          S )ac	  Guess if bonds exist between two atoms based on their distance.

    Bond between two atoms is created, if the two atoms are within

    .. math::

          d < f \cdot (R_1 + R_2)

    of each other, where :math:`R_1` and :math:`R_2` are the VdW radii
    of the atoms and :math:`f` is an ad-hoc *fudge_factor*. This is
    the `same algorithm that VMD uses`_.

    Parameters
    ----------
    atoms : AtomGroup
         atoms for which bonds should be guessed
    coords : array
         coordinates of the atoms (i.e., `AtomGroup.positions)`)
    fudge_factor : float, optional
        The factor by which atoms must overlap eachother to be considered a
        bond.  Larger values will increase the number of bonds found. [0.55]
    vdwradii : dict, optional
        To supply custom vdwradii for atoms in the algorithm. Must be a dict
        of format {type:radii}. The default table of van der Waals radii is
        hard-coded as :data:`MDAnalysis.topology.tables.vdwradii`.  Any user
        defined vdwradii passed as an argument will supercede the table
        values. [``None``]
    lower_bound : float, optional
        The minimum bond length. All bonds found shorter than this length will
        be ignored. This is useful for parsing PDB with altloc records where
        atoms with altloc A and B maybe very close together and there should be
        no chemical bond between them. [0.1]
    box : array_like, optional
        Bonds are found using a distance search, if unit cell information is
        given, periodic boundary conditions will be considered in the distance
        search. [``None``]

    Returns
    -------
    list
        List of tuples suitable for use in Universe topology building.

    Warnings
    --------
    No check is done after the bonds are guessed to see if Lewis
    structure is correct. This is wrong and will burn somebody.

    Raises
    ------
    :exc:`ValueError` if inputs are malformed or `vdwradii` data is missing.


    .. _`same algorithm that VMD uses`:
       http://www.ks.uiuc.edu/Research/vmd/vmd-1.9.1/ug/node26.html

    .. versionadded:: 0.7.7
    .. versionchanged:: 0.9.0
       Updated method internally to use more :mod:`numpy`, should work
       faster.  Should also use less memory, previously scaled as
       :math:`O(n^2)`.  *vdwradii* argument now augments table list
       rather than replacing entirely.
    z+'atoms' and 'coord' must be the same lengthfudge_factorg?vdwradiiNc              3       K   | ]}|v V  	d S Nr   )r   valrB   s     r   	<genexpr>zguess_bonds.<locals>.<genexpr>S  s'      993sh999999r   zvdw radii for types: z, c                     g | ]}|v|	S r   r   r   trB   s     r   r   zguess_bonds.<locals>.<listcomp>W  s    LLL1a8mmQmmmr   z). These can be defined manually using thez keyword 'vdwradii'lower_boundg?c                      g | ]
}|         S r   r   rH   s     r   r   zguess_bonds.<locals>.<listcomp>e  s    22218A;222r   g       @)
max_cutoff
min_cutoffbox)r=   
ValueErrorgetr   rB   copyupdatetypesallsetjoinr   asarraymaxr   self_capped_distance	enumerateappendindextuple)atomscoordsrN   kwargsrA   user_vdwradii	atomtypesrJ   max_vdwbondspairsdistidxijdrB   s                   @r   guess_bondsrk     s   B 5zzS[[  FGGG::nd33L##%%HJJz400M '&&& I 9999#i..99999 
'))LLLLILLLMMN=> ((
 
 	
 **]C00K
joo
 2222	22233GE03=[c  KE4 !'' ; ;Vail#hy|&<<L9q==LL%(.%(.9:::<<r   c                 j   t                      }| D ]}|D ]}|                    |          }|j        D ]p}||k    rh|                    |          }t          |j        |j        |j        g          }|d         |d         k    r|ddd         }|                    |           qt          |          S )a  Given a list of Bonds, find all angles that exist between atoms.

    Works by assuming that if atoms 1 & 2 are bonded, and 2 & 3 are bonded,
    then (1,2,3) must be an angle.

    Returns
    -------
    list of tuples
        List of tuples defining the angles.
        Suitable for use in u._topology


    See Also
    --------
    :meth:`guess_bonds`


    .. versionadded 0.9.0
    r   r2   N)rU   partnerrd   r]   r\   add)rd   angles_foundbatomother_aother_bthird_adescs           r   guess_anglesrv   s  s    * 55L 	+ 	+ 	+ 	+DiiooG: + +a<<%ood33G '-W]!KLLDAwb))#DDbDz $$T***+	+ r   c                    t                      }| D ]}t          d |D                       }t          |j        d         |j        d         g|ddd         |g          D ]x\  }}|j        D ]k}|                    |          |vrR|                    |          }||j        fz   }|d         |d         k    r|ddd         }|                    |           lyt          |          S )aX  Given a list of Angles, find all dihedrals that exist between atoms.

    Works by assuming that if (1,2,3) is an angle, and 3 & 4 are bonded,
    then (1,2,3,4) must be a dihedral.

    Returns
    -------
    list of tuples
        List of tuples defining the dihedrals.
        Suitable for use in u._topology

    .. versionadded 0.9.0
    c                     g | ]	}|j         
S r   r\   )r   as     r   r   z#guess_dihedrals.<locals>.<listcomp>  s    ***1qw***r   r   r2   N)rU   r]   zipr^   rd   rm   r\   rn   )	anglesdihedrals_foundrp   a_tuprq   prefixrs   rt   ru   s	            r   guess_dihedralsr     s    eeO . .*****++  WQZ%dddU';
 
 		. 		.LD&  : . .t,,11%ood33G!W]$44DAwb))#DDbDz#''---.		. !!!r   c                 N   t                      }| D ]d         }t          fddD                       }|j        D ]X}|                    |          }|vr=||j        fz   }|d         |d         k    r|ddd         }|                    |           Yt          |          S )a  Given a list of Angles, find all improper dihedrals that exist between
    atoms.

    Works by assuming that if (1,2,3) is an angle, and 2 & 4 are bonded,
    then (2, 1, 3, 4) must be an improper dihedral.
    ie the improper dihedral is the angle between the planes formed by
    (1, 2, 3) and (1, 3, 4)

    Returns
    -------
        List of tuples defining the improper dihedrals.
        Suitable for use in u._topology

    .. versionadded 0.9.0
    r3   c                 *    g | ]}|         j         S r   ry   )r   rz   rp   s     r   r   z,guess_improper_dihedrals.<locals>.<listcomp>  s    555aqtz555r   )r3   r   r   r   r2   N)rU   r]   rd   rm   r\   rn   )r|   r}   rq   r~   rs   
other_atomru   rp   s          @r   guess_improper_dihedralsr     s    " eeO * *t5555955566 z 	* 	*G ..J??
 0227T"X%%":D##D)))	* !!!r   c                     	 t           j        |          S # t          $ r: 	 t           j        |                                          cY S # t          $ r Y Y dS w xY ww xY w)zReturn the atomic mass in u for *element*.

    Masses are looked up in :data:`MDAnalysis.topology.tables.masses`.

    .. Warning:: Unknown masses are set to 0.0

    .. versionchanged:: 0.20.0
       Try uppercase atom type name as well
            )r   r   r   r   )elements    r   r   r     ss    }W%%   	=1111 	 	 	333	s,    
A#AA
AAAAc                 :    t          t          |                     S )zGuess a mass based on the atom name.

    :func:`guess_atom_element` is used to determine the kind of atom.

    .. warning:: Anything not recognized is simply set to 0; if you rely on the
                 masses you might want to double check.
    )r   r'   r-   s    r   guess_atom_massr     s     +H55666r   c                     dS )zZGuess atom charge from the name.

    .. Warning:: Not implemented; simply returns 0.
    r   r   r-   s    r   guess_atom_charger      s	     3r   c                     |                      d          }t          j        d |                                D                       S )aF  Guess aromaticity of atoms using RDKit

    Parameters
    ----------
    atomgroup : mda.core.groups.AtomGroup
        Atoms for which the aromaticity will be guessed

    Returns
    -------
    aromaticities : numpy.ndarray
        Array of boolean values for the aromaticity of each atom


    .. versionadded:: 2.0.0
    RDKITc                 6    g | ]}|                                 S r   )GetIsAromaticr   rq   s     r   r   z'guess_aromaticities.<locals>.<listcomp>  s$    EEEdT''))EEEr   )
convert_tor   r   GetAtoms)	atomgroupmols     r   guess_aromaticitiesr   
  s>    " 

w
'
'C8EEcllnnEEEFFFr   c                     |                      d          }ddlm}  ||d           t          j        d |                                D             t          j                  S )aC  Guess Gasteiger partial charges using RDKit

    Parameters
    ----------
    atomgroup : mda.core.groups.AtomGroup
        Atoms for which the charges will be guessed

    Returns
    -------
    charges : numpy.ndarray
        Array of float values representing the charge of each atom


    .. versionadded:: 2.0.0
    r   r   )ComputeGasteigerChargesT)throwOnParamFailurec                 8    g | ]}|                     d           S )_GasteigerCharge)GetDoublePropr   s     r   r   z+guess_gasteiger_charges.<locals>.<listcomp>5  s'    KKKD		.	/	/KKKr   r   )r   rdkit.Chem.rdPartialChargesr   r   r   r   float32)r   r   r   s      r   guess_gasteiger_chargesr     sv    " 

w
'
'CCCCCCCCT::::8KKCLLNNKKKj   r   rD   )__doc__numpyr   r    r5   libr   MDAnalysis.guesserr   MDAnalysis.lib.utilr   deprecation_msgr   r   r+   r/   compiler9   r7   r'   rk   rv   r   r   r   r   r   r   r   r   r   r   <module>r      s5  .P Pb      				       % % % % % % ) ) ) ) ) )?  77ODDD  ED& 77ODDD  ED: 77ODDD  ED" 77ODDD( ( ED(" "*X


"*X

 77ODDD. . ED.b 77ODDDk k k EDk\ 77ODDD! ! ED!H 77ODDD" " ED"D 77ODDD!" !" ED!"H 77ODDD  ED& 77ODDD7 7 ED7 77ODDD  ED 77ODDDG G EDG( 77ODDD  ED  r   