ztforce
Forced PSF photometry on ZTF science images — measures flux at a fixed sky position in every available epoch, even below the detection threshold, producing a calibrated AB-magnitude lightcurve.
Installation
pip install ztforce
Python 3.10–3.13 is supported.
Credentials
ztforce downloads ZTF science images from IRSA and requires an IRSA account (free at irsa.ipac.caltech.edu). Set your credentials in one of three ways:
Environment variables (recommended for scripts/CI):
export ZTFORCE_IRSA_USER=your_username
export ZTFORCE_IRSA_PASS=your_password
Config file at ~/.ztforce/config.toml:
[credentials]
irsa_user = "your_username"
irsa_pass = "your_password"
Direct argument:
from ztforce import build_config
config = build_config(irsa_user="your_username", irsa_pass="your_password")
Quick start
from ztforce import run_forced_photometry
# Measure flux at a fixed position across all ZTF g- and r-band epochs.
# A tqdm progress bar tracks downloads and PSF fitting; results are cached
# on disk so repeated calls return instantly.
lcs = run_forced_photometry(ra=210.08, dec=-6.88, bands=["g", "r"])
lcs["g"].df # pandas DataFrame of all epochs
lcs["g"].stack() # inverse-variance weighted stack of all good epochs
lcs["g"].save("my_source_g.ecsv") # save to ECSV
Batch processing
from astropy.coordinates import SkyCoord
from ztforce import run_forced_photometry_batch
targets = SkyCoord(ra=[210.08, 130.13], dec=[-6.88, 19.70], unit="deg")
# Processes targets in parallel; downloads are shared across all workers.
results = run_forced_photometry_batch(targets, bands=["g", "r"], n_workers=4)
results[0]["g"].stack() # stacked photometry for first target, g-band
Quality cuts, stacking, and uncertainties
Epochs failing the ZFPS quality cuts (bad calibration, noisy image, seeing > 4″) are flagged and never counted as detections or stacked. Stacks follow the ZFPS recipe: all good epochs, rescaled to a common zero point, inverse-variance averaged, and reported as a 5σ upper limit below S/N 3.
Uncertainties are statistical only and so underestimated, especially for bright sources (calibration/PSF systematics) and sources on extended hosts (the fit is on science images, not difference images).
Related services
Several official ZTF services offer complementary photometry — ztforce fills a gap none of them cover:
| Service | What it does | Why you'd use ztforce instead |
|---|---|---|
| ZTF Forced Photometry Service (ZFPS) (Masci et al. 2023) | Forced PSF photometry on ZTF difference images at user positions | Science-image photometry avoids subtraction artifacts; no account/queue required; runs locally |
| ZTF DR lightcurves (IRSA) | Catalog lightcurves for sources detected in ZTF data releases | Forced photometry works for transients and sub-threshold sources not in any catalog and at any arbitrary position |
| ZuberCal | Ubercalibrated PSF photometry catalog for PS1-matched ZTF sources | Only covers sources detected in PS1; ztforce works at any arbitrary position |
ztforce is designed for cases where the source may not appear in any existing catalog — supernovae, kilonova, flares, or any transient — and you need calibrated flux measurements at a fixed sky position across every available epoch, including non-detections.
Citation
If you find ztforce useful for your work, please cite the Zenodo release:
@software{Boesky2026_ztforce,
author = {Adam Boesky},
title = {Adam-Boesky/ztforce: v0.1.2},
month = may,
year = 2026,
publisher = {Zenodo},
version = {v0.1.2},
doi = {10.5281/zenodo.20434975},
url = {https://doi.org/10.5281/zenodo.20434975},
}
Dev Guide - Getting Started
Before installing any dependencies or writing code, it's a great idea to create a
virtual environment. LINCC-Frameworks engineers primarily use conda to manage virtual
environments. If you have conda installed locally, you can run the following to
create and activate a new environment.
>> conda create -n <env_name> python=3.11
>> conda activate <env_name>
Once you have created a new environment, you can install this project for local development using the following commands:
>> ./.setup_dev.sh
>> conda install pandoc
Notes:
./.setup_dev.shwill initialize pre-commit for this local repository, so that a set of tests will be run prior to completing a local commit. For more information, see the Python Project Template documentation on pre-commit- Install
pandocallows you to verify that automatic rendering of Jupyter notebooks into documentation for ReadTheDocs works as expected. For more information, see the Python Project Template documentation on Sphinx and Python Notebooks
Metadata
Release files for ztforce 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ztforce-0.3.0.tar.gz | 95.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ztforce-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 123.0 kB
Release files / ztforce-0.3.0.tar.gz
| Download URL | ztforce-0.3.0.tar.gz |
|---|---|
| Size | 95.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f50e44044cce63f17e845a03b91923e5fcf039d05ec0d496a2f43c37f6e562cf
|
|
BLAKE2b-256 checksum How to use checksums |
8591c781b1799a6f978fd5a7b0a527674c0eb073b7e6e5f673efe777b0011cea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / ztforce-0.3.0-py3-none-any.whl
| Download URL | ztforce-0.3.0-py3-none-any.whl |
|---|---|
| Size | 27.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9641ab023155dc0e0920c1631204fd36a7bb39ff9d9b5bf1b5dea573921d4306
|
|
BLAKE2b-256 checksum How to use checksums |
1ef5aaeafec6ab19b79ff5bc2be1388885af08250198c8f3f3d84cd55bdf0ca9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log