.. _sec-developer_guides-radiometric_kernel_interface:

Radiometric kernel interface
============================

Eradiate's radiometric computations are performed by its radiometric kernel
Mitsuba 3, with minor modifications. Mitsuba is accessed through a set of
convenience functions and classes presented in this document.

Basic concepts
--------------

.. glossary::

    Mitsuba object
    Kernel object
        Mitsuba has its internal scene representation. It consists of a tree
        whose nodes and leaves are :class:`mitsuba.Object` instances.

    Mitsuba scene
    Kernel scene
        A :class:`mitsuba.Scene` instance.

    Mitsuba scene dictionary
    Kernel dictionary
        Mitsuba's Python interface can load objects specified in the XML format,
        through the :func:`mitsuba.load_file` and :func:`mitsuba.load_string`
        functions, or as Python dictionaries, using the
        :func:`mitsuba.load_dict` function. Eradiate uses the latter and its
        scene generator emits scene dictionaries based on the Eradiate scene
        specification.

    Mitsuba scene rendering
    Radiometric computation
        A Mitsuba scene can be rendered for a specific sensor using the
        :func:`mitsuba.render` function. This triggers a radiometric
        computation.

    Mitsuba scene parameters
        Mitsuba objects declare parameters which can be collected using the
        :func:`mitsuba.traverse` function. The parameter table yielded by this
        function (a :class:`mitsuba.SceneParameters` instance) can then be
        modified to edit scene parameters.

        .. seealso::

            `Editing a scene tutorial \
            <https://mitsuba.readthedocs.io/en/latest/src/rendering/editing_a_scene.html>`_
            in the Mitsuba docs.

    Parametric loop
        Upon a call to :func:`eradiate.run`, Eradiate initializes a
        :term:`kernel scene`. It then runs a sequence of
        :term:`radiometric computations <radiometric computation>` as part of
        a `parametric loop`. Each iteration of the parametric loop corresponds
        to different :term:`Mitsuba scene parameters`. Consequently, each
        iteration consists of a `parameter update` operation and a `rendering`
        operation.

    Kernel context
        Scene parameters are determined by a parametric context internal to the
        :term:`experiment` being processed. The context can carry any kind of
        relevant information: the current spectral coordinate, the Mitsuba ID
        of a :class:`mitsuba.Medium` object attached to a sensor, etc. The
        kernel context is defined by a :class:`.KernelContext` instance.

    Kernel dictionary template
        :term:`Kernel dictionaries <kernel dictionary>` can be created from
        templates defined using the :class:`.KernelDictTemplate` class. Those
        objects are dict-like containers whose entries may be
        :class:`.InitParameter` objects, which are expanded contextually upon
        a call to the :meth:`.KernelDictTemplate.render` method.

    Parameter update map
        A scene parameter update map is generated at each iteration of the
        :term:`parametric loop` depending on contextual information. It is then
        used to update the :term:`scene parameters <Mitsuba scene parameters>`
        using the :meth:`mitsuba.SceneParameters.update` method.

    Parameter update map template
        :term:`Parameter update maps <parameter update map>` are generated by
        rendering a parameter update map template, defined using a
        :class:`.UpdateMapTemplate`, a dict-like container whose entries are
        :class:`.UpdateParameter` instances.

How Eradiate calls Mitsuba
--------------------------

Eradiate's core processing logic is defined in the :meth:`.Experiment.process`
method, which performs the following steps:

1. Translate the scene defined by the configuration of the current
   :class:`.Experiment` into a :class:`.KernelDictTemplate` and an
   :class:`.UpdateMapTemplate`.
2. Render the :term:`kernel dictionary template` into a
   :term:`kernel dictionary` using an arbitrary initialization
   :term:`kernel context`.
3. Load the :term:`kernel scene`.
4. For each :term:`kernel context` of the experiment:

   1. Render the :class:`.UpdateMapTemplate` into a :term:`parameter update map`.
   2. Update the kernel scene.
   3. Launch a :term:`radiometric computation` with the updated scene.
   4. Collect the raw results and store them in a simple data structure.

Low-level kernel interface
--------------------------

Step 4 of the :meth:`.Experiment.process` is implemented by the
:func:`.mi_render` function. It manipulates an instance of the
:class:`.MitsubaObjectWrapper` which encapsulates a Mitsuba scene alongside
its :term:`scene parameters <Mitsuba scene parameters>`
and an :term:`update map template <parameter update map template>` and makes a
Mitsuba scene update and render for each :term:`kernel context` it gets as
argument.

The :class:`.MitsubaObjectWrapper` instance should be obtained by traversing a
Mitsuba object (typically a :class:`mitsuba.Scene` with the :func:`.mi_traverse`
function. The latter reimplements :func:`mitsuba.traverse` and adds an advanced
parameter name lookup protocol used.

Mitsuba scene parameter name lookup
-----------------------------------

Mitsuba's scene definition and internal representation can differ, which can
make the task of predicting scene parameter names very challenging. This problem
is documented in `this discussion on the Mitsuba repository \
<https://github.com/mitsuba-renderer/mitsuba3/discussions/508>`_. Our solution
is the addition of a name lookup protocol to the Mitsuba object tree
traversal function :func:`.mi_traverse`. In addition to the traversed Mitsuba
object, :func:`.mi_traverse` can be passed a parameter update map template.
Each :class:`.UpdateParameter` of the update map template has an optional
``lookup_strategy`` field, which can be used to detect the name of the
corresponding scene parameter.

Currently, only the :class:`.TypeIdLookupStrategy` is available. This strategy
searches for a Mitsuba object tree node of a specified type and with the
specified object identifier. :class:`mitsuba.Medium` and :class:`mitsuba.BSDF`
objects usually require a name lookup because they can be referenced by an
arbitrary number of other objects, with no certainty on which of the referencing
objects will be visited first during traversal and therefore will define the
parameter names.
