B
    b                 @   s  d Z ddlmZ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l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 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#m$Z$m%Z% ddl&m'Z' ddl(m)Z)m*Z*m+Z+m,Z, ddl-m.Z. e,rddlm/Z/ nddl0m/Z/ e1dddZ2e
3de2 Z4e
3de2 Z5e
3de2 Z6e
3de2 Z7e
3de2 Z8e
3de2 Z9e
3de2 Z:e
3dZ;e
3d e2 e
j<Z=e
3d!e2 e
j<Z>e
3d"e2 e
j<Z?[2d#d$ Z@e)eG d%d& d&eZAdS )'z
This module contains classes for parsing and processing Amber parameter files.

Author: Jason M. Swails
Contributors:
Date: Aug. 11, 2015
    )divisionprint_function)defaultdict)closingN   )AmberOFFLibrary   )TINY)ParameterErrorAmberWarningParameterWarning)ResidueTemplateContainer)Mol2File)FileFormatType)ParameterSet)Masselement_by_mass	AtomicNum)AtomTypeBondType	AngleTypeDihedralTypeDihedralTypeList)genopen)add_metaclassstring_types	iteritemsPY2)map)Sequencez([+-]?(?:\d+(?:\.\d*)?|\.\d+))z(".+?"|'.+?'|[\S]*))ZFLOATREZ
FILENAMEREz'(..?)-(..?)\s+%(FLOATRE)s\s+%(FLOATRE)sz-(..?)-(..?)-(..?)\s+%(FLOATRE)s\s+%(FLOATRE)szO(..?)-(..?)-(..?)-(..?)\s+%(FLOATRE)s\s+%(FLOATRE)s\s+%(FLOATRE)s\s+%(FLOATRE)sz8\s*%(FLOATRE)s\s+%(FLOATRE)s\s+%(FLOATRE)s\s+%(FLOATRE)szSCEE=\s*%(FLOATRE)szSCNB=\s*%(FLOATRE)szA(..?)-(..?)-(..?)-(..?)\s+%(FLOATRE)s\s+%(FLOATRE)s\s+%(FLOATRE)sz=({\s*["']([\w\+\-]+)["']\s*["'](\w+)["']\s*["'](\w+)["']\s*})z loadamberparams\s+%(FILENAMERE)szloadoff\s+%(FILENAMERE)sz((\S+)\s*=\s*loadmol[23]\s*%(FILENAMERE)sc             C   s   ddl m} t| dkr@| d | d hdhdhfkr@| dd } tj| rP| S tj|dd}tjtj|d	| rtj|d	| S tjtj|d
| rtj|d
| S |rtjtj|d	d| rtj|d	d| S td|  dS )z
    Finds an Amber file. Looks in the current directory, then the following
    locations:

    - $AMBERHOME/dat/leap/lib
    - $AMBERHOME/dat/leap/parm
    r   )	AMBERHOMEr   "'ZdatZleaplibparmZoldffzCannot find Amber file [%s]N)Zparmed.amberr    lenospathexistsjoin
ValueError)fnamesearch_oldffr    Zleapdir r.   6lib/python3.7/site-packages/parmed/amber/parameters.py_find_amber_file7   s    (r0   c                   s   e Zd ZdZedd Z fddZed$ddZe fd	d
Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd%ddZd&d"d#Z  ZS )'AmberParameterSetas   Class storing parameters from an Amber parameter set

    Parameters
    ----------
    filenames : str, list of str, file-like, or list of file-like; optional
        Either the name of a file or a list of filenames from which parameters
        should be parsed.

    Notes
    -----
    Order is important in the list of files provided. The parameters are loaded
    in the order they are provided, and any parameters that are specified in
    multiple places are overwritten (that is, the *last* occurrence is the
    parameter type that is used)

    See Also
    --------
    :class:`parmed.parameters.ParameterSet`
    c          
   C   s4  t t| d}|  | }| s\x|rB| sB| }q,W |sLdS | dkr\dS | dkrldS | }t|dk rdS t|d dkrdS yt|d  dS  tk
r   Y nX yt|d  W n tk
r   dS X yt|d  W n t	tfk
r   t|d dkr|d d 
 r^|d d 
 r|d d  |d d   }|tkrtt| t|d  dkr|d dkrttd t|d  dkrdS |d dkrdS nB|tkr\|d tkrtt|d  t|d  dkrdS dS nJ|d d  }|tkrNtt| t|d  dkrNdS |tkrdS nB|d d  }|tkrtt| t|d  dkrdS ndS nB|d d  }|tkrtt| t|d  dkrdS ndS Y nX t|d	kr"yt|d	  dS  tk
