pyreduce-astro 0.7a4__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. pyreduce/__init__.py +67 -0
  2. pyreduce/__main__.py +322 -0
  3. pyreduce/cli.py +342 -0
  4. pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.exp +0 -0
  5. pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.lib +0 -0
  6. pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.exp +0 -0
  7. pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.lib +0 -0
  8. pyreduce/clib/Release/_slitfunc_2d.cp313-win_amd64.exp +0 -0
  9. pyreduce/clib/Release/_slitfunc_2d.cp313-win_amd64.lib +0 -0
  10. pyreduce/clib/Release/_slitfunc_2d.cp314-win_amd64.exp +0 -0
  11. pyreduce/clib/Release/_slitfunc_2d.cp314-win_amd64.lib +0 -0
  12. pyreduce/clib/Release/_slitfunc_2d.obj +0 -0
  13. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.exp +0 -0
  14. pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.lib +0 -0
  15. pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.exp +0 -0
  16. pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.lib +0 -0
  17. pyreduce/clib/Release/_slitfunc_bd.cp313-win_amd64.exp +0 -0
  18. pyreduce/clib/Release/_slitfunc_bd.cp313-win_amd64.lib +0 -0
  19. pyreduce/clib/Release/_slitfunc_bd.cp314-win_amd64.exp +0 -0
  20. pyreduce/clib/Release/_slitfunc_bd.cp314-win_amd64.lib +0 -0
  21. pyreduce/clib/Release/_slitfunc_bd.obj +0 -0
  22. pyreduce/clib/__init__.py +0 -0
  23. pyreduce/clib/_slitfunc_2d.cp311-win_amd64.pyd +0 -0
  24. pyreduce/clib/_slitfunc_2d.cp312-win_amd64.pyd +0 -0
  25. pyreduce/clib/_slitfunc_2d.cp313-win_amd64.pyd +0 -0
  26. pyreduce/clib/_slitfunc_2d.cp314-win_amd64.pyd +0 -0
  27. pyreduce/clib/_slitfunc_bd.cp311-win_amd64.pyd +0 -0
  28. pyreduce/clib/_slitfunc_bd.cp312-win_amd64.pyd +0 -0
  29. pyreduce/clib/_slitfunc_bd.cp313-win_amd64.pyd +0 -0
  30. pyreduce/clib/_slitfunc_bd.cp314-win_amd64.pyd +0 -0
  31. pyreduce/clib/build_extract.py +75 -0
  32. pyreduce/clib/slit_func_2d_xi_zeta_bd.c +1313 -0
  33. pyreduce/clib/slit_func_2d_xi_zeta_bd.h +55 -0
  34. pyreduce/clib/slit_func_bd.c +362 -0
  35. pyreduce/clib/slit_func_bd.h +17 -0
  36. pyreduce/clipnflip.py +147 -0
  37. pyreduce/combine_frames.py +861 -0
  38. pyreduce/configuration.py +191 -0
  39. pyreduce/continuum_normalization.py +329 -0
  40. pyreduce/cwrappers.py +404 -0
  41. pyreduce/datasets.py +238 -0
  42. pyreduce/echelle.py +413 -0
  43. pyreduce/estimate_background_scatter.py +130 -0
  44. pyreduce/extract.py +1362 -0
  45. pyreduce/extraction_width.py +77 -0
  46. pyreduce/instruments/__init__.py +0 -0
  47. pyreduce/instruments/aj.py +9 -0
  48. pyreduce/instruments/aj.yaml +51 -0
  49. pyreduce/instruments/andes.py +102 -0
  50. pyreduce/instruments/andes.yaml +72 -0
  51. pyreduce/instruments/common.py +711 -0
  52. pyreduce/instruments/common.yaml +57 -0
  53. pyreduce/instruments/crires_plus.py +103 -0
  54. pyreduce/instruments/crires_plus.yaml +101 -0
  55. pyreduce/instruments/filters.py +195 -0
  56. pyreduce/instruments/harpn.py +203 -0
  57. pyreduce/instruments/harpn.yaml +140 -0
  58. pyreduce/instruments/harps.py +312 -0
  59. pyreduce/instruments/harps.yaml +144 -0
  60. pyreduce/instruments/instrument_info.py +140 -0
  61. pyreduce/instruments/jwst_miri.py +29 -0
  62. pyreduce/instruments/jwst_miri.yaml +53 -0
  63. pyreduce/instruments/jwst_niriss.py +98 -0
  64. pyreduce/instruments/jwst_niriss.yaml +60 -0
  65. pyreduce/instruments/lick_apf.py +35 -0
  66. pyreduce/instruments/lick_apf.yaml +60 -0
  67. pyreduce/instruments/mcdonald.py +123 -0
  68. pyreduce/instruments/mcdonald.yaml +56 -0
  69. pyreduce/instruments/metis_ifu.py +45 -0
  70. pyreduce/instruments/metis_ifu.yaml +62 -0
  71. pyreduce/instruments/metis_lss.py +45 -0
  72. pyreduce/instruments/metis_lss.yaml +62 -0
  73. pyreduce/instruments/micado.py +45 -0
  74. pyreduce/instruments/micado.yaml +62 -0
  75. pyreduce/instruments/models.py +257 -0
  76. pyreduce/instruments/neid.py +156 -0
  77. pyreduce/instruments/neid.yaml +61 -0
  78. pyreduce/instruments/nirspec.py +215 -0
  79. pyreduce/instruments/nirspec.yaml +63 -0
  80. pyreduce/instruments/nte.py +42 -0
  81. pyreduce/instruments/nte.yaml +55 -0
  82. pyreduce/instruments/uves.py +46 -0
  83. pyreduce/instruments/uves.yaml +65 -0
  84. pyreduce/instruments/xshooter.py +39 -0
  85. pyreduce/instruments/xshooter.yaml +63 -0
  86. pyreduce/make_shear.py +607 -0
  87. pyreduce/masks/mask_crires_plus_det1.fits.gz +0 -0
  88. pyreduce/masks/mask_crires_plus_det2.fits.gz +0 -0
  89. pyreduce/masks/mask_crires_plus_det3.fits.gz +0 -0
  90. pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
  91. pyreduce/masks/mask_elodie.fits.gz +0 -0
  92. pyreduce/masks/mask_feros3.fits.gz +0 -0
  93. pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
  94. pyreduce/masks/mask_harps_blue.fits.gz +0 -0
  95. pyreduce/masks/mask_harps_red.fits.gz +0 -0
  96. pyreduce/masks/mask_hds_blue.fits.gz +0 -0
  97. pyreduce/masks/mask_hds_red.fits.gz +0 -0
  98. pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
  99. pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz +0 -0
  100. pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz +0 -0
  101. pyreduce/masks/mask_lick_apf_.fits.gz +0 -0
  102. pyreduce/masks/mask_mcdonald.fits.gz +0 -0
  103. pyreduce/masks/mask_nes.fits.gz +0 -0
  104. pyreduce/masks/mask_nirspec_nirspec.fits.gz +0 -0
  105. pyreduce/masks/mask_sarg.fits.gz +0 -0
  106. pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
  107. pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
  108. pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
  109. pyreduce/masks/mask_uves_blue.fits.gz +0 -0
  110. pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz +0 -0
  111. pyreduce/masks/mask_uves_middle.fits.gz +0 -0
  112. pyreduce/masks/mask_uves_middle_2x2_split.fits.gz +0 -0
  113. pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz +0 -0
  114. pyreduce/masks/mask_uves_red.fits.gz +0 -0
  115. pyreduce/masks/mask_uves_red_2x2.fits.gz +0 -0
  116. pyreduce/masks/mask_uves_red_2x2_split.fits.gz +0 -0
  117. pyreduce/masks/mask_uves_red_binned_2_2.fits.gz +0 -0
  118. pyreduce/masks/mask_xshooter_nir.fits.gz +0 -0
  119. pyreduce/pipeline.py +619 -0
  120. pyreduce/rectify.py +138 -0
  121. pyreduce/reduce.py +2065 -0
  122. pyreduce/settings/settings_AJ.json +19 -0
  123. pyreduce/settings/settings_ANDES.json +89 -0
  124. pyreduce/settings/settings_CRIRES_PLUS.json +89 -0
  125. pyreduce/settings/settings_HARPN.json +73 -0
  126. pyreduce/settings/settings_HARPS.json +69 -0
  127. pyreduce/settings/settings_JWST_MIRI.json +55 -0
  128. pyreduce/settings/settings_JWST_NIRISS.json +55 -0
  129. pyreduce/settings/settings_LICK_APF.json +62 -0
  130. pyreduce/settings/settings_MCDONALD.json +58 -0
  131. pyreduce/settings/settings_METIS_IFU.json +77 -0
  132. pyreduce/settings/settings_METIS_LSS.json +77 -0
  133. pyreduce/settings/settings_MICADO.json +78 -0
  134. pyreduce/settings/settings_NEID.json +73 -0
  135. pyreduce/settings/settings_NIRSPEC.json +58 -0
  136. pyreduce/settings/settings_NTE.json +60 -0
  137. pyreduce/settings/settings_UVES.json +54 -0
  138. pyreduce/settings/settings_XSHOOTER.json +78 -0
  139. pyreduce/settings/settings_pyreduce.json +184 -0
  140. pyreduce/settings/settings_schema.json +850 -0
  141. pyreduce/tools/__init__.py +0 -0
  142. pyreduce/tools/combine.py +117 -0
  143. pyreduce/trace.py +979 -0
  144. pyreduce/util.py +1366 -0
  145. pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz +0 -0
  146. pyreduce/wavecal/atlas/thar.fits +4946 -13
  147. pyreduce/wavecal/atlas/thar_list.txt +4172 -0
  148. pyreduce/wavecal/atlas/une.fits +0 -0
  149. pyreduce/wavecal/convert.py +38 -0
  150. pyreduce/wavecal/crires_plus_J1228_Open_det1.npz +0 -0
  151. pyreduce/wavecal/crires_plus_J1228_Open_det2.npz +0 -0
  152. pyreduce/wavecal/crires_plus_J1228_Open_det3.npz +0 -0
  153. pyreduce/wavecal/harpn_harpn_2D.npz +0 -0
  154. pyreduce/wavecal/harps_blue_2D.npz +0 -0
  155. pyreduce/wavecal/harps_blue_pol_2D.npz +0 -0
  156. pyreduce/wavecal/harps_red_2D.npz +0 -0
  157. pyreduce/wavecal/harps_red_pol_2D.npz +0 -0
  158. pyreduce/wavecal/mcdonald.npz +0 -0
  159. pyreduce/wavecal/metis_lss_l_2D.npz +0 -0
  160. pyreduce/wavecal/metis_lss_m_2D.npz +0 -0
  161. pyreduce/wavecal/nirspec_K2.npz +0 -0
  162. pyreduce/wavecal/uves_blue_360nm_2D.npz +0 -0
  163. pyreduce/wavecal/uves_blue_390nm_2D.npz +0 -0
  164. pyreduce/wavecal/uves_blue_437nm_2D.npz +0 -0
  165. pyreduce/wavecal/uves_middle_2x2_2D.npz +0 -0
  166. pyreduce/wavecal/uves_middle_565nm_2D.npz +0 -0
  167. pyreduce/wavecal/uves_middle_580nm_2D.npz +0 -0
  168. pyreduce/wavecal/uves_middle_600nm_2D.npz +0 -0
  169. pyreduce/wavecal/uves_middle_665nm_2D.npz +0 -0
  170. pyreduce/wavecal/uves_middle_860nm_2D.npz +0 -0
  171. pyreduce/wavecal/uves_red_580nm_2D.npz +0 -0
  172. pyreduce/wavecal/uves_red_600nm_2D.npz +0 -0
  173. pyreduce/wavecal/uves_red_665nm_2D.npz +0 -0
  174. pyreduce/wavecal/uves_red_760nm_2D.npz +0 -0
  175. pyreduce/wavecal/uves_red_860nm_2D.npz +0 -0
  176. pyreduce/wavecal/xshooter_nir.npz +0 -0
  177. pyreduce/wavelength_calibration.py +1871 -0
  178. pyreduce_astro-0.7a4.dist-info/METADATA +106 -0
  179. pyreduce_astro-0.7a4.dist-info/RECORD +182 -0
  180. pyreduce_astro-0.7a4.dist-info/WHEEL +4 -0
  181. pyreduce_astro-0.7a4.dist-info/entry_points.txt +2 -0
  182. pyreduce_astro-0.7a4.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,55 @@
