pyreduce-astro 0.7a5__cp314-cp314-win_amd64.whl → 0.7a7__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/__main__.py +114 -20
- pyreduce/cli.py +1 -1
- pyreduce/clib/Release/_slitfunc_2d.obj +0 -0
- pyreduce/clib/Release/_slitfunc_bd.obj +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.cp313-win_amd64.pyd +0 -0
- pyreduce/clib/_slitfunc_bd.cp314-win_amd64.pyd +0 -0
- pyreduce/combine_frames.py +8 -0
- pyreduce/configuration.py +20 -0
- pyreduce/estimate_background_scatter.py +8 -8
- pyreduce/extract.py +126 -126
- pyreduce/{extraction_width.py → extraction_height.py} +4 -4
- pyreduce/instruments/common.py +201 -15
- pyreduce/instruments/harpn.py +2 -2
- pyreduce/instruments/harps.py +2 -2
- pyreduce/instruments/models.py +24 -0
- pyreduce/instruments/neid.py +49 -77
- pyreduce/instruments/neid.yaml +39 -40
- pyreduce/instruments/nirspec.py +2 -2
- pyreduce/make_shear.py +12 -12
- pyreduce/pipeline.py +6 -6
- pyreduce/rectify.py +10 -10
- pyreduce/reduce.py +14 -14
- pyreduce/settings/settings_AJ.json +2 -2
- pyreduce/settings/settings_ANDES.json +7 -7
- pyreduce/settings/settings_CRIRES_PLUS.json +7 -7
- pyreduce/settings/settings_HARPN.json +7 -7
- pyreduce/settings/settings_HARPS.json +7 -7
- pyreduce/settings/settings_JWST_MIRI.json +7 -7
- pyreduce/settings/settings_JWST_NIRISS.json +7 -7
- pyreduce/settings/settings_LICK_APF.json +7 -7
- pyreduce/settings/settings_MCDONALD.json +7 -7
- pyreduce/settings/settings_METIS_IFU.json +7 -7
- pyreduce/settings/settings_METIS_LSS.json +7 -7
- pyreduce/settings/settings_MICADO.json +7 -7
- pyreduce/settings/settings_NEID.json +15 -24
- pyreduce/settings/settings_NIRSPEC.json +7 -7
- pyreduce/settings/settings_NTE.json +6 -6
- pyreduce/settings/settings_UVES.json +4 -4
- pyreduce/settings/settings_XSHOOTER.json +5 -5
- pyreduce/settings/settings_pyreduce.json +8 -8
- pyreduce/settings/settings_schema.json +10 -10
- {pyreduce_astro-0.7a5.dist-info → pyreduce_astro-0.7a7.dist-info}/METADATA +3 -3
- {pyreduce_astro-0.7a5.dist-info → pyreduce_astro-0.7a7.dist-info}/RECORD +48 -48
- {pyreduce_astro-0.7a5.dist-info → pyreduce_astro-0.7a7.dist-info}/WHEEL +0 -0
- {pyreduce_astro-0.7a5.dist-info → pyreduce_astro-0.7a7.dist-info}/entry_points.txt +0 -0
- {pyreduce_astro-0.7a5.dist-info → pyreduce_astro-0.7a7.dist-info}/licenses/LICENSE +0 -0
pyreduce/__main__.py
CHANGED
|
@@ -4,8 +4,8 @@ PyReduce command-line interface.
|
|
|
4
4
|
Usage:
|
|
5
5
|
uv run reduce --help
|
|
6
6
|
uv run reduce run UVES HD132205 --night 2010-04-01
|
|
7
|
-
uv run reduce run UVES HD132205 --steps bias,flat,
|
|
8
|
-
uv run reduce
|
|
7
|
+
uv run reduce run UVES HD132205 --steps bias,flat,trace
|
|
8
|
+
uv run reduce trace UVES HD132205
|
|
9
9
|
uv run reduce combine --output combined.fits *.final.fits
|
|
10
10
|
"""
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ import click
|
|
|
14
14
|
ALL_STEPS = (
|
|
15
15
|
"bias",
|
|
16
16
|
"flat",
|
|
17
|
-
"
|
|
17
|
+
"trace",
|
|
18
18
|
"curvature",
|
|
19
19
|
"scatter",
|
|
20
20
|
"norm_flat",
|
|
@@ -67,6 +67,12 @@ def cli():
|
|
|
67
67
|
default=None,
|
|
68
68
|
help="Order range to process (e.g., '1,21')",
|
|
69
69
|
)
|
|
70
|
+
@click.option(
|
|
71
|
+
"--settings",
|
|
72
|
+
default=None,
|
|
73
|
+
type=click.Path(exists=True),
|
|
74
|
+
help="JSON file with settings overrides",
|
|
75
|
+
)
|
|
70
76
|
def run(
|
|
71
77
|
instrument,
|
|
72
78
|
target,
|
|
@@ -78,13 +84,14 @@ def run(
|
|
|
78
84
|
output_dir,
|
|
79
85
|
plot,
|
|
80
86
|
order_range,
|
|
87
|
+
settings,
|
|
81
88
|
):
|
|
82
89
|
"""Run the reduction pipeline.
|
|
83
90
|
|
|
84
91
|
INSTRUMENT: Name of the instrument (e.g., UVES, HARPS, XSHOOTER)
|
|
85
92
|
TARGET: Target star name or regex pattern
|
|
86
93
|
"""
|
|
87
|
-
from .configuration import get_configuration_for_instrument
|
|
94
|
+
from .configuration import get_configuration_for_instrument, load_settings_override
|
|
88
95
|
from .reduce import main as reduce_main
|
|
89
96
|
|
|
90
97
|
# Parse steps
|
|
@@ -100,6 +107,8 @@ def run(
|
|
|
100
107
|
|
|
101
108
|
# Load configuration
|
|
102
109
|
config = get_configuration_for_instrument(instrument)
|
|
110
|
+
if settings:
|
|
111
|
+
config = load_settings_override(config, settings)
|
|
103
112
|
|
|
104
113
|
# Run reduction
|
|
105
114
|
reduce_main(
|
|
@@ -279,30 +288,115 @@ def make_step_command(step_name):
|
|
|
279
288
|
|
|
280
289
|
@click.command(name=step_name)
|
|
281
290
|
@click.argument("instrument")
|
|
282
|
-
@click.argument("target")
|
|
291
|
+
@click.argument("target", required=False, default="")
|
|
283
292
|
@click.option("--night", "-n", default=None, help="Observation night")
|
|
284
293
|
@click.option("--channel", "-c", default=None, help="Instrument channel")
|
|
285
294
|
@click.option("--base-dir", "-b", default=None, help="Base directory")
|
|
286
295
|
@click.option("--input-dir", "-i", default="raw", help="Input directory")
|
|
287
296
|
@click.option("--output-dir", "-o", default="reduced", help="Output directory")
|
|
288
297
|
@click.option("--plot", "-p", default=0, help="Plot level")
|
|
289
|
-
|
|
290
|
-
|
|
298
|
+
@click.option(
|
|
299
|
+
"--file",
|
|
300
|
+
"-f",
|
|
301
|
+
default=None,
|
|
302
|
+
help="Specific input file (bypasses file discovery)",
|
|
303
|
+
)
|
|
304
|
+
@click.option(
|
|
305
|
+
"--settings",
|
|
306
|
+
default=None,
|
|
307
|
+
type=click.Path(exists=True),
|
|
308
|
+
help="JSON file with settings overrides",
|
|
309
|
+
)
|
|
310
|
+
def cmd(
|
|
311
|
+
instrument,
|
|
312
|
+
target,
|
|
313
|
+
night,
|
|
314
|
+
channel,
|
|
315
|
+
base_dir,
|
|
316
|
+
input_dir,
|
|
317
|
+
output_dir,
|
|
318
|
+
plot,
|
|
319
|
+
file,
|
|
320
|
+
settings,
|
|
321
|
+
):
|
|
322
|
+
from .configuration import (
|
|
323
|
+
get_configuration_for_instrument,
|
|
324
|
+
load_settings_override,
|
|
325
|
+
)
|
|
291
326
|
from .reduce import main as reduce_main
|
|
292
327
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
328
|
+
if file:
|
|
329
|
+
# Direct file mode: run step on specific file
|
|
330
|
+
import os
|
|
331
|
+
|
|
332
|
+
import numpy as np
|
|
333
|
+
|
|
334
|
+
from . import reduce as reduce_module
|
|
335
|
+
from .instruments.instrument_info import load_instrument
|
|
336
|
+
|
|
337
|
+
inst = load_instrument(instrument)
|
|
338
|
+
channel = channel or (inst.channels[0] if inst.channels else "")
|
|
339
|
+
output_dir_full = output_dir
|
|
340
|
+
if base_dir:
|
|
341
|
+
output_dir_full = os.path.join(base_dir, output_dir)
|
|
342
|
+
os.makedirs(output_dir_full, exist_ok=True)
|
|
343
|
+
|
|
344
|
+
# Load configuration for this step
|
|
345
|
+
config = get_configuration_for_instrument(instrument)
|
|
346
|
+
if settings:
|
|
347
|
+
config = load_settings_override(config, settings)
|
|
348
|
+
step_config = config.get(step_name, {})
|
|
349
|
+
step_config["plot"] = plot
|
|
350
|
+
|
|
351
|
+
# Get the step class
|
|
352
|
+
step_classes = {
|
|
353
|
+
"bias": reduce_module.Bias,
|
|
354
|
+
"flat": reduce_module.Flat,
|
|
355
|
+
"trace": reduce_module.OrderTracing,
|
|
356
|
+
"curvature": reduce_module.SlitCurvatureDetermination,
|
|
357
|
+
"scatter": reduce_module.BackgroundScatter,
|
|
358
|
+
"norm_flat": reduce_module.NormalizeFlatField,
|
|
359
|
+
"wavecal_master": reduce_module.WavelengthCalibrationMaster,
|
|
360
|
+
"wavecal_init": reduce_module.WavelengthCalibrationInitialize,
|
|
361
|
+
"wavecal": reduce_module.WavelengthCalibrationFinalize,
|
|
362
|
+
"freq_comb_master": reduce_module.LaserFrequencyCombMaster,
|
|
363
|
+
"freq_comb": reduce_module.LaserFrequencyCombFinalize,
|
|
364
|
+
"science": reduce_module.ScienceExtraction,
|
|
365
|
+
"continuum": reduce_module.ContinuumNormalization,
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if step_name not in step_classes:
|
|
369
|
+
raise click.ClickException(
|
|
370
|
+
f"Step '{step_name}' does not support --file option"
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
step_class = step_classes[step_name]
|
|
374
|
+
step = step_class(
|
|
375
|
+
inst,
|
|
376
|
+
channel,
|
|
377
|
+
target=target or "",
|
|
378
|
+
night=night,
|
|
379
|
+
output_dir=output_dir_full,
|
|
380
|
+
order_range=None,
|
|
381
|
+
**step_config,
|
|
382
|
+
)
|
|
383
|
+
step.run(files=np.array([file]), mask=None, bias=None)
|
|
384
|
+
else:
|
|
385
|
+
config = get_configuration_for_instrument(instrument)
|
|
386
|
+
if settings:
|
|
387
|
+
config = load_settings_override(config, settings)
|
|
388
|
+
reduce_main(
|
|
389
|
+
instrument=instrument,
|
|
390
|
+
target=target,
|
|
391
|
+
night=night,
|
|
392
|
+
channels=channel,
|
|
393
|
+
steps=(step_name,),
|
|
394
|
+
base_dir=base_dir or "",
|
|
395
|
+
input_dir=input_dir,
|
|
396
|
+
output_dir=output_dir,
|
|
397
|
+
configuration=config,
|
|
398
|
+
plot=plot,
|
|
399
|
+
)
|
|
306
400
|
|
|
307
401
|
cmd.__doc__ = f"Run the '{step_name}' step."
|
|
308
402
|
return cmd
|
pyreduce/cli.py
CHANGED
|
@@ -287,7 +287,7 @@ def run(config_file: str, steps: str, skip_existing: bool, plot: int):
|
|
|
287
287
|
pipe = pipe.flat(_expand_globs(files["flat"]))
|
|
288
288
|
|
|
289
289
|
if "trace" in config_steps:
|
|
290
|
-
trace_files = files.get("
|
|
290
|
+
trace_files = files.get("trace") or files.get("flat")
|
|
291
291
|
pipe = pipe.trace_orders(_expand_globs(trace_files) if trace_files else None)
|
|
292
292
|
|
|
293
293
|
if "scatter" in config_steps:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
pyreduce/combine_frames.py
CHANGED
|
@@ -305,6 +305,14 @@ def combine_frames(
|
|
|
305
305
|
if instrument is None or isinstance(instrument, str):
|
|
306
306
|
instrument = load_instrument(instrument)
|
|
307
307
|
|
|
308
|
+
# For multi-amplifier instruments, use simple combination since the
|
|
309
|
+
# row-by-row approach doesn't work with multi-extension assembly
|
|
310
|
+
if instrument.config.amplifiers is not None:
|
|
311
|
+
logger.debug("Multi-amplifier instrument detected, using simple combination")
|
|
312
|
+
return combine_frames_simple(
|
|
313
|
+
files, instrument, channel, extension=extension, dtype=dtype, **kwargs
|
|
314
|
+
)
|
|
315
|
+
|
|
308
316
|
# summarize file info
|
|
309
317
|
logger.debug("Files:")
|
|
310
318
|
for i, fname in zip(range(len(files)), files, strict=False):
|
pyreduce/configuration.py
CHANGED
|
@@ -43,6 +43,26 @@ def get_configuration_for_instrument(instrument, **kwargs):
|
|
|
43
43
|
return config
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def load_settings_override(config, settings_file):
|
|
47
|
+
"""Apply settings overrides from a JSON file.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
config : dict
|
|
52
|
+
Base configuration to override
|
|
53
|
+
settings_file : str
|
|
54
|
+
Path to JSON file with override settings
|
|
55
|
+
|
|
56
|
+
Returns
|
|
57
|
+
-------
|
|
58
|
+
config : dict
|
|
59
|
+
Updated configuration
|
|
60
|
+
"""
|
|
61
|
+
with open(settings_file) as f:
|
|
62
|
+
overrides = json.load(f)
|
|
63
|
+
return update(config, overrides, check=False)
|
|
64
|
+
|
|
65
|
+
|
|
46
66
|
def load_config(configuration, instrument, j=0):
|
|
47
67
|
if configuration is None:
|
|
48
68
|
logger.info(
|
|
@@ -18,7 +18,7 @@ def estimate_background_scatter(
|
|
|
18
18
|
img,
|
|
19
19
|
orders,
|
|
20
20
|
column_range=None,
|
|
21
|
-
|
|
21
|
+
extraction_height=0.1,
|
|
22
22
|
scatter_degree=4,
|
|
23
23
|
sigma_cutoff=2,
|
|
24
24
|
border_width=10,
|
|
@@ -38,7 +38,7 @@ def estimate_background_scatter(
|
|
|
38
38
|
order polynomial coefficients
|
|
39
39
|
column_range : array[nord, 2], optional
|
|
40
40
|
range of columns to use in each order (default: None == all columns)
|
|
41
|
-
|
|
41
|
+
extraction_height : float, array[nord, 2], optional
|
|
42
42
|
extraction width for each order, values below 1.5 are considered fractional, others as number of pixels (default: 0.1)
|
|
43
43
|
scatter_degree : int, optional
|
|
44
44
|
polynomial degree of the 2d fit for the background scatter (default: 4)
|
|
@@ -56,8 +56,8 @@ def estimate_background_scatter(
|
|
|
56
56
|
nrow, ncol = img.shape
|
|
57
57
|
nord, _ = orders.shape
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
extraction_height, column_range, orders = fix_parameters(
|
|
60
|
+
extraction_height,
|
|
61
61
|
column_range,
|
|
62
62
|
orders,
|
|
63
63
|
nrow,
|
|
@@ -73,16 +73,16 @@ def estimate_background_scatter(
|
|
|
73
73
|
mask[:bw] = mask[-bw:] = mask[:, :bw] = mask[:, -bw:] = False
|
|
74
74
|
for i in range(nord):
|
|
75
75
|
left, right = column_range[i]
|
|
76
|
-
left -=
|
|
77
|
-
right +=
|
|
76
|
+
left -= extraction_height[i, 1] * 2
|
|
77
|
+
right += extraction_height[i, 0] * 2
|
|
78
78
|
left = max(0, left)
|
|
79
79
|
right = min(ncol, right)
|
|
80
80
|
|
|
81
81
|
x_order = np.arange(left, right)
|
|
82
82
|
y_order = np.polyval(orders[i], x_order)
|
|
83
83
|
|
|
84
|
-
y_above = y_order +
|
|
85
|
-
y_below = y_order -
|
|
84
|
+
y_above = y_order + extraction_height[i, 1]
|
|
85
|
+
y_below = y_order - extraction_height[i, 0]
|
|
86
86
|
|
|
87
87
|
y_above = np.floor(y_above)
|
|
88
88
|
y_below = np.ceil(y_below)
|