
     i͟                     r   d Z ddlZddlZddlZddlZddlZej        dk    rddZnddZ[ G d de          Z	 G d	 d
e	          Z
 G d de	          Z G d de	          Z G d de	          Z G d de          Z G d de          Z G d d          Z G d de          Z G d de          ZdS )a  
:mod:`~gridData.OpenDX` --- routines to read and write simple OpenDX files
==========================================================================

The OpenDX format for multi-dimensional grid data. OpenDX is a free
visualization software, see http://www.opendx.org.

.. Note:: This module only implements a primitive subset, sufficient
          to represent n-dimensional regular grids.

The OpenDX scalar file format is specified in Appendix `B.2 Data
Explorer Native Files`_ [#OpenDXformat]_.

If you want to build a dx object from your data you can either use the
convenient :class:`~gridData.core.Grid` class from the top level
module (:class:`gridData.Grid`) or see the lower-level methods
described below.


.. _opendx-read-write:

Reading and writing OpenDX files
--------------------------------

If you have OpenDX files from other software and you just want to
**read** it into a Python array then you do not really need to use the
interface in :mod:`gridData.OpenDX`: just use
:class:`~gridData.core.Grid` and load the file::

  from gridData import Grid
  g = Grid("data.dx")

This should work for files produced by common visualization programs
(VMD_, PyMOL_, Chimera_). The documentation for :mod:`gridData` tells
you more about what to do with the :class:`~gridData.core.Grid`
object.

If you want to **write** an OpenDX file then you just use the
:meth:`gridData.core.Grid.export` method with `file_format="dx"` (or
just use a filename with extension ".dx")::

  g.export("data.dx")

However, some visualization programs do not implement full OpenDX
specifications and only read very specific, "OpenDX-like"
files. :mod:`gridData.OpenDX` tries to be compatible with these
formats. However, sometimes additional help is needed to write an
OpenDX file that can be read by a specific software, as described
below:

Known issues for writing OpenDX files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* APBS require the delta to be written to the seventh significant figure.
  The delta is now written to reflect this increase in precision.

  .. versionchanged:: 0.6.0

* PyMOL_ requires OpenDX files with the type specification "double" in
  the `class array` section (see issue `#35`_). By default (since
  release 0.4.0), the type is set to the one that most closely
  approximates the dtype of the numpy array :attr:`Grid.grid`, which
  holds all data. This is often :class:`numpy.float64`, which will
  create an OpenDX type "double", which PyMOL will read.

  However, if you want to *force* a specific OpenDX type (such as
  "float" or "double", see :attr:`gridData.OpenDX.array.dx_types` for
  available values) then you can use the ``type`` keyword argument::

    g.export("for_pymol.dx", type="double")

  If you always want to be able to read OpenDX files with PyMOL, it is
  suggested to always export with ``type="double"``.

  .. versionadded:: 0.4.0



.. _VMD: http://www.ks.uiuc.edu/Research/vmd/
.. _PyMOL: http://www.pymol.org/
.. _Chimera: https://www.cgl.ucsf.edu/chimera/
.. _`#35`: https://github.com/MDAnalysis/GridDataFormats/issues/35




Building a dx object from a numpy array ``A``
---------------------------------------------

If you have a numpy array ``A`` that represents a density in cartesian
space then you can construct a dx object (named a *field* in OpenDX
parlance) if you provide some additional information that fixes the
coordinate system in space and defines the units along the axes.

The following data are required:

grid
    numpy nD array (typically a nD histogram)
grid.shape
    the shape of the array
origin
    the cartesian coordinates of the center of the (0,0,..,0) grid cell
delta
    :math:`n \times n` array with the length of a grid cell along
    each axis; for regular rectangular grids the off-diagonal
    elements are 0 and the diagonal ones correspond to the
    'bin width' of the histogram, eg ``delta[0,0] = 1.0`` (Angstrom)

The DX data type ("type" in the DX file) is determined from the
:class:`numpy.dtype` of the :class:`numpy.ndarray` that is provided as
the *grid* (or with the *type* keyword argument to
:class:`gridData.OpenDX.array`).

For example, to build a :class:`field`::

  dx = OpenDX.field('density')
  dx.add('positions', OpenDX.gridpositions(1, grid.shape, origin, delta))
  dx.add('connections', OpenDX.gridconnections(2, grid.shape))
  dx.add('data', OpenDX.array(3, grid))

or all with the constructor::

  dx = OpenDX.field('density', components=dict(
            positions=OpenDX.gridpositions(1,grid.shape, d.origin, d.delta),
            connections=OpenDX.gridconnections(2, grid.shape),
            data=OpenDX.array(3, grid)))


Building a dx object from a dx file
-----------------------------------

One can also read data from an existing dx file::

 dx = OpenDX.field(0)
 dx.read('file.dx')

Only simple arrays are read and initially stored as a 1-d
:class:`numpy.ndarray` in the `dx.components['data'].array` with the
:class:`numpy.dtype` determined by the DX type in the file.

The dx :class:`field` object has a method
:meth:`~OpenDX.field.histogramdd` that produces output identical to
the :func:`numpy.histogramdd` function by taking the stored dimension
and deltas into account. In this way, one can store nD histograms in a
portable and universal manner::

  histogram, edges = dx.histogramdd()

.. rubric:; Footnotes

.. [#OpenDXformat] The original link to the OpenDX file format specs
   http://opendx.sdsc.edu/docs/html/pages/usrgu068.htm#HDREDF is dead so I am linking
   to an archived copy at the Internet Archive , `B.2 Data Explorer Native Files`_.

.. _`B.2 Data Explorer Native Files`:
   https://web.archive.org/web/20080808140524/http://opendx.sdsc.edu/docs/html/pages/usrgu068.htm
.. http://opendx.sdsc.edu/docs/html/pages/usrgu068.htm#HDREDF

Classes
-------

DX field class
~~~~~~~~~~~~~~

The primary class is :class:`field`, which is a container for the other classes.
It contains the following classes:

* :class:`gridpositions`
* :class:`gridconnections`
* :class:`array`

The :class:`gridpositions` class contains the position of the grid cells.
The :class:`gridconnections` class contains the connections between the grid cells.
The :class:`array` class contains the data on the grid.

.. autoclass:: field
   :members:

DX components
~~~~~~~~~~~~~

The :class:`field` class contains the following components:

.. autoclass:: gridpositions
   :members:

.. autoclass:: gridconnections
   :members:

.. autoclass:: array
   :members:

DX parser
~~~~~~~~~~
The :class:`DXParser` class is used to parse the DX file and construct the :class:`field` object.

.. autoclass:: DXParser
   :members:

    N)   rtc                 ,    t          j        | |          S Ngzipopenfilenamemodes     Y/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/gridData/OpenDX.py
_gzip_openr      s    y4(((    c                 *    t          j        |           S r   r   r
   s     r   r   r      s    y"""r   c                   J    e Zd ZdZd ZddZedd            Zd Zd Z	d	 Z
d
S )DXclassz#'class' object as defined by OpenDXc                 >    || _         d| _        d| _        d| _        dS )zid is the object numberN)idname	componentD)selfclassids     r   __init__zDXclass.__init__   s"    	r    Fc                     t          | j                  }|rd|z   dz   }d|z   dz   t          | j                  z   dz   |z   dz   }|                     ||           dS )z=write the 'object' line; additional args are packed in string"zobject z class  
N)strr   r   _write_line)r   stream	optstringquoter   to_writes         r   writezDXclass.write   sj    dg,,+CKO' W$Y.s49~~=cA)KDP*****r   c                     t          | t          j                  r|                                }|                     |           dS )zwrite a line to the fileN)
isinstancer   GzipFileencoder&   )r"   liner$   s      r   r!   zDXclass._write_line   s=     fdm,, 	!;;==DTr   c                      t          d          )Nz#Reading is currently not supported.)NotImplementedError)r   r"   s     r   readzDXclass.read   s    !"GHHHr   c                 0    |t          | j                  z  S )zbReturns a string with as many repetitions of s as self
        has dimensions (derived from shape))lenshape)r   ss     r   ndformatzDXclass.ndformat   s     3tz??""r   c                 f    dt          | j                  z   dz   t          | j                  z   dz   S )Nz<OpenDX.z object, id=>)r    r   r   r   s    r   __repr__zDXclass.__repr__   s,    #di..(7DGDSHHr   N)r   F)__name__
__module____qualname____doc__r   r&   staticmethodr!   r.   r3   r7    r   r   r   r      s        --  + + + +    \I I I# # #
I I I I Ir   r   c                   0     e Zd ZdZddZ fdZd Z xZS )gridpositionszOpenDX gridpositions class.

    shape     D-tuplet describing size in each dimension
    origin    coordinates of the centre of the grid cell with index 0,0,...,0
    delta     DxD array describing the deltas
    Nc                    |||t          d          || _        d| _        d| _        t	          j        |          | _        t	          j        |          | _        t          | j                  | _	        t	          j        |          | _
        t          | j
        j                  dk    rt	          j        |          | _
        | j
        j        | j	        | j	        fk    r't          d                    | j
                            d S )N"all keyword arguments are requiredr?   	positions   z1Only regularly spaced grids allowed, not delta={})
ValueErrorr   r   r   numpyasarrayr1   originr0   rankdeltadiagr-   format)r   r   r1   rG   rI   kwargss         r   r   zgridpositions.__init__  s    =FNemABBB#	$]5))
mF++
OO	]5))
 tz  A%%E**DJ:	49555 & '55;VDJ5G5GI I I 65r   c           	         t          t          |                               |d|                     d          z   t	          | j                  z             |                     |dt	          | j                  z             | j        D ]9}|                     |d |                     d          j	        | z   dz              :d S )Ncounts  %dzorigin %f %f %f
zdelta z {:.7g}r   )
superr?   r&   r3   tupler1   r!   rG   rI   rK   )r   r"   rI   	__class__s      r   r&   zgridpositions.write   s    mT""((Yt}}U333uTZ7H7HH	J 	J 	J!4uT[7I7I!IJJJZ 	  	 E8y118%@A       	  	 r   c                 D      fdt           j                  D             S )z}Edges of the grid cells, origin at centre of 0,0,..,0 grid cell.

        Only works for regular, orthonormal grids.
        c                     g | ]U}j         ||f         t          j        j        |         d z             z  j        |         z   dj         ||f         z  z
  VS )rC   g      ?)rI   rE   aranger1   rG   ).0dr   s     r   
<listcomp>z'gridpositions.edges.<locals>.<listcomp>/  st     E E E./ 
1Q3%,tz!}Q"?"??$+a.Pdj1o%& E E Er   )rangerH   r6   s   `r   edgeszgridpositions.edges*  s@    
E E E E383C3CE E E 	Er   )NNN)r8   r9   r:   r;   r   r&   rZ   __classcell__rR   s   @r   r?   r?     sp         I I I I*         E E E E E E Er   r?   c                   *     e Zd ZdZddZ fdZ xZS )gridconnectionszOpenDX gridconnections classNc                     |t          d          || _        d| _        d| _        t	          j        |          | _        d S )NrA   r^   connections)rD   r   r   r   rE   rF   r1   )r   r   r1   rL   s       r   r   zgridconnections.__init__5  s@    =ABBB%	&]5))


r   c                     t          t          |                               |d|                     d          z   t	          | j                  z             d S )NrN   rO   )rP   r^   r&   r3   rQ   r1   )r   r"   rR   s     r   r&   zgridconnections.write=  sY    ot$$**Yt}}U333uTZ7H7HH	J 	J 	J 	J 	Jr   r   )r8   r9   r:   r;   r   r&   r[   r\   s   @r   r^   r^   3  s[        &&* * * *J J J J J J J J Jr   r^   c                   b     e Zd ZdZdddddddddd	dd
ZddddddddddddZddZ fdZ xZS )arrayzOpenDX array class.

    See `Array Objects`_ for details.

    .. _Array Objects:
       https://web.archive.org/web/20080808140524/http://opendx.sdsc.edu/docs/html/pages/usrgu068.htm#Header_440
    bytesigned byteunsigned shortshortunsigned intintfloatdouble)uint8int8uint16int16uint32int32uint64int64float32float64float16rl   rm   rn   ro   rp   rq   rt   ru   )rd   zunsigned bytere   rf   rg   zsigned shortrh   ri   z
signed intrj   rk   Nr   c           
         |t          d          || _        d| _        d| _        |t	          j        |          | _        	 | j        | j        j        j                 | _	        n# t          $ rO t          j        d                    | j        j        j                             | j        j        j        | _	        Y nw xY w	 t	          j        || j        |                   | _        nU# t          $ rH t          d                    |t          | j                                                                      w xY w|| _	        || _        dS )av  
        Parameters
        ----------
        classid : int
        array : array_like
        type : str (optional)
             Set the DX type in the output file and cast `array` to
             the closest numpy dtype.  `type` must be one of the
             allowed types in DX files as defined under `Array
             Objects`_.  The default ``None`` tries to set the type
             from the :class:`numpy.dtype` of `array`.

             .. versionadded:: 0.4.0

        Raises
        ------
        ValueError
             if `array` is not provided; or if `type` is not of the correct
             DX type
        Nz"array keyword argument is requiredrc   datazarray dtype.name = {0} can not be automatically converted to a DX array type. Use the 'type' keyword to manually specify the correct type.)dtypezWDX type {0} cannot be converted to an appropriate numpy dtype. Available types are: {1})rD   r   r   r   rE   rF   rc   np_typesry   typeKeyErrorwarningswarnrK   dx_typeslistvalues	typequote)r   r   rc   r{   r   rL   s         r   r   zarray.__init__p  sd   , =ABBB	<u--DJ2 M$**:*?@		 2 2 2  GHN#':#3#8I: I:; ; ; !J,1			2Z"]5d8KLLL

 Z Z Z  #3396$:>t}?S?S?U?U:V:V4X 4XZ Z ZZ
 DI"s    !A% %AB>=B>&C) )AD;c           	         | j         | j        vrLt          d                    | j         t	          | j                                                                      | j        | j         z   | j        z   }t          t          |           	                    |d                    || j        j
                             d}| j        j        j        dk    s| j        j        j        dk    r>t          j        | j        j                  j        }dd                    |          z   dz   }d}| j        j        }	 	 t#          |          D ];}|                     ||                    t'          |                    d
z              <|                     |d           n&# t(          $ r |                     |d           Y nw xY w|                     |d           dS )zWrite the *class array* section.

        Parameters
        ----------
        stream : stream

        Raises
        ------
        ValueError
             If the `dxtype` is not a valid type, :exc:`ValueError` is
             raised.

        zlDX type {} is not supported in the DX format. 
Supported valus are: {}
Use the type=<type> keyword argument.z&type {0} rank 0 items {1} data followsz{:d}fcz{:.zf}r   rC   	r   z#attribute "dep" string "positions"
N)r{   r   rD   rK   r   keysr   rP   rc   r&   sizery   kindrE   finfo	precisionflatrY   r!   nextStopIteration)	r   r"   	typelabel
fmt_stringr   values_per_liner   irR   s	           r   r&   zarray.write  s    9DM)) FGMv"&)T$-2D2D2F2F-G-GHI HIJ J J ^DI-dn<	eT  )Q)X)Xtz*( *( 	) 	) 	) 
J!S((DJ,<,AS,H,HDJ$455?Iv}}Y777<J	// U UA$$VZ->->tF||-L-Lt-STTTT  ....      ...	 	!GHHHHHs   4A!F  F98F9)NNr   )	r8   r9   r:   r;   rz   r   r   r&   r[   r\   s   @r   rc   rc   B  s          "   H(  "  H /# /# /# /#b(I (I (I (I (I (I (I (I (Ir   rc   c                   `     e Zd ZdZddZd Z fdZd Zd Zd	 Z	d
 Z
d Zd Zd Zd Z xZS )fieldzOpenDX container class

    The *field* is the top-level object and represents the whole
    OpenDX file. It contains a number of other objects.

    Instantiate a DX object from this class and add subclasses with
    :meth:`add`.

    0Nc                     |t          ddd          }|ddg}n&t          |          t          urt          |          g}|| _        d| _        d| _        || _        || _        dS )a,  OpenDX object, which is build from a list of components.

        Parameters
        ----------

        id : str
               arbitrary string
        components : dict
               dictionary of DXclass instances (no sanity check on the
               individual ids!) which correspond to

               * positions
               * connections
               * data

        comments : list
               list of strings; each string becomes a comment line
               prefixed with '#'. Avoid newlines.


        A field must have at least the components 'positions',
        'connections', and 'data'. Those components are associated
        with objects belonging to the field. When writing a dx file
        from the field, only the required objects are dumped to the file.

        (For a more general class that can use field:
        Because there could be more objects than components, we keep a
        separate object list. When dumping the dx file, first all
        objects are written and then the field object describes its
        components. Objects are referenced by their unique id.)

        .. Note:: uniqueness of the *id* is not checked.


        Example
        -------
        Create a new dx object::

           dx = OpenDX.field('density',[gridpoints,gridconnections,array])

        N)rB   r`   rx   z!OpenDX written by gridData.OpenDXz2from https://github.com/MDAnalysis/GridDataFormatsr   )	dictr{   r   r    r   r   r   
componentscomments)r   r   r   r   s       r   r   zfield.__init__  sz    T 4HHHJ;LNHH(^^4''HH	$r   c                 v    |                     d          rt          j        |d          S t          |d          S )z/Returns a regular or gz file stream for writing.gzwbw)endswithr   r	   r   r   s     r   _openfile_writingzfield._openfile_writing  s:    U## 	'9Xt,,,#&&&r   c                 B   d}|                      t          |                    5 }| j        D ]5}dt          |          z   }|                     ||d|         dz              6|                                 D ]\  }}|                    |           t          t          |                               |d           |                                 D ]4\  }}|                     |d|dt          |j                  d           5	 ddd           dS # 1 swxY w Y   dS )	a8  Write the complete dx object to the file.

        This is the simple OpenDX format which includes the data into
        the header via the 'object array ... data follows' statement.

        Only simple regular arrays are supported.

        The format should be compatible with VMD's dx reader plugin.
        P   z# Nr   T)r$   zcomponent "z" value )	r   r    r   r!   sorted_componentsr&   rP   r   r   )	r   r   maxcoloutfiler+   commentr   objectrR   s	           r   r&   zfield.write  s    ##CMM22 	0g A As4yy.  ''6'*:4*?@@@@%)%;%;%=%= & &!	6W%%%%%$$WD$999%)%;%;%=%= 0 0!	6  IIs69~~~~+/ 0 0 0 00	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0s   C DDDc                 R    | }t          |          }|                    |           dS )zRead DX field from file.

            dx = OpenDX.field.read(dxfile)

        The classid is discarded and replaced with the one from the file.
        N)DXParserparse)r   r"   DXfieldps       r   r.   z
field.read.  s.     V	r   c                     || |<   dS )zadd a component to the fieldNr=   )r   r   DXobjs      r   addz	field.add9  s    Yr   c                 :    | j                             |           dS )zadd commentsN)r   append)r   r   s     r   add_commentzfield.add_comment=  s    W%%%%%r   c              #   t   K   t          | j                                        d           D ]\  }}||fV  dS )z4iterator that returns (component,object) in id orderc                     | d         j         S )NrC   )r   )comp_objs    r   <lambda>z)field.sorted_components.<locals>.<lambda>E  s    HQKN r   )keyN)sortedr   items)r   r   r   s      r   r   zfield.sorted_componentsA  sa       t,,..::< < <	$ 	$Iv V#####	$ 	$r   c                     | j         d         j        }| j         d                                         }| j         d         j                            |          }||fS )z=Return array data as (edges,grid), i.e. a numpy nD histogram.rB   rx   )r   r1   rZ   rc   reshape)r   r1   rZ   hists       r   histogramddzfield.histogramddH  sP    ,2,2244v&,44U;;U|r   c                     | j         |         S r   r   )r   r   s     r   __getitem__zfield.__getitem__O  s    s##r   c                     || j         |<   d S r   r   )r   r   values      r   __setitem__zfield.__setitem__R  s    $r   c                     dt          | j                  z   dz   t          t          | j                            z   dz   t          t          | j                            z   dz   S )Nz<OpenDX.field object, id=z, with z components and z	 objects>)r    r   r0   r   r6   s    r   r7   zfield.__repr__U  s`    *3tw<<7	A3t''(());<3t''(())45 	5r   )r   NN)r8   r9   r:   r;   r   r   r&   r.   r   r   r   r   r   r   r7   r[   r\   s   @r   r   r     s         5  5  5  5 n' ' '0 0 0 0 02	 	 	     & & &$ $ $  $ $ $% % %5 5 5 5 5 5 5r   r   c                       e Zd ZdZdS )DXParseErrorz0general exception for parsing errors in DX filesNr8   r9   r:   r;   r=   r   r   r   r   _  s        ::Dr   r   c                       e Zd ZdZdS )DXParserNoTokensz)raised when the token buffer is exhaustedNr   r=   r   r   r   r   b  s        33Dr   r   c            
       n    e Zd Zdgdgg ddgdgdgddgdZd eeeed	eeed
	Zd Zd Z	d Z
ddZd Zd	S )TokenCOMMENTWORD)QUOTEDSTRING
BARESTRINGSTRING
WHITESPACEINTEGERREAL)r   r   r   r   r   r   NUMBERc                 .    t          j        dd|           S )Nz#\s*r   )resub)r2   s    r   r   zToken.<lambda>p  s    wr! 4 4 r   N)	r   r   r   r   r   r   r   r   r   c                 "    || _         || _        d S r   )codetext)r   r   r   s      r   r   zToken.__init__v  s    				r   c                     | j         |k    S r   )r   )r   vs     r   equalszToken.equalsy  s    yA~r   c                 *    | j         | j        |         v S r   )r   category)r   r   s     r   iscodezToken.iscode{  s    yDM$///r   c                 J    || j         } | j        |         | j                  S )z9Return text cast to the correct type or the selected type)r   castr   )r   ascodes     r   r   zToken.value}  s'    >YF ty +++r   c                     dt          | j                  z   dz   t          |                                           z   dz   S )Nz<token ,r5   )r    r   r   r6   s    r   r7   zToken.__repr__  s4    TY'+C

,=,==cAAr   r   )r8   r9   r:   r   r    rj   ri   r   r   r   r   r   r7   r=   r   r   r   r   f  s        %;@@@+n%;$V,. .H 543cU	< <D    0 0 0, , , ,
B B B B Br   r   c                   >    e Zd ZdZeeeedZd Z	d Z
d Zd Zd ZdS )	DXInitObjectzStorage class that holds data to initialize one of the 'real'
    classes such as OpenDX.array, OpenDX.gridconnections, ...

    All variables are stored in args which will be turned into the
    arguments for the DX class.
    )r?   r^   rc   r   c                 H    || _         || _        t                      | _        d S r   )r{   r   r   args)r   	classtyper   s      r   r   zDXInitObject.__init__  s    	FF			r   c                 H     | j         | j                 | j        fi | j        S )zgInitialize the corresponding DXclass from the data.

        class = DXInitObject.initialize()
        )	DXclassesr{   r   r   r6   s    r   
initializezDXInitObject.initialize  s)    
 )t~di(==49===r   c                     | j         |         S r   r   )r   ks     r   r   zDXInitObject.__getitem__  s    y|r   c                     || j         |<   d S r   r   )r   r   r   s      r   r   zDXInitObject.__setitem__  s    	!r   c                 f    dt          | j                  z   dz   t          | j                  z   dz   S )Nz<DXInitObject instance type=z, id=r5   )r    r{   r   r6   s    r   r7   zDXInitObject.__repr__  s-    -c$)nn<WDS\\QRUUUr   N)r8   r9   r:   r;   r?   r^   rc   r   r   r   r   r   r   r7   r=   r   r   r   r     s          "/#2 I
  > > >    V V V V Vr   r   c                       e Zd ZdZ ej        dej                  Zd Zd Z	d Z
d Zd Zd Zd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd ZdS )r   a  Brain-dead baroque implementation to read a simple (VMD) dx file.

    Requires a OpenDX.field instance.

    1) scan for 'object' lines:
       'object' id 'class' class  [data]
       [data ...]
    2) parse data according to class
    3) construct dx field from classes
    a
  
    (?P<COMMENT>\#.*$)            # comment (until end of line)
    |(?P<WORD>(object|class|counts|origin|delta|type|counts|rank|items|data))
    |"(?P<QUOTEDSTRING>[^\"]*)"   # string in double quotes  (quotes removed)
    |(?P<WHITESPACE>\s+)          # white space
    |(?P<REAL>[-+]?               # true real number (decimal point or
    (\d+(\.\d*)?|\.\d+)           # scientific notation) and integers
    ([eE][-+]?\d+)?)
    |(?P<BARESTRING>[a-zA-Z_][^\s\#\"]+) # unquoted strings, starting with non-numeric
    c                     t          |          | _        t          dd                    | j                  g          | _        | j        | j        | j        | j        | j        | j	        | j
        d| _        dS )a  Setup a parser for a simple DX file (from VMD)

        >>> DXfield_object = OpenDX.field(id)
        >>> p = DXparser('bulk.dx')
        >>> p.parse(DXfield_object)

        The field object will be completely rewritten (including the
        id if one is found in the input file. The input files
        component layout is currently ignored.

        Note that quotes are removed from quoted strings.
        z	grid datazfilename: {0})r   )generalr   r   r?   r^   rc   r   N)r    r   r   rK   _DXParser__general_DXParser__comment_DXParser__object_DXParser__gridpositions_DXParser__gridconnections_DXParser__array_DXParser__fieldparsersr   s     r   r   zDXParser.__init__  so     H;1G1G1V1V0WXXX
 #'."&.4=(,(<*.*@ $dl	 r   c                 D   || _         d| _        g | _        g | _        | j                            d          rHt          | j        d          5 | _        |                     d           ddd           n# 1 swxY w Y   nGt          | j        d          5 | _        |                     d           ddd           n# 1 swxY w Y   | j        D ]N}|j
        dk    r|j        |_        |                                }| j                             |j        |           O| `| `dS )aB  Parse the dx file and construct a DX field object with component classes.

        A :class:`field` instance *DXfield* must be provided to be
        filled by the parser::

           DXfield_object = OpenDX.field(*args)
           parse(DXfield_object)

        A tokenizer turns the dx file into a stream of tokens. A
        hierarchy of parsers examines the stream. The level-0 parser
        ('general') distinguishes comments and objects (level-1). The
        object parser calls level-3 parsers depending on the object
        found. The basic idea is that of a 'state machine'. There is
        one parser active at any time. The main loop is the general
        parser.

        * Constructing the dx objects with classtype and classid is
          not implemented yet.
        * Unknown tokens raise an exception.
        Nr   r   r   rr   )r   currentobjectobjectstokensr   r   r   dxfile
use_parserr	   r{   r   r   r   r   )r   r   or   s       r   r   zDXParser.parse  s   , !=!!%(( 	+DM400 +DK	***+ + + + + + + + + + + + + + + dmS)) +T[	***+ + + + + + + + + + + + + + +  	, 	,Av   T
ALQ[++++ s$   A33A7:A7B;;B?B?c                    	 	 |                                  }nE# t          $ r8 | j        r-| j        | j        vr| j                            | j                   Y dS w xY w|                    d          r|                     d           nm|                    d          r+|                    d          r|                     d           n-| j        | j	        u rt          dt          |          z             |                                  	)zlLevel-0 parser and main loop.

        Look for a token that matches a level-1 parser and hand over control.rC   Nr   r   r   r   zUnknown level-1 construct at )_DXParser__peekr   r   r  r   r   
set_parserr   _DXParser__parserr   r   r    apply_parserr   toks     r   	__generalzDXParser.__general  s   	 kkmm#    % <$*<DL*P*PL''(:;;; zz)$$ 
M	****F## M

8(<(< M))))$.00 ##B3s88#KLLL1	 s    >AAc                     |                                  }| j                            |                                           |                     d           dS )zLevel-1 parser for comments.

        pattern: #.*
        Append comment (with initial '# ' stripped) to all comments.
        r   N)_DXParser__consumer   r   r   r  r  s     r   	__commentzDXParser.__comment,  sI     nn  ---	"""""r   c                    |                                   |                                  j        }|                                  j        }|dk    rt          d|z            | j        r| j                            | j                   |                                  j        }t          ||          | _        |                     |           dS )zLevel-1 parser for objects.

        pattern: 'object' id 'class' type ...

        id ::=   integer|string|'"'white space string'"'
        type ::= string
        classz*reserved word %s should have been 'class'.)r   r   N)r  r   r   r   r  r   r   r  )r   r   wordr   s       r   __objectzDXParser.__object6  s     	..""'~~$7??KdRSSS 	4L 2333NN$$)	)IgNNN	"""""r   c                 :   	 |                                  }n# t          $ r Y dS w xY w|                    d          rg }	 	 |                                                     d           |                                  }|                    |                    d                     d# t          t          f$ r Y nw xY wt          |          dk    rt          d          || j	        d<   dS |                    d          rg }	 |                                 
                    d          s'|                                 
                    d	          r|                                  }|                    |                                           |                                 
                    d          b|                                 
                    d	          n# t          $ r Y nw xY wt          |          dk    rt          d
          || j	        d<   dS |                    d          rLg }	 |                                 
                    d          s'|                                 
                    d	          r|                                  }|                    |                                           |                                 
                    d          b|                                 
                    d	          n# t          $ r Y nw xY wt          |          dk    rt          d          	 | j	        d                             |           dS # t          $ r |g| j	        d<   Y dS w xY wt          dt          |          z   dz             )zLevel-2 parser for gridpositions.

        pattern:
        object 1 class gridpositions counts 97 93 99
        origin -46.5 -45.5 -48.5
        delta 1 0 0
        delta 0 1 0
        delta 0 0 1
        NcountsTr   r   z"gridpositions: no shape parametersr1   rG   r   z#gridpositions: no origin parametersrI   z'gridpositions: missing delta parameterszgridpositions:  not recognized.)r  r   r   r  r   r   rD   r0   r   r   r   r|   r    )r   r  r1   rG   rW   s        r   __gridpositionszDXParser.__gridpositionsM  s   	..""CC 	 	 	FF	 ::h )	NE7KKMM''	222..**CLL9!5!5666	7
 %j1   5zzQ"#GHHH*/Dw'''ZZ!! 	NF{{}}++I66 /{{}}++F33/..**CMM#))++... {{}}++I66 /{{}}++F33/ $   6{{a"#HIII+1Dx(((ZZ   	NA{{}}++I66 *{{}}++F33*..**CHHSYY[[))) {{}}++I66 *{{}}++F33* $   1vv{{"#LMMM2"7+22155555 2 2 2/0c"7++++2 0S9:LLMMMsW    
