Comprehensive README describing how PhotometryPy works, how to run it, configuration details, data layout, and troubleshooting.
PhotometryPy is a small pipeline to perform ensemble aperture photometry on simulated/real mosaicked infrared images (IRAC-like). The code: reads a list of targets, converts sky coordinates to pixel coordinates using the image WCS, performs a one-shot circular aperture photometry measurement, then carries out an ensemble of simulated PRF placements around the source to measure the noise/flux behaviour and estimate sensitivity (5-sigma) limits.
Key features:
- One-shot circular aperture photometry for each target and channel.
- Ensemble photometry by placing and scaling PRFs on a grid to measure photometric scatter.
- Automatic aggregation of intermediate measurements and calculation of 5-sigma sensitivities.
- Create a Python environment and install dependencies:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt-
Edit
configs/default.ymlif you want to change file paths or photometry parameters. -
Run the pipeline (uses
configs/default.ymlby default):
python main.py -i configs/default.ymlThis will:
- Read the magnetar list from
magnetars_list_path_file. - For each target, run
ensemble_photometry(per-channel) which will write to an intermediate CSV indicated byintermediate_path_file. - After all targets, the script runs
process_all_magnetars(flux_snr5) to compute 5-sigma sensitivities and writeresult_path_file.
main.py— entry point that loads the YAML config, iterates targets, runs ensemble photometry, and computes SNR=5 results.requirements.txt— Python dependencies (astropy, scipy, numpy, pandas, matplotlib, pyyaml).configs/default.yml— default configuration file (paths and photometry parameters).mag_info/— containsCORRECTED_mag_dec.coldat(target name, RA, DEC).prf/— contains PRF/PSF FITS files used when placing simulated PRFs (e.g.apex_sh_IRAC1_...fits).simtar_partial/— top-level directory with per-target mosaics (expected subdirs likemosaici1/,mosaici2/, ...).results/— output files (intermediate and final results).plots/— generated figures (per-target photometry plots and diagnostics).src/— core modules and library code:config.py— YAML loader and validator (produces anAppConfigdataclass).ensemble_photometry.py— main per-target photometry workflow.idl_circapphot.py— aperture photometry routines (ported from IDL:circ_apphot,get_annulus).psf.py— PSF object and helpers (trimming, resampling, normalization).utils.py— image/PSF I/O helpers, plotting, saving CSV results.flux_snr5.py— aggregation and linear-regression based computation of 5-sigma sensitivities.combine_results.py— helper to merge one-shot and sensitivity outputs into a combined table.logging_setup.py— logging configuration used bymain.py.
The YAML file expects a flat mapping (see configs/default.yml). src/config.py maps these keys into the AppConfig dataclass and validates values.
Important keys (and how they map):
magnetars_list_path_file— path to the file listing targets (name RA DEC). Mapped toAppConfig.magnetars_list_path_file.data_path_folder— directory containing per-target mosaics (simtar_partialin this repo). Mapped todata_path_folder.prf_path— directory containing PRF/PSF FITS files. Mapped toprf_path.intermediate_path_file— path to CSV where every ensemble photometry measurement is appended (created bysave_results). Mapped tointermediate_path_file.result_path_file— final aggregated sensitivity file (written byflux_snr5.process_all_magnetars). Mapped toresult_path_file.channels— list of channels to process (allowed values: 1,2,3,4).grid— integer grid size for ensemble PRF placements (NxN grid).spacing— pixel spacing between simulated PRF centers.- Aperture radii keys (note: the YAML uses
rap_(cam_pix),rbackin_(cam_pix),rbackout_(cam_pix)): these are converted torap_cam_pix,rbackin_cam_pix,rbackout_cam_pixinAppConfigand are used to compute radii for each channel with a pixel scale correction.
Validation and behavior notes:
config.load_yaml_config()validates types and ranges (e.g., radii ordering rap < rbackin < rbackout, positive spacing, grid >= 1, channels subset of [1,2,3,4]).- It also checks that
magnetars_list_path_fileis a file anddata_path_folderandprf_pathare directories; missing paths will raise aValueError.
For each target listed in magnetars_list_path_file:
- Build
mag_configwith paths and photometry parameters derived from the top-levelAppConfig. - For each requested channel (1–4):
- Resolve PSF and mosaic FITS paths. The code expects PRFs named like
apex_sh_IRAC{ch}_col129_row129_x100.fitsinprf/and mosaics at<data_path_folder>/<target>/mosaici{ch}/Combine/mosaic.fits. - Convert RA/DEC to pixel coordinates using
astropy.wcs.WCSapplied to the mosaic FITS header. - Run
circ_apphot()(one-shot) on the real mosaic at the target pixel position to gettotal_countsandsigma. One-shot results are appended toresults/all_one_shot.csvbysave_one_shot(). - Compute aperture and annulus sizes in pixels for the current channel using a per-channel pixel scale (
PSIZE_ASECinensemble_photometry.py) relative to mosaic pixel scale. - Create a set of normalization scales (FACTORS * measured sigma) and for each scale place a resampled+shifted+normalized PSF into a copy of the image at positions defined by a grid (centered on the target) with spacing
spacing. - For each simulated image perform
circ_apphot()and append a measurement tointermediate_path_fileviasave_results(). - Save plots of the aperture/annulus overlays and other diagnostics under
plots/.
- Resolve PSF and mosaic FITS paths. The code expects PRFs named like
After all targets are processed, main.py calls process_all_magnetars(intermediate_path_file, result_path_file) from flux_snr5.py which:
- Reads the intermediate ensemble results and
results/all_one_shot.csv. - Bins ensemble photometry into windows (default WINDOW_SIZE=9), computes per-window standard deviations, and performs a linear regression of sigma_ensemble vs expected flux.
- Uses the one-shot sigma (multiplied by 5) to calculate the ensemble sigma corresponding to a 5-sigma detection (the code computes
sigma_en_at_5 = slope * sigma_5 + intercept). - Writes final sensitivity results to
result_path_file(tab-separated values, header begins with#). It also optionally saves diagnostic plots per source and channel underplots/.
-
Intermediate CSV (
intermediate_path_file): appended rows viasave_results()with header (if file not present):name, ra, dec, channel, x_pos, y_pos, expected_flux, phot_flux_(µJy), phot_sigma_(µJy)
-
One-shot CSV (
results/all_one_shot.csv) columns:name, phot, sigma, channel
-
Final sensitivity output (
result_path_file) is a tab-separated file where each row isnamefollowed by ch1..ch4 sens5 values (µJy). Seeflux_snr5.pyfor exact formatting.
main.py— orchestrates the run (config load → per-target ensemble photometry → SNR calculations).src/config.py— loads and normalizes YAML config intoAppConfig, validates inputs.src/utils.py— FITS reading, PSF placement, plotting, CSV helpers.src/psf.py— PSF trimming, resampling (congrid/PSF.congrid), shifting and normalization.src/idl_circapphot.py— core aperture photometry:get_annulus()andcirc_apphot()(returns total counts and sigma among other values).src/ensemble_photometry.py— high-level per-target workflow that calls the utilities above.src/flux_snr5.py— aggregates ensemble results and computes 5-sigma sensitivity via regression.src/combine_results.py— utilities for merging one-shot and sensitivity outputs into a single table (useful post-processing).
- Inputs: YAML config, target list file (name RA DEC), per-target mosaics and PRF FITS.
- Outputs:
results/all_one_shot.csv,intermediate_path_file(ensemble rows),result_path_file(5-sigma sensitivities), plots underplots/. - Error modes:
- Missing files or directories →
config.load_yaml_config()will raise ValueError earlier, ensemble_photometry will log errors and continue to next channel/target. - WCS conversion failures → logged and that channel is skipped for that target.
- PSF trimming/resizing issues → PSF methods may raise ValueError if trim is too large.
- Missing files or directories →
Success: program completes and writes the final result_path_file. Partial failures will be logged in logs/photometrypy.log and processing will continue for other targets.
- If the script complains about missing PRF files, confirm
prf_pathinconfigs/default.ymlpoints to the directory containingapex_sh_IRAC{n}...fitsfiles. - If WCS conversion fails, inspect the mosaic FITS headers:
astropy.wcs.WCSrequires valid WCS keywords. You can open the file withastropy.io.fitsto inspect headers. - If the YAML loader raises
Invalid configuration, fix the indicated keys or create directories/files expected by the config. - If you want to run only the SNR step on an existing intermediate file:
python -c "from src.flux_snr5 import process_all_magnetars; process_all_magnetars('results/photometry/all_phot.coldat', 'results/snr5_output.coldat', plot=True)"- The pipeline assumes mosaics are at
<data_path_folder>/<target>/mosaici{ch}/Combine/mosaic.fitsand PRFs follow the naming convention in the repo. If your data are arranged differently, updatemain.pyor restructure data folders. - The code currently writes intermediate outputs by appending rows to CSVs. For very large runs you might prefer batching or using a database/file format that supports parallel writes.
- Suggested small improvements: add CLI flags in
main.pyto restrict to a subset of targets, parallelize per-target processing, parameterize PSF trim size and output directories.
Repository owner: drkh-n (local repo metadata). For code comments and history, see file headers (e.g., flux_snr5.py includes author metadata).