B
    b7                 @   s   d 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mZ ddlmZmZmZ ddlmZmZmZ dd	lmZ dd
lmZmZ ddlmZ ddlmZ ddlm Z m!Z! G dd de"Z#e eG dd de"Z$dS )z
This module contains functionality relevant to loading and parsing GROMACS GRO
(coordinate) files and building a stripped-down Structure from it
    )print_functiondivisionabsolute_import)closing)TINY)GromacsError)FileFormatType)!box_vectors_to_lengths_and_angles!box_lengths_and_angles_to_vectorsreduce_box_vectors)	AtomicNumelement_by_nameMass)	Structure)Atom
ExtraPoint)unit)genopen)add_metaclassstring_typesc               @   s    e Zd ZdZdd Zdd ZdS )_AtomLineParserz" Parses atom lines from GRO files c             C   s   d | _ d| _d| _d S )Nr   )_digits_pdeci_ndeci)self r   8lib/python3.7/site-packages/parmed/gromacs/gromacsgro.py__init__   s    z_AtomLineParser.__init__c       
         s8  t  dd } dd  } dd  }t|}t| }t| }t  dd }|dkrnt||d}	nt||||d}	jdkr d	d_	 d	j	d
 _
j
j	 _ fddtdD \|	_|	_|	_djd  j    r. fddtdD \|	_|	_|	_|	||fS )a7   Reads a line

        Parameters
        ----------
        line : str
            A line with an atom record from a GRO file

        Returns
        -------
        atom, resname, resnum : Atom, str, int
            The Atom instance, residue name, and residue number containing the
            atom
        N   
         r   )namenumber)atomic_numberr"   r#   mass.   c             3   s:   | ]2}t  d |j  d |d j   d V  qdS )r!   r'   r   N)floatr   ).0i)liner   r   r   	<genexpr>;   s   z'_AtomLineParser.read.<locals>.<genexpr>   c             3   s6   | ].}t  |j  |j   d  V  qdS )r   N)r(   r   )r)   r*   )r+   r   wbegwendr   r   r,   B   s   )intstripr   r   r   r   r   r   indexr   r   rangexxxyxzvxvyvz)
r   r+   resnumresnameZatomnameelemr$   r%   Zatnumatomr   )r+   r   r.   r/   r   read   s.    


z_AtomLineParser.readN)__name__
__module____qualname____doc__r   r>   r   r   r   r   r      s   r   c               @   s8   e Zd ZdZedd ZedddZeddd	Zd
S )GromacsGroFilez% Parses and writes Gromacs GRO files c          	   C   s  t t| }|  yt|   W n tk
r@   dS X | }ynt|dd  |dd  srdS |dd  sdS t|dd  dd t|D }|d	 |d
  d }xVtd	dD ]H}|d
 d d| |d	   }|d
 d d| |  }t|||  qW d}|d
 d d| |d	   }|d
 d d| |  }|||  rxXtddD ]J}|d
 d d| |d	   }|d
 d d| |  }t|||  qjW W n tk
r   dS X dS Q R X dS )aJ   Identifies the file as a GROMACS GRO file

        Parameters
        ----------
        filename : str
            Name of the file to check if it is a Gromacs GRO file

        Returns
        -------
        is_fmt : bool
            If it is identified as a Gromacs GRO file, return True. False
            otherwise
        FNr   r   r    r!   c             S   s   g | ]\}}|d kr|qS )r&   r   )r)   r*   xr   r   r   
<listcomp>g   s    z,GromacsGroFile.id_format.<locals>.<listcomp>r'   r         T)	r   r   readliner0   r1   
ValueError	enumerater3   r(   )filenamefr+   ZpdeciZndecir*   r.   r/   r   r   r   	id_formatL   s>      zGromacsGroFile.id_formatFc          
   C   sB  t  }t| tr t| d}d}n| }d}z|  yt|  }W n  tk
rh   td|  Y nX t	 }xt
|D ]Z\}}||krP y||\}	}
}W n$ ttfk
r   td|  Y nX ||	|
| qzW | }|d |krtd|d |f | rydd	 | D }W n" tk
rD   td
|  Y nX t|dkr|d d |d d |d d dddg|_nt|dkrt|d |d |d gtj |d |d |d gtj |d |d |d gtj \}}|tj\}}}|tj\}}}||||||g|_W d|r.|  X |s>|  |S )a"   Parses a Gromacs GRO file

        Parameters
        ----------
        filename : str or file-like
            Name of the file or the GRO file object
        skip_bonds : bool, optional
            If True, skip trying to assign bonds. This can save substantial time
            when parsing large files with non-standard residue names. However,
            no bonds are assigned. This is OK if, for instance, the GRO file is
            being parsed simply for its coordinates. This will also reduce the
            accuracy of assigned atomic numbers for typical ions. Default is
            False.

        Returns
        -------
        struct : :class:`Structure`
            The Structure instance instantiated with *just* residues and atoms
            populated (with coordinates)
        rTFzCould not parse %s as GRO filez.Could not parse the atom record of GRO file %sr'   z(Truncated GRO file. Found %d of %d atomsc             S   s   g | ]}t |qS r   )r(   )r)   rD   r   r   r   rE      s    z(GromacsGroFile.parse.<locals>.<listcomp>z,Could not understand box line of GRO file %sr-   r   r      g     V@	   rF   r      rG      N)r   