r   dS X ndS W d
Q R X d
S )aT  
        Identifies the file type as either an Amber-style frcmod or parm.dat
        file.

        Parameters
        ----------
        filename : str
            Name of the file to check format for

        Returns
        -------
        is_fmt : bool
            True if it is an Amber-style parameter file. False otherwise.
        rF)MASSBONDANGLEANGLDIHEDIHEDDIHEDRALIMPRIMPROPIMPROPERNONBNONBONNONBOND	NONBONDEDTr   r   r   C   N)r   r   readlinestriprstripsplitr&   floatr+   
IndexErrorisalphaupperlowerr   abs)filenameflinewordskeyr.   r.   r/   	id_formatg   s      (,
0(



zAmberParameterSet.id_formatc                s   t t|   d| _d| _g | _x|D ]}t|tr^t	|rR| j
t| q| | q&t|trx@|D ],}t	|r| j
t| qn| | qnW q&| | q&W d S )Ng333333?g       @)superr1   __init__Zdefault_sceeZdefault_scnbtitles
isinstancer   r   rR   residuesupdateparseload_parametersr   )self	filenamesrM   r,   )	__class__r.   r/   rT      s    





zAmberParameterSet.__init__Fc             C   s  |  }t |tr t|d}d}n|}d}dd }|tdd |}d|}|rX|  | }	d	d
 }
x|D ]}|dd}t	|r|
t	|d }|
t|| qnt	|r|
t	|d }|jtt|| qnt	|rnt	|\\}}tt||}t |trBtdt x&|D ]}||j|j< q*W qn||j|< qnW y|	d}W n tk
rx   d}Y nX |td }x@|t|k r|| dkr|| dkrtd|d7 }qW |t|krtdg }d}|d7 }xp|t|k r^|| }|dkr|d7 }n.|dkr:|d8 }|dkrHP n|dkrHd}|| |d7 }qW d| }xNt	|D ]@\}}}}|tkrtd| ||j krzt| |j | _!qzW |S )a   Load a parameter set from a leaprc file

        Parameters
        ----------
        fname : str or file-like
            Name of the file or open file-object from which a leaprc-style file
            will be read

        search_oldff : bool, optional, default=False
            If True, search the oldff directories in the main Amber leap
            folders. Default is False

        Notes
        -----
        This does not read all parts of a leaprc file -- only those pertinent to
        defining force field information. For instance, the following sections
        and commands are processed:

        - addAtomTypes
        - loadAmberParams
        - loadOFF
        - loadMol2
        - loadMol3
        r2   TFc             S   sl   g }g }xJ| D ]B}| dr2||d d  qn
|| |d| g }qW |rh|d| |S )Nz\
 )endswithappendr*   )linesnewlinesZ	compositerO   r.   r.   r/   	joinlines  s    


z0AmberParameterSet.from_leaprc.<locals>.joinlinesc             S   s   d| kr| S | d |  d S )N#)index)rO   r.   r.   r/   <lambda>      z/AmberParameterSet.from_leaprc.<locals>.<lambda>r_   c             S   s0   | d dkr| dd } |  dd dd} | S )Nr   )r"   r#   r   r!   	_BSTOKEN_z\  )replace)r,   r.   r.   r/   process_fname"  s    z4AmberParameterSet.from_leaprc.<locals>.process_fnamez\ ri   r   zSMulti-residue mol2 files not supported by tleap. Loading anyway using names in mol2Zaddatomtypes{z
	 z.Unsupported addAtomTypes syntax in leaprc filer   }
rj   z%s is not a recognized element)"rV   r   r   r   r*   closerK   rk   _loadparamsrefindallrZ   r0   
_loadoffrerW   rX   r   rY   _loadmol2rer   r   warningswarnr   namerf   r+   r&   r
   ra   rD   _atomtyperer   
atom_typesZatomic_number)clsr,   r-   ZparamsrN   
own_handlerd   rb   textZ	lowertextrl   rO   ZresnameZresidueZresidxZatom_types_stricharsZnopenchar_rw   ZsymbZhybr.   r.   r/   from_leaprc   s~    


 









 


