PSFCraft

Home

  • Overview
  • Getting Started
  • Web Interface
  • Generation Scripts
  • Publications
  • People
  • Funding

Tutorials

  • PSFCraft — Introduction
    • What is PSFCraft?
    • Minimal Example
      • Understanding the output
    • Key Takeaways
  • Getting Started with PSFCraft
  • Aperture Geometry and Pupil Configurations
  • Wavefront Aberrations with Zernike Polynomials
  • Encircled Energy Analysis
  • Polychromatic PSF Simulation
  • End-to-End PSF Dataset Generation Pipeline

API Reference

  • Overview
  • Telescope Models
  • Aperture & Optics
  • Display & Metrics
  • Source Building
  • Batch Generation
  • Constants
PSFCraft
  • Tutorials
  • PSFCraft — Introduction

PSFCraft — Introduction¶

What you will learn:

  • What PSFCraft is and what problem it solves
  • The core object model (telescope → PSF)
  • How to compute and visualise a PSF in under 20 lines

What is PSFCraft?¶

PSFCraft is a Python library for simulating the Point Spread Function (PSF) of optical telescopes.

A PSF describes how a point source of light (e.g. a distant star) is spread across detector pixels by an optical system. Accurate PSF modelling is essential for:

  • Astronomical image analysis (source detection, photometry, shape measurement)
  • Optical system design and performance evaluation
  • Training machine-learning models for wavefront sensing

PSFCraft builds on top of POPPY, a Fourier-optics propagation library, and adds:

  • Ready-to-use telescope models (Newtonian, Euclid-like, …)
  • Zernike-polynomial wavefront error (WFE) injection
  • Polychromatic source support (black-body stellar spectra)
  • Batch PSF dataset generation for ML pipelines

Minimal Example¶

The snippet below is everything you need to simulate your first PSF.

In [1]:
Copied!
%matplotlib inline
import psfcraft
import matplotlib.pyplot as plt

# --- 1. Create a Newtonian telescope (default: 0.5 m primary, 0.1 m secondary) ---
tel = psfcraft.NewtonianTelescope()

# --- 2. Compute a monochromatic PSF at 1 µm ---
psf = tel.calc_psf(monochromatic=1e-6, fov_pixels=64)

# --- 3. Display the result ---
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
psfcraft.display_psf(psf, ax=axes[0], title="Oversampled PSF  (ext 0)", ext=0)
psfcraft.display_psf(psf, ax=axes[1], title="Detector-sampled PSF (ext 1)", ext=1)
plt.suptitle("First PSF with PSFCraft", fontsize=14)
plt.tight_layout()
plt.show()
%matplotlib inline import psfcraft import matplotlib.pyplot as plt # --- 1. Create a Newtonian telescope (default: 0.5 m primary, 0.1 m secondary) --- tel = psfcraft.NewtonianTelescope() # --- 2. Compute a monochromatic PSF at 1 µm --- psf = tel.calc_psf(monochromatic=1e-6, fov_pixels=64) # --- 3. Display the result --- fig, axes = plt.subplots(1, 2, figsize=(10, 4)) psfcraft.display_psf(psf, ax=axes[0], title="Oversampled PSF (ext 0)", ext=0) psfcraft.display_psf(psf, ax=axes[1], title="Detector-sampled PSF (ext 1)", ext=1) plt.suptitle("First PSF with PSFCraft", fontsize=14) plt.tight_layout() plt.show()
pysynphot is not installed. Please install it to use PSF generation with polychromatic sources.
No description has been provided for this image

Understanding the output¶

calc_psf() returns a FITS HDUList with two extensions:

Extension Content Sampling
psf[0] Oversampled PSF (Fourier-optics resolution) OVERSAMP × pixelscale
psf[1] Detector-binned PSF pixelscale (arcsec/pixel)

You can inspect the metadata directly from the FITS header:

In [2]:
Copied!
psf.info()
print()
for ext in [0, 1]:
    print(
        f"Extension {ext}: "
        f"oversample={psf[ext].header['OVERSAMP']}, "
        f"pixelscale={psf[ext].header['PIXELSCL']:.4f} arcsec/pix, "
        f"shape={psf[ext].data.shape}"
    )
psf.info() print() for ext in [0, 1]: print( f"Extension {ext}: " f"oversample={psf[ext].header['OVERSAMP']}, " f"pixelscale={psf[ext].header['PIXELSCL']:.4f} arcsec/pix, " f"shape={psf[ext].data.shape}" )
Filename: (No file associated with this HDUList)
No.    Name      Ver    Type      Cards   Dimensions   Format
  0  OVERSAMP      1 PrimaryHDU      37   (256, 256)   float64   
  1  DET_SAMP      1 ImageHDU        39   (64, 64)   float64   

Extension 0: oversample=4, pixelscale=0.0745 arcsec/pix, shape=(256, 256)
Extension 1: oversample=1, pixelscale=0.2980 arcsec/pix, shape=(64, 64)

Extension 0: oversample=4, pixelscale=0.0745 arcsec/pix, shape=(256, 256)
Extension 1: oversample=1, pixelscale=0.2980 arcsec/pix, shape=(64, 64)

Key Takeaways¶

  • psfcraft.NewtonianTelescope() creates a ready-to-use reflector telescope model.
  • tel.calc_psf(monochromatic=λ) runs a Fourier-optics propagation and returns a FITS HDUList.
  • The result always contains two images: oversampled (ideal) and detector-binned (realistic).
  • psfcraft.display_psf() provides a single-call convenience wrapper for visualisation.

Next steps:
→ 02_getting_started.ipynb — explore telescope parameters, pixel scale, and FOV.

Previous Next

Copyright © CNRS 2022–2026 — PSFCraft is part of the ANR DISPERS project (ANR-22-CE46-0009). Maintained by Lucas Sauniere, William Gillard, and Julien Zoubian.

Built with MkDocs using a theme provided by Read the Docs.
« Previous Next »