%% A%B% %B98B9CG 
G('G(2CL
 

LL= M M87M8c                    	 |                                  }n# t          $ r Y dS w xY w|                    d          rg }	 	 |                                                     d           |                                  }|                    |                    d                     d# t          t          f$ r Y nw xY wt          |          dk    rt          d          || j	        d<   dS t          dt          |          z   d	z             )
zuLevel-2 parser for gridconnections.

        pattern:
        object 2 class gridconnections counts 97 93 99
        Nr  Tr   r   z$gridconnections: no shape parametersr1   zgridconnections: r  )r  r   r   r  r   r   rD   r0   r   r   r    )r   r  r1   s      r   __gridconnectionszDXParser.__gridconnections  s&   	..""CC 	 	 	FF	 ::h 	PE7KKMM''	222..**CLL9!5!5666	7
 %j1   5zzQ"#IJJJ*/Dw'''23s88;<NNOOOs    
%% A%B% %B98B9c                    	 |                                  }n# t          $ r Y dS w xY w|                    d          r^|                                  }|                    d          st	          d|j        z            |                                | j        d<   dS |                    d          rY|                                  }	 |                    d          | j        d<   dS # t          $ r t	          d|j        z            w xY w|                    d          rY|                                  }	 |                    d          | j        d	<   dS # t          $ r t	          d
|j        z            w xY w|                    d          r1|                                  }|                    d          st	          d|j        z            |j        dk    rt          d          | j        d	         st	          d          g | j        d<   t          | j        d                   | j        d	         k     r| j        d                             | j                                                                                                                   t          | j        d                   | j        d	         k     dS dS |                    d          r|                                                                  }|                                                      d          st	          d          |                                                                  }dS t	          dt!          |          z   dz             )zLevel-2 parser for arrays.

        pattern:
        object 3 class array type double rank 0 items 12 data follows
        0 2 0
        0 0 3.6
        0 -2.0 1e-12
        +4.534e+01 .34534 0.43654
        attribute "dep" string "positions"
        Nr{   r   z#array: type was "%s", not a string.rH   r   z%array: rank was "%s", not an integer.r   r   z&array: items was "%s", not an integer.rx   z#array: data was "%s", not a string.followsz:array: Only the "data follows header" format is supported.zarray: missing number of itemsrc   	attributestringzarray: "string" expected.zarray: r  )r  r   r   r   r   r   r   r   rD   r-   r0   extendr  readlinestripsplitr    )r   r  r  r   s       r   __arrayzDXParser.__array  s   	..""CC 	 	 	FF	 ::f 3	F..""C::h'' -"#H#&8$, - - -),Dv&&&ZZ -	F..""C--0YYy-A-A"6*** - - -"#J#&8$, - - -- ZZ   &	F..""C--0YYy-A-A"6*** - - -"#K#&8$, - - -- ZZ 	F..""C::h'' -"#H#&8$, - - -x9$$)XZ Z Z%f- E"#CDDD +-Dw'd(122D4Fv4NNN#G,33DK4H4H4J4J4P4P4R4R4X4X4Z4Z[[[ d(122D4Fv4NNNNNNN ZZ$$ 	F((..00I>>##**844 @"#>???NN$$**,,EEEyS12DDEEEs$    
%%C$ $"D3E "E4c                 "   	 |                                  }n# t          $ r Y dS w xY w|                    d          r|                                                                  }|                                                      d          st	          d          |                                                                  }	 || j        d         |<   dS # t          $ r ||i| j        d<   Y dS w xY wt	          dt          |          z   dz             )zLevel-2 parser for a DX field object.

        pattern:
        object "site map 1" class field
        component "positions" value 1
        component "connections" value 2
        component "data" value 3
        Nr   r   zfield: "value" expectedr   zfield: r  )r  r   r   r   r   r   r|   r    )r   r  r   r   s       r   __fieldzDXParser.__field  s/   	..""CC 	 	 	FF	 ::k"" 
	F((..00I>>##**733 >"#<===nn&&,,..GG>E"<0;;; G G G4=g3F"<0000G yS12DDEEEs    
%% C C,+C,c                 R    | j         |         | _        |                                  dS )z2Set parsername as the current parser and apply it.Nr   r	  r   
parsernames     r   r  zDXParser.use_parser  s!    Z0r   c                 *    | j         |         | _        dS )z%Set parsername as the current parser.Nr'  r(  s     r   r  zDXParser.set_parser  s    Z0r   c                 .    |                                   dS )z-Apply the current parser to the token stream.N)r	  r6   s    r   r
  zDXParser.apply_parser  s    r   c                 $   | j                             |                                          D ]b}|j        }|                    |j                  }t          ||          }|                    d          s| j                            |           cdS )zSplit s into tokens and update the token buffer.

        __tokenize(string)

        New tokens are appended to the token buffer, discarding white
        space.  Based on http://effbot.org/zone/xml-scanner.htm
        r   N)	dx_regexfinditerr!  	lastgroupgroupr   r   r  r   )r   r  mr   r   r  s         r   
