# Handler Implementation Patterns

:::{seealso}
**Related Documentation:**
- {doc}`index` - VIPR Core API Reference
- {doc}`vipr-reflectometry:index` - Reflectometry Plugin Documentation
- [VIPR Framework Architecture](../../README.md) - Framework overview
:::

This document details how the Reflectometry Plugin implements VIPR handler interfaces for data loading, model loading, and prediction.

## DataLoader Handlers

### CSV/DAT/TXT DataLoader

**Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.shared.load_data.csv_spectrareader_data_loader.CSVSpectraReaderDataLoader`  
**Label**: `csv_spectrareader`  
**Interface**: {py:class}`vipr.interfaces.data_loader.DataLoaderInterface`

**Key Patterns**:
- `@discover_data_loader` decorator exposes parameters to UI and API (see [Discovery Plugin](../../built-in/discovery.md))
- Parameter schema defines type, requirement, defaults, and descriptions
- Inherits from {py:class}`vipr.handlers.data_loader.DataLoaderHandler` (VIPR base class)
- Method signature matches interface: `_load_data(**kwargs) -> DataSet`
- Uses VIPR path resolution for package paths
- Returns immutable {py:class}`vipr.plugins.inference.dataset.DataSet` transfer object
- Metadata includes loader provenance and data characteristics

### HDF5 DataLoader

**Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.shared.load_data.hdf5_spectrareader_data_loader.HDF5SpectraReaderDataLoader`  
**Label**: `hdf5_spectrareader`  
**Batch Loading**: Loads multiple spectra (batch_size > 1)

**Key Patterns**:
- Inherits from {py:class}`vipr.handlers.data_loader.DataLoaderHandler`
- Batch loading requires stacking arrays into `(batch_size, n_points)` shape

## ModelLoader Handlers

### Reflectorch ModelLoader

**Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.reflectorch.load_model.reflectorch_model_loader.ReflectorchModelLoader`  
**Label**: `reflectorch`  
**External Library**: `reflectorch` (EasyInferenceModel)

**Key Patterns**:
- Inherits from {py:class}`vipr.handlers.model_loader.ModelLoaderHandler`
- Method signature: `_load_model(**kwargs) -> Any`
- Environment variable integration for paths (`REFLECTOMETRY_ROOT_DIR`)
- Returns library-specific model object (no wrapping required)
- Uses local model/config files from `REFLECTOMETRY_ROOT_DIR/reflectorch` (typically prepared via the Hugging Face plugin)

### Flow Model Loader

**Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.flow_models.load_model.flow_model_loader.FlowModelLoader`  
**Label**: `flow_model_loader`  
**External Library**: PyTorch + custom NSF-based flow architectures

**Key Patterns**:
- Inherits from {py:class}`vipr.handlers.model_loader.ModelLoaderHandler`
- Access inference workflow attributes: `self.app.inference.device`
- Configuration loading from external libraries
- Checkpoint loading and state dict management
- Model preparation (device placement, eval mode)

## Predictor Handlers

### Reflectorch Predictor

**Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.reflectorch.predict.reflectorch_predictor.ReflectorchPredictor`  
**Label**: `reflectorch_predictor`  
**Input**: DataSet + Model  
**Output**: Dictionary with predictions

**Key Patterns**:
- Inherits from {py:class}`vipr.handlers.predictor.PredictorHandler`
- Access workflow state: `self.app.inference.preprocessed_data`, `self.app.inference.model`
- Method signature: `_predict(dataset, model, params) -> dict[str, Any]`
- Configurable post-processing via parameters
- Returns structured dictionary (not DataSet)

### Flow Predictor

**Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.flow_models.predict.flow_predictor.FlowPredictor`  
**Label**: `flow_predictor`  
**Output**: Posterior samples

**Key Patterns**:
- Inherits from {py:class}`vipr.handlers.predictor.PredictorHandler`
- Flow models generate probability distributions (posterior samples) rather than point predictions

## Handler Registration

Handlers are registered in submodule `load(app)` functions:

```python
# shared/__init__.py
def load(app):
    """Load shared handlers used by multiple submodules."""
    # Register shared data loaders
    app.handler.register(HDF5SpectraReaderDataLoader)
    app.handler.register(CSVSpectraReaderDataLoader)
    
    # Register shared controller
    app.handler.register(ReflectometryController)

# reflectorch/__init__.py
def load(app):
    """Load reflectorch-specific handlers."""
    # Register only reflectorch handlers
    app.handler.register(ReflectorchModelLoader)
    app.handler.register(ReflectorchPredictor)

# flow_models/__init__.py
def load(app):
    """Load flow-specific handlers."""
    # Register only flow handlers
    app.handler.register(FlowModelLoader)
    app.handler.register(FlowPredictor)
```

**Pattern**: 
- Shared handlers registered in `shared/__init__.py` (single source of truth)
- Each submodule registers only its own handlers
- Main plugin loads shared first, then submodules

## Configuration Usage

Handlers are selected in YAML configuration:

```yaml
vipr:
  inference:
    load_data:
      handler: csv_spectrareader  # Handler label
      parameters:
        data_path: '@vipr_reflectometry/examples/data/D17_SiO.dat'
        column_mapping:
          q: 0
          I: 1
          dI: 2
    
    load_model:
      handler: reflectorch  # Handler label
      parameters:
        config_name: e_mc_point_neutron_conv_standard_L1_InputQDq_n256_size1024
    
    prediction:
      handler: reflectorch_predictor  # Handler label
      parameters:
        calc_pred_curve: true
        calc_pred_sld_profile: true
```

## Key Takeaways

### Handler Implementation Checklist

1. ✅ Inherit from appropriate base class (`DataLoaderHandler`, `ModelLoaderHandler`, `PredictorHandler`)
2. ✅ Use `@discover_*` decorator with parameter schema
3. ✅ Implement required method (`_load_data`, `_load_model`, `_predict`)
4. ✅ Return appropriate type (`DataSet`, model object, dict)
5. ✅ Register handler in submodule `load(app)` function

### VIPR Framework Patterns Used

- **Discovery System**: Parameter exposure via decorators
- **Handler Registry**: Dynamic handler lookup by label
- **Transfer Object**: Immutable `DataSet` for data flow
- **Workflow Integration**: Access workflow state via `self.app.inference.*`
- **Configuration-Driven**: YAML configuration selects handlers and parameters
