Utilities and validation¶
Scan construction helpers and scan-data validation.
Utility functions for beamline operations.
This module provides helper functions for common beamline tasks like motor alignment, grid scan generation, and data analysis.
- resonance.api.utils.calculate_center_of_mass(scan_data: DataFrame, motor_col: str, signal_col: str, use_mean: bool = True) float[source]¶
Calculate center of mass for alignment.
- Parameters:
- Returns:
Center of mass position
- Return type:
Examples
>>> results = await server.scan_from_dataframe(scan_df, ...) >>> com = calculate_center_of_mass( ... results, ... motor_col="Sample X_position", ... signal_col="Photodiode_mean" ... ) >>> # Move to center of mass >>> await server.motor.set("Sample X", com)
- resonance.api.utils.create_energy_scan(energies: ndarray, exposure_time: float | ndarray = 1.0, energy_motor: str = 'Beamline Energy') DataFrame[source]¶
Create an energy scan DataFrame.
- Parameters:
- Returns:
Scan definition ready for scan_from_dataframe
- Return type:
pd.DataFrame
Examples
>>> # Carbon K-edge >>> energies = np.linspace(280, 320, 200) >>> scan = create_energy_scan(energies, exposure_time=1.0) >>> >>> # Variable exposure times >>> energies = np.linspace(280, 320, 200) >>> exposure = np.ones(200) >>> exposure[100:150] = 2.0 # Longer at edge >>> scan = create_energy_scan(energies, exposure_time=exposure)
- resonance.api.utils.create_grid_scan(x_range: tuple[float, float, int], y_range: tuple[float, float, int], exposure_time: float = 1.0, x_motor: str = 'Sample X', y_motor: str = 'Sample Y') DataFrame[source]¶
Create a 2D grid scan DataFrame.
- Parameters:
x_range (tuple[float, float, int]) – X range as (start, stop, num_points)
y_range (tuple[float, float, int]) – Y range as (start, stop, num_points)
exposure_time (float, optional) – Exposure time for all points (default: 1.0)
x_motor (str, optional) – X motor name (default: “Sample X”)
y_motor (str, optional) – Y motor name (default: “Sample Y”)
- Returns:
Scan definition ready for scan_from_dataframe
- Return type:
pd.DataFrame
Examples
>>> # Create 3x3 grid >>> grid = create_grid_scan( ... x_range=(10, 12, 3), ... y_range=(0, 2, 3), ... exposure_time=1.0 ... ) >>> print(len(grid)) # 9 points 9
- resonance.api.utils.create_line_scan(motor: str, start: float, stop: float, num_points: int, exposure_time: float = 1.0) DataFrame[source]¶
Create a 1D line scan DataFrame.
- Parameters:
- Returns:
Scan definition ready for scan_from_dataframe
- Return type:
pd.DataFrame
Examples
>>> scan = create_line_scan( ... motor="Sample X", ... start=10, ... stop=15, ... num_points=11, ... exposure_time=1.5 ... )
- resonance.api.utils.find_peak_position(scan_data: DataFrame, motor_col: str, signal_col: str, use_mean: bool = True) tuple[float, float][source]¶
Find peak position in 1D scan data.
- Parameters:
- Returns:
(peak_position, peak_value)
- Return type:
Examples
>>> results = await server.scan_from_dataframe(scan_df, ...) >>> peak_x, peak_signal = find_peak_position( ... results, ... motor_col="Sample X_position", ... signal_col="Photodiode_mean" ... ) >>> print(f"Peak at {peak_x:.2f} with signal {peak_signal:.3f}")
- resonance.api.utils.knife_edge_analysis(scan_data: DataFrame, motor_col: str, signal_col: str, threshold: float = 0.5, direct_beam: Literal['above', 'below'] = 'above') float[source]¶
Analyze knife-edge scan to find edge position.
Useful for aligning samples to incident beam.
- Parameters:
scan_data (pd.DataFrame) – Scan results from scan_from_dataframe
motor_col (str) – Motor position column name
signal_col (str) – Signal column name
threshold (float, optional) – Fraction of max signal to define edge (default: 0.5)
direct_beam (Literal["above", "below"], optional) – Direction of direct beam relative to edge (default: “above”)
- Returns:
Estimated edge position
- Return type:
Examples
>>> results = await server.scan_from_dataframe(scan_df, ...) >>> edge_pos = knife_edge_analysis( ... results, ... motor_col="Sample Z_position", ... signal_col="Photodiode_mean" ... ) >>> print(f"Edge position at {edge_pos:.2f}")
- resonance.api.utils.merge_scans(scans: list[DataFrame], motor_col: str, average_overlaps: bool = True) DataFrame[source]¶
Merge multiple scans into a single dataset.
- Parameters:
- Returns:
Merged scan data
- Return type:
pd.DataFrame
Examples
>>> # Combine multiple energy ranges >>> scan1 = await nexafs_scan(server, np.linspace(280, 290, 50)) >>> scan2 = await nexafs_scan(server, np.linspace(288, 300, 100)) >>> merged = merge_scans([scan1, scan2], motor_col="energy")
- resonance.api.utils.resample_scan_data(scan_data: DataFrame, motor_col: str, num_points: int, columns_to_interpolate: list[str] | None = None) DataFrame[source]¶
Resample scan data to uniform grid.
Useful for combining scans with different point densities.
- Parameters:
- Returns:
Resampled data with uniform spacing
- Return type:
pd.DataFrame
Examples
>>> # Resample to 100 points >>> resampled = resample_scan_data( ... results, ... motor_col="Beamline Energy_position", ... num_points=100 ... )
DataFrame validation utilities for scan plan creation
- resonance.api.validation.find_exposure_column(df: DataFrame) str | None[source]¶
Find exposure time column using pattern matching.
Handles common variations: - “exposure”, “exp” - “count_time”, “count time” - “Unnamed: 2” (pandas default for unnamed columns) - “” (empty string column name)
- Parameters:
df: Input DataFrame
- Returns:
Column name if found, None otherwise
- resonance.api.validation.validate_motor_columns(df: DataFrame) list[str][source]¶
Validate that DataFrame columns match known motor names.
- Parameters:
df: Input DataFrame
- Returns:
List of valid motor column names
- Raises:
ValidationError: If invalid columns found or no motor columns present
- resonance.api.validation.validate_scan_dataframe(df: DataFrame) tuple[list[str], str | None][source]¶
Validate complete scan DataFrame.
- Parameters:
df: Input DataFrame with motor columns and optional exposure column
- Returns:
Tuple of (motor_column_names, exposure_column_name)
- Raises:
ValidationError: If validation fails