Calibration Manager

The CalibrationManager class provides a structured way to organize and manage calibration files in SPECULA simulations. It maintains a hierarchical directory structure and handles file paths automatically.

Overview

The calibration manager organizes files into predefined subdirectories based on their type:

  • phasescreens/: Atmospheric phase screens

  • pupils/: Pupil data and masks

  • pupilstop/: Pupil stop masks and configurations

  • subapdata/: Sub-aperture data for Shack-Hartmann sensors

  • im/: Interaction matrices

  • rec/: Reconstruction matrices

  • data/: General data files

  • filter/: Control filters

  • m2c/: Mirror-to-commands matrices

  • And many more…

Basic Usage

Initialize the calibration manager with a root directory:

from specula.calib_manager import CalibManager

# Initialize with root calibration directory
calib = CalibManager('/path/to/calibration/root')

The manager will automatically create subdirectories under this root path as needed.

Automatic data_dir Handling in Simul

When using the Simul class to build your simulation from a YAML file, any object parameter named data_dir is automatically replaced with a path managed by the CalibrationManager. This ensures that all calibration and data files are stored in the correct subdirectory of your calibration root.

Example: Using ImCalibrator with automatic data_dir

im_calibrator:
  class: ImCalibrator
  nmodes: 100
  # data_dir: ""   # This will be replaced automatically
  im_tag: auto
  # ... other parameters ...

When the simulation is built, data_dir will be set to something like:

/your/calibration/root/im/

This is handled transparently by Simul and the CalibrationManager.

Saving and Loading Pupil Stops

One common use case is saving pupil stop configurations and masks:

Example 1: Creating and Saving a Pupil Stop

import numpy as np
from specula.data_objects.pupilstop import Pupilstop
from specula.data_objects.simul_params import SimulParams
from specula.calib_manager import CalibManager

# Initialize calibration manager with root_dir
# (same as root_dir in main section of the yml file)
calib = CalibManager('/data/specula_calibrations')

# Create simulation parameters
simul_params = SimulParams(
    pixel_pupil=512,
    pixel_pitch=0.1  # meters
)

# Create a pupil stop with circular aperture
pupilstop = Pupilstop(
    simul_params=simul_params,
    mask_diam=1.0,        # Normalized diameter
    obs_diam=0.15,        # Central obstruction (normalized)
    shiftXYinPixel=(0.0, 0.0),
    rotInDeg=0.0,
    magnification=1.0
)

# Save using calibration manager - automatically goes to pupilstop/ subdirectory
pupil_filename = calib.filename('Pupilstop', 'main_telescope_pupil')
pupilstop.save(pupil_filename)

print(f"Pupil stop saved to: {pupil_filename}")

Example 2: Loading a Pupil Stop

# Load the pupil stop back
pupil_filename = calib.filename('Pupilstop', 'main_telescope_pupil')
loaded_pupilstop = Pupilstop.restore(pupil_filename)

print(f"Loaded pupil stop: {loaded_pupilstop.pixel_pupil}x{loaded_pupilstop.pixel_pupil} pixels")
print(f"Pixel pitch: {loaded_pupilstop.pixel_pitch} m")
print(f"Shift: {loaded_pupilstop.shiftXYinPixel} pixels")

Example 3: Creating Custom Pupil Masks

from specula.lib.make_mask import make_mask

# Create custom pupil mask with spiders
pixel_pupil = 256
custom_mask = make_mask(pixel_pupil, obs_diam=0.14, mask_diam=1.0)

