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.
- pyreduce/__init__.py +67 -0
- pyreduce/__main__.py +322 -0
- pyreduce/cli.py +342 -0
- pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp311-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp312-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp313-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp313-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp314-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_2d.cp314-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_2d.obj +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp311-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp312-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp313-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp313-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp314-win_amd64.exp +0 -0
- pyreduce/clib/Release/_slitfunc_bd.cp314-win_amd64.lib +0 -0
- pyreduce/clib/Release/_slitfunc_bd.obj +0 -0
- pyreduce/clib/__init__.py +0 -0
- pyreduce/clib/_slitfunc_2d.cp311-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_2d.cp312-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_2d.cp313-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_2d.cp314-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_bd.cp311-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_bd.cp312-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_bd.cp313-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_bd.cp314-win_amd64.pyd +0 -0
- pyreduce/clib/build_extract.py +75 -0
- pyreduce/clib/slit_func_2d_xi_zeta_bd.c +1313 -0
- pyreduce/clib/slit_func_2d_xi_zeta_bd.h +55 -0
- pyreduce/clib/slit_func_bd.c +362 -0
- pyreduce/clib/slit_func_bd.h +17 -0
- pyreduce/clipnflip.py +147 -0
- pyreduce/combine_frames.py +861 -0
- pyreduce/configuration.py +191 -0
- pyreduce/continuum_normalization.py +329 -0
- pyreduce/cwrappers.py +404 -0
- pyreduce/datasets.py +238 -0
- pyreduce/echelle.py +413 -0
- pyreduce/estimate_background_scatter.py +130 -0
- pyreduce/extract.py +1362 -0
- pyreduce/extraction_width.py +77 -0
- pyreduce/instruments/__init__.py +0 -0
- pyreduce/instruments/aj.py +9 -0
- pyreduce/instruments/aj.yaml +51 -0
- pyreduce/instruments/andes.py +102 -0
- pyreduce/instruments/andes.yaml +72 -0
- pyreduce/instruments/common.py +711 -0
- pyreduce/instruments/common.yaml +57 -0
- pyreduce/instruments/crires_plus.py +103 -0
- pyreduce/instruments/crires_plus.yaml +101 -0
- pyreduce/instruments/filters.py +195 -0
- pyreduce/instruments/harpn.py +203 -0
- pyreduce/instruments/harpn.yaml +140 -0
- pyreduce/instruments/harps.py +312 -0
- pyreduce/instruments/harps.yaml +144 -0
- pyreduce/instruments/instrument_info.py +140 -0
- pyreduce/instruments/jwst_miri.py +29 -0
- pyreduce/instruments/jwst_miri.yaml +53 -0
- pyreduce/instruments/jwst_niriss.py +98 -0
- pyreduce/instruments/jwst_niriss.yaml +60 -0
- pyreduce/instruments/lick_apf.py +35 -0
- pyreduce/instruments/lick_apf.yaml +60 -0
- pyreduce/instruments/mcdonald.py +123 -0
- pyreduce/instruments/mcdonald.yaml +56 -0
- pyreduce/instruments/metis_ifu.py +45 -0
- pyreduce/instruments/metis_ifu.yaml +62 -0
- pyreduce/instruments/metis_lss.py +45 -0
- pyreduce/instruments/metis_lss.yaml +62 -0
- pyreduce/instruments/micado.py +45 -0
- pyreduce/instruments/micado.yaml +62 -0
- pyreduce/instruments/models.py +257 -0
- pyreduce/instruments/neid.py +156 -0
- pyreduce/instruments/neid.yaml +61 -0
- pyreduce/instruments/nirspec.py +215 -0
- pyreduce/instruments/nirspec.yaml +63 -0
- pyreduce/instruments/nte.py +42 -0
- pyreduce/instruments/nte.yaml +55 -0
- pyreduce/instruments/uves.py +46 -0
- pyreduce/instruments/uves.yaml +65 -0
- pyreduce/instruments/xshooter.py +39 -0
- pyreduce/instruments/xshooter.yaml +63 -0
- pyreduce/make_shear.py +607 -0
- pyreduce/masks/mask_crires_plus_det1.fits.gz +0 -0
- pyreduce/masks/mask_crires_plus_det2.fits.gz +0 -0
- pyreduce/masks/mask_crires_plus_det3.fits.gz +0 -0
- pyreduce/masks/mask_ctio_chiron.fits.gz +0 -0
- pyreduce/masks/mask_elodie.fits.gz +0 -0
- pyreduce/masks/mask_feros3.fits.gz +0 -0
- pyreduce/masks/mask_flames_giraffe.fits.gz +0 -0
- pyreduce/masks/mask_harps_blue.fits.gz +0 -0
- pyreduce/masks/mask_harps_red.fits.gz +0 -0
- pyreduce/masks/mask_hds_blue.fits.gz +0 -0
- pyreduce/masks/mask_hds_red.fits.gz +0 -0
- pyreduce/masks/mask_het_hrs_2x5.fits.gz +0 -0
- pyreduce/masks/mask_jwst_miri_lrs_slitless.fits.gz +0 -0
- pyreduce/masks/mask_jwst_niriss_gr700xd.fits.gz +0 -0
- pyreduce/masks/mask_lick_apf_.fits.gz +0 -0
- pyreduce/masks/mask_mcdonald.fits.gz +0 -0
- pyreduce/masks/mask_nes.fits.gz +0 -0
- pyreduce/masks/mask_nirspec_nirspec.fits.gz +0 -0
- pyreduce/masks/mask_sarg.fits.gz +0 -0
- pyreduce/masks/mask_sarg_2x2a.fits.gz +0 -0
- pyreduce/masks/mask_sarg_2x2b.fits.gz +0 -0
- pyreduce/masks/mask_subaru_hds_red.fits.gz +0 -0
- pyreduce/masks/mask_uves_blue.fits.gz +0 -0
- pyreduce/masks/mask_uves_blue_binned_2_2.fits.gz +0 -0
- pyreduce/masks/mask_uves_middle.fits.gz +0 -0
- pyreduce/masks/mask_uves_middle_2x2_split.fits.gz +0 -0
- pyreduce/masks/mask_uves_middle_binned_2_2.fits.gz +0 -0
- pyreduce/masks/mask_uves_red.fits.gz +0 -0
- pyreduce/masks/mask_uves_red_2x2.fits.gz +0 -0
- pyreduce/masks/mask_uves_red_2x2_split.fits.gz +0 -0
- pyreduce/masks/mask_uves_red_binned_2_2.fits.gz +0 -0
- pyreduce/masks/mask_xshooter_nir.fits.gz +0 -0
- pyreduce/pipeline.py +619 -0
- pyreduce/rectify.py +138 -0
- pyreduce/reduce.py +2065 -0
- pyreduce/settings/settings_AJ.json +19 -0
- pyreduce/settings/settings_ANDES.json +89 -0
- pyreduce/settings/settings_CRIRES_PLUS.json +89 -0
- pyreduce/settings/settings_HARPN.json +73 -0
- pyreduce/settings/settings_HARPS.json +69 -0
- pyreduce/settings/settings_JWST_MIRI.json +55 -0
- pyreduce/settings/settings_JWST_NIRISS.json +55 -0
- pyreduce/settings/settings_LICK_APF.json +62 -0
- pyreduce/settings/settings_MCDONALD.json +58 -0
- pyreduce/settings/settings_METIS_IFU.json +77 -0
- pyreduce/settings/settings_METIS_LSS.json +77 -0
- pyreduce/settings/settings_MICADO.json +78 -0
- pyreduce/settings/settings_NEID.json +73 -0
- pyreduce/settings/settings_NIRSPEC.json +58 -0
- pyreduce/settings/settings_NTE.json +60 -0
- pyreduce/settings/settings_UVES.json +54 -0
- pyreduce/settings/settings_XSHOOTER.json +78 -0
- pyreduce/settings/settings_pyreduce.json +184 -0
- pyreduce/settings/settings_schema.json +850 -0
- pyreduce/tools/__init__.py +0 -0
- pyreduce/tools/combine.py +117 -0
- pyreduce/trace.py +979 -0
- pyreduce/util.py +1366 -0
- pyreduce/wavecal/MICADO_HK_3arcsec_chip5.npz +0 -0
- pyreduce/wavecal/atlas/thar.fits +4946 -13
- pyreduce/wavecal/atlas/thar_list.txt +4172 -0
- pyreduce/wavecal/atlas/une.fits +0 -0
- pyreduce/wavecal/convert.py +38 -0
- pyreduce/wavecal/crires_plus_J1228_Open_det1.npz +0 -0
- pyreduce/wavecal/crires_plus_J1228_Open_det2.npz +0 -0
- pyreduce/wavecal/crires_plus_J1228_Open_det3.npz +0 -0
- pyreduce/wavecal/harpn_harpn_2D.npz +0 -0
- pyreduce/wavecal/harps_blue_2D.npz +0 -0
- pyreduce/wavecal/harps_blue_pol_2D.npz +0 -0
- pyreduce/wavecal/harps_red_2D.npz +0 -0
- pyreduce/wavecal/harps_red_pol_2D.npz +0 -0
- pyreduce/wavecal/mcdonald.npz +0 -0
- pyreduce/wavecal/metis_lss_l_2D.npz +0 -0
- pyreduce/wavecal/metis_lss_m_2D.npz +0 -0
- pyreduce/wavecal/nirspec_K2.npz +0 -0
- pyreduce/wavecal/uves_blue_360nm_2D.npz +0 -0
- pyreduce/wavecal/uves_blue_390nm_2D.npz +0 -0
- pyreduce/wavecal/uves_blue_437nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_2x2_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_565nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_580nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_600nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_665nm_2D.npz +0 -0
- pyreduce/wavecal/uves_middle_860nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_580nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_600nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_665nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_760nm_2D.npz +0 -0
- pyreduce/wavecal/uves_red_860nm_2D.npz +0 -0
- pyreduce/wavecal/xshooter_nir.npz +0 -0
- pyreduce/wavelength_calibration.py +1871 -0
- pyreduce_astro-0.7a4.dist-info/METADATA +106 -0
- pyreduce_astro-0.7a4.dist-info/RECORD +182 -0
- pyreduce_astro-0.7a4.dist-info/WHEEL +4 -0
- pyreduce_astro-0.7a4.dist-info/entry_points.txt +2 -0
- 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
|