.. index:: !EPICS; examples

.. _EPICS_Area_Detector.examples.HDF5:

EPICS Area Detector Examples
############################

Two examples in this section show how to write NeXus HDF5 data files 
with EPICS Area Detector images.  
The first shows how to configure the HDF5 File Writing Plugin
of the EPICS Area Detector software.
The second example shows how to write an EPICS Area Detector image
using Python.

HDF5 File Writing Plugin
************************

This example  describes how to write a NeXus HDF5 data file
using the EPICS [#]_ Area Detector [#]_ HDF5 file writing plugin [#]_.
We will use the EPICS SimDetector [#]_ as an example.
(PV prefix: ``13SIM1:``)  
Remember to replace that with the prefix for your detector's IOC.

One data file will be produced for each image generated by EPICS.

You'll need AreaDetector version 2.5 or higher to use this
as the procedures for using the HDF5 file writing plugin 
changed with this release.

configuration files
===================

There are two configuration files we must edit 
to configure an EPICS AreaDetector 
to write NeXus files using the HDF5 File Writer plugin:

===================  ====================================
file                 description
===================  ====================================
``attributes.xml``   what information to know about from EPICS and other sources
``layout.xml``       where to write that information in the HDF5 file
===================  ====================================

Put these files into a known directory where your EPICS IOC can find them.


``attributes.xml``
******************

The attributes file is easy to edit.
Any text editor will do.  
A wide screen will be helpful.  

.. index:: !ndattribute

Each ``<Attribute />`` element declares a single **ndattribute**
which is associated with an area detector image.  These **ndattribute** items can be
written to specific locations in the HDF5 file or placed by 
default in a *default location*.

.. note:: The attributes file shown here has been reformatted 
   for display in this manual.  The *downloads* section below
   provides an attributes file with the same content
   using its wide formatting (one complete Attribute per line).
   Either version of this file is acceptable.

.. literalinclude:: attributes-reformatted.xml
   :tab-width: 4
   :linenos:
   :language: xml

If you want to add additional EPICS process variables (PVs) 
to be written in the HDF5 file, 
create additional ``<Attribute />`` elements (such as the
``calc1_val``) and modify the ``name``, ``source``, and 
``description`` values.  Be sure to use a unique **name** 
for each **ndattribute** in the attributes file.

.. note:: **ndattribute** : item specified by
   an ``<Attribute />`` element in the attributes file.

``layout.xml``
**************

You might not need to edit the layout file.  
It will be fine (at least a good starting point) as it is, 
even if you add PVs (a.k.a. *ndattribute*) to the attributes.xml file.

.. literalinclude:: layout.xml
   :tab-width: 4
   :linenos:
   :language: xml

If you do not specify where in the file to write an *ndattribute* from the 
attributes file, it will be written within the group that has
``ndattr_default="true"``.  This identifies the group to the 
HDF5 file writing plugin as the *default location* to store
content from the attributes file.  In the example layout file, 
that *default location* is the ``/entry/instrument/NDAttributes`` group::

   <group 
         name="NDAttributes" 
         ndattr_default="true"> 
     <attribute 
         name="NX_class" 
         source="constant" 
         value="NXcollection" 
         type="string"/> 
   </group>


To specify where PVs are written in the HDF5 file, you must 
create ``<dataset />`` (or ``<attribute />``) elements at the 
appropriate place in the NeXus HDF5 file layout.  See 
the NeXus manual [#]_ for placement advice if you are unsure.

You reference each *ndattribute* by its ``name`` value from the attributes
file and use it as the value of the ``ndattribute`` in the layout file.
In this example, ``ndattribute="calc1_val"`` in the 
layout file references ``name="calc1_val"`` in the attributes file
and will be identified in the HDF5 file by the name ``userCalc1``::

   <dataset 
      name="userCalc1" 
      source="ndattribute"
      ndattribute="calc1_val"/> 

.. note:: A value from the attributes file is only written
   either in the *default location* or in the location named by
   a ``<dataset/>`` or ``<attribute/>`` entry in the layout file.
   Expect problems if you define the same *ndattribute*
   in more than one place in the layout file.

You can control when a value is written to the file, using 
``when=""`` in the layout file.  This can be set to one of these values:  
``OnFileOpen``, ``OnFileClose``

Such as::

   <dataset 
      name="userCalc1" 
      source="ndattribute"
      ndattribute="calc1_val"
      when="OnFileOpen"/> 

or::

   <attribute 
      name="exposure_s" 
      source="ndattribute"
      ndattribute="AcquireTime" 
      when="OnFileClose"/>


additional configuration
========================

Additional configurations of the EPICS Area Detector and the HDF5 File Plugin
are done using the EPICS screens (shown here using caQtDM [#]_):

.. figure:: screen2.png
   :width: 90%
   :alt: configuration screens
   
   **ADBase** and **NDFileHDF5** configuration screens
   

Additional configuration on the **ADBase** screen:

* Set *Image mode* to "Single"
* Set *Exposure time* as you wish
* Set *# Images* to 1
* for testing, it is common to bin the data to reduce the image size
* The full path to the ``attributes.xml`` file goes in the bottom/left **File** box


Additional configuration on the **NDFileHDF5** screen:

* Set the **File path** and "File name" to your choice.
* Set **Auto save** to "Yes".
* Set **Compression** to "zlib" if you wish (optional)
* Set **Enable** to "Enable" or the HDF5 plugin won't get images to write!
* Set **Callbacks block** to "Yes" if you want to wait for HDF5 files to finish writing before collecting the next image
* The full path to the ``layout.xml`` file goes into the bottom/right **XML File name** box
* Leave the **Attributes file** box empty in this screen.

When you enter the names of these files in the configuration screen 
boxes, AreaDetector will check the files for errors and let you know.


Example view
============

We collected data for one image, ``/tmp/mrinal_001.h5``, in the 
HDF5 file provided in the **downloads** section.  
You may notice that the values for ``calc1_val`` and ``calc2_val`` 
were arrays rather than single values.  That was due to an error in the original 
``attributes.xml`` file, which had ``type="PARAM"`` instead of ``type="EPICS_PV"``.
This has been fixed in the ``attributes.xml`` file presented here.


.. _EPICS_Area_Detector.examples.python:

Python code to store an image in a NeXus file
*********************************************

Suppose you want to write area detector images into NeXus HDF5 
files python code.  Let's assume 
you have the image already in memory in a numpy array, perhaps from 
reading a TIFF file or from an EPICS PV using PyEpics.  The file 
``write_nexus_file.py`` (provided below) reads an image from the sim 
detector and writes it to a NeXus HDF5 data file, along with some 
additional metadata.  

using the *h5py* package
========================

This example uses the *h5py* [#]_ package to write the HDF5 file.

.. literalinclude:: write_nexus_file.py
   :tab-width: 4
   :linenos:
   :language: python


The output from that code is given in the 
example.h5 file.  It has this tree structure:


.. literalinclude:: tree_structure.txt
   :tab-width: 4
   :linenos:
   :language: text

.. note::  Alternatively, the metadata shown in this example might 
   be placed in the ``/entry/instrument/detector`` (*NXdetector*)
   group along with the image ``data``
   since it provides image-related information such as size.
   
   In the interest of keeping this example simpler and similar to the one
   above using the HDF5 File Writing Plugin, the metadata has been
   written into a *NXcollection* group at ``/entry/instrument/metadata`` location.
   (Compare with the *NXcollection* group  ``/entry/instrument/NDAttributes`` above.)

using the *nexusformat* package
===============================

The *nexusformat* [#]_ package for python simplifies
the work to create a NeXus file.  Rewriting the above code
using *nexusformat*:

.. literalinclude:: write_nexus_file2.py
   :tab-width: 4
   :linenos:
   :language: python


Visualization
*************

You can visualize the HDF5 files with several programs, such as:
hdfview [#]_, nexpy [#]_, or pymca [#]_.  
Views of the test image shown using **NeXPy** (from the HDF5 file) 
and **caQtDM** (the image from EPICS) are shown.

.. figure:: screen1.png
   :width: 90%
   :alt: visualization screens
   
   Views of the image in **NeXPy** (left) and in **caQtDM** (right)

Get the installation instructions for any of these programs 
from a web search.  Other 
data analysis programs such as MatLab, IgorPro, and IDL can 
also read HDF5 files but you might have to work a bit more to 
get the data to a plot.


Downloads
*********

================================ ============================================================
file                             description
================================ ============================================================
:download:`attributes.xml`       The attributes file
:download:`layout.xml`           The layout file
:download:`mrinal_001.h5`        example NeXus HDF5 file written from EPICS
:download:`write_nexus_file.py`  Python code to get images from EPICS and write a NeXus file
:download:`write_nexus_file2.py` `write_nexus_file.py` rewritten with `nexusformat` package
:download:`example.h5`           example NeXus HDF5 file written from Python
================================ ============================================================


Footnotes
*********

.. [#] EPICS: https://epics-controls.org/
.. [#] EPICS Area Detector: https://areadetector.github.io/master/index.html
.. [#] HDF5 File Writer: https://areadetector.github.io/master/ADCore/NDFileHDF5.html
.. [#] EPICS SimDetector: https://github.com/areaDetector/ADSimDetector
.. [#] NeXus manual: https://manual.nexusformat.org/
.. [#] caQtDM: http://epics.web.psi.ch/software/caqtdm/
.. [#] h5py: http://docs.h5py.org
.. [#] nexusformat: This Python package is described on the NeXPy web site
.. [#] hdfview: https://support.hdfgroup.org/products/java/hdfview/
.. [#] nexpy: https://nexpy.github.io/nexpy/
.. [#] pymca: http://pymca.sourceforge.net/
