Skip to main content

A Python package to generate PSFs

Project description

PSFCraft

Python library for Point Spread Function (PSF) simulation of Newtonian telescopes

PSFCraft lets you generate physically accurate PSFs in a few lines of Python — with full control over aperture geometry, wavefront aberrations (Zernike polynomials), pixel scale, field of view, and broadband spectral weighting. It is built on top of POPPY and is designed for astronomers, optical engineers, and anyone building ML datasets from simulated telescope images.

Zernike PSF line


TL;DR

import psfcraft

tel = psfcraft.NewtonianTelescope(version="1_3")
tel.pixelscale = 0.1   # arcsec/pixel
psf = tel.calc_psf(monochromatic=1e-6, fov_pixels=64)
psfcraft.display_psf(psf)

Motivation

Simulating a realistic telescope PSF requires modelling many interacting effects: aperture shape and spider struts, Zernike wavefront errors, diffraction, and spectral weighting for broadband sources. PSFCraft wraps the rigorous Fourier-optics engine of POPPY and packages it into a clean, high-level API tailored to Newtonian/Cassegrain-style telescope geometries (originally developed for the Euclid space mission).


Features

  • Ready-made telescope models — preconfigured Newtonian apertures (circular, with 3/4/5-arm spider variants, adjustable secondary obstruction)
  • Zernike wavefront error injection — pass a coefficient vector (Noll indexing, in metres RMS) to simulate any combination of tip, tilt, defocus, astigmatism, coma, trefoil, …
  • Monochromatic and polychromatic PSFs — flat wavelength or flux-weighted black-body spectrum across Y / J / H photometric bands
  • Image quality metrics — Encircled Energy (EE) curves, EE50/EE80 radii, FWHM
  • Batch generation — WFE budget design + randomised dataset generation for ML pipelines
  • FITS output — standard astropy.io.fits HDUList, ready for downstream analysis
  • Interactive WebUI — single-file, no-dependency browser tool for real-time PSF exploration

Installation

Requirements: Python ≥ 3.11

From PyPI

pip install psfcraft

From source (recommended)

git clone https://gitlab.in2p3.fr/sauniere/psfcraft.git
cd psfcraft

python -m venv .venv
source .venv/bin/activate

pip install -e .

Minimal install (pip only)

pip install poppy astropy numpy scipy matplotlib h5py tqdm
pip install -e .

With notebook support

pip install -e ".[notebooks]"

Note on pysynphot: PSFCraft no longer requires pysynphot. Polychromatic source spectra are computed with a built-in Planck-law implementation that has no extra dependencies.


Quick Start

import psfcraft
import numpy as np

# --- 1. Perfect PSF (no aberrations) ---
tel = psfcraft.NewtonianTelescope(version="1_3")  # 3-arm spider
tel.pixelscale = 0.1   # arcsec/pixel

psf = tel.calc_psf(monochromatic=1.2e-6, fov_pixels=64)
psfcraft.display_psf(psf)

# --- 2. Inject wavefront aberrations ---
# Noll indexing, coefficients in metres RMS
#            piston tip  tilt  defocus  astig  astig  coma   coma
wfe = np.array([0,    0,    0,    50e-9,   80e-9, 80e-9, 30e-9, 30e-9])
tel.wfe_coefficients = wfe

psf_aberrated = tel.calc_psf(monochromatic=1.2e-6, fov_pixels=64)

# --- 3. Encircled energy ---
psfcraft.display_ee(psf_aberrated)
ee50 = psfcraft.measure_ee(psf_aberrated)(0.15)   # fraction within 0.15 arcsec radius
print(f"EE50 radius ≈ {ee50:.3f} arcsec")

Telescope Versions

The version string selects the aperture geometry:

version Geometry
"0" Circular aperture only (no secondary, no spider)
"1_3" Secondary + 3 evenly spaced spider arms
"1_4" Secondary + 4 spider arms
"1_5" Secondary + 5 spider arms
"2" Euclid-like asymmetric 3-arm spider
"3" Secondary obscuration only (no arms)

Main API

Function / Class Description
NewtonianTelescope(version, wfe_coefficients, ...) Build a telescope model
tel.calc_psf(monochromatic=λ, fov_pixels=N) Compute a monochromatic PSF
tel.calc_psf(source=dict, fov_pixels=N) Compute a polychromatic PSF
display_psf(psf, ax, title, ...) Plot a PSF on a log-stretch colour map
display_ee(psf) Plot Encircled Energy curve
measure_ee(psf)(r) Return EE fraction at radius r (arcsec)
build_polychromatic_star(T, filter_name, sampling) Build a black-body source dict
build_wfe_budget(radial_budget) Design a WFE budget for batch generation
utils.generate_coefficients(wfe_budget) Draw a random Zernike coefficient vector

