# Filters & Hooks Integration

This page describes how the Reflectometry plugin integrates with VIPR's filter and hook system.

## Filter System

Reflectometry filters operate on {py:class}`vipr.plugins.inference.dataset.DataSet` and are mainly used in preprocessing.

### Active filter namespaces

| Namespace | Purpose |
|---|---|
| `INFERENCE_PREPROCESS_PRE_FILTER` | Data transforms before prediction (cleaning/interpolation/scaling) |
| `INFERENCE_PREDICTION_POST_FILTER` | Post-prediction filtering (for example physical constraints) |

### Preprocess filters (`INFERENCE_PREPROCESS_PRE_FILTER`)

| Class | Method | Weight | Default in discovery config |
|---|---|---:|---|
| `vipr_reflectometry.reflectorch.preprocess.error_bar_filter.ErrorBarFilter` | `preprocess_error_bar_filter` | -10 | disabled |
| `vipr_reflectometry.reflectorch.preprocess.interpolation_filter.InterpolationFilter` | `preprocess_interpolate` | 0 | enabled |
| `vipr_reflectometry.flow_models.preprocess.flow_preprocessor.FlowPreprocessor` | `preprocess_flow` | 0 | disabled |

Execution order is weight-based (lower first), so error-bar cleaning runs before interpolation.

### Prediction post-filter (`INFERENCE_PREDICTION_POST_FILTER`)

| Class | Method | Weight | Purpose |
|---|---|---:|---|
| `vipr_reflectometry.flow_models.predict.physical_constraint_filter.PhysicalConstraintFilter` | `filter_unphysical_samples` | -5 | Remove unphysical flow samples (for example negative roughness/thickness) |

## Hook System

Reflectometry uses both decorator-discovered hooks and directly registered hooks.

### Environment setup hook

Registered in `vipr_reflectometry.load(app)`:

```python
app.hook.register('INFERENCE_BEFORE_START_HOOK', setup_reflectometry_env_defaults)
```

This sets `REFLECTOMETRY_ROOT_DIR` if missing.

### Postprocess visualization hooks

Decorator-discovered hooks (enabled via YAML):

| Namespace | Class | Method |
|---|---|---|
| `INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK` | `vipr_reflectometry.flow_models.postprocess.basic_corner_plot.BasicCornerPlot` | `create_basic_corner_plot` |
| `INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK` | `vipr_reflectometry.flow_models.postprocess.marginal_distributions.MarginalDistributions` | `create_marginal_distributions` |
| `INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK` | `vipr_reflectometry.flow_models.postprocess.cluster.clustering.hook.ClusterHook` | `cluster_posterior_samples` |
| `INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK` | `vipr_reflectometry.flow_models.postprocess.cluster.model_selection.hook.ClusterDiagnosticsHook` | `cluster_model_selection` |

Directly registered collector hooks (active once plugin is loaded):

| Namespace | Callback |
|---|---|
| `INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK` | `ReflectorchDataCollector.collect_prediction_results` |
| `INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK` | `PanpeDataCollector.collect_panpe_results` (PANPE optional) |

## YAML Configuration

### Example: Reflectorch preprocess chain

```yaml
vipr:
  inference:
    filters:
      INFERENCE_PREPROCESS_PRE_FILTER:
      - class: vipr_reflectometry.reflectorch.preprocess.error_bar_filter.ErrorBarFilter
        enabled: true
        method: preprocess_error_bar_filter
        weight: -10
        parameters:
          filter_threshold: 0.3
          filter_consecutive: 3
          filter_remove_singles: true
          filter_remove_consecutives: true
          filter_q_start_trunc: 0.1

      - class: vipr_reflectometry.reflectorch.preprocess.interpolation_filter.InterpolationFilter
        enabled: true
        method: preprocess_interpolate
        weight: 0
```

### Example: Flow postprocess hooks

```yaml
vipr:
  inference:
    hooks:
      INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK:
      - class: vipr_reflectometry.flow_models.postprocess.basic_corner_plot.BasicCornerPlot
        enabled: true
        method: create_basic_corner_plot
        weight: 0

      - class: vipr_reflectometry.flow_models.postprocess.cluster.clustering.hook.ClusterHook
        enabled: true
        method: cluster_posterior_samples
        weight: 1
        parameters:
          method: gmm
          n_components: 5
          n_init: 10
```

## Execution Flow (Simplified)

```text
LoadDataStep
  -> LoadModelStep
  -> PreprocessStep
       -> INFERENCE_PREPROCESS_PRE_FILTER (weight order)
  -> PredictionStep
       -> INFERENCE_PREDICTION_POST_FILTER (optional)
  -> PostprocessStep
       -> INFERENCE_POSTPROCESS_PRE_PRE_FILTER_HOOK
```

There is no separate normalize step in the current inference workflow; normalization is part of preprocessing filters.
