.. _obs_config_doc:
Observation Configuration
=========================
`NenuFAR `_
is a versatile low-frequency radio telescope. Several
observing modes are available, as represented by the
diversity of its `receivers `_.
Observations are configured thanks to text files
called *parsets* in which the details of the instrumental set-up,
the observation mode(s),
the data sampling parameters,
the operations applied on the data, etc. are listed.
The :mod:`~nenupy.observation.obs_config` module aims at
handling these different observing configurations as well
as providing estimation on the data volume output by
*NenuFAR* in one or several given set-up(s).
NenuFAR Receiver setup
----------------------
Manual setting
^^^^^^^^^^^^^^
The various `receivers `_
configurations may be set 'manually'. In such case, the user
needs to fill in the different parameters relevant to
characterize the observation with the desired receiver.
For instance, say one is interested in performing an observation
and wants to estimate the volume of the most basic *NenuFAR* data
output: the *Beamlet Statistics* (or *BST*) FITS files. Instanciating
an 'empty' :class:`~nenupy.observation.obs_config.BSTConfig` object
and printing it gives a quicklook of all the properties one may want
to modify, as well as their current values that are set by default:
.. code-block:: python
>>> from nenupy.observation import BSTConfig
>>> bstconf = BSTConfig()
>>> print(bstconf)
Backend configuration of type 'BSTConfig'
Properties: 'nSubBands=768', 'nPolars=2', 'durationSec=0'
.. note::
At any time, the user may query the receiver parameters
by printing the corresponding instance.
.. seealso::
The other receivers dedicated classes are listed in :ref:`obs_config_class_summary`.
Attribute values can be directly set to the user preferences
to update the status of the current :class:`~nenupy.observation.obs_config.BSTConfig`
instance:
.. code-block:: python
>>> bstconf.durationSec = 1800
Alternatively, the object can be initialized with specific
property values given as keyword arguments:
.. code-block:: python
>>> bstconf = BSTConfig(durationSec=1800)
Finally, to compute an estimation of the data volume
(returned as a :class:`~astropy.units.Quantity` object):
.. code-block:: python
>>> bstconf.volume
10.546875 Mibyte
>>> vol = bstconf.volume
>>> vol.to('Gibyte')
0.010299683Gibyte
.. warning::
The *beamformer* receivers allow for multi-beams observations. These
properties cannot be set manually in a straightforward way.
Instead, it is recommended to either treat each individual beam
separately or to instanciate the relevant objects with a parset file.
Setting from Parset file
^^^^^^^^^^^^^^^^^^^^^^^^
The most convenient way to set a given receiver's properties
associated to as specific observation is to initialize the
corresponding object instance from the observation *parset*:
.. code-block:: python
>>> from nenupy.observation import BSTConfig
>>> bstconf = BSTConfig.fromParset('/path/to/observation.parset')
Calling the class method ``fromParset`` automatically loads the given file
as a :class:`~nenupy.observation.parset.Parset`. The contained instrumental
information is parsed and the properties relevant to the receiver class
are used to initialize the object instance.
If an observation is configured to use the multi-beams capability of
*NenuFAR*, the receiver properties will take that into account
and the data volume estimation will then be computed accordingly.
.. warning::
At the current stage of development, the *NenuFAR* configuration files
called *parset user*
(ending with ``'.parset_user'``) are not supported.
Observation setup
-----------------
Rather than configuring each receiver individually, one might be
interested in setting all of the *NenuFAR* receivers at once, from one
or several *parset* file(s).
This is achieved using the :class:`~nenupy.observation.obs_config.ObsConfig`
class which stores information on all available receivers and update their
configuration parameters according to what is described in the *parset* file(s).
Single observation
^^^^^^^^^^^^^^^^^^
In the case of a single observation, described by a unique *parset* file
(namely ``'/path/to/observation.parset'`` in the following example),
an instance of :class:`~nenupy.observation.obs_config.ObsConfig` is
simply created using the class method
:meth:`~nenupy.observation.obs_config.ObsConfig.fromParset`:
.. code-block:: python
>>> from nenupy.observation import ObsConfig
>>> obsconf = ObsConfig.fromParset('/path/to/observation.parset')
The variable called ``obsconf`` of type :class:`~nenupy.observation.obs_config.ObsConfig`
now contains attributes named after
the various *NenuFAR* receivers. Every one of these attributes is a
list (of only one element in this case) of corresponding configuration
class instances:
.. code-block:: python
>>> type(obsconf.tf[0])
nenupy.observation.obs_config.TFConfig
>>> type(obsconf.nickel[0])
nenupy.observation.obs_config.NICKELConfig
Querying :attr:`~nenupy.observation.obs_config.ObsConfig.volume` returns
a dictionnary composed of the *NenuFAR* receivers as keys and their
corresponding raw data volume estimations for the current observation:
.. code-block:: python
>>> obsconf.volume
{'nickel': ,
'raw': ,
'tf': ,
'bst': ,
'pulsar_fold': ,
'pulsar_waveolaf': ,
'pulsar_single': }
List of observations
^^^^^^^^^^^^^^^^^^^^
Conveniently, it is also possible to initialize an
:class:`~nenupy.observation.obs_config.ObsConfig` object
from a list of several *parset* files.
In order to do that, one simply needs to call the
:meth:`~nenupy.observation.obs_config.ObsConfig.fromParsetList`
class method:
.. code-block:: python
>>> from nenupy.observation import ObsConfig
>>> obsconf = ObsConfig.fromParsetList(
[
'/path/to/observation_1.parset',
'/path/to/observation_2.parset',
'/path/to/observation_3.parset'
]
)
Querying the :attr:`~nenupy.observation.obs_config.ObsConfig.volume`
attribute returns a dictionnary with the summed estimated raw
data volumes for all the *NenuFAR* receivers over all the
observations described by the *parset* files:
.. code-block:: python
>>> obsconf.volume
{'nickel': ,
'raw': ,
'tf': ,
'bst': ,
'pulsar_fold': ,
'pulsar_waveolaf': ,
'pulsar_single': }
To get the total estimated raw data volume for a specific
receiver, and convert its unit to *Terabytes* for instance, on can
do:
.. code-block:: python
>>> obsconf.volume['tf'].to('Tibyte')
1.0675194 Tibyte
Assuming ``dec2020_parset_list`` is a list of parsets asociated with
the past observations done in December 2020, plotting the cumulative
estimated raw data volume is also eased by the method
:meth:`~nenupy.observation.obs_config.ObsConfig.plotCumulativeVolume`:
.. code-block:: python
>>> from nenupy.observation import ObsConfig
>>> obsconf = ObsConfig.fromParsetList(dec2020_parset_list)
>>> obsconf.plotCumulativeVolume(
title='NenuFAR observations, December 2020',
scale='log'
)
.. image:: ../_images/volume_december20_log.png
:width: 800
.. _obs_config_class_summary:
Classes summary
---------------
.. autosummary::
:nosignatures:
~nenupy.observation.obs_config.ObsConfig
~nenupy.observation.obs_config.BSTConfig
~nenupy.observation.obs_config.NICKELConfig
~nenupy.observation.obs_config.TFConfig
~nenupy.observation.obs_config.RAWConfig
~nenupy.observation.obs_config.PulsarFoldConfig
~nenupy.observation.obs_config.PulsarWaveConfig
~nenupy.observation.obs_config.PulsarSingleConfig