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

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:

# 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:

# 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:

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:

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:

@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:

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:

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:

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

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

Installation

Basic installation

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

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

Local development

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

Quick Start

CLI usage

# 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

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