1
+ typedef struct
2
+ {
3
+ int x;
4
+ int y; /* Coordinates of target pixel x,y */
5
+ double w; /* Contribution weight <= 1/osample */
6
+ } xi_ref;
7
+
8
+ typedef struct
9
+ {
10
+ int x;
11
+ int iy; /* Contributing subpixel x,iy */
12
+ double w; /* Contribution weight <= 1/osample */
13
+ } zeta_ref;
14
+
15
+ int slit_func_curved(int ncols,
16
+ int nrows,
17
+ int ny,
18
+ double *im,
19
+ double *pix_unc,
20
+ unsigned char *mask,
21
+ double *ycen,
22
+ int *ycen_offset,
23
+ int y_lower_lim,
24
+ int osample,
25
+ double lambda_sP,
26
+ double lambda_sL,
27
+ int maxiter,
28
+ double *PSF_curve,
29
+ double *sP,
30
+ double *sL,
31
+ double *model,
32
+ double *unc,
33
+ double *info);
34
+
35
+ int xi_zeta_tensors(
36
+ int ncols,
37
+ int nrows,
38
+ int ny,
39
+ double *ycen,
40
+ int *ycen_offset,
41
+ int y_lower_lim,
42
+ int osample,
43
+ double *PSF_curve,
44
+ xi_ref *xi,
45
+ zeta_ref *zeta,
46
+ int *m_zeta);
47
+
48
+ int create_spectral_model(
49
+ int ncols,
50
+ int nrows,
51
+ int osample,
52
+ xi_ref* xi,
53
+ double* spec,
54
+ double* slitfunc,
55
+ double* img);
@@ -0,0 +1,362 @@
1
+ #include <stdio.h>
2
+ #include <string.h>
3
+ #include <stdlib.h>
4
+ #include <math.h>
5
+
6
+ #define min(a, b) (((a) < (b)) ? (a) : (b))
7
+ #define max(a, b) (((a) > (b)) ? (a) : (b))
8
+
9
+ #define omega_index(x, y, z) z + (y * ny) + (x * ny * nrows)
10
+ /*----------------------------------------------------------------------------*/
11
+ /**
12
+ @brief Solve a sparse system of linear equations
13
+ @param a 2D array [n,nd]i
14
+ @param r array of RHS of size n
15
+ @param n number of equations
16
+ @param nd width of the band (3 for tri-diagonal system)
17
+ @return 0 on success, -1 on incorrect size of "a" and -4 on
18
+ degenerate matrix
19
+
20
+ Solve a sparse system of linear equations with band-diagonal matrix.
21
+ Band is assumed to be symmetrix relative to the main diaginal.
22
+
23
+ nd must be an odd number. The main diagonal should be in a(*,nd/2)
24
+ The first lower subdiagonal should be in a(1:n-1,nd/2-1), the first
25
+ upper subdiagonal is in a(0:n-2,nd/2+1) etc. For example:
26
+ / 0 0 X X X \
27
+ | 0 X X X X |
28
+ | X X X X X |
29
+ | X X X X X |
30
+ A = | X X X X X |
31
+ | X X X X X |
32
+ | X X X X X |
33
+ | X X X X 0 |
34
+ \ X X X 0 0 /
35
+ */
36
+ /*----------------------------------------------------------------------------*/
37
+ static int bandsol(
38
+ double *a,
39
+ double *r,
40
+ int n,
41
+ int nd)
42
+ {
43
+ double aa;
44
+ int i, j, k;
45
+
46
+ //if(fmod(nd,2)==0) return -1;
47
+
48
+ /* Forward sweep */
49
+ for (i = 0; i < n - 1; i++)
50
+ {
51
+ aa = a[i + n * (nd / 2)];
52
+ //if(aa==0.e0) return -3;
53
+ r[i] /= aa;
54
+ for (j = 0; j < nd; j++)
55
+ a[i + j * n] /= aa;
56
+ for (j = 1; j < min(nd / 2 + 1, n - i); j++)
57
+ {
58
+ aa = a[i + j + n * (nd / 2 - j)];
59
+ //if(aa==0.e0) return -j;
60
+ r[i + j] -= r[i] * aa;
61
+ for (k = 0; k < n * (nd - j); k += n)
62
+ a[i + j + k] -= a[i + k + n * j] * aa;
63
+ }
64
+ }
65
+
66
+ /* Backward sweep */
67
+ r[n - 1] /= a[n - 1 + n * (nd / 2)];
68
+ for (i = n - 1; i > 0; i--)
69
+ {
70
+ for (j = 1; j <= min(nd / 2, i); j++)
71
+ r[i - j] -= r[i] * a[i - j + n * (nd / 2 + j)];
72
+ //if(a[i-1+n*(nd/2)]==0.e0) return -5;
73
+ r[i - 1] /= a[i - 1 + n * (nd / 2)];
74
+ }
75
+
76
+ //if(a[n*(nd/2)]==0.e0) return -6;
77
+ r[0] /= a[n * (nd / 2)];
78
+ return 0;
79
+ }
80
+
81
+ int slit_func_vert(int ncols, /* Swath width in pixels */
82
+ int nrows, /* Extraction slit height in pixels */
83
+ double *im, /* Image to be decomposed */
84
+ double *pix_unc, /* Image Uncertianty to be decomposed */
85
+ int *mask, /* Initial and final mask for the swath */
86
+ double *ycen, /* Order centre line offset from pixel row boundary */
87
+ int osample, /* Subpixel ovsersampling factor */
88
+ double lambda_sP, /* Smoothing parameter for the spectrum, coiuld be zero */
89
+ double lambda_sL, /* Smoothing parameter for the slit function, usually >0 */
90
+ double *sP, /* Spectrum resulting from decomposition */
91
+ double *sL, /* Slit function resulting from decomposition */
92
+ double *model, /* Model constructed from sp and sf */
93
+ double *unc /* Spectrum uncertainties */
94
+ )
95
+ {
96
+ int x, y, iy, jy, iy1, iy2, ny, nd;
97
+ double step, d1, d2, sum, norm, dev, lambda, diag_tot, sP_change, sP_max;
98
+ int info, iter, isum;
99
+ /* Initialise */
100
+ nd = 2 * osample + 1;
101
+ ny = osample * (nrows + 1) + 1; /* The size of the sf array */
102
+ step = 1.e0 / osample;
103
+ double *E = malloc(ncols * sizeof(double)); // double E[ncols];
104
+ double *sP_old = malloc(ncols * sizeof(double)); // double sP_old[ncols];
105
+ double *Aij = malloc(ny * (2 * osample + 1) * sizeof(double)); // double Aij[ny*ny];
106
+ double *bj = malloc(ny * sizeof(double)); // double bj[ny];
107
+ double *Adiag = malloc(ncols * 3 * sizeof(double)); // double Adiag[ncols*3];
108
+ double *omega = malloc(ny * nrows * ncols * sizeof(double)); // double omega[ny][nrows][ncols];
109
+ double *p_bj = malloc(ncols * sizeof(double)); // index as: [iy+(y*ny)+(x*ny*nrows)]
110
+
111
+ for (int k = 0; k < ncols * 3; k++)
112
+ Adiag[k] = 0; // Initialize to zero
113
+
114
+ /*
115
+ Construct the omega tensor. Normally it has the dimensionality of
116
+ ny*nrows*ncols.
117
+ The tensor is mostly empty and can be easily compressed to ny*nx, but
118
+ this will complicate matrix operations at later stages. I will keep
119
+ it as it is for now.
120
+ Note, that omega is used in in the equations for sL, sP and for the model
121
+ but it does not involve the data, only the geometry. Thus it can be
122
+ pre-computed once.
123
+ */
124
+ for (x = 0; x < ncols; x++)
125
+ {
126
+ iy2 = osample - floor(ycen[x] / step) - 1;
127
+ iy1 = iy2 - osample;
128
+
129
+ d1 = fmod(ycen[x], step);
130
+ if (d1 == 0)
131
+ d1 = step;
132
+ d2 = step - d1;
133
+
134
+ for (y = 0; y < nrows; y++)
135
+ {
136
+ iy1 += osample;
137
+ iy2 += osample;
138
+ for (iy = 0; iy < ny; iy++)
139
+ {
140
+ if (iy < iy1)
141
+ omega[omega_index(x, y, iy)] = 0.;
142
+ else if (iy == iy1)
143
+ omega[omega_index(x, y, iy)] = d1;
144
+ else if (iy > iy1 && iy < iy2)
145
+ omega[omega_index(x, y, iy)] = step;
146
+ else if (iy == iy2)
147
+ omega[omega_index(x, y, iy)] = d2;
148
+ else
149
+ omega[omega_index(x, y, iy)] = 0.;
150
+ }
151
+ }
152
+ }
153
+
154
+ /* Loop through sL , sP reconstruction until convergence is reached */
155
+ iter = 0;
156
+ do
157
+ {
158
+ /* Compute slit function sL */
159
+ /* Fill in SLE arrays */
160
+ diag_tot = 0.e0;
161
+ for (iy = 0; iy < ny; iy++)
162
+ {
163
+ bj[iy] = 0.e0;
164
+ for (jy = max(iy - osample, 0); jy <= min(iy + osample, ny - 1); jy++)
165
+ {
166
+ Aij[iy + ny * (jy - iy + osample)] = 0.e0;
167
+ for (x = 0; x < ncols; x++)
168
+ {
169
+ sum = 0.e0;
170
+ for (y = 0; y < nrows; y++)
171
+ sum += omega[omega_index(x, y, iy)] *
172
+ omega[omega_index(x, y, jy)] * mask[y * ncols + x];
173
+ Aij[iy + ny * (jy - iy + osample)] += sum * sP[x] * sP[x];
174
+ }
175
+ }
176
+ for (x = 0; x < ncols; x++)
177
+ {
178
+ sum = 0.e0;
179
+ for (y = 0; y < nrows; y++)
180
+ sum += omega[omega_index(x, y, iy)] *
181
+ mask[y * ncols + x] * im[y * ncols + x];
182
+ bj[iy] += sum * sP[x];
183
+ }
184
+ diag_tot += Aij[iy + ny * osample];
185
+ }
186
+
187
+ /* Scale regularization parameters */
188
+ lambda = lambda_sL * diag_tot / ny;
189
+
190
+ /* Add regularization parts for the slit function */
191
+ Aij[ny * osample] += lambda; /* Main diagonal */
192
+ Aij[ny * (osample + 1)] -= lambda; /* Upper diagonal */
193
+ for (iy = 1; iy < ny - 1; iy++)
194
+ {
195
+ Aij[iy + ny * (osample - 1)] -= lambda; /* Lower diagonal */
196
+ Aij[iy + ny * osample] += lambda * 2.e0; /* Main diagonal */
197
+ Aij[iy + ny * (osample + 1)] -= lambda; /* Upper diagonal */
198
+ }
199
+ Aij[ny - 1 + ny * (osample - 1)] -= lambda; /* Lower diagonal */
200
+ Aij[ny - 1 + ny * osample] += lambda; /* Main diagonal */
201
+
202
+ /* Solve the system of equations */
203
+ info = bandsol(Aij, bj, ny, nd);
204
+ if (info)
205
+ printf("Bandsol exited with %d", info);
206
+
207
+ /* Normalize the slit function */
208
+ norm = 0.e0;
209
+ for (iy = 0; iy < ny; iy++)
210
+ {
211
+ sL[iy] = bj[iy];
212
+ norm += sL[iy];
213
+ }
214
+ norm /= osample;
215
+ for (iy = 0; iy < ny; iy++)
216
+ sL[iy] /= norm;
217
+
218
+ /* Compute spectrum sP */
219
+ for (x = 0; x < ncols; x++)
220
+ {
221
+ Adiag[x + ncols] = 0.e0;
222
+ E[x] = 0.e0;
223
+ for (y = 0; y < nrows; y++)
224
+ {
225
+ sum = 0.e0;
226
+ for (iy = 0; iy < ny; iy++)
227
+ {
228
+ sum += omega[omega_index(x, y, iy)] * sL[iy];
229
+ }
230
+
231
+ Adiag[x + ncols] += sum * sum * mask[y * ncols + x];
232
+ E[x] += sum * im[y * ncols + x] * mask[y * ncols + x];
233
+ }
234
+ }
235
+ if (lambda_sP > 0.e0)
236
+ {
237
+ norm = 0.e0;
238
+ for (x = 0; x < ncols; x++)
239
+ {
240
+ sP_old[x] = sP[x];
241
+ norm += sP[x];
242
+ }
243
+ norm /= ncols;
244
+ lambda = lambda_sP * norm;
245
+ Adiag[0] = 0.e0;
246
+ Adiag[0 + ncols] += lambda;
247
+ Adiag[0 + ncols * 2] -= lambda;
248
+ for (x = 1; x < ncols - 1; x++)
249
+ {
250
+ Adiag[x] = -lambda;
251
+ Adiag[x + ncols] += 2.e0 * lambda;
252
+ Adiag[x + ncols * 2] = -lambda;
253
+ }
254
+ Adiag[ncols - 1] -= lambda;
255
+ Adiag[ncols - 1 + ncols] += lambda;
256
+ Adiag[ncols - 1 + 2 * ncols] = 0.e0;
257
+
258
+ info = bandsol(Adiag, E, ncols, 3);
259
+ for (x = 0; x < ncols; x++)
260
+ sP[x] = E[x];
261
+ }
262
+ else
263
+ {
264
+ for (x = 0; x < ncols; x++)
265
+ {
266
+ sP_old[x] = sP[x];
267
+ sP[x] = E[x] / Adiag[x + ncols];
268
+ }
269
+ }
270
+
271
+ /* Compute the model */
272
+ for (y = 0; y < nrows; y++)
273
+ {
274
+ for (x = 0; x < ncols; x++)
275
+ {
276
+ sum = 0.e0;
277
+ for (iy = 0; iy < ny; iy++)
278
+ sum += omega[omega_index(x, y, iy)] * sL[iy];
279
+ model[y * ncols + x] = sum * sP[x];
280
+ }
281
+ }
282
+
283
+ /* Compare model and data */
284
+ sum = 0.e0;
285
+ isum = 0;
286
+ for (y = 0; y < nrows; y++)
287
+ {
288
+ for (x = 0; x < ncols; x++)
289
+ {
290
+ sum += mask[y * ncols + x] * (model[y * ncols + x] - im[y * ncols + x]) *
291
+ (model[y * ncols + x] - im[y * ncols + x]);
292
+ isum += mask[y * ncols + x];
293
+ }
294
+ }
295
+ dev = sqrt(sum / isum);
296
+
297
+ /* Adjust the mask marking outlyers */
298
+ for (y = 0; y < nrows; y++)
299
+ {
300
+ for (x = 0; x < ncols; x++)
301
+ {
302
+ if (fabs(model[y * ncols + x] - im[y * ncols + x]) > 6. * dev)
303
+ mask[y * ncols + x] = 0;
304
+ else
305
+ mask[y * ncols + x] = 1;
306
+ }
307
+ }
308
+
309
+ /* Compute the change in the spectrum */
310
+ sP_change = 0.e0;
311
+ sP_max = 1.e0;
312
+ for (x = 0; x < ncols; x++)
313
+ {
314
+ if (sP[x] > sP_max)
315
+ sP_max = sP[x];
316
+ if (fabs(sP[x] - sP_old[x]) > sP_change)
317
+ sP_change = fabs(sP[x] - sP_old[x]);
318
+ }
319
+ /* Check the convergence */
320
+ } while (iter++ < 5 && sP_change > 1e-5 * sP_max);
321
+
322
+ /* Uncertainty estimate */
323
+ for (x = 0; x < ncols; x++)
324
+ {
325
+ unc[x] = 0.;
326
+ p_bj[x] = 0.;
327
+ }
328
+ for (x = 0; x < ncols; x++)
329
+ {
330
+ // Loop through all pixels contributing to x
331
+ for (y = 0; y < nrows; y++)
332
+ {
333
+ unc[x] += (im[y * ncols + x] - model[y * ncols + x]) *
334
+ (im[y * ncols + x] - model[y * ncols + x]) *
335
+ sL[y] * mask[y * ncols + x];
336
+ unc[x] += pix_unc[y * ncols + x] * pix_unc[y * ncols + x] *
337
+ sL[y] * mask[y * ncols + x];
338
+ // Norm
339
+ p_bj[x] += sL[y] * mask[y * ncols + x];
340
+ }
341
+ }
342
+ for (x = 0; x < ncols; x++)
343
+ {
344
+ unc[x] = sqrt(unc[x] / p_bj[x] * nrows);
345
+ }
346
+
347
+ if (!(sP[0] == sP[0]))
348
+ {
349
+ printf("SOMETHING WENT WRONG STOP HERE!!!\n");
350
+ // raise(SIGINT);
351
+ }
352
+
353
+ free(E);
354
+ free(sP_old);
355
+ free(omega);
356
+ free(Aij);
357
+ free(bj);
358
+ free(Adiag);
359
+ free(p_bj);
360
+
361
+ return 0;
362
+ }
@@ -0,0 +1,17 @@
1
+
2
+ //int locate_clusters(int argc, void *argv[]);
3
+
4
+ int slit_func_vert(int ncols, /* Swath width in pixels */
5
+ int nrows, /* Extraction slit height in pixels */
6
+ double *im, /* Image to be decomposed */
7
+ double *pix_unc, /* Image Uncertianty to be decomposed */
8
+ int *mask, /* Initial and final mask for the swath */
9
+ double *ycen, /* Order centre line offset from pixel row boundary */
10
+ int osample, /* Subpixel ovsersampling factor */
11
+ double lambda_sP, /* Smoothing parameter for the spectrum, coiuld be zero */
12
+ double lambda_sL, /* Smoothing parameter for the slit function, usually >0 */
13
+ double *sP, /* Spectrum resulting from decomposition */
14
+ double *sL, /* Slit function resulting from decomposition */
15
+ double *model, /* Model constructed from sp and sf */
16
+ double *unc /* Spectrum uncertainties */
17
+ );
pyreduce/clipnflip.py ADDED
@@ -0,0 +1,147 @@
1
+ """
2
+ Module that
3
+ - Clips remove pre- and overscan regions
4
+ - Flips orients the image so that orders are roughly horizontal
5
+ """
6
+
7
+ import logging
8
+
9
+ import numpy as np
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def clipnflip(
15
+ image, header, xrange=None, yrange=None, orientation=None, transpose=None
16
+ ):
17
+ """
18
+ Process an image and associated FITS header already in memory as follows:
19
+ 1. Trim image to desired subregion: newimage = image(xlo:xhi,ylo:yhi)
20
+ 2. Transform to standard orientation (red at top, orders run left to right)
21
+
22
+ Parameters
23
+ -----------
24
+ image : array[nrow, ncol]
25
+ raw image to be processed.
26
+ header : fits.header, dict
27
+ FITS header of the image
28
+ xrange : tuple(int, int), optional
29
+ column - range to keep in the image (default: data from header/instrument)
30
+ yrange : tuple(int, int), optional
31
+ row - range to keep in the image (default: data from header/instrument)
32
+ orientation : int, optional
33
+ number of counterclockwise 90 degrees rotation to apply to the image (default: data from header/instrument)
34
+ transpose : bool, optional
35
+ if True the image will be transposed before rotation (default: data from header/instrument)
36
+
37
+ Returns
38
+ -------
39
+ image : array[yrange, xrange]
40
+ clipped and flipped image
41
+
42
+ Raises
43
+ -------
44
+ NotImplementedError
45
+ nonlinear images are not supported yet
46
+ """
47
+
48
+ # This part depends on how many amplifiers were used for the readout
49
+ n_amp = header.get("e_ampl", 1)
50
+ image = np.asarray(image)
51
+
52
+ if n_amp > 1: # pragma: no cover
53
+ raise NotImplementedError
54
+ xlo = np.array(header["e_xlo*"].values())
55
+ xhi = np.array(header["e_xhi*"].values())
56
+ ylo = np.array(header["e_ylo*"].values())
57
+ yhi = np.array(header["e_yhi*"].values())
58
+
59
+ # Make sure trim region is a subset of actual image.
60
+ sz = image.shape
61
+ if (
62
+ np.any(xlo < 0)
63
+ | np.any(xlo >= sz[1])
64
+ | np.any(ylo < 0)
65
+ | np.any(ylo >= sz[0])
66
+ | np.any(xhi < 0)
67
+ | np.any(xhi > sz[1])
68
+ | np.any(yhi < 0)
69
+ | np.any(yhi > sz[0])
70
+ ):
71
+ raise ValueError("Error specifying trim region")
72
+
73
+ linear = header.get("e_linear", False)
74
+ if not linear:
75
+ # TODO
76
+ raise NotImplementedError("only linear for now")
77
+ # pref = header["e_prefmo"]
78
+ # image = call_function("nonlinear_" + pref, image, header)
79
+
80
+ # i = np.where(header["e_linear"] >= 0)
81
+ # if len(i) > 0:
82
+ # header = header[0 : i - 1 + 1] + header[i + 1 :]
83
+ # header["e_linear"] = ("t", "image corrected of non-linearity")
84
+ # ii = np.where(header["e_gain*"] >= 0)
85
+ # if len(ii) > 0:
86
+ # for i in np.arange(0, len(ii) - 1 + 1, 1):
87
+ # k = ii[i]
88
+ # header = [header[0 : k - 1 + 1], header[k + 1 :]]
89
+ # header["e_gain"] = (1, "image was converted to e-")
90
+
91
+ # Trim image to leave only the subimage containing valid image data.
92
+ # For two amplifiers we assume a single vertical or horizontal gap.
93
+ # With four amplifiers we can have a cross.
94
+
95
+ if n_amp == 2:
96
+ # TODO this needs testing
97
+ if xlo[0] == xlo[1]:
98
+ xsize = xhi[0] - xlo[0]
99
+ ysize = yhi[0] - ylo[0] + yhi[1] - ylo[1]
100
+ timage = np.empty((xsize, ysize), dtype=image.dtype)
101
+ ysize = yhi[0] - ylo[0]
102
+ timage[:ysize, :xsize] = image[xlo[0]]
103
+ timage[ysize:, :xsize] = image[xlo[1]]
104
+ elif ylo[0] == ylo[1]:
105
+ xsize = xhi[0] - xlo[0] + xhi[1] - xlo[1]
106
+ ysize = yhi[0] - ylo[0]
107
+ timage = np.empty((xsize, ysize), dtype=image.dtype)
108
+ xsize = xhi[0] - xlo[0]
109
+ timage[:ysize, :xsize] = image[xlo[0]]
110
+ timage[:ysize, xsize:] = image[xlo[1]]
111
+ else:
112
+ raise Exception(
113
+ "The two ccd sections are aligned neither in x nor in y"
114
+ )
115
+ elif n_amp == 4:
116
+ raise NotImplementedError("4-amplifier section is not implemented yet")
117
+ else:
118
+ xlo, xhi = xrange if xrange is not None else (header["e_xlo"], header["e_xhi"])
119
+ ylo, yhi = yrange if yrange is not None else (header["e_ylo"], header["e_yhi"])
120
+
121
+ # Make sure trim region is a subset of actual image.
122
+ sz = image.shape[-2:]
123
+ if not (0 <= xlo < xhi <= sz[1] and 0 <= ylo < yhi <= sz[0]):
124
+ raise IndexError(
125
+ "Image Clipping Indices are not within the image (or in inverse order)"
126
+ )
127
+
128
+ # Trim image to leave only the subimage containing valid image data.
129
+ timage = image[..., ylo:yhi, xlo:xhi] # trimmed image
130
+
131
+ # Flip image (if necessary) to achieve standard image orientation.
132
+ orientation = orientation if orientation is not None else header.get("e_orient", 0)
133
+ # As per the old IDL definition, transpose is true for orientations larger than 4
134
+ transpose = (
135
+ transpose
136
+ if transpose is not None
137
+ else header.get("e_transpose", (orientation % 8) >= 4)
138
+ )
139
+ if transpose:
140
+ timage = np.transpose(timage, axes=(-1, -2))
141
+ timage = np.rot90(timage, -1 * orientation, axes=(-2, -1))
142
+
143
+ # TODO just sum up groups and stuff?
144
+ while timage.ndim > 2:
145
+ timage = np.sum(timage, axis=0)
146
+
147
+ return timage