zAmberParameterSet.from_leaprcc                s   t t| j|ddS )a   Extracts known parameters from a Structure instance

        Parameters
        ----------
        struct : :class:`parmed.structure.Structure`
            The parametrized ``Structure`` instance from which to extract
            parameters into a ParameterSet

        Returns
        -------
        params : :class:`ParameterSet`
            The parameter set with all parameters defined in the Structure
        F)Zallow_unequal_duplicates)rS   r1   from_structure)rz   Zstruct)r]   r.   r/   r   `  s    z AmberParameterSet.from_structurec             C   s   t |trt|d}d}n|}d}| j|   zJxD|D ]<}| sV| ||S | dkrn| ||S | ||S q>W W d|r|	  X dS )z Load a set of parameters from a single parameter file

        Parameters
        ----------
        fname : str or file-like
            Parameter file to parse
        r2   TF)r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   N)
rV   r   r   rU   ra   rC   rD   _parse_frcmod_parse_parm_datrp   )r[   r,   rN   r{   rO   r.   r.   r/   rZ   s  s    


z!AmberParameterSet.load_parametersc                sX   fdd}d}t dd }d}x.| D ]" s@q,drRd}q,njdrdd}q,nXdrvd	}q,nFd
rd}q,n4drd}q,n"drd}q,ndrd}q,|dkr|  q,|dkr|  q,|d	kr|  q,|dkr| ||}q,|dkr(|  q,|dkr>|  q,|dkr,| 	 q,W dS )z0 Parses an frcmod file from an open file object c              3   s   V  x D ]
} | V  qW d S )Nr.   )l)rN   rO   r.   r/   fiter  s    
 z.AmberParameterSet._parse_frcmod.<locals>.fiterNc               S   s   dS )NTr.   r.   r.   r.   r/   rg     rh   z1AmberParameterSet._parse_frcmod.<locals>.<lambda>r3   r4   r6   r5   r7   r9   r:   r<   r=   r?   LJEDITZNBFIX)
r   rE   
startswith_process_mass_line_process_bond_line_process_angle_line_process_dihedral_line_process_improper_line_process_nonbond_line_process_nbfix_line)r[   rN   rO   r   Zsectionfinished_dihedsrQ   r.   )rN   rO   r/   r     sV     









zAmberParameterSet._parse_frcmodc                s   fdd}| }t |}tdd }x(|rP| s<P |  t |}q*W t | t |}x(|r| svP |  t |}qdW t |}x(|r| sP |  t |}qW t |}d}x,|r| sP | ||}t |}qW t |}x.|r.| sP |  t |}qW t |}x|r| sPP y, dd \}}}	}
t	|	}	t	|
}
W n t
k
r   tdY nX |	dks|
dkrtd	t |}q:W t |}t }tt}xb|r>| sP  }x4|d
d D ]$}|d ||< ||d  | q
W t |}qW t | }t|dk rbtd|d
  dkr|tdt |}x.|r| sP |  t |}qW xt|D ]\}}| j| }|| jkr| j| jdk	rb| j| jdk	rbt|j| j| j tks8t|j| j| j tkrbtd|j|f t ||j | q| j| |j|j qW t | dkrt |}x0|r| sP | | t |}qW dS )z: Internal parser for parm.dat files from open file handle c              3   s$   V  x D ]
} | V  qW dV  d S )Nr_   r.   )r   )rN   rO   r.   r/   r     s    
 
z0AmberParameterSet._parse_parm_dat.<locals>.fiterc               S   s   dS )NTr.   r.   r.   r.   r/   rg     rh   z3AmberParameterSet._parse_parm_dat.<locals>.<lambda>N   zTrouble parsing 10-12 termsr   z<10-12 potential not supported in AmberParameterSet currentlyr   r   zHCould not parse the kind of nonbonded parameters in Amber parameter fileZREz&Only RE nonbonded parameters supportedzBEquivalency defined between %s and %s but parameters are not equalr   )nextr   rD   r   r   r   r   r   rF   rG   r+   r
   dictlistra   r&   rJ   r   r   ry   rminepsilonrL   r	   ru   rv   rw   r   removeset_lj_paramsr   )r[   rN   rO   r   Zrawliner   rQ   a1a2ZacoefZbcoefZequivalent_ljtypesZequivalent_typesrP   typatypZotypr.   )rN   rO   r/   r     s    






z!AmberParameterSet._parse_parm_datc             C   s   |  }yt|d }W n> tk
r<   td|d  Y n tk
rV   tdY nX |d | jkrx|| j|d  _nj|d dkrt|d t| jd |d}|| j|d < n2t|d t| jd |t	t
| }|| j|d < d S )Nr   z$Could not convert mass to float [%s]z*Error parsing MASS line. Not enough tokensr   )ZEPZLP)rF   rG   r+   r
   rH   ry   massr   r&   r   r   )r[   rO   rP   r   Zatyper.   r.   r/   r   ;  s    z$AmberParameterSet._process_mass_linec             C   sl   t |}|std| | \}}}}| }| }tt|t|}|| j||f< || j||f< d S )Nz#Could not understand BOND line [%s])_bondrematchr
   groupsrD   r   rG   
bond_types)r[   rO   rematchr   r   keqr   r.   r.   r/   r   O  s    
 z$AmberParameterSet._process_bond_linec       	      C   sz   t |}|std| | \}}}}}| }| }| }tt|t|}|| j|||f< || j|||f< d S )Nz$Could not understand ANGLE line [%s])_anglerer   r
   r   rD   r   rG   angle_types)	r[   rO   r   r   r   a3r   r   r   r.   r.   r/   r   Y  s    
  z%AmberParameterSet._process_angle_linec             C   s  t |}|s$|dkr$td| n|st|}|sBtd| | \}}}}|}	tt|	}
|	|ksnt||	 r~tdn| \}}}}}}}}| | | | f\}}}}||||f}	||||f}
|dk	r||	kr||
krt	
d||	f t dd t|D p dg}dd t|D p<d	g}t|}tt|t| t|t||d
 |d
 }||	 rt }|| | | j|	< | j|
< n| j|	 | |d
k ||	< ||
< |d
k r|	S dS )at   Processes a dihedral line, possibly part of a multi-term dihedral

        Parameters
        ----------
        line : str
            Line of the file that contains a dihedral term
        finished_diheds : dict
            Dictionary of dihedral parameters whose final term has been read in
            already (which means additional terms will overwrite, not add)
        last_key : str or None
            If not None, this is the key for the last dihedral type that should
            be implied if the atom types are missing. Atom types seem to only be
            required for the first term in a multi-term torsion definition

        Returns
        -------
        key or None
            If a negative periodicity indicates another term is coming, the
            current key is returned so it can be passed as key to the next
            _process_dihedral_call
        Nz'Could not understand DIHEDRAL line [%s]z9Cannot have an implied torsion that has already finished!zBExpecting next term in dihedral %r, got definition for dihedral %rc             S   s   g | ]}t |qS r.   )rG   ).0xr.   r.   r/   
<listcomp>  s    z<AmberParameterSet._process_dihedral_line.<locals>.<listcomp>g333333?c             S   s   g | ]}t |qS r.   )rG   )r   r   r.   r.   r/   r     s    g       @r   )_dihedrer   r
   	_dihed2rer   tuplereversedAssertionErrorrD   ru   rv   r   _sceererr   _scnbrerG   r   rL   r   ra   dihedral_types)r[   rO   r   Zlast_keyr   Zdivr   phiperrQ   Zrkeyr   r   r   a4sceescnbr   Ztypsr.   r.   r/   r   c  sH    



$


z(AmberParameterSet._process_dihedral_linec             C   s   t |}|std| | \}}}}}}}	| }| }| }| }t|||g\}}}||||f}
tt|t|	t|| j|
< d S )Nz'Could not understand IMPROPER line [%s])		_improprer   r
   r   rD   sortedr   rG   improper_periodic_types)r[   rO   r   r   r   r   r   r   r   r   rQ   r.   r.   r/   r     s    
  z(AmberParameterSet._process_improper_linec             C   s   y|  d d \}}}W n  tk
r:   td| Y nX y| j| t|t| W nB tk
rz   td| Y n$ tk
r   td||f Y nX d S )NrB   z0Could not understand nonbond parameter line [%s]z)Atom type %s not present in the database.z7Could not convert nonbond parameters to floats [%s, %s])rF   r+   r
   ry   r   rG   KeyError)r[   rO   r   r   epsr.   r.   r/   r     s    z'AmberParameterSet._process_nonbond_lineNc             C   s  y |  d d \}}}}}}W n  tk
r@   td| Y nX y$t|}t|}t|}t|}W n tk
r   tdY nX t|| || f| jt||t||f< |d k	rx<|| D ]0}	t|| || f| jt|	|t|	|f< qW x>|| D ]2}
t|| || f| jt||
t||
f< qW xR|| D ]F}	x>|| D ]2}
t|| || f| jt|	|
t|	|
f< qPW qBW d S )N   z%Could not understand LJEDIT line [%s]z.Could not convert LJEDIT parameters to floats.)	rF   r+   r
   rG   mathZsqrtnbfix_typesminmax)r[   rO   Zequivalentsr   r   Zrmin1Zeps1Zrmin2Zeps2Zoa1Zoa2r.   r.   r/   r     s(     ,
02z%AmberParameterSet._process_nbfix_lineCreated by ParmEdfrcmodc             C   s  t |trt|d}d}n|}d}|dkr6td| ||d |d |d x0t| jD ]"\}}|d	|d
|j	f  qfW |d |d t
 }x\t| jD ]N\\}	}
}t||krq|t| |d|	d|
d|j|jf  qW |d |d t
 }xlt| jD ]^\\}	}
}}t||krJq*|t| |d|	d|
d|d|j|jf  q*W |d |d t
 }x`t| jD ]P\\}	}
}}}t||krؐq|t| t |ts t|dkrZt |ts|d }|d|	d|
d|d|dd|j|j|j|j|jf
  nx\|dd D ]L}|d|	d|
