ó
É™xTc           @   sd  d  Z  d d l m Z d d l Z d d l m Z m Z m Z d d l	 m
 Z
 d d l m Z d d l m Z d d l Z d d l Z d d l Z d d	 d
 d g Z d d d d g Z d d d d d d
 d g Z e e d d d d	 d d g Z d „  Z d „  Z d „  Z d e f d „  ƒ  YZ d e f d „  ƒ  YZ d  „  Z e ƒ  Z d! e f d" „  ƒ  YZ d S(#   s…  
This package is used to model elemental ions in crystal structures. It handles
both identification and building of ions, but relies on the solvent module to
flag candidate sites for screening.

Notes
-----
.. [1] Echols, N. et al. Automated identification of elemental ions in
       macromolecular crystal structures. Acta Crystallogr. D. Biol.
       Crystallogr. 70, 1104â€“14 (2014).
iÿÿÿÿ(   t   divisionN(   t
   group_argst   Autot   slots_getstate_setstate(   t   Sorry(   R   (   t   expt   MGt   CAt   ZNt   CLt   Ft   BRt   IODt   MNt   FEt   COt   CUt   NIt   PTt   NAt   Kt   CDt   HGc         C   s   |  d k r d  S|  j d ƒ S(   Nt   .t   ,(   t   Nonet   split(   t   param(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   _cif_param_as_list   s     c         C   s   |  d k r d  St |  ƒ S(   NR   (   R   t   int(   R   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   _cif_param_as_int!   s     c         C   s   |  d k r d  St |  ƒ S(   NR   (   R   t   float(   R   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   _cif_param_as_float%   s     t   metal_parametersc           B   s#   e  Z d  „  Z d „  Z d „  Z RS(   c         C   s   d |  j  j ƒ  |  j f S(   Ns   %s%+d(   t   elementt   uppert   charge(   t   self(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   __str__*   s    c         C   s   |  j  S(   sX   
    Gets the charge of a parameter as an integer.

    Returns
    -------
    int
    (   R$   (   R%   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   charge_as_int-   s    c         C   s_   d } |  j  d k r d } n |  j  d k  r6 d } n  d |  j j ƒ  t |  j  ƒ | f } | S(   s*  
    Makes a string showing the element and its associated charge. Note that this
    format is slightly different from the __str__ method, which puts the +/-
    between the element symbol and the charge number.

    Returns
    -------
    str

    Examples
    --------
    >>> from mmtbx.ions import metal_parameters
    >>> print metal_parameters(element="FE", charge=3)
    FE+3
    >>> print metal_parameters(element="FE", charge=3).scattering_type()
    FE3+
    >>> print metal_parameters(element="CL", charge=-1).scattering_type()
    CL1-
    t    i    t   +t   -s   %2s%1d%s(   R$   R"   t   stript   abs(   R%   t   charge_symbolt   s(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   scattering_type7   s    		%(   t   __name__t
   __module__R&   R'   R/   (    (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyR!   )   s   		
t   parameter_serverc           B   s’   e  Z d  Z d d d d d g Z d „  Z d „  Z d „  Z d	 „  Z d
 „  Z d d „ Z
 d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z RS(   sz   
  Class for retrieving information from ion_parameters.cif

  Attributes
  ----------
  params : iotbx.cif.model.block
  t   paramst   _metal_paramst   _charge_paramst   _resname_elemt   _default_chargesc         C   s�   t  j j t  j j t ƒ d d ƒ } t  j j | ƒ s= t ‚ t j j	 d | ƒ j
 ƒ  } | d |  _ i  |  _ i  |  _ i  |  _ i  |  _ d  S(   Ni    s   ion_parameters.cift	   file_patht   ions(   t   ost   patht   joinR   t   __file__t   isfilet   AssertionErrort   iotbxt   cift   readert   modelR3   R4   R5   R6   R7   (   R%   t   params_patht	   cif_model(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   __init__^   s    				c         C   s   | |  j  d k S(   s�   
    Checks if symbol is a supported element by this parameter server.

    Parameters
    ----------
    symbol : str

    Returns
    -------
    bool
    s   _lib_valence.atom_symbol(   R3   (   R%   t   symbol(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   is_supported_elementi   s    c         C   s   | |  j  d k S(   s‹   
    Checks if an element is a supported donor atom.

    Parameters
    ----------
    symbol : str

    Returns
    -------
    bool
    s   _lib_valence.donor_symbol(   R3   (   R%   RG   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   is_supported_donorw   s    c         C   så   xÆ t  |  j d ƒ D]± \ } } | | j k r t |  j d | ƒ } |  j d | } t |  j d | ƒ } | | j ƒ  k rÅ | | j k rÅ | | j ƒ  k rÅ t |  j d | ƒ } | d f Sq q W| j ƒ  }	 | j ƒ  }
 d S(	   sŠ  
    Gets the valence parameters (r_0 and b) used for calculating valences from
    bond distances.

    Parameters
    ----------
    atom1 : mmtbx.ions.metal_parameters
    atom2 : mmtbx.ions.metal_parameters

    Returns
    -------
    float or None
        r_0 in the equation exp((r - r_0) / b)
    float or None
        b in the equation exp((r - r_0) / b)

    Examples
    --------
    >>> from mmtbx.ions import server, metal_parameters
    >>> zn_params = metal_parameters(element="ZN", charge=2)
    >>> n_params = metal_parameters(element="N", charge=-3)
    >>> print server.get_valence_params(zn_params, n_params)
    (1.77, 0.37)
    s   _lib_valence.atom_symbols   _lib_valence.atom_charges   _lib_valence.donor_symbols   _lib_valence.donor_charges   _lib_valence.valueg®Gáz®×?N(   NN(   t	   enumerateR3   R"   R   R'   R   R   (   R%   t   atom1t   atom2t   i_elemRG   t   i_charget   i_othert   i_other_charget   valencet   charge1t   charge2(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   get_valence_params…   s     c         C   sy   | |  j  k r |  j  | S|  j } xO t | d ƒ D]= \ } } | | k r4 t | d | ƒ } | |  j  | <| Sq4 Wd S(   Ns   _lib_charge.elements   _lib_charge.chargei    (   R7   R3   RJ   R   (   R%   R"   t   pRM   t   elemR$   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   _get_default_charge¬   s    	c         C   sË  | j  ƒ  j ƒ  } | d  k	 r3 | j  ƒ  j ƒ  } n  |  j } | d  k r| |  j k rg |  j | } qg  t | d ƒ D], \ } } | | k rx | | d | f ^ qx } t | ƒ d k rÏ t d | ƒ ‚ n% t | ƒ d k  rô t d | ƒ ‚ n  | d d } | |  j | <n  | | f |  j k r8|  j | | f Sxy t | d ƒ D]R \ } } | | k rI| | d | k rI| d | t	 | d | ƒ f } PqIqIW| |  j
 | ƒ f } | |  j | | f <| S(   Ns   _lib_charge.resnames   _lib_charge.elementi   s   Ambiguous element for residue: s   Unknown element for residue: i    s   _lib_charge.charge(   R+   R#   R   R3   R6   RJ   t   lenR   R5   R   RW   (   R%   t   resnameR"   RU   t   i_resnt   resnt   resn_elementst   elem_charge(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   _get_charge_params·   s2    	& "c         C   sž   t  | t ƒ r; | j ƒ  j ƒ  } | |  j d k rŠ | SnO t | d ƒ ro t  | j t ƒ ro | j j ƒ  j ƒ  S| j ƒ  j j ƒ  j ƒ  } |  j	 d | ƒ d S(   sž   
    Gets the element associated with an atom.

    Parameters
    ----------
    atom : iotbx.pdb.hierarchy.atom or str

    Returns
    -------
    str
    s   _lib_charge.elementR"   RY   i    (
   t
   isinstancet   strR+   R#   R3   t   hasattrR"   t   fetch_labelsRY   R^   (   R%   t   atomRY   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   get_elementÖ   s    !c         C   sõ   t  | t ƒ rn | j ƒ  j ƒ  } y |  j d | ƒ d } Wqñ t k
 rj |  j d d d | ƒ d } qñ Xnƒ | j } t  | t ƒ s• | j ƒ  } n  | d k r¥ | S| j	 ƒ  j
 j ƒ  j ƒ  } | j j ƒ  j ƒ  } |  j d | d | ƒ d } | S(   sÓ  
    Gets the charge associated with an atom or element.

    Parameters
    ----------
    atom : iotbx.pdb.hierarchy.atom or str

    Returns
    -------
    int

    Examples
    --------
    >>> from iotbx.pdb.hierarchy import atom
    >>> from mmtbx.ions import server
    >>> atom_dummy = atom()
    >>> atom_dummy.element = "N"
    >>> atom_dummy.charge = "-3"
    >>> print server.get_charge(atom_dummy)
    -3
    >>> print server.get_charge("N")
    -3
    RY   i   R(   R"   i    (   R_   R`   R+   R#   R^   R   R$   R   R'   Rb   RY   R"   (   R%   Rc   R$   RY   R"   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt
   get_chargeì   s    #	c         C   sv   |  j  | ƒ } |  j } t ƒ  } xH t | d ƒ D]6 \ } } | | k r2 | j t | d | ƒ ƒ q2 q2 Wt | ƒ S(   sÞ  
    Retrieves all charges that are expected to be associated with an atom or
    element within ion_parameters.cif. This list is manually updated based on
    the ligand IDs listed by the PDB.

    Parameters
    ----------
    atom : iotbx.pdb.hierarchy.atom or str

    Returns
    -------
    list of int

    Examples
    --------
    >>> from mmtbx.ions import server
    >>> print server.get_charges("CU")
    [1, 2, 3]
    >>> print server.get_charges("ZN")
    [2]
    s   _lib_charge.elements   _lib_charge.charge(   Rd   R3   t   setRJ   t   addR   t   sorted(   R%   Rc   R"   RU   t   chargesRM   RV   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   get_charges  s    		"c         C   s„  |  j  } xtt | d ƒ D]b\ } } | | j ƒ  k r | |  j k rR |  j | S| d | | k sl t ‚ t d | d t | d | ƒ d t | d | ƒ d t | d	 | ƒ d
 t | d | ƒ d t | d | ƒ d t | d | ƒ d t | d | ƒ d t | d | ƒ d t | d | ƒ d t | d | ƒ d t | d | ƒ d t | d | ƒ ƒ } | |  j | <| Sq Wd S(   s±   
    Gets all metal parameters associated with an element.

    Parameters
    ----------
    element : str

    Returns
    -------
    mmtbx.ions.metal_parameters or None
    s   _lib_elems.elements   _lib_ligands.elementR"   R$   s   _lib_elems.charget   vec_sum_cutoffs   _lib_elems.vec_sum_cutofft   coord_num_lowers   _lib_elems.coord_num_lowert   coord_num_uppers   _lib_elems.coord_num_uppert   min_coordinating_non_waterss&   _lib_elems.min_coordinating_non_waterst
   cvbs_lowers   _lib_elems.cvbs_lowert
   cvbs_uppers   _lib_elems.cvbs_uppert   cvbs_expecteds   _lib_elems.cvbs_expectedt   allowed_coordinating_atomss'   _lib_ligands.allowed_coordinating_atomst   allowed_coordinating_residuess*   _lib_ligands.allowed_coordinating_residuest   allowed_geometriess   _lib_ligands.allowed_geometriest   allowed_backbone_atomss#   _lib_ligands.allowed_backbone_atomsN(
   R3   RJ   R#   R4   R?   R!   R   R    R   R   (   R%   R"   RU   RM   RG   R3   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   get_metal_parameters3  s@    	c         C   s›   | j  } |  j | ƒ s d S|  j | | ƒ \ } } | d k r‰ t d |  j | ƒ d | ƒ } |  j | | ƒ \ } } | d k r‰ d Sn  t | | | ƒ S(   sZ  
    Calculates the single valence contribution of one ion donor pair,
    separated by distance. ion and donor should be AtomGuess objects.

    Parameters
    ----------
    ion : mmtbx.ions.metal_parameters
    donor : mmtbx.ions.metal_parameters
    distance : float

    Returns
    -------
    float

    Examples
    --------
    >>> from mmtbx.ions import server, metal_parameters
    >>> ion = server.get_metal_parameters("ZN")
    >>> donor = metal_parameters(element="N", charge="-3")
    >>> valence = server.calculate_valence(ion, donor, 2.20)
    >>> print round(valence, 2)
    0.31
    i    R$   R"   N(   R"   RI   RT   R   R!   Re   R   (   R%   t   iont   donort   distanceR"   t   r_0t   b(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   calculate_valence`  s    		c         C   s¼   g  } x¯ | D]§ } t  d | j d | j ƒ } t | j ƒ } |  j | | | ƒ | j } | d k r� | j d k r´ |  j | j ƒ r´ q´ q | d k r | j | j | | ƒ q q W| S(   s	  
    Calculates all of the valence contributions between ion and each
    atom of nearby_atoms, each element of which should be a tuple of an
    atom and a vector from the ion's location.

    Parameters
    ----------
    ion : mmtbx.ions.metal_parameters
    nearby_atoms : list of mmtbx.ions.environment.atom_contact

    Returns
    -------
    list of scitbx.matrix.rec
        List of vectors, whose magnitudes are equal to the valence contributions
        from each donor atom.

    Examples
    --------
    >>> from libtbx import group_args
    >>> from iotbx.pdb.hierarchy import atom
    >>> from mmtbx.ions import server
    >>> from mmtbx.ions.environment import atom_contact
    >>> from scitbx.matrix import rec
    >>> ion = server.get_metal_parameters("ZN")
    >>> vector_1 = rec([2.0, 0, 0], [1, 3])
    >>> vector_2 = rec([-2.0, 0, 0], [1, 3])
    >>> vector_3 = rec([0, 2.0, 0], [1, 3])
    >>> vector_4 = rec([0, 0, 2.0], [1, 3])
    >>> atom_dummy = atom()
    >>> atom_dummy.element = "N"
    >>> atom_dummy.charge = "-3"
    >>> atom_dummy.occ = 1
    >>> atom_dummy.parent = lambda: group_args(atoms=lambda: [])
    >>> donors = [atom_contact(atom_dummy, vector_1, None, None),
    ...           atom_contact(atom_dummy, vector_2, None, None),
    ...           atom_contact(atom_dummy, vector_3, None, None),
    ...           atom_contact(atom_dummy, vector_4, None, None)]
    >>> vectors = server.calculate_valences(ion, donors)
    >>> bvs = sum(abs(i) for i in vectors)
    >>> print round(bvs, 2)
    2.15
    R"   R$   i    t   Ht   Ct   AX(   R}   R~   R   (	   R!   R"   R$   R,   t   vectorR|   t   occRI   t   append(   R%   Rw   t   nearby_atomst   vectorst   contactRx   Ry   RQ   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   calculate_valences†  s    +	N(   R0   R1   t   __doc__t	   __slots__RF   RH   RI   RT   RW   R   R^   Rd   Re   Rj   Rv   R|   R†   (    (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyR2   S   s   					'			)		-	&c         C   s  |  d
 k r t d d ƒ ‚ ná |  t k	 r t |  t ƒ sI t |  t ƒ rd |  j d d ƒ j ƒ  }  n7 t |  t ƒ r› t	 |  ƒ d k r› |  d j d ƒ }  n  |  d g k r® t
 SxO |  D]D } | j ƒ  j ƒ  t k rµ t d d	 | d j t ƒ f ƒ ‚ qµ qµ Wn  t
 S(   s2  
  Checks if elements are supported by ion identitication process.

  Parameters
  ----------
  elements : list of str

  Returns
  -------
  bool

  Raises
  ------
  libtbx.utils.Sorry

  Examples
  --------
  >>> from mmtbx.ions import check_supported
  >>> check_supported(["CA", "ZN", "FE"])
  True
  s7   No elements specified for ion picking - must be either s4   'Auto' or a comma-separated list of element symbols.R   t    i   i    t   XsB   Identification of ions with element symbol '%s' is not supported! s   Choices are: %sN(   R   R   R   R_   R`   t   unicodet   replaceR   t   listRX   t   TrueR+   R#   t	   SUPPORTEDR<   (   t   elementsRV   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   check_supportedÀ  s     !'t   atom_type_flagsc           B   s¬   e  Z d  Z d: d; d< d= d> d? d@ dA dB dC dD dE dF dG dH dI dJ dK dL dM dN dO dP dQ dR dS g Z g  e D] \ Z Z e ^ qg d5 g Z d6 „  Z d7 „  Z e	 j
 d8 d9 „ Z RS(T   sŠ  
  Simple container for information about the identity of an atom via a set of
  enumerated boolean flags.  The responsibility for toggling these flags based
  on analysis of the site is left to external code.

  Parameters
  ----------
  name: element symbol or HOH

  Examples
  --------
  >>> flags = atom_type_flags("HOH")
  >>> if (fofc_map_value > 3.0) :
  ...   flags.high_fofc = True
  t	   low_b_isos   Abnormally low B-factort   high_occs   Abnormally high occupancyt	   high_fofcs   mFo-DFc peakt   high_two_fofcs"   Abnormally high 2mFo-DFc map valuet	   high_anoms   Anomalous map peakt   high_fdps   Abnormally high refined f''t
   high_b_isos   Abnormally high B-factort   low_occs   Abnormally low occupancyt   low_two_fofcs   Low 2mFo-DFc map valuet   low_fofcs   mFo-DFc holet   low_anoms   Poor anomalous map valuet   low_fdps   Abnormally low refined f''t   bad_geoms    Unexpected coordination geometryt   missing_geoms%   No recognizable coordination geometryt   bad_vectorss   Bad coordination vectorst   bad_valences   Bad bond valence sumt   too_few_non_waterss$   Too few non-water coordinating atomst   too_few_coords   Too few coordinating atomst   too_many_coords   Too many coordinating atomst
   like_coords    Coordinating atom of same charget   bad_coord_atoms'   Disallowed or unusual coordinating atomt   bad_coord_residues*   Disallowed or unusual coordinating residuet   very_bad_valences   Very bad bond valence sumt
   bad_halides   Poor halide sitet
   coord_geoms>   Appears to be coordinating another site with distinct geometryt   close_contacts&   Unusually close contact to oxygen atomt   namec         C   s5   | |  _  x% |  j d  D] } t |  | t ƒ q Wd  S(   Niÿÿÿÿ(   R­   Rˆ   t   setattrt   False(   R%   R­   t   attr(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyRF     s    	c         C   s¾   g  } x± t  |  j d  ƒ D]œ \ } } t |  | ƒ r | d k  r` | j d |  j | d ƒ q¶ d | k ow d k  n r› | j d |  j | d ƒ q¶ | j |  j | d ƒ q q W| S(   sí   
    Retrieve a list of strings describing the issues that have been identified.
    These will have '+++' or '---' appended if they indicate that the actual
    element is heavier or lighter than the current refined scatterer type.
    iÿÿÿÿi   s   %s (+++)i   i   s   %s (---)(   RJ   Rˆ   t   getattrR‚   t   flag_names_and_labels(   R%   t   captionst   i_attrR°   (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   get_flag_captions!  s     R(   c         C   s¼   |  j  ƒ  } t | ƒ d k r/ | | d IJn‰ | | d |  j IJt } } xJ | D]B } | | d | IJd | k r‚ t } qU d | k rU t } qU qU W| s§ | r¸ | | d IJn  d S(	   sC   
    Print out a list of all issues that have been identified.
    i    s   (No problems detected.)s-   The following problems were detected with %s:s     %ss   ---s   +++s>   (+++ indicates a heavier element, --- indicates a lighter one)N(   Rµ   RX   R­   R¯   RŽ   (   R%   t   outt   prefixR³   t	   have_plust
   have_minust   caption(    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   show2  s    

 	 (   R“   s   Abnormally low B-factor(   R”   s   Abnormally high occupancy(   R•   s   mFo-DFc peak(   R–   s"   Abnormally high 2mFo-DFc map value(   R—   s   Anomalous map peak(   R˜   s   Abnormally high refined f''(   R™   s   Abnormally high B-factor(   Rš   s   Abnormally low occupancy(   R›   s   Low 2mFo-DFc map value(   Rœ   s   mFo-DFc hole(   R�   s   Poor anomalous map value(   Rž   s   Abnormally low refined f''(   RŸ   s    Unexpected coordination geometry(   R    s%   No recognizable coordination geometry(   R¡   s   Bad coordination vectors(   R¢   s   Bad bond valence sum(   R£   s$   Too few non-water coordinating atoms(   R¤   s   Too few coordinating atoms(   R¥   s   Too many coordinating atoms(   R¦   s    Coordinating atom of same charge(   R§   s'   Disallowed or unusual coordinating atom(   R¨   s*   Disallowed or unusual coordinating residue(   R©   s   Very bad bond valence sum(   Rª   s   Poor halide site(   R«   s>   Appears to be coordinating another site with distinct geometry(   R¬   s&   Unusually close contact to oxygen atom(   R0   R1   R‡   R²   t   flt   labelRˆ   RF   Rµ   t   syst   stdoutR»   (    (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyR’   ë  s@    	&		(   R‡   t
   __future__R    t	   iotbx.cifR@   t   libtbxR   R   R   t   libtbx.utilsR   t   mathR   t   timeR:   R¾   t   DEFAULT_IONSt   HALIDESt   TRANSITION_METALSR�   R   R   R    R!   R2   R‘   t   servert   objectR’   (    (    (    sA   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ions/__init__.pyt   <module>   s,    			*ÿ n	)	