From f8733838c9245a2803b3ffcef22dc64ced2bca43 Mon Sep 17 00:00:00 2001 From: KerryPaterson Date: Mon, 29 Sep 2025 13:03:00 +0200 Subject: [PATCH 1/8] Fixed instrument list --- paper/paper.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index eda83ab1..b3fc4ed7 100755 --- a/paper/paper.md +++ b/paper/paper.md @@ -39,15 +39,15 @@ This pipeline was developed for the reduction and stacking of imaging data for a The pipeline is written in Python (currently deployed and tested on Python 3.12) and uses packages from Astropy [@astropy:2013;@astropy:2018], ccdproc, astroquery [@Ginsburg2019] and photutils [@photutils:2024]; with the additional use of external dependencies including SExtractor [@Bertin1996] and Astrometry.net [@Lang2010]. The code is available on GitHub at https://github.com/CIERA-Transients/POTPyRI, where instructions on the installation and detailed use can be found. The code is also installable with pip and is release at PyPI at https://pypi.org/p/potpyri. Currently available instruments (as of June 2025 - see the GitHub for the most recent list) include: - - MMIRS (MMT) [@McLeod2012] - - Binospec (MMT) [@Fabricant2019] - - MOSFIRE (Keck) [@McLean2008] - - DEIMOS (Keck) [@Cowley1997] - - LRIS (Keck) [@Oke1995] - - GMOS (Gemini-N and Gemini-S) [@Davies1997] - - Flamingos2 (Gemini) [@Eikenberry2012] - - FourStar (Magellan) [@Persson2013] - - IMACS (Magellan) [@Bigelow2003] +- MMIRS (MMT) [@McLeod2012] +- Binospec (MMT) [@Fabricant2019] +- MOSFIRE (Keck) [@McLean2008] +- DEIMOS (Keck) [@Cowley1997] +- LRIS (Keck) [@Oke1995] +- GMOS (Gemini-N and Gemini-S) [@Davies1997] +- Flamingos2 (Gemini) [@Eikenberry2012] +- FourStar (Magellan) [@Persson2013] +- IMACS (Magellan) [@Bigelow2003] Since the pipeline is meant to provide the community with a way to reduce imaging data from these instruments; science applications include the rapid reduction and identification of transients, such as Gamma-Ray Burst (GRB) afterglows, as well as the reduction and stacking of follow-up observations of transients to identify potential host galaxies for associated and in depth study (see [@Paterson2020;@Rastinejad2021;@Fong2021;@Rastinejad2025;@Caleb2025]). From 64e749966ee70f3190c15e7443201d5a3fdb5777 Mon Sep 17 00:00:00 2001 From: KerryPaterson Date: Mon, 29 Sep 2025 13:36:48 +0200 Subject: [PATCH 2/8] Updated journal names in full --- paper/paper.bib | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/paper/paper.bib b/paper/paper.bib index 887de27e..5e2d6826 100755 --- a/paper/paper.bib +++ b/paper/paper.bib @@ -1,7 +1,7 @@ @ARTICLE{Bertin1996, author = {{Bertin}, E. and {Arnouts}, S.}, title = "{SExtractor: Software for source extraction.}", - journal = {\aaps}, + journal = {Astronomy and Astrophysics Supplement}, keywords = {METHODS: DATA ANALYSIS, TECHNIQUES: IMAGE PROCESSING, GALAXIES: PHOTOMETRY}, year = "1996", month = "Jun", @@ -46,7 +46,7 @@ @INPROCEEDINGS{Cowley1997 @ARTICLE{Oke1995, author = {{Oke}, J.~B. and {Cohen}, J.~G. and {Carr}, M. and {Cromer}, J. and {Dingizian}, A. and {Harris}, F.~H. and {Labrecque}, S. and {Lucinio}, R. and {Schaal}, W. and {Epps}, H. and {Miller}, J.}, title = "{The Keck Low-Resolution Imaging Spectrometer}", - journal = {\pasp}, + journal = {Publications of the Astronomical Society of the Pacific}, keywords = {INSTRUMENTATION: SPECTROGRAPHS}, year = 1995, month = apr, @@ -75,7 +75,7 @@ @INPROCEEDINGS{Davies1997 @ARTICLE{Fabricant2019, author = {{Fabricant}, Daniel and {Fata}, Robert and {Epps}, Harland and {Gauron}, Thomas and {Mueller}, Mark and {Zajac}, Joseph and {Amato}, Stephen and {Barberis}, Jack and {Bergner}, Henry and {Brennan}, Patricia and {Brown}, Warren and {Chilingarian}, Igor and {Geary}, John and {Kradinov}, Vladimir and {McLeod}, Brian and {Smith}, Matthew and {Woods}, Deborah}, title = "{Binospec: A Wide-field Imaging Spectrograph for the MMT}", - journal = {\pasp}, + journal = {Publications of the Astronomical Society of the Pacific}, keywords = {Astrophysics - Instrumentation and Methods for Astrophysics}, year = 2019, month = jul, @@ -93,7 +93,7 @@ @ARTICLE{Fabricant2019 @ARTICLE{McLeod2012, author = {{McLeod}, Brian and {Fabricant}, Daniel and {Nystrom}, George and {McCracken}, Ken and {Amato}, Stephen and {Bergner}, Henry and {Brown}, Warren and {Burke}, Michael and {Chilingarian}, Igor and {Conroy}, Maureen and {Curley}, Dylan and {Furesz}, Gabor and {Geary}, John and {Hertz}, Edward and {Holwell}, Justin and {Matthews}, Anne and {Norton}, Tim and {Park}, Sang and {Roll}, John and {Zajac}, Joseph and {Epps}, Harland and {Martini}, Paul}, title = "{MMT and Magellan Infrared Spectrograph}", - journal = {\pasp}, + journal = {Publications of the Astronomical Society of the Pacific}, keywords = {Astrophysics - Instrumentation and Methods for Astrophysics}, year = 2012, month = dec, @@ -119,7 +119,7 @@ @ARTICLE{Skrutskie2006 {Light}, R. and {Kopan}, E.~L. and {Marsh}, K.~A. and {McCallon}, H.~L. and {Tam}, R. and {Van Dyk}, S. and {Wheelock}, S.}, title = "{The Two Micron All Sky Survey (2MASS)}", - journal = {\aj}, + journal = {The Astronomical Journal}, keywords = {Catalogs, Infrared: General, Surveys}, year = "2006", month = "Feb", @@ -134,7 +134,7 @@ @ARTICLE{Skrutskie2006 @ARTICLE{Gaia2021, author = {{Gaia Collaboration} and {Brown}, A.~G.~A. and {Vallenari}, A. and {Prusti}, T. and {de Bruijne}, J.~H.~J. and {Babusiaux}, C. and {Biermann}, M. and {Creevey}, O.~L. and {Evans}, D.~W. and {Eyer}, L. and {Hutton}, A. and {Jansen}, F. and {Jordi}, C. and {Klioner}, S.~A. and {Lammers}, U. and {Lindegren}, L. and {Luri}, X. and {Mignard}, F. and {Panem}, C. and {Pourbaix}, D. and {Randich}, S. and {Sartoretti}, P. and {Soubiran}, C. and {Walton}, N.~A. and {Arenou}, F. and {Bailer-Jones}, C.~A.~L. and {Bastian}, U. and {Cropper}, M. and {Drimmel}, R. and {Katz}, D. and {Lattanzi}, M.~G. and {van Leeuwen}, F. and {Bakker}, J. and {Cacciari}, C. and {Casta{\~n}eda}, J. and {De Angeli}, F. and {Ducourant}, C. and {Fabricius}, C. and {Fouesneau}, M. and {Fr{\'e}mat}, Y. and {Guerra}, R. and {Guerrier}, A. and {Guiraud}, J. and {Jean-Antoine Piccolo}, A. and {Masana}, E. and {Messineo}, R. and {Mowlavi}, N. and {Nicolas}, C. and {Nienartowicz}, K. and {Pailler}, F. and {Panuzzo}, P. and {Riclet}, F. and {Roux}, W. and {Seabroke}, G.~M. and {Sordo}, R. and {Tanga}, P. and {Th{\'e}venin}, F. and {Gracia-Abril}, G. and {Portell}, J. and {Teyssier}, D. and {Altmann}, M. and {Andrae}, R. and {Bellas-Velidis}, I. and {Benson}, K. and {Berthier}, J. and {Blomme}, R. and {Brugaletta}, E. and {Burgess}, P.~W. and {Busso}, G. and {Carry}, B. and {Cellino}, A. and {Cheek}, N. and {Clementini}, G. and {Damerdji}, Y. and {Davidson}, M. and {Delchambre}, L. and {Dell'Oro}, A. and {Fern{\'a}ndez-Hern{\'a}ndez}, J. and {Galluccio}, L. and {Garc{\'\i}a-Lario}, P. and {Garcia-Reinaldos}, M. and {Gonz{\'a}lez-N{\'u}{\~n}ez}, J. and {Gosset}, E. and {Haigron}, R. and {Halbwachs}, J. -L. and {Hambly}, N.~C. and {Harrison}, D.~L. and {Hatzidimitriou}, D. and {Heiter}, U. and {Hern{\'a}ndez}, J. and {Hestroffer}, D. and {Hodgkin}, S.~T. and {Holl}, B. and {Jan{\ss}en}, K. and {Jevardat de Fombelle}, G. and {Jordan}, S. and {Krone-Martins}, A. and {Lanzafame}, A.~C. and {L{\"o}ffler}, W. and {Lorca}, A. and {Manteiga}, M. and {Marchal}, O. and {Marrese}, P.~M. and {Moitinho}, A. and {Mora}, A. and {Muinonen}, K. and {Osborne}, P. and {Pancino}, E. and {Pauwels}, T. and {Petit}, J. -M. and {Recio-Blanco}, A. and {Richards}, P.~J. and {Riello}, M. and {Rimoldini}, L. and {Robin}, A.~C. and {Roegiers}, T. and {Rybizki}, J. and {Sarro}, L.~M. and {Siopis}, C. and {Smith}, M. and {Sozzetti}, A. and {Ulla}, A. and {Utrilla}, E. and {van Leeuwen}, M. and {van Reeven}, W. and {Abbas}, U. and {Abreu Aramburu}, A. and {Accart}, S. and {Aerts}, C. and {Aguado}, J.~J. and {Ajaj}, M. and {Altavilla}, G. and {{\'A}lvarez}, M.~A. and {{\'A}lvarez Cid-Fuentes}, J. and {Alves}, J. and {Anderson}, R.~I. and {Anglada Varela}, E. and {Antoja}, T. and {Audard}, M. and {Baines}, D. and {Baker}, S.~G. and {Balaguer-N{\'u}{\~n}ez}, L. and {Balbinot}, E. and {Balog}, Z. and {Barache}, C. and {Barbato}, D. and {Barros}, M. and {Barstow}, M.~A. and {Bartolom{\'e}}, S. and {Bassilana}, J. -L. and {Bauchet}, N. and {Baudesson-Stella}, A. and {Becciani}, U. and {Bellazzini}, M. and {Bernet}, M. and {Bertone}, S. and {Bianchi}, L. and {Blanco-Cuaresma}, S. and {Boch}, T. and {Bombrun}, A. and {Bossini}, D. and {Bouquillon}, S. and {Bragaglia}, A. and {Bramante}, L. and {Breedt}, E. and {Bressan}, A. and {Brouillet}, N. and {Bucciarelli}, B. and {Burlacu}, A. and {Busonero}, D. and {Butkevich}, A.~G. and {Buzzi}, R. and {Caffau}, E. and {Cancelliere}, R. and {C{\'a}novas}, H. and {Cantat-Gaudin}, T. and {Carballo}, R. and {Carlucci}, T. and {Carnerero}, M.~I. and {Carrasco}, J.~M. and {Casamiquela}, L. and {Castellani}, M. and {Castro-Ginard}, A. and {Castro Sampol}, P. and {Chaoul}, L. and {Charlot}, P. and {Chemin}, L. and {Chiavassa}, A. and {Cioni}, M. -R.~L. and {Comoretto}, G. and {Cooper}, W.~J. and {Cornez}, T. and {Cowell}, S. and {Crifo}, F. and {Crosta}, M. and {Crowley}, C. and {Dafonte}, C. and {Dapergolas}, A. and {David}, M. and {David}, P. and {de Laverny}, P. and {De Luise}, F. and {De March}, R. and {De Ridder}, J. and {de Souza}, R. and {de Teodoro}, P. and {de Torres}, A. and {del Peloso}, E.~F. and {del Pozo}, E. and {Delbo}, M. and {Delgado}, A. and {Delgado}, H.~E. and {Delisle}, J. -B. and {Di Matteo}, P. and {Diakite}, S. and {Diener}, C. and {Distefano}, E. and {Dolding}, C. and {Eappachen}, D. and {Edvardsson}, B. and {Enke}, H. and {Esquej}, P. and {Fabre}, C. and {Fabrizio}, M. and {Faigler}, S. and {Fedorets}, G. and {Fernique}, P. and {Fienga}, A. and {Figueras}, F. and {Fouron}, C. and {Fragkoudi}, F. and {Fraile}, E. and {Franke}, F. and {Gai}, M. and {Garabato}, D. and {Garcia-Gutierrez}, A. and {Garc{\'\i}a-Torres}, M. and {Garofalo}, A. and {Gavras}, P. and {Gerlach}, E. and {Geyer}, R. and {Giacobbe}, P. and {Gilmore}, G. and {Girona}, S. and {Giuffrida}, G. and {Gomel}, R. and {Gomez}, A. and {Gonzalez-Santamaria}, I. and {Gonz{\'a}lez-Vidal}, J.~J. and {Granvik}, M. and {Guti{\'e}rrez-S{\'a}nchez}, R. and {Guy}, L.~P. and {Hauser}, M. and {Haywood}, M. and {Helmi}, A. and {Hidalgo}, S.~L. and {Hilger}, T. and {H{\l}adczuk}, N. and {Hobbs}, D. and {Holland}, G. and {Huckle}, H.~E. and {Jasniewicz}, G. and {Jonker}, P.~G. and {Juaristi Campillo}, J. and {Julbe}, F. and {Karbevska}, L. and {Kervella}, P. and {Khanna}, S. and {Kochoska}, A. and {Kontizas}, M. and {Kordopatis}, G. and {Korn}, A.~J. and {Kostrzewa-Rutkowska}, Z. and {Kruszy{\'n}ska}, K. and {Lambert}, S. and {Lanza}, A.~F. and {Lasne}, Y. and {Le Campion}, J. -F. and {Le Fustec}, Y. and {Lebreton}, Y. and {Lebzelter}, T. and {Leccia}, S. and {Leclerc}, N. and {Lecoeur-Taibi}, I. and {Liao}, S. and {Licata}, E. and {Lindstr{\o}m}, E.~P. and {Lister}, T.~A. and {Livanou}, E. and {Lobel}, A. and {Madrero Pardo}, P. and {Managau}, S. and {Mann}, R.~G. and {Marchant}, J.~M. and {Marconi}, M. and {Marcos Santos}, M.~M.~S. and {Marinoni}, S. and {Marocco}, F. and {Marshall}, D.~J. and {Martin Polo}, L. and {Mart{\'\i}n-Fleitas}, J.~M. and {Masip}, A. and {Massari}, D. and {Mastrobuono-Battisti}, A. and {Mazeh}, T. and {McMillan}, P.~J. and {Messina}, S. and {Michalik}, D. and {Millar}, N.~R. and {Mints}, A. and {Molina}, D. and {Molinaro}, R. and {Moln{\'a}r}, L. and {Montegriffo}, P. and {Mor}, R. and {Morbidelli}, R. and {Morel}, T. and {Morris}, D. and {Mulone}, A.~F. and {Munoz}, D. and {Muraveva}, T. and {Murphy}, C.~P. and {Musella}, I. and {Noval}, L. and {Ord{\'e}novic}, C. and {Orr{\`u}}, G. and {Osinde}, J. and {Pagani}, C. and {Pagano}, I. and {Palaversa}, L. and {Palicio}, P.~A. and {Panahi}, A. and {Pawlak}, M. and {Pe{\~n}alosa Esteller}, X. and {Penttil{\"a}}, A. and {Piersimoni}, A.~M. and {Pineau}, F. -X. and {Plachy}, E. and {Plum}, G. and {Poggio}, E. and {Poretti}, E. and {Poujoulet}, E. and {Pr{\v{s}}a}, A. and {Pulone}, L. and {Racero}, E. and {Ragaini}, S. and {Rainer}, M. and {Raiteri}, C.~M. and {Rambaux}, N. and {Ramos}, P. and {Ramos-Lerate}, M. and {Re Fiorentin}, P. and {Regibo}, S. and {Reyl{\'e}}, C. and {Ripepi}, V. and {Riva}, A. and {Rixon}, G. and {Robichon}, N. and {Robin}, C. and {Roelens}, M. and {Rohrbasser}, L. and {Romero-G{\'o}mez}, M. and {Rowell}, N. and {Royer}, F. and {Rybicki}, K.~A. and {Sadowski}, G. and {Sagrist{\`a} Sell{\'e}s}, A. and {Sahlmann}, J. and {Salgado}, J. and {Salguero}, E. and {Samaras}, N. and {Sanchez Gimenez}, V. and {Sanna}, N. and {Santove{\~n}a}, R. and {Sarasso}, M. and {Schultheis}, M. and {Sciacca}, E. and {Segol}, M. and {Segovia}, J.~C. and {S{\'e}gransan}, D. and {Semeux}, D. and {Shahaf}, S. and {Siddiqui}, H.~I. and {Siebert}, A. and {Siltala}, L. and {Slezak}, E. and {Smart}, R.~L. and {Solano}, E. and {Solitro}, F. and {Souami}, D. and {Souchay}, J. and {Spagna}, A. and {Spoto}, F. and {Steele}, I.~A. and {Steidelm{\"u}ller}, H. and {Stephenson}, C.~A. and {S{\"u}veges}, M. and {Szabados}, L. and {Szegedi-Elek}, E. and {Taris}, F. and {Tauran}, G. and {Taylor}, M.~B. and {Teixeira}, R. and {Thuillot}, W. and {Tonello}, N. and {Torra}, F. and {Torra}, J. and {Turon}, C. and {Unger}, N. and {Vaillant}, M. and {van Dillen}, E. and {Vanel}, O. and {Vecchiato}, A. and {Viala}, Y. and {Vicente}, D. and {Voutsinas}, S. and {Weiler}, M. and {Wevers}, T. and {Wyrzykowski}, {\L}. and {Yoldas}, A. and {Yvard}, P. and {Zhao}, H. and {Zorec}, J. and {Zucker}, S. and {Zurbach}, C. and {Zwitter}, T.}, title = "{Gaia Early Data Release 3. Summary of the contents and survey properties}", - journal = {\aap}, + journal = {Astronomy & Astrophysics,}, keywords = {catalogs, astrometry, parallaxes, proper motions, techniques: photometric, techniques: radial velocities, Astrophysics - Astrophysics of Galaxies}, year = 2021, month = may, @@ -152,7 +152,7 @@ @ARTICLE{Gaia2021 @ARTICLE{Tonry2012, author = {{Tonry}, J.~L. and {Stubbs}, C.~W. and {Lykke}, K.~R. and {Doherty}, P. and {Shivvers}, I.~S. and {Burgett}, W.~S. and {Chambers}, K.~C. and {Hodapp}, K.~W. and {Kaiser}, N. and {Kudritzki}, R. -P. and {Magnier}, E.~A. and {Morgan}, J.~S. and {Price}, P.~A. and {Wainscoat}, R.~J.}, title = "{The Pan-STARRS1 Photometric System}", - journal = {\apj}, + journal = {The Astrophysical Journal}, keywords = {atmospheric effects, instrumentation: photometers, surveys, techniques: photometric, Astrophysics - Instrumentation and Methods for Astrophysics}, year = 2012, month = may, @@ -171,7 +171,7 @@ @ARTICLE{Tonry2012 @ARTICLE{Eisenstein2011, author = {{Eisenstein}, Daniel J. and {Weinberg}, David H. and {Agol}, Eric and {Aihara}, Hiroaki and {Allende Prieto}, Carlos and {Anderson}, Scott F. and {Arns}, James A. and {Aubourg}, {\'E}ric and {Bailey}, Stephen and {Balbinot}, Eduardo and {Barkhouser}, Robert and {Beers}, Timothy C. and {Berlind}, Andreas A. and {Bickerton}, Steven J. and {Bizyaev}, Dmitry and {Blanton}, Michael R. and {Bochanski}, John J. and {Bolton}, Adam S. and {Bosman}, Casey T. and {Bovy}, Jo and {Brandt}, W.~N. and {Breslauer}, Ben and {Brewington}, Howard J. and {Brinkmann}, J. and {Brown}, Peter J. and {Brownstein}, Joel R. and {Burger}, Dan and {Busca}, Nicolas G. and {Campbell}, Heather and {Cargile}, Phillip A. and {Carithers}, William C. and {Carlberg}, Joleen K. and {Carr}, Michael A. and {Chang}, Liang and {Chen}, Yanmei and {Chiappini}, Cristina and {Comparat}, Johan and {Connolly}, Natalia and {Cortes}, Marina and {Croft}, Rupert A.~C. and {Cunha}, Katia and {da Costa}, Luiz N. and {Davenport}, James R.~A. and {Dawson}, Kyle and {De Lee}, Nathan and {Porto de Mello}, Gustavo F. and {de Simoni}, Fernando and {Dean}, Janice and {Dhital}, Saurav and {Ealet}, Anne and {Ebelke}, Garrett L. and {Edmondson}, Edward M. and {Eiting}, Jacob M. and {Escoffier}, Stephanie and {Esposito}, Massimiliano and {Evans}, Michael L. and {Fan}, Xiaohui and {Femen{\'\i}a Castell{\'a}}, Bruno and {Dutra Ferreira}, Leticia and {Fitzgerald}, Greg and {Fleming}, Scott W. and {Font-Ribera}, Andreu and {Ford}, Eric B. and {Frinchaboy}, Peter M. and {Garc{\'\i}a P{\'e}rez}, Ana Elia and {Gaudi}, B. Scott and {Ge}, Jian and {Ghezzi}, Luan and {Gillespie}, Bruce A. and {Gilmore}, G. and {Girardi}, L{\'e}o and {Gott}, J. Richard and {Gould}, Andrew and {Grebel}, Eva K. and {Gunn}, James E. and {Hamilton}, Jean-Christophe and {Harding}, Paul and {Harris}, David W. and {Hawley}, Suzanne L. and {Hearty}, Frederick R. and {Hennawi}, Joseph F. and {Gonz{\'a}lez Hern{\'a}ndez}, Jonay I. and {Ho}, Shirley and {Hogg}, David W. and {Holtzman}, Jon A. and {Honscheid}, Klaus and {Inada}, Naohisa and {Ivans}, Inese I. and {Jiang}, Linhua and {Jiang}, Peng and {Johnson}, Jennifer A. and {Jordan}, Cathy and {Jordan}, Wendell P. and {Kauffmann}, Guinevere and {Kazin}, Eyal and {Kirkby}, David and {Klaene}, Mark A. and {Knapp}, G.~R. and {Kneib}, Jean-Paul and {Kochanek}, C.~S. and {Koesterke}, Lars and {Kollmeier}, Juna A. and {Kron}, Richard G. and {Lampeitl}, Hubert and {Lang}, Dustin and {Lawler}, James E. and {Le Goff}, Jean-Marc and {Lee}, Brian L. and {Lee}, Young Sun and {Leisenring}, Jarron M. and {Lin}, Yen-Ting and {Liu}, Jian and {Long}, Daniel C. and {Loomis}, Craig P. and {Lucatello}, Sara and {Lundgren}, Britt and {Lupton}, Robert H. and {Ma}, Bo and {Ma}, Zhibo and {MacDonald}, Nicholas and {Mack}, Claude and {Mahadevan}, Suvrath and {Maia}, Marcio A.~G. and {Majewski}, Steven R. and {Makler}, Martin and {Malanushenko}, Elena and {Malanushenko}, Viktor and {Mandelbaum}, Rachel and {Maraston}, Claudia and {Margala}, Daniel and {Maseman}, Paul and {Masters}, Karen L. and {McBride}, Cameron K. and {McDonald}, Patrick and {McGreer}, Ian D. and {McMahon}, Richard G. and {Mena Requejo}, Olga and {M{\'e}nard}, Brice and {Miralda-Escud{\'e}}, Jordi and {Morrison}, Heather L. and {Mullally}, Fergal and {Muna}, Demitri and {Murayama}, Hitoshi and {Myers}, Adam D. and {Naugle}, Tracy and {Neto}, Angelo Fausti and {Nguyen}, Duy Cuong and {Nichol}, Robert C. and {Nidever}, David L. and {O'Connell}, Robert W. and {Ogando}, Ricardo L.~C. and {Olmstead}, Matthew D. and {Oravetz}, Daniel J. and {Padmanabhan}, Nikhil and {Paegert}, Martin and {Palanque-Delabrouille}, Nathalie and {Pan}, Kaike and {Pandey}, Parul and {Parejko}, John K. and {P{\^a}ris}, Isabelle and {Pellegrini}, Paulo and {Pepper}, Joshua and {Percival}, Will J. and {Petitjean}, Patrick and {Pfaffenberger}, Robert and {Pforr}, Janine and {Phleps}, Stefanie and {Pichon}, Christophe and {Pieri}, Matthew M. and {Prada}, Francisco and {Price-Whelan}, Adrian M. and {Raddick}, M. Jordan and {Ramos}, Beatriz H.~F. and {Reid}, I. Neill and {Reyle}, Celine and {Rich}, James and {Richards}, Gordon T. and {Rieke}, George H. and {Rieke}, Marcia J. and {Rix}, Hans-Walter and {Robin}, Annie C. and {Rocha-Pinto}, Helio J. and {Rockosi}, Constance M. and {Roe}, Natalie A. and {Rollinde}, Emmanuel and {Ross}, Ashley J. and {Ross}, Nicholas P. and {Rossetto}, Bruno and {S{\'a}nchez}, Ariel G. and {Santiago}, Basilio and {Sayres}, Conor and {Schiavon}, Ricardo and {Schlegel}, David J. and {Schlesinger}, Katharine J. and {Schmidt}, Sarah J. and {Schneider}, Donald P. and {Sellgren}, Kris and {Shelden}, Alaina and {Sheldon}, Erin and {Shetrone}, Matthew and {Shu}, Yiping and {Silverman}, John D. and {Simmerer}, Jennifer and {Simmons}, Audrey E. and {Sivarani}, Thirupathi and {Skrutskie}, M.~F. and {Slosar}, An{\v{z}}e and {Smee}, Stephen and {Smith}, Verne V. and {Snedden}, Stephanie A. and {Stassun}, Keivan G. and {Steele}, Oliver and {Steinmetz}, Matthias and {Stockett}, Mark H. and {Stollberg}, Todd and {Strauss}, Michael A. and {Szalay}, Alexander S. and {Tanaka}, Masayuki and {Thakar}, Aniruddha R. and {Thomas}, Daniel and {Tinker}, Jeremy L. and {Tofflemire}, Benjamin M. and {Tojeiro}, Rita and {Tremonti}, Christy A. and {Vargas Maga{\~n}a}, Mariana and {Verde}, Licia and {Vogt}, Nicole P. and {Wake}, David A. and {Wan}, Xiaoke and {Wang}, Ji and {Weaver}, Benjamin A. and {White}, Martin and {White}, Simon D.~M. and {Wilson}, John C. and {Wisniewski}, John P. and {Wood-Vasey}, W. Michael and {Yanny}, Brian and {Yasuda}, Naoki and {Y{\`e}che}, Christophe and {York}, Donald G. and {Young}, Erick and {Zasowski}, Gail and {Zehavi}, Idit and {Zhao}, Bo}, title = "{SDSS-III: Massive Spectroscopic Surveys of the Distant Universe, the Milky Way, and Extra-Solar Planetary Systems}", - journal = {\aj}, + journal = {The Astronomical Journal}, keywords = {cosmology: observations, Galaxy: evolution, planets and satellites: detection, surveys, Astrophysics - Instrumentation and Methods for Astrophysics}, year = 2011, month = sep, @@ -195,7 +195,7 @@ @article{astropy:2013 Doi = {10.1051/0004-6361/201322068}, Eid = {A33}, Eprint = {1307.6212}, -Journal = {\aap}, +Journal = {Astronomy & Astrophysics,}, Keywords = {methods: data analysis, methods: miscellaneous, virtual observatory tools}, Month = oct, Pages = {A33}, @@ -250,7 +250,7 @@ @ARTICLE{astropy:2018 {Weaver}, B.~A. and {Whitmore}, J.~B. and {Woillez}, J. and {Zabalza}, V. and {Astropy Contributors}}, title = "{The Astropy Project: Building an Open-science Project and Status of the v2.0 Core Package}", - journal = {\aj}, + journal = {The Astronomical Journal}, keywords = {methods: data analysis, methods: miscellaneous, methods: statistical, reference systems, Astrophysics - Instrumentation and Methods for Astrophysics}, year = 2018, month = sep, @@ -269,7 +269,7 @@ @ARTICLE{astropy:2018 @ARTICLE{Ginsburg2019, author = {{Ginsburg}, Adam and {Sip{\H{o}}cz}, Brigitta M. and {Brasseur}, C.~E. and {Cowperthwaite}, Philip S. and {Craig}, Matthew W. and {Deil}, Christoph and {Guillochon}, James and {Guzman}, Giannina and {Liedtke}, Simon and {Lian Lim}, Pey and {Lockhart}, Kelly E. and {Mommert}, Michael and {Morris}, Brett M. and {Norman}, Henrik and {Parikh}, Madhura and {Persson}, Magnus V. and {Robitaille}, Thomas P. and {Segovia}, Juan-Carlos and {Singer}, Leo P. and {Tollerud}, Erik J. and {de Val-Borro}, Miguel and {Valtchanov}, Ivan and {Woillez}, Julien and {Astroquery Collaboration} and {a subset of astropy Collaboration}}, title = "{astroquery: An Astronomical Web-querying Package in Python}", - journal = {\aj}, + journal = {The Astronomical Journal}, keywords = {astronomical databases: miscellaneous, virtual observatory tools, Astrophysics - Instrumentation and Methods for Astrophysics}, year = 2019, month = mar, @@ -288,7 +288,7 @@ @ARTICLE{Ginsburg2019 @ARTICLE{Paterson2020, author = {{Paterson}, K. and {Fong}, W. and {Nugent}, A. and {Escorial}, A. Rouco and {Leja}, J. and {Laskar}, T. and {Chornock}, R. and {Miller}, A.~A. and {Scharw{\"a}chter}, J. and {Cenko}, S.~B. and {Perley}, D. and {Tanvir}, N.~R. and {Levan}, A. and {Cucchiara}, A. and {Cobb}, B.~E. and {De}, K. and {Berger}, E. and {Terreran}, G. and {Alexander}, K.~D. and {Nicholl}, M. and {Blanchard}, P.~K. and {Cornish}, D.}, title = "{Discovery of the Optical Afterglow and Host Galaxy of Short GRB 181123B at z = 1.754: Implications for Delay Time Distributions}", - journal = {\apjl}, + journal = {The Astrophysical Journal}, keywords = {Gamma-ray bursts, 629, Astrophysics - High Energy Astrophysical Phenomena}, year = 2020, month = aug, @@ -307,7 +307,7 @@ @ARTICLE{Paterson2020 @ARTICLE{Rastinejad2021, author = {{Rastinejad}, J.~C. and {Fong}, W. and {Kilpatrick}, C.~D. and {Paterson}, K. and {Tanvir}, N.~R. and {Levan}, A.~J. and {Metzger}, B.~D. and {Berger}, E. and {Chornock}, R. and {Cobb}, B.~E. and {Laskar}, T. and {Milne}, P. and {Nugent}, A.~E. and {Smith}, N.}, title = "{Probing Kilonova Ejecta Properties Using a Catalog of Short Gamma-Ray Burst Observations}", - journal = {\apj}, + journal = {The Astrophysical Journal}, keywords = {Gamma-ray bursts, Neutron stars, 629, 1108, Astrophysics - High Energy Astrophysical Phenomena}, year = 2021, month = aug, @@ -326,7 +326,7 @@ @ARTICLE{Rastinejad2021 @ARTICLE{Fong2021, author = {{Fong}, W. and {Laskar}, T. and {Rastinejad}, J. and {Escorial}, A. Rouco and {Schroeder}, G. and {Barnes}, J. and {Kilpatrick}, C.~D. and {Paterson}, K. and {Berger}, E. and {Metzger}, B.~D. and {Dong}, Y. and {Nugent}, A.~E. and {Strausbaugh}, R. and {Blanchard}, P.~K. and {Goyal}, A. and {Cucchiara}, A. and {Terreran}, G. and {Alexander}, K.~D. and {Eftekhari}, T. and {Fryer}, C. and {Margalit}, B. and {Margutti}, R. and {Nicholl}, M.}, title = "{The Broadband Counterpart of the Short GRB 200522A at z = 0.5536: A Luminous Kilonova or a Collimated Outflow with a Reverse Shock?}", - journal = {\apj}, + journal = {The Astrophysical Journal}, keywords = {Gamma-ray bursts, Magnetars, R-process, 629, 992, 1324, Astrophysics - High Energy Astrophysical Phenomena}, year = 2021, month = jan, @@ -345,7 +345,7 @@ @ARTICLE{Fong2021 @ARTICLE{Lang2010, author = {{Lang}, Dustin and {Hogg}, David W. and {Mierle}, Keir and {Blanton}, Michael and {Roweis}, Sam}, title = "{Astrometry.net: Blind Astrometric Calibration of Arbitrary Astronomical Images}", - journal = {\aj}, + journal = {The Astronomical Journal}, keywords = {astrometry, catalogs, instrumentation: miscellaneous, methods: data analysis, methods: statistical, techniques: image processing, Astrophysics - Instrumentation and Methods for Astrophysics}, year = 2010, month = may, @@ -363,7 +363,7 @@ @ARTICLE{Lang2010 @ARTICLE{Onken2024, author = {{Onken}, Christopher A. and {Wolf}, Christian and {Bessell}, Michael S. and {Chang}, Seo-Won and {Luvaul}, Lance C. and {Tonry}, John L. and {White}, Marc C. and {Da Costa}, Gary S.}, title = "{SkyMapper Southern Survey: Data release 4}", - journal = {\pasa}, + journal = {Publications of the Astronomical Society of Australia}, keywords = {Optical astronomy, sky surveys, catalogs, Astrophysics - Cosmology and Nongalactic Astrophysics, Astrophysics - Astrophysics of Galaxies, Astrophysics - Instrumentation and Methods for Astrophysics, Astrophysics - Solar and Stellar Astrophysics}, year = 2024, month = oct, @@ -381,7 +381,7 @@ @ARTICLE{Onken2024 @ARTICLE{Rastinejad2025, author = {{Rastinejad}, Jillian C. and {Levan}, Andrew J. and {Jonker}, Peter G. and {Kilpatrick}, Charles D. and {Fryer}, Christopher L. and {Sarin}, Nikhil and {Gompertz}, Benjamin P. and {Liu}, Chang and {Eyles-Ferris}, Rob A.~J. and {Fong}, Wen-fai and {Burns}, Eric and {Gillanders}, James H. and {Mandel}, Ilya and {Malesani}, Daniele Bj{\o}rn and {O'Brien}, Paul T. and {Tanvir}, Nial R. and {Ackley}, Kendall and {Aryan}, Amar and {Bauer}, Franz E. and {Bloemen}, Steven and {de Boer}, Thomas and {Bom}, Cl{\'e}cio R. and {Chac{\'o}n}, Jennifer A. and {Chambers}, Ken and {Chen}, Ting-Wan and {Chrimes}, Ashley A. and {van Dalen}, Joyce N.~D. and {D'Elia}, Valerio and {De Pasquale}, Massimiliano and {Fulton}, Michael D. and {Groot}, Paul J. and {Gupta}, Rahul and {Hartmann}, Dieter H. and {van Hoof}, Agnes P.~C. and {Huber}, Mark E. and {Izzo}, Luca and {Jacobson-Galan}, Wynn and {Jakobsson}, P{\'a}ll and {Kong}, Albert and {Laskar}, Tanmoy and {Lowe}, Thomas B. and {Magnier}, Eugene A. and {Maiorano}, Elisabetta and {Martin-Carrillo}, Antonio and {Mas-Ribas}, Lluis and {Mata S{\'a}nchez}, Daniel and {Nicholl}, Matt and {Nixon}, Christopher J. and {Oates}, Samantha R. and {Paek}, Gregory and {Palmerio}, Jesse and {Paris}, Diego and {Pieterse}, Dani{\"e}lle L.~A. and {Pugliese}, Giovanna and {Quirola Vasquez}, Jonathan A. and {van Roestel}, Jan and {Rossi}, Andrea and {Rouco Escorial}, Alicia and {Salvaterra}, Ruben and {Schneider}, Benjamin and {Smartt}, Stephen J. and {Smith}, Ken and {Smith}, Ian A. and {Srivastav}, Shubham and {Torres}, Manuel A.~P. and {Ventura}, Chiara and {Vreeswijk}, Paul and {Wainscoat}, Richard and {Yang}, Yi-Jung and {Yang}, Sheng}, title = "{EP 250108a/SN 2025kg: Observations of the Most Nearby Broad-line Type Ic Supernova Following an Einstein Probe Fast X-Ray Transient}", - journal = {\apjl}, + journal = {The Astrophysical Journal}, keywords = {Core-collapse supernovae, Gamma-ray bursts, X-ray transient sources, 304, 629, 1852, High Energy Astrophysical Phenomena}, year = 2025, month = jul, @@ -433,7 +433,7 @@ @INPROCEEDINGS{Eikenberry2012 @ARTICLE{Persson2013, author = {{Persson}, S.~E. and {Murphy}, D.~C. and {Smee}, S. and {Birk}, C. and {Monson}, A.~J. and {Uomoto}, A. and {Koch}, E. and {Shectman}, S. and {Barkhouser}, R. and {Orndorff}, J. and {Hammond}, R. and {Harding}, A. and {Scharfstein}, G. and {Kelson}, D. and {Marshall}, J. and {McCarthy}, P.~J.}, title = "{FourStar: The Near-Infrared Imager for the 6.5 m Baade Telescope at Las Campanas Observatory}", - journal = {\pasp}, + journal = {Publications of the Astronomical Society of the Pacific}, year = 2013, month = jun, volume = {125}, From b5bbd274bb5f721a97c406ecf644aad37f43237f Mon Sep 17 00:00:00 2001 From: KerryPaterson Date: Tue, 10 Mar 2026 09:19:42 +0100 Subject: [PATCH 3/8] Update paper.bib Added new reference. --- paper/paper.bib | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/paper/paper.bib b/paper/paper.bib index 5e2d6826..7f87b5b6 100755 --- a/paper/paper.bib +++ b/paper/paper.bib @@ -497,3 +497,22 @@ @software{photutils:2024 doi = {10.5281/zenodo.13989456}, url = {https://doi.org/10.5281/zenodo.13989456}, } + +@ARTICLE{DRAGONS, + author = {{Labrie}, K. and {Simpson}, C. and {Cardenes}, R. and {Turner}, J. and {Soraisam}, M. and {Quint}, B. and {Oberdorf}, O. and {Placco}, V.~M. and {Berke}, D. and {Smirnova}, O. and {Conseil}, S. and {Vacca}, W.~D. and {Thomas-Osip}, J.}, + title = "{DRAGONS-A Quick Overview}", + journal = {Research Notes of the American Astronomical Society}, + keywords = {Astronomy software, Astronomy data reduction, 1855, 1861, Astrophysics - Instrumentation and Methods for Astrophysics}, + year = 2023, + month = oct, + volume = {7}, + number = {10}, + eid = {214}, + pages = {214}, + doi = {10.3847/2515-5172/ad0044}, +archivePrefix = {arXiv}, + eprint = {2310.03048}, + primaryClass = {astro-ph.IM}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2023RNAAS...7..214L}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} From e80d21b5f873e8e14fe253d1024d25a2d8af103b Mon Sep 17 00:00:00 2001 From: KerryPaterson Date: Tue, 10 Mar 2026 10:24:02 +0100 Subject: [PATCH 4/8] Update paper.md Added new sections required by new format for JOSS. --- paper/paper.md | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index b3fc4ed7..42377d82 100755 --- a/paper/paper.md +++ b/paper/paper.md @@ -24,7 +24,7 @@ affiliations: - name: Max-Planck-Institut für Astronomie, Königstuhl 17, 69117 Heidelberg, Germany index: 2 -date: 2 Sep 2025 +date: 10 Mar 2026 bibliography: paper.bib @@ -32,13 +32,13 @@ bibliography: paper.bib # Summary -This pipeline was developed for the reduction and stacking of imaging data for a number of telescopes and instruments in the optical and near-infrared (NIR) bands. The purpose of the pipeline is to provide an automated way to reduce imaging data, create a median stack with reliable astrometry and photometric calibration, and perform aperture and PSF photometry on sources within the stacked image. +The Pipeline for Optical/infrared Telescopes in Python for Reducing Images (POTPyRI) was developed for the reduction and stacking of imaging data for a number of telescopes and instruments in the optical and near-infrared (NIR) bands. The purpose of the pipeline is to provide an automated way to reduce imaging data, create a median stack with reliable astrometry and photometric calibration, and perform aperture and Point Spread Function (PSF) photometry on sources within the stacked image. # Statement of need -The pipeline is written in Python (currently deployed and tested on Python 3.12) and uses packages from Astropy [@astropy:2013;@astropy:2018], ccdproc, astroquery [@Ginsburg2019] and photutils [@photutils:2024]; with the additional use of external dependencies including SExtractor [@Bertin1996] and Astrometry.net [@Lang2010]. The code is available on GitHub at https://github.com/CIERA-Transients/POTPyRI, where instructions on the installation and detailed use can be found. The code is also installable with pip and is release at PyPI at https://pypi.org/p/potpyri. +POTPyRI is written in Python (currently deployed and tested on Python 3.12) and uses packages from Astropy [@astropy:2013;@astropy:2018], ccdproc, astroquery [@Ginsburg2019] and photutils [@photutils:2024]; with the additional use of external dependencies including SExtractor [@Bertin1996] and Astrometry.net [@Lang2010]. The code is available on GitHub at https://github.com/CIERA-Transients/POTPyRI, where instructions on the installation and detailed use can be found. The code is also installable with pip and is release at PyPI at https://pypi.org/p/potpyri. -Currently available instruments (as of June 2025 - see the GitHub for the most recent list) include: +Currently available instruments (as of March 2026 - see the GitHub for the most recent list) include: - MMIRS (MMT) [@McLeod2012] - Binospec (MMT) [@Fabricant2019] - MOSFIRE (Keck) [@McLean2008] @@ -49,11 +49,19 @@ Currently available instruments (as of June 2025 - see the GitHub for the most r - FourStar (Magellan) [@Persson2013] - IMACS (Magellan) [@Bigelow2003] -Since the pipeline is meant to provide the community with a way to reduce imaging data from these instruments; science applications include the rapid reduction and identification of transients, such as Gamma-Ray Burst (GRB) afterglows, as well as the reduction and stacking of follow-up observations of transients to identify potential host galaxies for associated and in depth study (see [@Paterson2020;@Rastinejad2021;@Fong2021;@Rastinejad2025;@Caleb2025]). +POTPyRI is meant to provide the community with a way to reduce imaging data from these instruments in a streamlined manner, using easily accessible code. + +# State of the field + +Given the more complex suite of reductions often needed for spectroscopic data, many pipelines have been developed to reduced spectroscopic data from many intruments. However, at the start of developemnet, no other automated pipeline was available to reduced images from a number of theses intruments, with only guidelines and recipes often decribed. As the main research undertaken by the developers and collaborators often used data from these instruments, a need to have a way to quickly and automatically reduce these data to provide infomation on subsequent follow-up obseravtions was born. While Gemmi has since setup the Data Reduction for Astronomy from Gemini Observatory North and South (DRAGONS) [@DRAGONS] to try and bring about a uniform way to reduce data from their facility, including imaging, most other pipelines available still focus on spectroscopic data reduction. Even now, POTPyRI still provides additional functionality beyond the reduction and stacking of images, including additional astrometric fitting to ensure accurate astrometry on the stacks, photometric calibration, and both aperture and PSF photometry on all detected sources in the stack. + +# Software design + +POTPyRI was developed in Python, to take advantage of the increased use and development of Python based reduction of astronomy data, and move away from older "blackbox" and lisenced programs. Through the use of other community supported packages, the pipeline builts on already supported packages without duplication of effort. POTPyRI is hosted on GitHub, to promote users to provide feedback, ask for help, or contribute to the pipeline itself. # Method -The pipeline requires two parameters to run. The first is the name of the instrument in order to load the correct settings file. This settings file allows new and user instruments to be added as needed. The second is the full data path to the data to be reduced. The data are expected to be in a particular format, including the file name and the number of extensions, as specified in the setting file. For example, for Keck, the pipeline expects the data in the format in which it is download from the Keck Observatory Archive. In this case, the user can specify that the input data conform to the archive format using *--proc archive*. The details on data formats, including scripts to download and sort data, can be found on GitHub. +POTPyRI requires two parameters to run. The first is the name of the instrument in order to load the correct settings file. This settings file allows new and user instruments to be added as needed. The second is the full data path to the data to be reduced. The data are expected to be in a particular format, including the file name and the number of extensions, as specified in the setting file. For example, for Keck, the pipeline expects the data in the format in which it is download from the Keck Observatory Archive. In this case, the user can specify that the input data conform to the archive format using *--proc archive*. The details on data formats, including scripts to download and sort data, can be found on GitHub. ![Flow diagram showing the basic steps taken by the pipeline. The dashed box shows all steps taken under the process science function, while all steps after the calibration creation is done per target.\label{fig:flow}](../images/Pipeline_flow_diagram.pdf){height="450pt"} @@ -61,7 +69,7 @@ Figure \autoref{fig:flow} shows the basic pipeline operations. The pipeline will After solving for all the astrometry, the pipeline will remove any images which high astrometric dispersion (i.e. images that have dispersion $>5\sigma$ either in RA or DEC), except if the user specified the *--keep\_all\_astro* option, before stacking images. Images are median stacked, using the uncertainty masks and exposure times as weights, and a final stack mask is created (see Figure \autoref{fig:stacks} for examples of median stacks from MOSFIRE, MMIRS, LRIS (blue channel), BINOSPEC (left side) and DEIMOS). -The pipeline will then perform both aperture and Point Spread Function (PSF) photometry on sources in the stacked image. For the aperture photometry, the pipeline will detect sources within the image and determine statistics within a fiducial aperture radius, which is written as an extension to the stacked image. For the PSF photometry, the PSF is determined using a list of bright unsaturated stars, determined based on cuts on roundness, Full Width Half Maximum (FWHM), and signal-to-noise. +The pipeline will then perform both aperture and PSF photometry on sources in the stacked image. For the aperture photometry, the pipeline will detect sources within the image and determine statistics within a fiducial aperture radius, which is written as an extension to the stacked image. For the PSF photometry, the PSF is determined using a list of bright unsaturated stars, determined based on cuts on roundness, Full Width Half Maximum (FWHM), and signal-to-noise. Next, the pipeline uses the PSF to calculate PSF photometry for all the originally extracted sources. After the PSF photometry has been calculated, the pipeline will then calculate a zero point based on aperture photometry by downloading a catalog of standard stars. Currently supported catalogs are the Sloan Digital Sky Survey DR12 [@Eisenstein2011], Pan-STARRS [@Tonry2012], SkyMapper [@Onken2024], and 2MASS [@Skrutskie2006] covering most optical and infrared bands in the north and south. The zero point is then transformed to the AB system and written to the header. In addition, an approximate limiting magnitude is calculated for each stack using the FWHM and the approximate standard deviation in the sky background per pixel. These values are propagated into the image header as 3-, 5-, and 10-$\sigma$ limiting magnitudes as *M3SIGMA*, *M5SIGMA*, and *M10SIGMA*. @@ -72,6 +80,14 @@ While the pipeline runs, the pipeline will also created a detailed log of operat ![Examples of stacks produced by the pipeline from MOSFIRE, MMIRS, LRIS (blue side), BINOSPEC (left side) and DEIMOS data. The position of Gaia DR3 stars are shown by the green circles.\label{fig:stacks}](../images/Stack_examples.pdf) +# Research impact statement + +POTPyRI has science applications in areas where deep stacked imaging, with accuray astrometry and phtotometry is required. This includes the rapid reduction and identification of transients, such as Gamma-Ray Burst (GRB) afterglows, as well as the reduction and stacking of follow-up observations of transients to identify potential host galaxies for association and in-depth study. Examples of such work can by found in [@Paterson2020;@Rastinejad2021;@Fong2021;@Rastinejad2025;@Caleb2025]), while the pipeline continues to be improved while under use in ongoing projects by the developers and their collaborators. + +# AI usage disclosure + +No AI tools were used in the building and preparation of this pipeline. + # Acknowledgements KP acknowledges the help of the Fong group at Center for Interdisciplinary Exploration and Research in Astrophysics, including W. Fong, J. Rastinejad, A. Rouco Escorial, G. Schroeder, A. E. Nugent, A. Gordon for helping to test the pipeline and providing feedback. KP acknowledges support by the National Science Foundation under grant Nos. AST-1814782, AST-1909358 and CAREER grant No. AST-2047919. From ac532c0e650fd462fad283753826a559e01273a7 Mon Sep 17 00:00:00 2001 From: charliekilpatrick Date: Tue, 10 Mar 2026 10:09:05 -0500 Subject: [PATCH 5/8] Revise paper.md for clarity and formatting - Improved the summary section to better articulate the purpose and functionality of the POTPyRI pipeline. - Enhanced the statement of need and state of the field sections for better readability and detail. - Made minor formatting adjustments to the affiliations and software design sections for consistency. --- paper/paper.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index 42377d82..3ef00422 100755 --- a/paper/paper.md +++ b/paper/paper.md @@ -19,10 +19,10 @@ authors: affiliation: 1 affiliations: - - name: Center for Interdisciplinary Exploration and Research in Astrophysics and Department of Physics and Astronomy, Northwestern University, 1800 Sherman Ave, Evanston, IL 60201, USA - index: 1 - - name: Max-Planck-Institut für Astronomie, Königstuhl 17, 69117 Heidelberg, Germany - index: 2 + - name: Center for Interdisciplinary Exploration and Research in Astrophysics and Department of Physics and Astronomy, Northwestern University, 1800 Sherman Ave, Evanston, IL 60201, USA + index: 1 + - name: Max-Planck-Institut für Astronomie, Königstuhl 17, 69117 Heidelberg, Germany + index: 2 date: 10 Mar 2026 @@ -32,11 +32,11 @@ bibliography: paper.bib # Summary -The Pipeline for Optical/infrared Telescopes in Python for Reducing Images (POTPyRI) was developed for the reduction and stacking of imaging data for a number of telescopes and instruments in the optical and near-infrared (NIR) bands. The purpose of the pipeline is to provide an automated way to reduce imaging data, create a median stack with reliable astrometry and photometric calibration, and perform aperture and Point Spread Function (PSF) photometry on sources within the stacked image. +Astronomers often need to turn raw telescope images into calibrated, aligned, and combined images before measuring the brightness and positions of stars and galaxies. The Pipeline for Optical/infrared Telescopes in Python for Reducing Images (POTPyRI) automates this process for a number of optical and near-infrared (NIR) telescopes and instruments. It was developed to provide an automated way to reduce imaging data, create a median stack with reliable astrometry and photometric calibration, and perform aperture and Point Spread Function (PSF) photometry on sources within the stacked image. # Statement of need -POTPyRI is written in Python (currently deployed and tested on Python 3.12) and uses packages from Astropy [@astropy:2013;@astropy:2018], ccdproc, astroquery [@Ginsburg2019] and photutils [@photutils:2024]; with the additional use of external dependencies including SExtractor [@Bertin1996] and Astrometry.net [@Lang2010]. The code is available on GitHub at https://github.com/CIERA-Transients/POTPyRI, where instructions on the installation and detailed use can be found. The code is also installable with pip and is release at PyPI at https://pypi.org/p/potpyri. +POTPyRI is written in Python (currently deployed and tested on Python 3.12) and uses packages from Astropy [@astropy:2013;@astropy:2018], ccdproc, astroquery [@Ginsburg2019] and photutils [@photutils:2024]; with the additional use of external dependencies including SExtractor [@Bertin1996] and Astrometry.net [@Lang2010]. The code is available on GitHub at https://github.com/CIERA-Transients/POTPyRI, where instructions on the installation and detailed use can be found. The code is also installable with pip and is released on PyPI at https://pypi.org/p/potpyri. The pipeline has been developed openly on GitHub since 2020, with public releases on PyPI and a public issue tracker for community feedback and contributions. Currently available instruments (as of March 2026 - see the GitHub for the most recent list) include: - MMIRS (MMT) [@McLeod2012] @@ -53,11 +53,11 @@ POTPyRI is meant to provide the community with a way to reduce imaging data from # State of the field -Given the more complex suite of reductions often needed for spectroscopic data, many pipelines have been developed to reduced spectroscopic data from many intruments. However, at the start of developemnet, no other automated pipeline was available to reduced images from a number of theses intruments, with only guidelines and recipes often decribed. As the main research undertaken by the developers and collaborators often used data from these instruments, a need to have a way to quickly and automatically reduce these data to provide infomation on subsequent follow-up obseravtions was born. While Gemmi has since setup the Data Reduction for Astronomy from Gemini Observatory North and South (DRAGONS) [@DRAGONS] to try and bring about a uniform way to reduce data from their facility, including imaging, most other pipelines available still focus on spectroscopic data reduction. Even now, POTPyRI still provides additional functionality beyond the reduction and stacking of images, including additional astrometric fitting to ensure accurate astrometry on the stacks, photometric calibration, and both aperture and PSF photometry on all detected sources in the stack. +Given the more complex suite of reductions often needed for spectroscopic data, many pipelines have been developed to reduce spectroscopic data from many instruments. However, at the start of development, no other automated pipeline was available to reduce images from a number of these instruments, with only guidelines and recipes often described. As the main research undertaken by the developers and collaborators often used data from these instruments, a need to have a way to quickly and automatically reduce these data to provide information on subsequent follow-up observations was born. Gemini has since set up DRAGONS [@DRAGONS] for that facility, including imaging; other projects offer instrument-specific or spectroscopic-focused pipelines. We built POTPyRI rather than contributing only to DRAGONS or a single-facility tool because our research required one pipeline for imaging from multiple facilities (Keck, Gemini, MMT, Magellan) with consistent calibration and photometry, and features such as optional relative flux calibration before stacking, Gaia-based astrometric refinement, and both aperture and PSF photometry in one workflow. POTPyRI provides fine astrometric fitting, photometric calibration, and aperture and PSF photometry on all detected sources in the stack. # Software design -POTPyRI was developed in Python, to take advantage of the increased use and development of Python based reduction of astronomy data, and move away from older "blackbox" and lisenced programs. Through the use of other community supported packages, the pipeline builts on already supported packages without duplication of effort. POTPyRI is hosted on GitHub, to promote users to provide feedback, ask for help, or contribute to the pipeline itself. +POTPyRI was developed in Python to take advantage of Python-based astronomy data reduction and to move away from older "blackbox" and licensed programs. Key design trade-offs: we use instrument-specific settings files rather than one global configuration, so each telescope defines its own keywords and calibration options and new instruments can be added without changing core code; we use external tools (SExtractor, Astrometry.net) for source detection and initial WCS to improve robustness while the pipeline focuses on orchestration and photometry; and we build on the Astropy ecosystem (ccdproc, photutils, astroquery) for units, coordinates, combination, and catalog queries. The core reduction flow is shared across instruments (calibration, masking, sky subtraction, astrometry, alignment, stacking, photometry), with instrument subclasses supplying detector-specific parameters and file-naming. POTPyRI is hosted on GitHub to encourage feedback and contributions. # Method @@ -65,9 +65,9 @@ POTPyRI requires two parameters to run. The first is the name of the instrument ![Flow diagram showing the basic steps taken by the pipeline. The dashed box shows all steps taken under the process science function, while all steps after the calibration creation is done per target.\label{fig:flow}](../images/Pipeline_flow_diagram.pdf){height="450pt"} -Figure \autoref{fig:flow} shows the basic pipeline operations. The pipeline will first sort the files in the given path, and create a file list which contains information about each file such as the type, filter, configuration, and target. Using the file list and the settings file, the pipeline will then create calibration files (e.g. bias, dark, flat) and performs the necessary basic reductions to science files, grouped by target, including gain correction, bias subtraction, dark subtraction, flat correction, and trimming. During this step, a static mask, if available, is used to identify bad pixels. This mask is later extended to include image-specific issues such as satellites trails, cosmic rays (cleaned from images) and saturated stars. A 2D sky background is created for each image and subtracted. Astrometry.net is used on each image to provide a rough WCS solution, after which a fine astrometric solution is computed using Gaia-DR3 catalogs [@Gaia2021]. Images are then aligned using the new WCS. After basic reductions, additional corrections where applicable are applied. For the NIR, the sky background can change during the night. Thus, for NIR observations, an additional NIR sky map is created for each science image, based on observations for each target. In the optical, redder filters such as $i$ and $z$-bands, can also suffer from fringing, which introduces low-level structure in the background. Thus, for filters that require this correction (based on each instrument and thus set in the settings file for the instrument), the pipeline creates a fringe map based on all science images for a target for that filter. An uncertainty map for each image is created to include noise added by the reduction such as the background subtraction. +Figure \autoref{fig:flow} shows the basic pipeline operations. The pipeline will first sort the files in the given path, and create a file list which contains information about each file such as the type, filter, configuration, and target. Using the file list and the settings file, the pipeline will then create calibration files (e.g. bias, dark, flat) and performs the necessary basic reductions to science files, grouped by target, including gain correction, bias subtraction, dark subtraction, flat correction, and trimming. During this step, a static mask, if available, is used to identify bad pixels. This mask is later extended to include image-specific issues such as satellite trails, cosmic rays (cleaned from images) and saturated stars. A 2D sky background is created for each image and subtracted. Astrometry.net is used on each image to provide a rough WCS solution, after which a fine astrometric solution is computed using Gaia-DR3 catalogs [@Gaia2021]. Images are then aligned using the new WCS. After basic reductions, additional corrections where applicable are applied. For the NIR, the sky background can change during the night. Thus, for NIR observations, an additional NIR sky map is created for each science image, based on observations for each target. In the optical, redder filters such as $i$ and $z$-bands, can also suffer from fringing, which introduces low-level structure in the background. Thus, for filters that require this correction (based on each instrument and thus set in the settings file for the instrument), the pipeline creates a fringe map based on all science images for a target for that filter. An uncertainty map for each image is created to include noise added by the reduction such as the background subtraction. -After solving for all the astrometry, the pipeline will remove any images which high astrometric dispersion (i.e. images that have dispersion $>5\sigma$ either in RA or DEC), except if the user specified the *--keep\_all\_astro* option, before stacking images. Images are median stacked, using the uncertainty masks and exposure times as weights, and a final stack mask is created (see Figure \autoref{fig:stacks} for examples of median stacks from MOSFIRE, MMIRS, LRIS (blue channel), BINOSPEC (left side) and DEIMOS). +After solving for all the astrometry, the pipeline will remove any images with high astrometric dispersion (i.e. images that have dispersion $>5\sigma$ either in RA or DEC), except if the user specified the *--keep\_all\_astro* option, before stacking images. Images are median stacked, using the uncertainty masks and exposure times as weights, and a final stack mask is created (see Figure \autoref{fig:stacks} for examples of median stacks from MOSFIRE, MMIRS, LRIS (blue channel), BINOSPEC (left side) and DEIMOS). The pipeline will then perform both aperture and PSF photometry on sources in the stacked image. For the aperture photometry, the pipeline will detect sources within the image and determine statistics within a fiducial aperture radius, which is written as an extension to the stacked image. For the PSF photometry, the PSF is determined using a list of bright unsaturated stars, determined based on cuts on roundness, Full Width Half Maximum (FWHM), and signal-to-noise. Next, the pipeline uses the PSF to calculate PSF photometry for all the originally extracted sources. After the PSF photometry has been calculated, the pipeline will then calculate a zero point based on aperture photometry by downloading a catalog of standard stars. Currently supported catalogs are the Sloan Digital Sky Survey DR12 [@Eisenstein2011], Pan-STARRS [@Tonry2012], SkyMapper [@Onken2024], and 2MASS [@Skrutskie2006] covering most optical and infrared bands in the north and south. The zero point is then transformed to the AB system and written to the header. @@ -76,13 +76,13 @@ In addition, an approximate limiting magnitude is calculated for each stack usin For more detailed instructions on running the pipeline and a description of pipeline outputs, please see the documentation available on the GitHub. For user support or errors running the pipeline, please open a Github issue. -While the pipeline runs, the pipeline will also created a detailed log of operations. Along with the log, the pipeline will also write information such as the readnoise, effective gain, and zero point to the stack. The pipeline also produces a number of other output files, including source catalogs, star lists, error plots etc. For more details on these outputs, refer to the documentation of the GitHub. +While the pipeline runs, the pipeline will also create a detailed log of operations. Along with the log, the pipeline will also write information such as the readnoise, effective gain, and zero point to the stack. The pipeline also produces a number of other output files, including source catalogs, star lists, error plots etc. For more details on these outputs, refer to the documentation on GitHub. ![Examples of stacks produced by the pipeline from MOSFIRE, MMIRS, LRIS (blue side), BINOSPEC (left side) and DEIMOS data. The position of Gaia DR3 stars are shown by the green circles.\label{fig:stacks}](../images/Stack_examples.pdf) # Research impact statement -POTPyRI has science applications in areas where deep stacked imaging, with accuray astrometry and phtotometry is required. This includes the rapid reduction and identification of transients, such as Gamma-Ray Burst (GRB) afterglows, as well as the reduction and stacking of follow-up observations of transients to identify potential host galaxies for association and in-depth study. Examples of such work can by found in [@Paterson2020;@Rastinejad2021;@Fong2021;@Rastinejad2025;@Caleb2025]), while the pipeline continues to be improved while under use in ongoing projects by the developers and their collaborators. +POTPyRI has been used to reduce and stack imaging in published and in-preparation work on transient follow-up and host galaxy association, including Paterson et al. (2020), Rastinejad et al. (2021), Fong et al. (2021), Rastinejad et al. (2025), and Caleb et al. (2025) [@Paterson2020;@Rastinejad2021;@Fong2021;@Rastinejad2025;@Caleb2025]. Applications include rapid reduction and identification of transients such as Gamma-Ray Burst (GRB) afterglows, and reduction and stacking of follow-up observations to identify host galaxies for association and study. The package is available on PyPI and is developed openly on GitHub with contributions from multiple developers. The pipeline continues to be improved while in use in ongoing projects by the developers and their collaborators. # AI usage disclosure From a18be59ff812fd440abf69eb3f575f83b857ccdb Mon Sep 17 00:00:00 2001 From: KerryPaterson Date: Tue, 10 Mar 2026 18:18:41 +0100 Subject: [PATCH 6/8] Update paper.md Fixed in line references. --- paper/paper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/paper.md b/paper/paper.md index 3ef00422..a5158360 100755 --- a/paper/paper.md +++ b/paper/paper.md @@ -82,7 +82,7 @@ While the pipeline runs, the pipeline will also create a detailed log of operati # Research impact statement -POTPyRI has been used to reduce and stack imaging in published and in-preparation work on transient follow-up and host galaxy association, including Paterson et al. (2020), Rastinejad et al. (2021), Fong et al. (2021), Rastinejad et al. (2025), and Caleb et al. (2025) [@Paterson2020;@Rastinejad2021;@Fong2021;@Rastinejad2025;@Caleb2025]. Applications include rapid reduction and identification of transients such as Gamma-Ray Burst (GRB) afterglows, and reduction and stacking of follow-up observations to identify host galaxies for association and study. The package is available on PyPI and is developed openly on GitHub with contributions from multiple developers. The pipeline continues to be improved while in use in ongoing projects by the developers and their collaborators. +POTPyRI has been used to reduce and stack imaging in published and in-preparation work on transient follow-up and host galaxy association, including @Paterson2020, @Rastinejad2021, @Fong2021, @Rastinejad2025, and @Caleb2025. Applications include rapid reduction and identification of transients such as Gamma-Ray Burst (GRB) afterglows, and reduction and stacking of follow-up observations to identify host galaxies for association and study. The package is available on PyPI and is developed openly on GitHub with contributions from multiple developers. The pipeline continues to be improved while in use in ongoing projects by the developers and their collaborators. # AI usage disclosure From d1c8fc89d1b6a3887d16dfe4c08482b30aebafca Mon Sep 17 00:00:00 2001 From: charliekilpatrick Date: Thu, 19 Mar 2026 13:16:53 -0500 Subject: [PATCH 7/8] Add tests for Gaia alignment fallback scenarios - Implemented unit tests to verify the behavior of the align_to_gaia function when the Gaia catalog is unavailable or when SExtractor returns no sources. - Enhanced the solve_wcs module with helper functions for logging and writing fallback headers to FITS files, ensuring clear documentation of fallback reasons in the header. - Improved the validation of refined WCS by adding checks for pixel scale and anisotropy, enhancing the robustness of the WCS alignment process. --- potpyri/primitives/solve_wcs.py | 505 ++++++++++++++++++-------------- tests/test_wcs.py | 66 +++++ 2 files changed, 349 insertions(+), 222 deletions(-) diff --git a/potpyri/primitives/solve_wcs.py b/potpyri/primitives/solve_wcs.py index b66b6b7d..adefbb33 100755 --- a/potpyri/primitives/solve_wcs.py +++ b/potpyri/primitives/solve_wcs.py @@ -38,6 +38,70 @@ import warnings warnings.simplefilter('ignore', category=AstropyWarning) +def _log_gaia(log, level, message): + """Small helper to keep Gaia-stage logging consistent.""" + if log: + getattr(log, level)(message) + else: + print(message) + +def _write_gaia_fallback_header(hdu, file, reason, log=None, disp_arcsec=1.0): + """Write fallback astrometric dispersion values when Gaia refinement fails. + + This preserves a coarse astrometry.net WCS solution while making the + failure mode explicit in the header and logs. + """ + _log_gaia(log, 'warning', + f'Gaia alignment fallback for {file}: {reason}. ' + f'Keeping coarse astrometry.net WCS.') + hdu[0].header['RADISP'] = (disp_arcsec, 'Dispersion in R.A. of WCS [Arcsec]') + hdu[0].header['DEDISP'] = (disp_arcsec, 'Dispersion in Decl. of WCS [Arcsec]') + hdu[0].header['GAIAFAIL'] = (reason[:32], 'Gaia fallback reason') + hdu.writeto(file, overwrite=True, output_verify='silentfix') + +def _validate_refined_wcs(w, header, tel, log=None): + """Validate refined WCS against expected pixel scale and anisotropy. + + Returns + ------- + tuple + (is_valid, reason_string) + """ + try: + m = np.asarray(w.pixel_scale_matrix, dtype=float) + _, s, _ = np.linalg.svd(m) + # singular-value pixel scales in arcsec/pixel + scales_arcsec = s * 3600.0 + max_scale = float(np.max(scales_arcsec)) + min_scale = float(np.min(scales_arcsec)) + aniso = float(max_scale / max(min_scale, 1e-12)) + det = float(np.linalg.det(m)) + except Exception: + return (False, 'could not compute WCS pixel-scale matrix diagnostics') + + # Expected scale from instrument + binning in header + try: + binn = tel.get_binning(header) + expected = float(tel.get_pixscale() * int(str(binn)[0])) + except Exception: + expected = None + + _log_gaia(log, 'info', + f'Gaia WCS diagnostics: scales={scales_arcsec}, anisotropy={aniso:.3f}, det={det:.3e}, expected_scale={expected}') + + # Basic physical sanity + if min_scale <= 0.0 or max_scale <= 0.0: + return (False, 'non-positive WCS pixel scale') + if aniso > 3.0: + return (False, f'excessive WCS anisotropy ({aniso:.2f} > 3.0)') + if expected is not None: + if min_scale < 0.5 * expected: + return (False, f'WCS min scale too small ({min_scale:.4f} < {0.5*expected:.4f} arcsec/pix)') + if max_scale > 1.5 * expected: + return (False, f'WCS max scale too large ({max_scale:.4f} > {1.5*expected:.4f} arcsec/pix)') + + return (True, '') + def get_gaia_catalog(input_file, log=None): """Query Gaia DR3 for stars in the field; return filtered catalog table. @@ -423,256 +487,253 @@ def align_to_gaia(file, tel, radius=0.5, max_search_radius=5.0*u.arcsec, """ cat = get_gaia_catalog(file, log=log) - if cat is None or len(cat)==0: - if log: - log.error(f'Could not get Gaia catalog or no stars for {file}') - else: - print(f'Could not get Gaia catalog or no stars for {file}') - return(False) - - if log: - log.info(f'Got {len(cat)} Gaia DR3 alignment stars') - else: - print(f'Got {len(cat)} Gaia DR3 alignment stars') - - # Estimate sources that land within the image using WCS from header - hdu = fits.open(file) - w = WCS(hdu[0].header, relax=True) - naxis1 = hdu[0].header['NAXIS1'] - naxis2 = hdu[0].header['NAXIS2'] - - # Get pixel coordinates of all stars in image - coords = SkyCoord(cat['RA_ICRS'], cat['DE_ICRS'], unit=(u.deg, u.deg)) - x_pix, y_pix = w.world_to_pixel(coords) - - # Mask to stars that are nominally in image - mask = (x_pix > 0) & (x_pix < naxis1) & (y_pix > 0) & (y_pix < naxis2) - x_pix = x_pix[mask] ; y_pix = y_pix[mask] - # Also mask catalog - cat = cat[mask] - - if cat is None or len(cat)==0: - if log: - log.error(f'No stars found in {file}') - else: - print(f'No stars found in {file}') - hdu.close() - return(False) - - if log: - log.info(f'Found {len(cat)} stars in the image') - else: - print(f'Found {len(cat)} stars in the image') - - if len(cat) 0) & (x_pix < naxis1) & (y_pix > 0) & (y_pix < naxis2) + x_pix = x_pix[mask] ; y_pix = y_pix[mask] + # Also mask catalog and coordinates + cat = cat[mask] + gaia_coords = gaia_coords[mask] - bar = progressbar.ProgressBar(maxval=10) - bar.start() - succeeded = False - for i in np.arange(10): - bar.update(i+1) + if cat is None or len(cat)==0: + _write_gaia_fallback_header(hdu, file, + 'no Gaia stars project into image bounds', log=log) + return(True) - cat_coords = w.pixel_to_world(sky_cat['X_IMAGE'], sky_cat['Y_IMAGE']) + _log_gaia(log, 'info', + f'Gaia stars projected into image bounds: {len(cat)} (of {len(mask)})') - idx, d2d, d3d = match_coordinates_sky(coords, cat_coords) + if len(cat)100: - sip_degree = 2 - if len(cat_coords_match)>500: - sip_degree = 4 - if len(cat_coords_match)>2000: - sip_degree = 6 + # Get central coordinate of image based on centroiding + central_pix = (float(naxis1)/2., float(naxis2)/2.) + central_coo = w.pixel_to_world(*central_pix) - cat_coords_match.add_column(Column(sky_coords_match.ra.degree, - name='RA_ICRS')) - cat_coords_match.add_column(Column(sky_coords_match.dec.degree, - name='DE_ICRS')) + _log_gaia(log, 'info', 'Converging on fine WCS solution') + + bar = progressbar.ProgressBar(maxval=10) + bar.start() + succeeded = False + cat_coords_match = None + best_n_match = 0 + best_iter = -1 + n_iter_no_match = 0 + for i in np.arange(10): + bar.update(i+1) + + cat_coords = w.pixel_to_world(sky_cat['X_IMAGE'], sky_cat['Y_IMAGE']) + + idx, d2d, d3d = match_coordinates_sky(gaia_coords, cat_coords) + + sep_mask = d2d < max_search_radius + n_match = int(np.sum(sep_mask)) + if n_match > best_n_match: + best_n_match = n_match + best_iter = int(i + 1) + if n_match == 0: + n_iter_no_match += 1 + continue + + sky_coords_match = gaia_coords[sep_mask] + cat_coords_match = sky_cat[idx[sep_mask]] + + sip_degree = 0 + if len(cat_coords_match)>100: + sip_degree = 2 + if len(cat_coords_match)>500: + sip_degree = 4 + if len(cat_coords_match)>2000: + sip_degree = 6 + + # Make a fresh table each iteration; avoid duplicate-column failures + cat_coords_match = Table(cat_coords_match) + cat_coords_match['RA_ICRS'] = sky_coords_match.ra.degree + cat_coords_match['DE_ICRS'] = sky_coords_match.dec.degree + fit_coords = SkyCoord(cat_coords_match['RA_ICRS'], + cat_coords_match['DE_ICRS'], unit=(u.deg, u.deg)) + + xy = (cat_coords_match['X_IMAGE'], cat_coords_match['Y_IMAGE']) + central_coo = w.pixel_to_world(*central_pix) + try: + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", category=RuntimeWarning, + message=".*cdelt will be ignored since cd is present.*") + w = fit_wcs_from_points(xy, fit_coords, proj_point=central_coo, + sip_degree=sip_degree) + succeeded = True + except ValueError: + # Try with next iteration + continue + + bar.finish() + _log_gaia(log, 'info', + f'Gaia match summary for {file}: ' + f'best matches={best_n_match} at iter={best_iter}, ' + f'iters with zero matches={n_iter_no_match}/10, ' + f'min required={min_gaia_match}, match radius={max_search_radius}.') + + if not succeeded: + _write_gaia_fallback_header(hdu, file, + 'fine WCS fit failed during iterative Gaia matching', log=log) + return(True) - xy = (cat_coords_match['X_IMAGE'], cat_coords_match['Y_IMAGE']) - coords = SkyCoord(cat_coords_match['RA_ICRS'], - cat_coords_match['DE_ICRS'], unit=(u.deg, u.deg)) + _log_gaia(log, 'info', f'Solved with SIP degree = {sip_degree}') - central_coo = w.pixel_to_world(*central_pix) - try: - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", category=RuntimeWarning, - message=".*cdelt will be ignored since cd is present.*") - w = fit_wcs_from_points(xy, coords, proj_point=central_coo, - sip_degree=sip_degree) - succeeded = True - except ValueError: - # Try with next iteration - pass - - if not succeeded: - if log: - log.error(f'Could not converge on fine WCS solution for: {file}') + if cat_coords_match is None or len(cat_coords_match)==0: + _write_gaia_fallback_header(hdu, file, + 'zero matched Gaia/SExtractor sources after iterations', log=log) + return(True) else: - print(f'Could not converge on fine WCS solution for: {file}') - hdu.close() - return(False) + _log_gaia(log, 'info', f'Matched to {len(cat_coords_match)} coordinates') + if len(cat_coords_match)= 8 and len(cat_coords_match) <= (min_gaia_match + 1): + _write_gaia_fallback_header(hdu, file, + f'unstable Gaia matching (zero-match iters={n_iter_no_match}/10, matched={len(cat_coords_match)})', + log=log) + return(True) - if log: - log.info(f'Solved with SIP degree = {sip_degree}') - else: - print(f'Solved with SIP degree = {sip_degree}') + # Bootstrap WCS solution and get center pixel + ra_cent = [] ; de_cent = [] + coords = SkyCoord(cat_coords_match['RA_ICRS'], cat_coords_match['DE_ICRS'], + unit=(u.deg, u.deg)) - if cat_coords_match is None or len(cat_coords_match)==0: - if log: - log.error(f'Could not centroid on any stars in {file}') - else: - print(f'Could not centroid on any stars in {file}') - hdu.close() - return(False) - else: - if log: - log.info(f'Matched to {len(cat_coords_match)} coordinates') - else: - print(f'Matched to {len(cat_coords_match)} coordinates') - - if len(cat_coords_match)200: + size = 100 + else: + size = int(len(idx)/2) - # Bootstrap WCS solution and get center pixel - ra_cent = [] ; de_cent = [] - coords = SkyCoord(cat_coords_match['RA_ICRS'], cat_coords_match['DE_ICRS'], - unit=(u.deg, u.deg)) + idxs = np.random.choice(idx, size=size, replace=False) - bar = progressbar.ProgressBar(maxval=1000) - bar.start() + xy = (cat_coords_match['X_IMAGE'][idxs], + cat_coords_match['Y_IMAGE'][idxs]) + c = coords[idxs] - idx = np.arange(len(cat_coords_match)) - for i in np.arange(1000): - bar.update(i+1) + central_coo = w.pixel_to_world(*central_pix) + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", category=RuntimeWarning, + message=".*cdelt will be ignored since cd is present.*") + new_wcs = fit_wcs_from_points(xy, c, projection=w) + + cent_coord = new_wcs.pixel_to_world(*central_pix) + ra_cent.append(cent_coord.ra.degree) + de_cent.append(cent_coord.dec.degree) + + bar.finish() + + ra_cent = np.array(ra_cent) + de_cent = np.array(de_cent) + + # Estimate systematic precision of new WCS + mean_ra, med_ra, std_ra = sigma_clipped_stats(ra_cent, maxiters=11, + sigma=3) + mean_de, med_de, std_de = sigma_clipped_stats(de_cent, maxiters=11, + sigma=3) + + mask = (np.abs(ra_cent-med_ra)<3*std_ra) & (np.abs(de_cent-med_de)<3*std_de) + + # Create a scatter plot of the centroid values to validate the astrometry + if save_centroids: + fig, ax = plt.subplots() + ax.scatter(ra_cent[mask], de_cent[mask]) + plt.savefig(file.replace('.fits','_centroids.png')) + + header = w.to_header() + header['CRPIX1']=central_pix[0] + header['CRPIX2']=central_pix[1] + header['CRVAL1']=med_ra + header['CRVAL2']=med_de + header['CUNIT1']='deg' + header['CUNIT2']='deg' + if sip_degree>0: + header['CTYPE1']='RA---TAN-SIP' + header['CTYPE2']='DEC--TAN-SIP' + for kw, val in w._write_sip_kw().items(): + header[kw] = val + + # Validate refined WCS; if pathological, fall back to coarse solution. + is_valid, reason = _validate_refined_wcs(w, hdu[0].header, tel, log=log) + if not is_valid: + _write_gaia_fallback_header(hdu, file, f'pathological refined WCS: {reason}', log=log) + return(True) - if len(idx)>200: - size = 100 - else: - size = int(len(idx)/2) + # Delete all old WCS keys + delkeys = ['WCSNAME','CUNIT1','CUNIT2','CTYPE1','CTYPE2','CRPIX1','CRPIX2', + 'CRVAL1','CRVAL2','CD1_1','CD1_2','CD2_1','CD2_2','RADECSYS', + 'PC1_1','PC1_2','PC2_1','PC2_2','LONPOLE','LATPOLE','CDELT1','CDELT2'] + while True: + found_key = False + for key in hdu[0].header.keys(): + if any([k in key for k in delkeys]): + found_key=True + del hdu[0].header[key] + if not found_key: + break - idxs = np.random.choice(idx, size=size, replace=False) + hdu[0].header.update(header) - xy = (cat_coords_match['X_IMAGE'][idxs], - cat_coords_match['Y_IMAGE'][idxs]) - c = coords[idxs] + ra_disp = std_ra*3600.0*np.cos(np.pi/180.0 * mean_de) + de_disp = std_de*3600.0 - central_coo = w.pixel_to_world(*central_pix) - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", category=RuntimeWarning, - message=".*cdelt will be ignored since cd is present.*") - new_wcs = fit_wcs_from_points(xy, c, projection=w) - - cent_coord = new_wcs.pixel_to_world(*central_pix) - ra_cent.append(cent_coord.ra.degree) - de_cent.append(cent_coord.dec.degree) - - bar.finish() - - ra_cent = np.array(ra_cent) - de_cent = np.array(de_cent) - - # Estimate systematic precision of new WCS - mean_ra, med_ra, std_ra = sigma_clipped_stats(ra_cent, maxiters=11, - sigma=3) - mean_de, med_de, std_de = sigma_clipped_stats(de_cent, maxiters=11, - sigma=3) - - mask = (np.abs(ra_cent-med_ra)<3*std_ra) & (np.abs(de_cent-med_de)<3*std_de) - - # Create a scatter plot of the centroid values to validate the astrometry - if save_centroids: - fig, ax = plt.subplots() - ax.scatter(ra_cent[mask], de_cent[mask]) - plt.savefig(file.replace('.fits','_centroids.png')) - - header = w.to_header() - header['CRPIX1']=central_pix[0] - header['CRPIX2']=central_pix[1] - header['CRVAL1']=med_ra - header['CRVAL2']=med_de - header['CUNIT1']='deg' - header['CUNIT2']='deg' - if sip_degree>0: - header['CTYPE1']='RA---TAN-SIP' - header['CTYPE2']='DEC--TAN-SIP' - for kw, val in w._write_sip_kw().items(): - header[kw] = val - - # Delete all old WCS keys - delkeys = ['WCSNAME','CUNIT1','CUNIT2','CTYPE1','CTYPE2','CRPIX1','CRPIX2', - 'CRVAL1','CRVAL2','CD1_1','CD1_2','CD2_1','CD2_2','RADECSYS', - 'PC1_1','PC1_2','PC2_1','PC2_2','LONPOLE','LATPOLE','CDELT1','CDELT2'] - while True: - found_key = False - for key in hdu[0].header.keys(): - if any([k in key for k in delkeys]): - found_key=True - del hdu[0].header[key] - if not found_key: - break - - hdu[0].header.update(header) - - ra_disp = std_ra*3600.0*np.cos(np.pi/180.0 * mean_de) - de_disp = std_de*3600.0 - - ra_disp = float('%.6f'%ra_disp) - de_disp = float('%.6f'%de_disp) + ra_disp = float('%.6f'%ra_disp) + de_disp = float('%.6f'%de_disp) - if log: - log.info(f'R.A. dispersion ={ra_disp}", Decl. dispersion={de_disp}"') - else: - print(f'R.A. dispersion ={ra_disp}", Decl. dispersion={de_disp}"') + _log_gaia(log, 'info', f'R.A. dispersion ={ra_disp}\", Decl. dispersion={de_disp}\"') - # Add header variables for dispersion in WCS solution - hdu[0].header['RADISP']=(ra_disp, 'Dispersion in R.A. of WCS [Arcsec]') - hdu[0].header['DEDISP']=(de_disp, 'Dispersion in Decl. of WCS [Arcsec]') + # Add header variables for dispersion in WCS solution + hdu[0].header['RADISP']=(ra_disp, 'Dispersion in R.A. of WCS [Arcsec]') + hdu[0].header['DEDISP']=(de_disp, 'Dispersion in Decl. of WCS [Arcsec]') + if 'GAIAFAIL' in hdu[0].header: + del hdu[0].header['GAIAFAIL'] - hdu.writeto(file, overwrite=True, output_verify='silentfix') - hdu.close() + hdu.writeto(file, overwrite=True, output_verify='silentfix') return(True) diff --git a/tests/test_wcs.py b/tests/test_wcs.py index 88d2634a..47ad7267 100644 --- a/tests/test_wcs.py +++ b/tests/test_wcs.py @@ -5,6 +5,7 @@ import pytest import requests from astropy.io import fits +from astropy.table import Table from potpyri.utils import options, logger from potpyri.primitives import solve_wcs @@ -109,3 +110,68 @@ def test_clean_up_astrometry(tmp_path): for f in to_create: path = os.path.join(tmp_path, f) assert not os.path.exists(path), f'{f} should have been removed' + + +def test_align_to_gaia_fallback_when_no_gaia_catalog(tmp_path, monkeypatch): + """align_to_gaia falls back to coarse WCS and returns True when Gaia catalog is unavailable.""" + file_path = os.path.join(tmp_path, 'test_no_gaia.fits') + hdu = fits.PrimaryHDU(data=np.zeros((40, 40), dtype=np.float32)) + hdu.header['NAXIS1'] = 40 + hdu.header['NAXIS2'] = 40 + hdu.header['CRPIX1'] = 20.0 + hdu.header['CRPIX2'] = 20.0 + hdu.header['CRVAL1'] = 30.0 + hdu.header['CRVAL2'] = -30.0 + hdu.header['CTYPE1'] = 'RA---TAN' + hdu.header['CTYPE2'] = 'DEC--TAN' + hdu.header['CD1_1'] = -2.2e-5 + hdu.header['CD1_2'] = 0.0 + hdu.header['CD2_1'] = 0.0 + hdu.header['CD2_2'] = 2.2e-5 + hdu.writeto(file_path, overwrite=True) + + monkeypatch.setattr(solve_wcs, 'get_gaia_catalog', lambda *args, **kwargs: None) + tel = instrument_getter('GMOS') + ok = solve_wcs.align_to_gaia(file_path, tel, log=None) + assert ok is True + with fits.open(file_path) as out: + assert out[0].header['RADISP'] == 1.0 + assert out[0].header['DEDISP'] == 1.0 + assert 'GAIAFAIL' in out[0].header + + +def test_align_to_gaia_fallback_when_no_sextractor_sources(tmp_path, monkeypatch): + """align_to_gaia falls back and returns True when SExtractor has no detections.""" + file_path = os.path.join(tmp_path, 'test_no_sex.fits') + hdu = fits.PrimaryHDU(data=np.zeros((40, 40), dtype=np.float32)) + hdu.header['NAXIS1'] = 40 + hdu.header['NAXIS2'] = 40 + hdu.header['CRPIX1'] = 20.0 + hdu.header['CRPIX2'] = 20.0 + hdu.header['CRVAL1'] = 30.0 + hdu.header['CRVAL2'] = -30.0 + hdu.header['CTYPE1'] = 'RA---TAN' + hdu.header['CTYPE2'] = 'DEC--TAN' + hdu.header['CD1_1'] = -2.2e-5 + hdu.header['CD1_2'] = 0.0 + hdu.header['CD2_1'] = 0.0 + hdu.header['CD2_2'] = 2.2e-5 + hdu.writeto(file_path, overwrite=True) + + cat = Table() + # Coordinates close to CRVAL so stars project in-frame with the test WCS. + cat['RA_ICRS'] = [30.0, 30.0001, 29.9999, 30.0002, 29.9998, 30.00005, 29.99995, 30.00015] + cat['DE_ICRS'] = [-30.0, -29.9999, -30.0001, -29.9998, -30.0002, -29.99995, -30.00005, -29.99985] + cat['PSS'] = [1.0] * 8 + cat['Plx'] = [1.0] * 8 + cat['PM'] = [1.0] * 8 + monkeypatch.setattr(solve_wcs, 'get_gaia_catalog', lambda *args, **kwargs: cat) + monkeypatch.setattr(solve_wcs.photometry, 'run_sextractor', lambda *args, **kwargs: None) + + tel = instrument_getter('GMOS') + ok = solve_wcs.align_to_gaia(file_path, tel, log=None) + assert ok is True + with fits.open(file_path) as out: + assert out[0].header['RADISP'] == 1.0 + assert out[0].header['DEDISP'] == 1.0 + assert 'GAIAFAIL' in out[0].header From 522095103bbaac3b52aa5506534538df768e31ea Mon Sep 17 00:00:00 2001 From: charliekilpatrick Date: Thu, 19 Mar 2026 13:16:59 -0500 Subject: [PATCH 8/8] Enhance WCS alignment process with improved fallback handling - Added functionality to the align_to_gaia function to handle scenarios where the Gaia catalog is unavailable or SExtractor returns no sources. - Introduced logging and fallback header writing in the solve_wcs module for better documentation of fallback reasons. - Enhanced validation checks for refined WCS, including pixel scale and anisotropy, to improve robustness. --- potpyri/_version.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/potpyri/_version.py b/potpyri/_version.py index 1c52449d..1559b5ad 100644 --- a/potpyri/_version.py +++ b/potpyri/_version.py @@ -28,7 +28,7 @@ commit_id: COMMIT_ID __commit_id__: COMMIT_ID -__version__ = version = '1.0.15.dev10' -__version_tuple__ = version_tuple = (1, 0, 15, 'dev10') +__version__ = version = '1.0.17.dev6' +__version_tuple__ = version_tuple = (1, 0, 17, 'dev6') -__commit_id__ = commit_id = 'g590b43389' +__commit_id__ = commit_id = 'gac532c0e6'