Skip to content

Commit ef37d6a

Browse files
ivhclaude
andcommitted
Add MOSAIC VIS quadrant support (VIS1-VIS4 channels)
VIS detector is a 12788x12394 mosaic with 4 quadrants separated by gaps. Each quadrant is processed as a separate channel with its own bundle centers. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4c0005e commit ef37d6a

9 files changed

Lines changed: 443 additions & 6 deletions

File tree

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@
7676
# - Groups 630 traces into 90 bundles of 7
7777
# - Selects center fiber from each bundle
7878
# - Uses grouped traces for curvature and science steps
79-
# pipe.trace_orders([flat_file])
80-
# pipe.curvature([thar_file])
79+
pipe.trace_orders([flat_file])
80+
pipe.curvature([thar_file])
8181
pipe.extract([thar_file, flat_file])
8282

8383
print("\n=== Running Pipeline ===")

examples/mosaic_vis.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# /// script
2+
# requires-python = ">=3.13"
3+
# dependencies = ["pyreduce-astro>=0.7b3"]
4+
# ///
5+
"""
6+
MOSAIC VIS spectrograph example.
7+
8+
The VIS detector is a 4-quadrant mosaic (12788x12394 pixels total).
9+
Each quadrant is processed as a separate channel:
10+
- VIS1: lower-left quadrant
11+
- VIS2: lower-right quadrant
12+
- VIS3: upper-left quadrant
13+
- VIS4: upper-right quadrant
14+
15+
This example processes VIS1. Run with different channel values for other quadrants.
16+
"""
17+
18+
import os
19+
from os.path import join
20+
21+
from pyreduce import util
22+
from pyreduce.configuration import load_config
23+
from pyreduce.pipeline import Pipeline
24+
25+
# Parameters
26+
# Change channel to VIS2, VIS3, or VIS4 for other quadrants
27+
instrument_name = "MOSAIC"
28+
target = "MOSAIC_VIS"
29+
night = ""
30+
channel = "VIS1"
31+
plot = 1
32+
33+
# Handle plot environment variables
34+
if "PYREDUCE_PLOT" in os.environ:
35+
plot = int(os.environ["PYREDUCE_PLOT"])
36+
plot_dir = os.environ.get("PYREDUCE_PLOT_DIR")
37+
util.set_plot_dir(plot_dir)
38+
39+
# Data location
40+
data_dir = os.environ.get("REDUCE_DATA", os.path.expanduser("~/REDUCE_DATA"))
41+
base_dir = join(data_dir, "MOSAIC", "REF_E2E", "VIS")
42+
output_dir = join(data_dir, "MOSAIC", "reduced", channel)
43+
44+
# File paths (simulated data)
45+
flat_file = join(
46+
base_dir,
47+
"E2E_as_built_FLAT_DIT_20s_MOSAIC_VIS_c01_FOCAL_PLANE_000.fits",
48+
)
49+
thar_file = join(
50+
base_dir,
51+
"E2E_as_built_ThAr_DIT_20s_MOSAIC_VIS_c01_FOCAL_PLANE.fits",
52+
)
53+
54+
# Verify files exist
55+
for fpath in [flat_file, thar_file]:
56+
if not os.path.exists(fpath):
57+
raise FileNotFoundError(f"Data file not found: {fpath}")
58+
59+
print(f"FLAT: {flat_file}")
60+
print(f"ThAr: {thar_file}")
61+
62+
# Load configuration
63+
config = load_config(None, instrument_name, plot)
64+
65+
# Create pipeline - fiber grouping is handled by config.yaml
66+
pipe = Pipeline(
67+
instrument=instrument_name,
68+
output_dir=output_dir,
69+
target=target,
70+
channel=channel,
71+
night=night,
72+
config=config,
73+
plot=plot,
74+
)
75+
76+
# Run pipeline steps
77+
pipe.trace_orders([flat_file])
78+
pipe.curvature([thar_file])
79+
pipe.extract([thar_file, flat_file])
80+
81+
print("\n=== Running Pipeline ===")
82+
results = pipe.run()
83+
84+
print("\n=== Results ===")
85+
orders, column_range = results["trace"]
86+
print(f"Raw traces: {len(orders)}")
87+
88+
if "trace_groups" in results and results["trace_groups"]:
89+
group_traces, group_cr = results["trace_groups"]
90+
print(
91+
f"Fiber groups: {list(group_traces.keys())[:5]}... ({len(group_traces)} total)"
92+
)

