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.
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.fitsHDUList, 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 requirespysynphot. 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.tomldependencies 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35ebe3fbfb21300c86b1c01ec67e360dec541653b77caede0fe5759fb7fb9bc7
|
|
| MD5 |
271cb7555a6abed4d07b3859f23d8ca0
|
|
| BLAKE2b-256 |
547fd9ed5148b9df47cfe4ccbeed00ba29b5b467b6f53b1b7a2df744b22e11e1
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65447264ba4db7e0ad4cc3fa1382fffe52e8f84afc7b1aa8cee9f3aac63d74c3
|
|
| MD5 |
94835b5a35092ed53805a305cf9248d6
|
|
| BLAKE2b-256 |
d08278d7782550ae2bffda9945229db9d0ca58bd9ab5844fd14c3b81e42472ad
|