Workflows
=========

This page describes the current class-based DEISM workflow and the main
ordering differences between shoebox and convex rooms.

Shared structure
----------------

Both workflows start from the same high-level pattern:

1. Create ``DEISM(mode, roomtype)``.
2. Update room geometry.
3. Update wall materials.
4. Update frequency-dependent state.
5. Update source/receiver geometry and directivities.
6. Run ``run_DEISM()``.

The key detail is that steps 5 and 6 are not ordered identically for all room
types.

Hard versus flexible ordering
-----------------------------

The documentation should be read with three categories in mind:

- **Hard prerequisite**: the later method depends directly on data produced by
  the earlier one.
- **Recommended order**: the sequence used in the examples for readability.
- **Order-flexible**: both methods must be run before execution, but neither is
  a prerequisite for the other.

Hard prerequisites shared by both room types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- ``update_room()`` should precede ``update_wall_materials()`` when material
  conversion depends on room volume and room areas.
- ``update_wall_materials()`` should precede ``update_freqs()`` because
  frequency updates interpolate materials and, in RIR mode, use
  ``reverberationTime``.
- ``update_freqs()`` should precede ``update_directivities()`` because loaded
  directivity data is checked against ``params["freqs"]``, and receiver
  normalization depends on frequency-derived terms.

Shoebox workflow
----------------

After ``update_freqs()``, the shoebox workflow becomes more flexible:

- ``update_directivities()`` and ``update_source_receiver()`` can be called in
  either order.
- Both still need to be completed before ``run_DEISM()``.
- The recommended example order is directivities first, then
  source/receiver update, because that is how the current class-based examples
  are written.

.. mermaid::

   flowchart TD
       A["Initialize: DEISM(mode, 'shoebox')"] --> B["update_room()"]
       B --> C["update_wall_materials()"]
       C --> D["update_freqs()"]
       D --> E["update_directivities()"]
       D --> F["update_source_receiver()"]
       E --> G["run_DEISM()"]
       F --> G
       E -. "order-flexible after update_freqs()" .- F

Recommended shoebox execution order
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   import numpy as np
   from deism.core_deism import DEISM

   deism = DEISM("RIR", "shoebox")
   deism.update_room(roomDimensions=np.array([10.0, 8.0, 2.5]))
   deism.update_wall_materials(datain=1.0, datatype="reverberationTime")
   deism.params["sampleRate"] = 48000
   deism.params["reverberationTime"] = 1.0
   deism.update_freqs()
   deism.update_directivities()
   deism.update_source_receiver()
   deism.run_DEISM()

Convex workflow
---------------

Convex-room execution is stricter:

- ``update_freqs()`` builds the convex room engine used later by the ARG path.
- ``update_source_receiver()`` computes image paths and ``reflection_matrix``.
- ``update_directivities()`` for ARG source directivity uses that reflection
  state.

As a result, the convex order is:

``update_room()`` -> ``update_wall_materials()`` -> ``update_freqs()`` ->
``update_source_receiver()`` -> ``update_directivities()`` -> ``run_DEISM()``.

.. mermaid::

   flowchart TD
       A["Initialize: DEISM(mode, 'convex')"] --> B["update_room() / set vertices"]
       B --> C["update_wall_materials()"]
       C --> D["update_freqs()"]
       D --> E["Build convex room engine"]
       E --> F["update_source_receiver()"]
       F --> I["images / reflection_matrix ready"]
       I --> G["update_directivities()"]
       G --> H["run_DEISM()"]

Recommended convex execution order
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   import numpy as np
   from deism.core_deism import DEISM
   from deism.core_deism_arg import find_wall_centers

   vertices = np.array(
       [
           [0.0, 0.0, 0.0],
           [0.0, 0.0, 3.5],
           [0.0, 3.0, 2.5],
           [0.0, 3.0, 0.0],
           [4.0, 0.0, 0.0],
           [4.0, 0.0, 3.5],
           [4.0, 3.0, 2.5],
           [4.0, 3.0, 0.0],
       ]
   )

   deism = DEISM("RIR", "convex")
   deism.update_room(roomDimensions=vertices, wallCenters=find_wall_centers(vertices))
   deism.update_wall_materials()
   deism.update_freqs()
   deism.update_source_receiver()
   deism.update_directivities()
   deism.run_DEISM()

Backends
--------

- ``run_DEISM()`` uses the Numba backend by default.
- ``run_DEISM_ray()`` is still available, but it should be treated as a legacy
  backend.

Best practices
--------------

- Treat geometry, materials, and frequency state as the shared prerequisite
  chain.
- For shoebox rooms, changing only source or receiver position usually means
  rerunning ``update_source_receiver()`` rather than rebuilding the full state.
- For convex rooms, any change that affects geometry, frequencies, or positions
  should be treated more conservatively because image and reflection-path state
  is coupled to later ARG directivity setup.
- If you run ``run_DEISM(if_clean_up=True)``, large image arrays are deleted
  after the computation. If you need them again, rerun
  ``update_source_receiver()``.
