# Reflectometry Plugin Documentation

## Overview

The Reflectometry plugin extends VIPR for inverse problems in X-ray reflectometry (XRR) and neutron reflectometry (NR). It supports three model families:

- Reflectorch
- Flow models (currently NSF-based)
- PANPE (optional)

The goal is to infer layer parameters such as thickness, roughness, and SLD from measured reflectivity curves.

## Plugin Architecture

### Modular structure

```text
vipr_reflectometry/
├── shared/         # Shared data loaders + shared controller
├── reflectorch/    # Reflectorch model loader, predictor, preprocess filters, postprocess collectors
├── flow_models/    # Flow model loader, predictor, preprocess/post filters, postprocess
└── panpe/          # Optional PANPE model loader, predictor, postprocess collector
```

### Loading pattern

The root plugin loads submodules in order and registers an environment-default hook:

```python
# vipr_reflectometry/__init__.py
def load(app):
    app.hook.register('INFERENCE_BEFORE_START_HOOK', setup_reflectometry_env_defaults)

    from . import shared
    shared.load(app)

    from . import reflectorch
    reflectorch.load(app)

    from . import flow_models
    flow_models.load(app)

    try:
        from . import panpe
        panpe.load(app)
    except ImportError:
        app.log.info("PANPE not installed (optional)")
```

### Handler registration

Submodules register handlers via `app.handler.register(...)`.  
Reflectorch also exposes a data collector extension:

```python
# vipr_reflectometry/reflectorch/__init__.py
def load(app):
    app.handler.register(ReflectorchModelLoader)
    app.handler.register(ReflectorchPredictor)
    app.extend('reflectorch_dc', ReflectorchDataCollector(app))
```

## Framework Integration Points

### 1. Discovery decorators

The current discovery API uses Pydantic parameter models:

```python
class CSVSpectraReaderParams(BaseModel):
    data_path: str
    column_mapping: Optional[dict[str, int | None]] = None

@discover_data_loader('csv_spectrareader', CSVSpectraReaderParams)
class CSVSpectraReaderDataLoader(DataLoaderHandler):
    pass
```

### 2. DataSet transfer object

Data loaders return `DataSet` with batch-first arrays:

```python
return DataSet(
    x=q_values,
    y=intensities,
    dx=q_errors,
    dy=intensity_errors,
    metadata={'loader': 'csv_spectrareader'}
)
```

### 3. Filter system integration

Reflectometry preprocessing is integrated via `INFERENCE_PREPROCESS_PRE_FILTER`, ordered by `weight`:

```python
@discover_filter('INFERENCE_PREPROCESS_PRE_FILTER', weight=-10, parameters=ErrorBarFilterParams)
def preprocess_error_bar_filter(self, data: DataSet, **kwargs) -> DataSet:
    return data
```

### 4. Hook system

Before inference starts, plugin defaults are set if env vars are missing:

```python
def setup_reflectometry_env_defaults(app):
    if 'REFLECTOMETRY_ROOT_DIR' not in os.environ:
        os.environ['REFLECTOMETRY_ROOT_DIR'] = str(Path.cwd() / 'storage' / 'reflectometry')
```

## Registered Components

### Model loaders

| Handler Label | Submodule | Purpose |
|---------------|-----------|---------|
| `reflectorch` | reflectorch | Load Reflectorch models |
| `flow_model_loader` | flow_models | Load flow models |
| `panpe` | panpe | Load PANPE model (optional) |

### Data loaders

| Handler Label | Format |
|---------------|--------|
| `csv_spectrareader` | CSV/DAT/TXT |
| `hdf5_spectrareader` | HDF5 |

### Predictors

| Handler Label | Submodule | Output |
|---------------|-----------|--------|
| `reflectorch_predictor` | reflectorch | Parameter predictions + optional curves/SLD |
| `flow_predictor` | flow_models | Posterior-like parameter samples |
| `panpe_predictor` | panpe | Bayesian posterior samples (optional) |

### Filters

| Filter | Namespace | Weight | Purpose |
|--------|-----------|--------|---------|
| `ErrorBarFilter.preprocess_error_bar_filter` | `INFERENCE_PREPROCESS_PRE_FILTER` | -10 | Remove/truncate high-error or invalid points |
| `InterpolationFilter.preprocess_interpolate` | `INFERENCE_PREPROCESS_PRE_FILTER` | 0 | Interpolate to model Q-grid |
| `FlowPreprocessor.preprocess_flow` | `INFERENCE_PREPROCESS_PRE_FILTER` | 0 | Flow-model-specific preprocessing |
| `PhysicalConstraintFilter.filter_unphysical_samples` | `INFERENCE_PREDICTION_POST_FILTER` | -5 | Remove unphysical flow samples |

## Environment Configuration

### `REFLECTOMETRY_ROOT_DIR`

Recommended for local reflectometry workflows. If unset, the reflectometry plugin sets a default before inference:

```bash
export REFLECTOMETRY_ROOT_DIR=${PWD}/storage/reflectometry
```

Used as the shared root for model families such as `reflectorch`, `flow_models`, and `panpe`.

### `HF_HOME`

Optional Hugging Face cache location:

```bash
export HF_HOME=${PWD}/storage/huggingface_cache
```

### PANPE note

PANPE also resolves its local files below `REFLECTOMETRY_ROOT_DIR/panpe/...`. `HF_HOME` remains relevant as the HuggingFace cache location for downloads.

### Typical directory layout

```text
storage/
├── reflectometry/
│   ├── reflectorch/
│   │   ├── configs/
│   │   └── saved_models/
│   ├── flow_models/
│   └── panpe/
│       ├── configs/
│       └── saved_models/
└── huggingface_cache/   # if HF_HOME points here
```

## Installation

### Basic installation

```bash
pip install git+https://codebase.helmholtz.cloud/vipr/vipr-core.git
pip install git+https://codebase.helmholtz.cloud/vipr/vipr-reflectometry-plugin.git
```

### With PANPE support

```bash
pip install "git+https://codebase.helmholtz.cloud/vipr/vipr-reflectometry-plugin.git[plugin-panpe]"
```

### Local development

```bash
cd vipr-reflectometry-plugin
pip install -e .
pip install -e .[plugin-panpe]
```

## Quick Start

### CLI usage

```bash
# Reflectorch example
vipr --config '@vipr_reflectometry/reflectorch/examples/configs/Ni500.yaml' inference run

# Flow model example
vipr --config '@vipr_reflectometry/flow_models/examples/configs/NSF_XRR.yaml' inference run
```

### Minimal config pattern

```yaml
vipr:
  inference:
    load_data:
      handler: csv_spectrareader
      parameters:
        data_path: '@vipr_reflectometry/examples/data/D17_SiO.dat'

    load_model:
      handler: reflectorch
      parameters:
        config_name: NR-1layer-basic-v1

    prediction:
      handler: reflectorch_predictor
      parameters:
        calc_pred_curve: true
        calc_pred_sld_profile: true
```

## Documentation

```{toctree}
:maxdepth: 1
:caption: Plugin Details

handlers
filters_hooks
examples
```