__tokenizezDXParser.__tokenize  s     ''77 	) 	)A;D771;''DT""C::l++ )##C(((	) 	)r   c                     t          | j                  dk    r.|                     | j                                                   dS dS )aG  Add a new tokenized line from the file to the token buffer.

        __refill_tokenbuffer()

        Only reads a new line if the buffer is empty. It is safe to
        call it repeatedly.

        At end of file, method returns empty strings and it is up to
        __peek and __consume to flag the end of the stream.
        r   N)r0   r  _DXParser__tokenizer  r   r6   s    r   __refill_tokenbufferzDXParser.__refill_tokenbuffer"  sG     t{q  OODK002233333 ! r   c                 p    |                                   	 | j        d         S # t          $ r t          w xY w)Nr   )_DXParser__refill_tokenbufferr  
IndexErrorr   r6   s    r   __peekzDXParser.__peek0  sF    !!###	#;q>! 	# 	# 	#""	#s   # 5c                     |                                   	 | j                            d          S # t          $ r t          w xY w)zGet the next token from the buffer and remove it/them.

        try:
          while 1:
             token = __consume()
        except DXParserNoTokens:
          pass
        r   )r7  r  popr8  r   r6   s    r   	__consumezDXParser.__consume7  sP     	!!###	#;??1%%% 	# 	# 	#""	#s	   0 AN)r8   r9   r:   r;   r   compileVERBOSEr-  r   r   r   r   r   r   r   r   r   r  r  r
  r4  r7  r  r  r=   r   r   r   r     sB       	 	 rz 	 
	 	H  21- 1- 1-j     @# # ## # #.8N 8N 8NvP P P8CF CF CFJF F F<  1 1 1  ) ) ) 4 4 4# # ## # # # #r   r   )r   )r;   rE   r   r   r}   sysversion_infor   r   r   r?   r^   rc   r   	Exceptionr   r   r   r   r   r=   r   r   <module>rB     s{  
G GP  				   


u) ) ) ) )# # # ##I #I #I #I #If #I #I #IL,E ,E ,E ,E ,EG ,E ,E ,E^J J J J Jg J J JGI GI GI GI GIG GI GI GIRM5 M5 M5 M5 M5G M5 M5 M5h	 	 	 	 	9 	 	 		 	 	 	 	| 	 	 	B B B B B B B B>V V V V V6 V V V:c# c# c# c# c#v c# c# c# c# c#r   