pyreduce/instruments/MOSAIC/__init__.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,37 @@
22
MOSAIC instrument - ELT multi-object spectrograph with 630 fibers.
33
44
NIR channel: 90 fiber groups (7 fibers each), 4096x4096 H4RG detector.
5+
VIS channel: 4 quadrants (VIS1-VIS4) from a 12788x12394 mosaic detector.
56
Fibers split into two halves with a gap in the middle.
67
"""
78

89
from ..common import Instrument
910

1011

1112
class MOSAIC(Instrument):
12-
pass
13+
# VIS detector quadrant boundaries (from gap analysis)
14+
# Full VIS frame: 12788 (height) x 12394 (width) pixels
15+
# Horizontal gap: rows 6144-6644, Vertical gap: cols 6144-6250
16+
# Active region: rows 2038-10734
17+
VIS_QUADRANTS = {
18+
"VIS1": {"xlo": 0, "xhi": 6144, "ylo": 2038, "yhi": 6144}, # lower-left
19+
"VIS2": {"xlo": 6250, "xhi": 12394, "ylo": 2038, "yhi": 6144}, # lower-right
20+
"VIS3": {"xlo": 0, "xhi": 6144, "ylo": 6644, "yhi": 10734}, # upper-left
21+
"VIS4": {"xlo": 6250, "xhi": 12394, "ylo": 6644, "yhi": 10734}, # upper-right
22+
}
23+
24+
def add_header_info(self, header, channel, **kwargs):
25+
"""Override to handle VIS quadrant extraction."""
26+
# Let parent populate all standard header info
27+
header = super().add_header_info(header, channel, **kwargs)
28+
29+
# For VIS quadrants, override the clip bounds
30+
channel_upper = channel.upper()
31+
if channel_upper in self.VIS_QUADRANTS:
32+
q = self.VIS_QUADRANTS[channel_upper]
33+
header["e_xlo"] = q["xlo"]
34+
header["e_xhi"] = q["xhi"]
35+
header["e_ylo"] = q["ylo"]
36+
header["e_yhi"] = q["yhi"]
37+
38+
return header
File renamed without changes.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Bundle centers for MOSAIC VIS1 (70 bundles)
2+
# Bundle ID -> y-position at detector center
3+
1: 39.0
4+
2: 100.0
5+
3: 160.5
6+
4: 221.0
7+
5: 281.5
8+
6: 342.0
9+
7: 402.5
10+
8: 463.0
11+
9: 524.0
12+
10: 584.5
13+
11: 645.0
14+
12: 705.5
15+
13: 766.0
16+
14: 827.0
17+
15: 887.0
18+
16: 948.0
19+
17: 1008.0
20+
18: 1069.0
21+
19: 1129.5
22+
20: 1190.5
23+
21: 1250.5
24+
22: 1311.5
25+
23: 1372.0
26+
24: 1432.5
27+
25: 1493.5
28+
26: 1553.5
29+
27: 1614.5
30+
28: 1675.0
31+
29: 1735.5
32+
30: 1796.0
33+
31: 1856.5
34+
32: 1917.0
35+
33: 1977.5
36+
34: 2038.5
37+
35: 2099.0
38+
36: 2159.5
39+
37: 2220.0
40+
38: 2281.0
41+
39: 2341.5
42+
40: 2402.0
43+
41: 2462.5
44+
42: 2523.0
45+
43: 2583.5
46+
44: 2644.5
47+
45: 2705.0
48+
46: 2765.5
49+
47: 2826.0
50+
48: 2886.5
51+
49: 2947.5
52+
50: 3007.5
53+
51: 3068.5
54+
52: 3129.0
55+
53: 3189.5
56+
54: 3250.0
57+
55: 3310.5
58+
56: 3371.5
59+
57: 3431.5
60+
58: 3492.5
61+
59: 3553.5
62+
60: 3613.5
63+
61: 3674.5
64+
62: 3734.5
65+
63: 3795.5
66+
64: 3856.0
67+
65: 3916.5
68+
66: 3969.5
69+
67: 3999.5
70+
68: 4022.5
71+
69: 4052.5
72+
70: 4087.0
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Bundle centers for MOSAIC VIS2 (70 bundles)
2+
# Bundle ID -> y-position at detector center
3+
1: 84.0
4+
2: 144.0
5+
3: 203.5
6+
4: 263.5
7+
5: 324.0
8+
6: 383.5
9+
7: 443.5
10+
8: 503.0
11+
9: 563.0
12+
10: 623.5
13+
11: 683.5
14+
12: 743.0
15+
13: 803.0
16+
14: 863.0
17+
15: 923.0
18+
16: 983.0
19+
17: 1043.0
20+
18: 1103.0
21+
19: 1163.0
22+
20: 1223.0
23+
21: 1282.5
24+
22: 1343.0
25+
23: 1403.0
26+
24: 1463.0
27+
25: 1522.5
28+
26: 1582.5
29+
27: 1642.5
30+
28: 1702.5
31+
29: 1762.5
32+
30: 1822.5
33+
31: 1882.5
34+
32: 1942.5
35+
33: 2002.5
36+
34: 2062.5
37+
35: 2122.5
38+
36: 2182.0
39+
37: 2242.5
40+
38: 2302.0
41+
39: 2362.5
42+
40: 2422.0
43+
41: 2482.5
44+
42: 2542.0
45+
43: 2602.0
46+
44: 2662.0
47+
45: 2722.0
48+
46: 2781.5
49+
47: 2842.0
50+
48: 2901.5
51+
49: 2961.5
52+
50: 3021.5
53+
51: 3081.5
54+
52: 3141.5
55+
53: 3201.5
56+
54: 3261.5
57+
55: 3321.5
58+
56: 3381.5
59+
57: 3441.5
60+
58: 3501.5
61+
59: 3561.5
62+
60: 3621.5
63+
61: 3681.5
64+
62: 3741.0
65+
63: 3801.0
66+
64: 3861.0
67+
65: 3921.5
68+
66: 3973.5
69+
67: 4003.5
70+
68: 4026.5
71+
69: 4055.5
72+
70: 4089.5
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Bundle centers for MOSAIC VIS3 (85 bundles)
2+
# Bundle ID -> y-position at detector center
3+
1: 9.5
4+
2: 51.5
5+
3: 111.5
6+
4: 172.5
7+
5: 233.0
8+
6: 293.5
9+
7: 354.5
10+
8: 414.5
11+
9: 475.5
12+
10: 517.0
13+
11: 547.2
14+
12: 592.5
15+
13: 619.5
16+
14: 657.0
17+
15: 717.5
18+
16: 778.5
19+
17: 838.5
20+
18: 899.5
21+
19: 960.0
22+
20: 1016.8
23+
21: 1081.0
24+
22: 1141.5
25+
23: 1202.5
26+
24: 1262.5
27+
25: 1319.8
28+
26: 1372.5
29+
27: 1403.0
30+
28: 1444.5
31+
29: 1509.0
32+
30: 1550.5
33+
31: 1581.0
34+
32: 1626.5
35+
33: 1687.0
36+
34: 1747.5
37+
35: 1808.5
38+
36: 1869.0
39+
37: 1906.5
40+
38: 1937.0
41+
39: 1990.0
42+
40: 2050.5
43+
41: 2111.0
44+
42: 2171.5
45+
43: 2209.5
46+
44: 2236.0
47+
45: 2293.0
48+
46: 2334.5
49+
47: 2364.5
50+
48: 2406.5
51+
49: 2436.5
52+
50: 2474.5
53+
51: 2535.0
54+
52: 2595.5
55+
53: 2656.5
56+
54: 2717.0
57+
55: 2762.5
58+
56: 2792.5
59+
57: 2838.0
60+
58: 2898.5
61+
59: 2940.2
62+
60: 2970.8
63+
61: 3020.0
64+
62: 3080.5
65+
63: 3141.0
66+
64: 3190.2
67+
65: 3224.5
68+
66: 3262.5
69+
67: 3330.5
70+
68: 3368.5
71+
69: 3402.5
72+
70: 3444.0
73+
71: 3508.5
74+
72: 3549.5
75+
73: 3580.0
76+
74: 3618.0
77+
75: 3686.5
78+
76: 3728.0
79+
77: 3758.2
80+
78: 3796.2
81+
79: 3830.5
82+
80: 3868.0
83+
81: 3906.0
84+
82: 3936.5
85+
83: 3974.0
86+
84: 4004.5
87+
85: 4049.5

0 commit comments

Comments
 (0)