# Reflectometry Plugin Documentation ## Overview The Reflectometry Plugin extends VIPR for analyzing thin film structures using X-ray (XRR) and neutron reflectometry (NR) data. It determines layer properties such as thickness, roughness, and scattering length density (SLD) through three distinct model approaches: **Reflectorch** (deep learning), **Flow Models** (NSF/MAF/CINN normalizing flows), and **PANPE** (prior-amortized neural posterior estimation). **Application Domain**: Inverse problem solving for reflectometry - predicting layer parameters from experimental reflectivity curves. ## Plugin Architecture ### Modular Structure The plugin implements a three-submodule architecture with shared components: ``` vipr_reflectometry/ ├── shared/ # Shared components (data loaders, preprocessing) ├── reflectorch/ # Deep learning models (EasyInferenceModel) ├── flow_models/ # Normalizing flow models (NSF, MAF, CINN) └── panpe/ # Prior-Amortized Neural Posterior Estimation (optional) ``` ### Submodule Loading Pattern Each submodule follows the VIPR plugin loading convention with a `load(app)` function: ```python # vipr_reflectometry/__init__.py def load(app): """Load plugin with all submodules.""" # Register environment defaults hook app.hook.register('INFERENCE_BEFORE_START_HOOK', setup_reflectometry_env_defaults) # Load shared components first (data loaders used by multiple submodules) from . import shared shared.load(app) # Load submodules from . import reflectorch reflectorch.load(app) from . import flow_models flow_models.load(app) # Optional submodule try: from . import panpe panpe.load(app) except ImportError: app.log.info("PANPE not installed (optional)") ``` **Key Pattern**: - Each submodule (including `shared`) has its own `load(app)` function - Clean separation of concerns - no cross-submodule handler registration ### Handler Registration Strategy Submodules register handlers specific to their model approach: ```python # reflectorch/load(app) def load(app): # Register handlers app.handler.register(ReflectorchModelLoader) app.handler.register(ReflectorchPredictor) # Extend app with custom functionality app.extend('reflectorch', Reflectorch(app)) app.extend('reflectorch_dc', ReflectorchDataCollector(app)) ``` **Pattern Used**: - Handler registration via `app.handler.register()` - App extension via `app.extend()` for domain-specific utilities - Data collector pattern for UI visualization ### Shared Components Shared components have their own submodule with a `load(app)` function: ```python # shared/__init__.py def load(app): """Load shared handlers used by multiple submodules.""" # Data loaders from .data_loader import HDF5SpectraReaderDataLoader, CSVSpectraReaderDataLoader app.handler.register(HDF5SpectraReaderDataLoader) app.handler.register(CSVSpectraReaderDataLoader) # Shared controller from .controllers import ReflectometryController app.handler.register(ReflectometryController) # flow_models/__init__.py def load(app): """Load flow-specific handlers only.""" # No shared handler registration here app.handler.register(FlowModelLoader) app.handler.register(FlowPredictor) ``` **Pattern**: Shared handlers are registered in one place (`shared/__init__.py`), avoiding duplication and clarifying ownership. ## Framework Integration Points ### 1. Discovery Decorators Handlers use `@discover_*` decorators for automatic parameter exposure (see [Discovery Plugin](../../built-in/discovery.md) for details): ```python @discover_data_loader('csv_spectrareader', { 'data_path': {'type': 'str', 'required': True}, 'column_mapping': {'type': 'dict', 'required': False} }) class CSVSpectraReaderDataLoader(DataLoaderHandler): pass ``` ### 2. DataSet Transfer Object All data loaders return the VIPR `DataSet` object: ```python return DataSet( x=q_values, # (batch_size, n_points) y=intensities, # (batch_size, n_points) dx=q_errors, # Optional uncertainties dy=intensity_errors, # Optional uncertainties metadata={'loader': 'csv_spectrareader', ...} ) ``` ### 3. Filter System Integration Preprocessing uses weighted filters in the inference pipeline: ```python @discover_filter( 'INFERENCE_PREPROCESS_PRE_FILTER', weight=-10, # Runs before Reflectorch interpolation (weight=0) parameters={...} ) def clean_experimental_data(self, data: DataSet, **kwargs) -> DataSet: # Transform and return DataSet return cleaned_dataset ``` ### 4. Hook System Environment setup via hooks before inference starts: ```python def setup_reflectometry_env_defaults(app): """Set environment defaults before inference.""" if 'REFLECTORCH_ROOT_DIR' not in os.environ: os.environ['REFLECTORCH_ROOT_DIR'] = str(Path.cwd() / 'storage' / 'reflectorch') # Register in plugin loading app.hook.register('INFERENCE_BEFORE_START_HOOK', setup_reflectometry_env_defaults) ``` ## Registered Components ### Model Loaders | Handler Label | Submodule | Purpose | |---------------|-----------|---------| | `reflectorch` | reflectorch | Load Reflectorch deep learning models | | `flow_model_loader` | flow_models | Load normalizing flow models | | `panpe_model_loader` | panpe | Load PANPE models (optional) | ### Data Loaders | Handler Label | Format | Batch Size | |---------------|--------|------------| | `csv_spectrareader` | CSV/DAT/TXT | 1 | | `hdf5_spectrareader` | HDF5 | N | ### Predictors | Handler Label | Submodule | Output Type | |---------------|-----------|-------------| | `reflectorch_predictor` | reflectorch | Layer parameters + SLD profiles | | `flow_predictor` | flow_models | Posterior samples | | `panpe_predictor` | panpe | Posterior samples (optional) | ### Filters | Filter | Weight | Purpose | |--------|--------|---------| | `NeutronDataCleaner.clean_experimental_data` | -10 | Remove negative/high-error points | | `Reflectorch._preprocess_interpolate` | 0 | Interpolate to model grid | | `FlowPreprocessor._preprocess_flow` | 0 | Prepare for flow models | ## Environment Configuration ### Required Variables ```bash export REFLECTORCH_ROOT_DIR=${PWD}/storage/reflectorch # Required for model/config storage ``` The plugin automatically sets this if not defined, using `${PWD}/storage/reflectorch` as default. ### Directory Structure ``` storage/reflectorch/ ├── configs/ # Model configuration files ├── saved_models/ # Trained model weights └── cache/ # Downloaded models (Reflectorch) ``` ## 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 . # With PANPE pip install -e .[plugin-panpe] ``` ## Quick Start ### CLI Usage ```bash # Reflectorch XRR analysis vipr --config '@vipr_reflectometry/reflectorch/examples/configs/PTCDI-C3.yaml' inference run # Flow model inference vipr --config '@vipr_reflectometry/flow_models/examples/configs/NSF_XRR.yaml' inference run ``` ### Configuration Pattern ```yaml vipr: inference: load_data: handler: csv_spectrareader parameters: data_path: '@vipr_reflectometry/reflectorch/examples/data/D17_SiO.dat' load_model: handler: reflectorch parameters: config_name: e_mc_point_neutron_conv_standard_L1_InputQDq_n256_size1024 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 ``` ## Quick Links - **Handler Implementation** - DataLoader, ModelLoader, Predictor patterns - **Filters & Hooks** - Preprocessing and workflow integration - **Examples** - Complete workflow configurations