# Add spider vanes (simplified example)
center = pixel_pupil // 2
spider_width = 3
custom_mask[center-spider_width//2:center+spider_width//2, :] = 0  # Horizontal spider
custom_mask[:, center-spider_width//2:center+spider_width//2] = 0  # Vertical spider

# Create pupil stop with custom mask
simul_params = SimulParams(pixel_pupil, 0.05)
pupilstop = Pupilstop(
    simul_params=simul_params,
    input_mask=custom_mask,  # Use custom mask
    shiftXYinPixel=(2.5, -1.0),  # Slight offset
    rotInDeg=15.0  # Rotate spiders
)

# Save custom pupil
custom_pupil_filename = calib.filename('Pupilstop', 'telescope_with_spiders')
pupilstop.save(custom_pupil_filename)

Example 4: Batch Processing Multiple Pupil Configurations

# Create multiple pupil configurations for different conditions
configurations = [
    {'name': 'nominal', 'shift': (0.0, 0.0), 'rot': 0.0, 'obs': 0.14},
    {'name': 'misaligned', 'shift': (2.0, 1.5), 'rot': 0.0, 'obs': 0.14},
    {'name': 'rotated', 'shift': (0.0, 0.0), 'rot': 45.0, 'obs': 0.14},
    {'name': 'large_obstruction', 'shift': (0.0, 0.0), 'rot': 0.0, 'obs': 0.20},
]

simul_params = SimulParams(512, 0.1)

for config in configurations:
    pupilstop = Pupilstop(
        simul_params=simul_params,
        mask_diam=1.0,
        obs_diam=config['obs'],
        shiftXYinPixel=config['shift'],
        rotInDeg=config['rot'],
        magnification=1.0
    )

    # Save with descriptive name
    pupil_name = f"pupil_{config['name']}"
    pupil_filename = calib.filename('Pupilstop', pupil_name)
    pupilstop.save(pupil_filename)

    print(f"Saved pupil configuration: {config['name']}")

Working with Different Data Types

The calibration manager supports many different data types:

General Pupil Data:

# Save general pupil mask data
pupil_mask = create_pupil_mask()  # Your function
calib.writefits('pupils', 'main_pupil_mask', pupil_mask)

# Load pupil mask
pupil_mask = calib.readfits('pupils', 'main_pupil_mask')

Interaction Matrices:

# Save interaction matrix
interaction_matrix = calibrate_interaction_matrix()  # Your function
calib.writefits('im', 'pyramid_interaction_matrix', interaction_matrix)

Phase Screens:

# Save atmospheric phase screen
phase_screen = generate_phase_screen()  # Your function
calib.writefits('phasescreen', 'kolmogorov_screen_001', phase_screen)

File Path Management

The manager automatically handles file extensions and paths:

# These are equivalent:
filename1 = calib.filename('Pupilstop', 'my_pupil')
filename2 = calib.filename('Pupilstop', 'my_pupil.fits')

# Both return: '/path/to/calibration/root/pupilstop/my_pupil.fits'

Getting just the filename without reading:

# Get filename for external use
filename = calib.readfits('Pupilstop', 'my_pupil', get_filename=True)

# Use with other libraries
with fits.open(filename) as hdul:
    # Process FITS file manually
    pass

Directory Structure

A typical calibration directory structure looks like:

/data/specula_calibrations/
├── data/
│   ├── my_custom_data.fits
│   └── measurement_data.fits
├── pupilstop/
│   ├── main_telescope_pupil.fits
│   ├── telescope_with_spiders.fits
│   └── pupil_misaligned.fits
├── pupils/
│   ├── main_pupil_mask.fits
│   └── secondary_mask.fits
├── phasescreens/
│   ├── kolmogorov_screen_001.fits
│   └── von_karman_screen_001.fits
├── im/
│   ├── pyramid_interaction_matrix.fits
│   └── sh_interaction_matrix.fits
└── rec/
    ├── mmse_reconstructor.fits
    └── least_squares_reconstructor.fits

API Reference

class specula.calib_manager.CalibManager(root_dir)

Bases: object

Initialize the calibration manager object.

Parameters: root_dir (str): Root path of the calibration tree

Methods

filename(subdir, name)

Construct the full file path for a calibration file.

read_data(name)

Read data from a FITS file in the 'data' subdirectory.

readfits(subdir, name)

Read data from a FITS file.

root_subdir(type)

Returns the full path to the subdirectory corresponding to the given type.

write_data(name, data)

Write data to a FITS file in the 'data' subdirectory.

writefits(subdir, name, data)

Write data to a FITS file.

filename(subdir, name)

Construct the full file path for a calibration file.

Parameters:
  • subdir (str) – The key representing the calibration data type or subdirectory.

  • name (str) – The base name of the file (without extension).

Returns:

The absolute path to the FITS file, ensuring the ‘.fits’ extension is present.

Return type:

str

read_data(name)

Read data from a FITS file in the ‘data’ subdirectory.

Parameters:

name (str) – The base name of the file (without extension).

Returns:

The data read from the file.

Return type:

array-like

readfits(subdir, name)

Read data from a FITS file.

Parameters:
  • subdir (str) – The key representing the calibration data type or subdirectory.

  • name (str) – The base name of the file (without extension).

Returns:

The data read from the file.

Return type:

array-like

root_subdir(type)

Returns the full path to the subdirectory corresponding to the given type.

Parameters:

type (str) – The key representing the calibration data type.

Returns:

The absolute path to the subdirectory for the specified type.

Return type:

str

write_data(name, data)

Write data to a FITS file in the ‘data’ subdirectory.

Parameters:
  • name (str) – The base name of the file (without extension).

  • data (array-like) – The data to be written to the file.

writefits(subdir, name, data)

Write data to a FITS file.

Parameters:
  • subdir (str) – The key representing the calibration data type or subdirectory.

  • name (str) – The base name of the file (without extension).

  • data (array-like) – The data to be written to the file.