isinstancer   r   rH   r0   r1   rI   r   r   rJ   r>   
IndexErrorZadd_atomsplitlenboxr	   uZ
nanometersZvalue_in_unitZ	angstromsZdegreescloseZassign_bonds)rK   Z
skip_bondsstructZfileobj
own_handleZnatomZline_parserr*   r+   r=   r;   r:   rW   ZlengZangabcZalphaZbetaZgammar   r   r   parse{   s`    

 
"
zGromacsGroFile.parser-   c                sD  dd }d}t |tr&t|d}d}nt|ds8td|d |d	t| j  td
d | jD }|dkrd\}}	| 	 }
t
dd |
D }t| j}xPt|D  ]  fdd|
D d }t }d}x|jD ]}|d7 }x|jD ]}x|D ]}|j|jkr|j|jkr|jj|jjkr|dk	rX|j|jd krXt||jdkrXq|	d7 }	|||	d |d ||| || |}|| P qW td| qW qW qW nBx@| jD ]6}|jjd d }|jd d }	|||	|||| qW | jdk	rtt| j  \}}}tdd | jdd D r`|d|d d |d d |d d f  nh|d|d d |d d |d d |d d |d d |d d |d d |d d |d d f	  |d n^|s2| jr2| j}|jdd|jdd d d }|d|d |d |d f  |d |r@|  dS )a   Write a Gromacs Topology File from a Structure

        Parameters
        ----------
        struct : :class:`Structure`
            The structure to write to a Gromacs GRO file (must have coordinates)
        dest : str or file-like
            The name of a file or a file object to write the Gromacs topology to
        precision : int, optional
            The number of decimal places to print in the coordinates. Default 3
        nobox : bool, optional
            If the system does not have a periodic box defined, and this option
            is True, no box will be written. If False, the periodic box will be
            defined to enclose the solute with 0.5 nm clearance on all sides. If
            periodic box dimensions *are* defined, this variable has no effect.
        combine : 'all', None, or list of iterables, optional
            Equivalent to the combine argument of the GromacsTopologyFile.write
            method. If None, system atom order may be changed to meet the need
            for contiguously bonded groups of atoms to be part of a single
            moleculetype. All other values leave the atom order unchanged.
            Default is None.
        c       	      S   s
  d| }d||f }d||d f }| d|| jjd d | jd d |f  | || jd  d |  | || jd  d |  | || jd  d |  |r| || jd  d |  | || jd  d |  | || jd  d |  | d d S )Nr   z%%%d.%dfr'   z%5d%-5s%5s%5dr   
)	writeresiduer"   r4   r5   r6   r7   r8   r9   )	r=   atidresidhas_velsdest	precisionZvarwidthZcrdfmtZvelfmtr   r   r   _write_atom_line   s    z.GromacsGroFile.write.<locals>._write_atom_lineFwTra   z,dest must be a file name or file-like objectz*GROningen MAchine for Chemical Simulation
z%5d
c             s   s   | ]}t |d V  qdS )r7   N)hasattr)r)   r\   r   r   r   r,      s    z'GromacsGroFile.write.<locals>.<genexpr>all)r   r   c             s   s   | ]}t |d  V  qdS )r'   N)rV   )r)   molr   r   r   r,     s    c                s    g | ]} |d  kr|d qS )r'   r   r   )r)   rl   )molidr   r   rE     s    z(GromacsGroFile.write.<locals>.<listcomp>r   Nr'   i zCould not find %sc             S   s   g | ]}t |d  tk qS )Z   )absr   )r)   rD   r   r   r   rE   ;  s    r-   z%10.5f%10.5f%10.5fr   rO   z6%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5fr`   )Zaxisg      ?)rS   r   r   rj   	TypeErrorra   rV   Zatomsrk   rU   sumlistr3   setZresiduestyper"   rb   idxintersectionZbond_partnersaddremoveRuntimeErrorrW   r   r
   ZcoordinatesmaxminrY   )rZ   rf   rg   ZnoboxZcombinerh   r[   re   rd   rc   Zsplit_structZn_molsZunused_atomsZmoleculeZnew_moleculeZlast_found_atomrb   r=   Zoriginal_atomr\   r]   r^   ZcrdsZdiffr   )rm   r   ra      sx    









..:  
zGromacsGroFile.writeN)F)r-   FF)r?   r@   rA   rB   staticmethodrM   r_   ra   r   r   r   r   rC   G   s   /SrC   N)%rB   Z
__future__r   r   r   
contextlibr   Zparmed.constantsr   Zparmed.exceptionsr   Zparmed.formats.registryr   Zparmed.geometryr	   r
   r   Zparmed.periodic_tabler   r   r   Zparmed.structurer   Zparmed.topologyobjectsr   r   Zparmedr   rX   Zparmed.utils.ior   Zparmed.utils.sixr   r   objectr   rC   r   r   r   r   <module>   s   2