Tutorial Notebooks

Step-by-step notebooks are located in docs/tutorials/:

# Notebook Topic
1 01_introduction.ipynb What is PSFCraft? 15-line example
2 02_getting_started.ipynb Configuration, pixel scale, FOV, FITS I/O
3 03_aperture_and_pupil.ipynb Spider struts, secondary obstruction
4 04_wavefront_aberrations.ipynb Zernike WFE injection, OPD maps
5 05_encircled_energy.ipynb EE curves and EE50/EE80 metrics
6 06_polychromatic_psf.ipynb Broadband PSFs, stellar temperature effects
7 07_psf_generation_pipeline.ipynb Batch generation, WFE budget, dataset I/O

Launch them with:

pip install -e ".[notebooks]"
jupyter lab docs/tutorials/

Interactive WebUI

A single-file, zero-dependency browser tool for real-time PSF exploration:

xdg-open webui/psfcraft-webui.html   # Linux
open webui/psfcraft-webui.html       # macOS

Features: Zernike sliders, aperture mask, OPD map, split/decomp modes, detector noise simulation, log/linear scale, multiple colormaps.

See docs/webui.md for the full reference.


Project Structure

psfcraft/
├── psfcraft/
│   ├── psfcraft_core.py   # GenericTelescope, NewtonianTelescope classes
│   ├── optics.py          # NewtonianTelescopeAperture (POPPY CompoundAnalyticOptic)
│   ├── utils.py           # display_psf, display_ee, build_polychromatic_star, PSF_Generator
│   ├── constants.py       # Filter cuts (Y/J/H), detector params, stellar types
│   └── simple_gen.py      # Entry point for batch PSF dataset generation
├── docs/tutorials/        # Step-by-step Jupyter notebooks
├── webui/                 # Single-file interactive PSF viewer
├── scripts/               # Standalone generation scripts (Euclid, SPIE, …)
└── pyproject.toml

Documentation

Full documentation (API reference + rendered notebooks) is built with MkDocs:

pip install -e ".[docs]"
mkdocs serve       # live-reloading local server
make build         # static build → site/

Contributing

Contributions are welcome. Please open an issue or merge request on GitLab.

  • Follow the existing code style (no linter enforced yet)
  • Add or update the relevant tutorial notebook if your change affects the public API
  • Keep pyproject.toml dependencies minimal

License

MIT — see LICENSE for details.


AI Usage

GitHub Copilot (powered by Claude) was used during the development of PSFCraft as an AI coding assistant for the following tasks:

  • Code assistance — autocompletion, boilerplate generation, and refactoring suggestions
  • Code review and quality improvement — identifying issues, enforcing consistency, and improving robustness
  • Documentation — completing and improving docstrings, tutorial notebooks, and the API reference
  • WebUI development — assisting with the single-file interactive PSF viewer

All AI-generated contributions were produced under the direct supervision and explicit validation of the authors. No AI output was integrated without human review.


Acknowledgements

PSFCraft was developed at Aix Marseille Univ, CNRS/IN2P3, CPPM, Marseille, France as part of the DISPERS project.

This work was supported by the Agence Nationale de la Recherche (ANR) through the DISPERS project grant.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

psfcraft-1.0.0.tar.gz (36.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

psfcraft-1.0.0-py3-none-any.whl (27.9 kB view details)

Uploaded Python 3

File details

Details for the file psfcraft-1.0.0.tar.gz.

File metadata

  • Download URL: psfcraft-1.0.0.tar.gz
  • Upload date:
  • Size: 36.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for psfcraft-1.0.0.tar.gz
Algorithm Hash digest
SHA256 35ebe3fbfb21300c86b1c01ec67e360dec541653b77caede0fe5759fb7fb9bc7
MD5 271cb7555a6abed4d07b3859f23d8ca0
BLAKE2b-256 547fd9ed5148b9df47cfe4ccbeed00ba29b5b467b6f53b1b7a2df744b22e11e1

See more details on using hashes here.

File details

Details for the file psfcraft-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: psfcraft-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 27.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for psfcraft-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 65447264ba4db7e0ad4cc3fa1382fffe52e8f84afc7b1aa8cee9f3aac63d74c3
MD5 94835b5a35092ed53805a305cf9248d6
BLAKE2b-256 d08278d7782550ae2bffda9945229db9d0ca58bd9ab5844fd14c3b81e42472ad

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page