Coverage for src/ufig/plugins/write_image.py: 100%
48 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-12 19:08 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-12 19:08 +0000
1# Copyright (c) 2013 ETH Zurich, Institute of Astronomy, Lukas Gamper
2# <lukas.gamper@usystems.ch>
4"""
5Created on Oct 7, 2013
6@author: Lukas Gamper
7"""
9import contextlib
11from astropy.io import fits
12from ivy.plugin.base_plugin import BasePlugin
15def header_keys(ctx):
16 """
17 Initializes and fills a FITS header with all relevant keywords.
19 :param par: Parameters in the context
20 :return: List with tuples containing header entries
21 """
23 # Note: CRPIX1 and CRPIX2 are in the convention where the bottom left corner is
24 # (0.5, 0.5) instead of (0, 0), how it is throughout UFig. Therefore, although the
25 # FITS convention is used for the origin pixel (e.g. in wcs_pix2world), i.e. that
26 # the first pixel center is (1, 1), the reference pixel is shifted by (-0.5, -0.5),
27 # to account for this.
29 par = ctx.parameters
31 keys = [
32 ("RADECSYS", "ICRS", "Astrometric system"),
33 ("CTYPE1", "RA---TAN", "CS projection type for this axis"),
34 ("CUNIT1", "deg", "Axis unit"),
35 ("CRVAL1", par.ra0, "World coordinate on this axis"),
36 ]
38 try:
39 keys += [("CRPIX1", par.crpix_ra, "Reference pixel on this axis")]
41 except AttributeError:
42 par.crpix_ra = par.size_x / 2.0 + 0.5
43 keys += [("CRPIX1", par.crpix_ra, "Reference pixel on this axis")]
45 keys += [
46 ("CD1_1", -1 * par.pixscale / 60 / 60, "Linear projection matrix"),
47 ("CD1_2", 0.00, "Linear projection matrix"),
48 ("CTYPE2", "DEC--TAN", "WCS projection type for this axis"),
49 ("CUNIT2", "deg", "Axis unit"),
50 ("CRVAL2", par.dec0, "World coordinate on this axis"),
51 ]
53 try:
54 keys += [("CRPIX2", par.crpix_dec, "Reference pixel on this axis")]
56 except AttributeError:
57 par.crpix_dec = par.size_y / 2.0 + 0.5
58 keys += [("CRPIX2", par.crpix_dec, "Reference pixel on this axis")]
60 keys += [
61 ("CD2_1", 0.00, "Linear projection matrix"),
62 ("CD2_2", par.pixscale / 60 / 60, "Linear projection matrix"),
63 (
64 "EXPTIME",
65 par.n_exp * par.exposure_time,
66 "Maximum equivalent exposure time (s)",
67 ),
68 ("GAIN", par.gain * par.n_exp, "Maximum equivalent gain (e-/ADU)"),
69 ("SATURATE", par.saturation_level, "Saturation Level (ADU)"),
70 ("SEXMGZPT", par.magzero, "Mag ZP"),
71 ("PSF_FWHM", get_seeing_value(ctx), "Seeing in pixels"),
72 ("SEED", par.seed, "General seed"),
73 ("GDSEEDO", par.gal_dist_seed_offset, "Galaxy distribution seed offset"),
74 (
75 "GSSEEDO",
76 par.gal_sersic_seed_offset,
77 "Sersic indices of gals dist seed offset",
78 ),
79 (
80 "GESEEDO",
81 par.gal_ellipticities_seed_offset,
82 "Ellipticities of gals dist seed offset",
83 ),
84 (
85 "GNPSEEDO",
86 par.gal_nphot_seed_offset,
87 "Number of photons of gals seed offset",
88 ),
89 ("SDSEEDO", par.star_dist_seed_offset, "Star distribution seed offset"),
90 (
91 "SNPSEEDO",
92 par.star_nphot_seed_offset,
93 "Number of photons of stars seed offset",
94 ),
95 ("GRSEEDO", par.gal_render_seed_offset, "Gal rendering seed offset"),
96 ("SRSEEDO", par.star_render_seed_offset, "Star rendering seed offset"),
97 ("BKGSEEDO", par.background_seed_offset, "Background seed offset"),
98 ]
100 with contextlib.suppress(AttributeError):
101 keys += [
102 (
103 "RESAMPT1",
104 "LANCZOS" + str(par.lanczos_n),
105 "RESAMPLING_TYPE config parameter",
106 ),
107 (
108 "RESAMPT2",
109 "LANCZOS" + str(par.lanczos_n),
110 "RESAMPLING_TYPE config parameter",
111 ),
112 ]
114 return keys
117def get_seeing_value(ctx):
118 """
119 Returns the seeing value of the simulated image.
121 :param ctx: Context
122 :return: Seeing in pixels
123 """
125 try:
126 seeing = ctx.average_seeing
127 except AttributeError:
128 try:
129 seeing = ctx.parameters.seeing / ctx.parameters.pixscale
130 except AttributeError:
131 seeing = 0.001 # Small value for SExtractor to not crash
133 return seeing
136def write_image(path, image, keys, overwrite):
137 """
138 Writes the image to disk
139 :param path: The path to write to (string)
140 :param image: the 2d array image
141 :param keys: list of header keys
142 :param overwrite: whether to overwrite existing files
143 """
145 header = fits.header.Header()
146 header["EQUINOX"] = (2000.00000000, "Mean equinox")
147 header["MJD-OBS"] = (
148 5.625609513605e04,
149 "Modified Julian date at start (Arbitrary Value)",
150 )
151 header["AUTHOR"] = ("ETHZ ", "Cosmology Research Group, ETH Zurich")
152 header["CENTERT1"] = ("MANUAL ", "CENTER_TYPE config parameter")
153 header["PSCALET1"] = ("MANUAL ", "PIXELSCALE_TYPE config parameter")
154 header["CENTERT2"] = ("MANUAL ", "CENTER_TYPE config parameter")
155 header["PSCALET2"] = ("MANUAL ", "PIXELSCALE_TYPE config parameter")
156 header.extend(keys)
158 fits.writeto(path, data=image, header=header, overwrite=overwrite)
161class Plugin(BasePlugin):
162 """
163 Write a general ufig image into a FITS file with minimum basic header information.
164 """
166 def __call__(self):
167 par = self.ctx.parameters
169 write_image(
170 par.image_name, self.ctx.image, header_keys(self.ctx), par.overwrite
171 )
173 del self.ctx.image
175 def __str__(self):
176 return "write image to fits"