d|d|dd|j|j|j |j|jf
  qhW |d }|d|	d|
d|d|dd|j|j|j|j|jf
  qW |d |d t }xt| jD ]\\}	}
}}}|
dkrt|dks^td|
|||	f\}	}
}}n|dkr||	||
f\}	}
}}t|	|
|g\}	}
}|	|
||f|kr||	|
||f |kr2tdq2|d|	d|
d|d|d|j|j|jf  |||	|
||f< q2W |d |d x6t| jD ](\}}|d|d|j|jf  qJW |d | j r|d xNt| j D ]@\\}	}
\}}|d|	d|
d||d ||d f  qW |r|!  dS )a   Writes a parm.dat file with the current parameters

        Parameters
        ----------
        dest : str or file-like
            The file name or file-like object to write the parameters to
        title : str, optional
            The title of the frcmod to write. Default is 'Created by ParmEd'
        style : str, optional
            If 'frcmod', the parameters are written in frcmod-format. If 'parm',
            the parameters are written in parm.dat-format. Default is 'frcmod'
        wTF)r   r%   z+style must be either frcmod or parm, not %sz
ro   zMASS
z%s%6.3f
r   zBOND
z%s-%s   %8.3f  %6.3f
r   zANGLE
z%s-%s-%s   %8.3f  %6.3f
zDIHE
r   r   z6%s-%s-%s-%s %4i %14.8f %8.3f %5.1f    SCEE=%s SCNB=%s
Nr!   z	IMPROPER
XzMalformed generic improper!z5Multiple impropers with the same atom set not allowedz%s-%s-%s-%s %14.8f %8.3f %5.1f
zNONB
z%s  %12.8f %12.8f
zLJEDIT
z"%s %s %12.8f %12.8f %12.8f %12.8f
)"rV   r   r   r+   writerE   r   ry   ljustr   setr   idaddr   Zreqr   Ztheteqr   r   r&   Zphi_kZphaser   r   r   r   r   r   r   r   r   r   rp   )r[   desttitleZstyleZoutfiler{   Zatomr   Zdoner   r   r   r   ZdtypZwritten_impropersr   r   r.   r.   r/   r     s    





 *

 

  &"$&



$

$

.zAmberParameterSet.write)F)N)r   r   )__name__
__module____qualname____doc__staticmethodrR   rT   classmethodr   r   rZ   r   r   r   r   r   r   r   r   r   r   __classcell__r.   r.   )r]   r/   r1   O   s"   ns2w

@
 r1   )Br   Z
__future__r   r   collectionsr   
contextlibr   r   r'   reru   Zofflibr   Z	constantsr	   
exceptionsr
   r   r   Zmodeller.residuer   Zformats.mol2r   Zformats.registryr   Z
parametersr   Zperiodic_tabler   r   r   Ztopologyobjectsr   r   r   r   r   Zutils.ior   Z	utils.sixr   r   r   r   Zutils.six.movesr   r   Zcollections.abcr   Zsubscompiler   r   r   r   r   r   r   rx   Irq   rs   rt   r0   r1   r.   r.   r.   r/   <module>   sT   
