# 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.data_loader.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.core.dataset.DataSet` transfer object - Metadata includes loader provenance and data characteristics ### HDF5 DataLoader **Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.shared.data_loader.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.model_loader.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 (`REFLECTORCH_ROOT_DIR`) - Returns library-specific model object (no wrapping required) - Integrates with Hugging Face Hub for model downloads ### Flow Model Loader **Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.flow_models.model_loader.flow_model_loader.FlowModelLoader` **Label**: `flow_model_loader` **External Library**: PyTorch + custom 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.predictor.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(**kwargs) -> dict` - Configurable post-processing via parameters - Returns structured dictionary (not DataSet) ### Flow Predictor **Handler**: {py:class}`vipr-reflectometry:vipr_reflectometry.flow_models.predictor.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/reflectorch/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