Loading config/config_overall.yaml +5 −5 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ # ok to pass either way or both, as long as they are consistent # work_dir: "/public/home/fangyuedong/project/workplace/" work_dir: "/home/yuedong/Work/CSST_sim/output/" run_name: "test_ghost" run_name: "legacy_v1" data_set: "csst-msc-c11-1000sqdeg-wide-v1" # Project cycle and run counter are used to name the outputs Loading @@ -21,7 +21,7 @@ run_counter: 1 # Versioned detector definitions used by Chip and the readout simulation steps instrument_data: release: next-v1 release: legacy-v1 release_directory: null detector_overrides: {} Loading Loading @@ -113,8 +113,8 @@ psf_setting: # path to PSF data # NOTE: only valid for "Interp" PSF # PSF models for photometry survey simulation # psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/PSFCube/set1_dynamic/" psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/psfCube202607/" psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/PSFCube/set1_dynamic/" # psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/psfCube202607/" # PSF models for slitless spectrum survey simulation psf_sls_dir: "/home/yuedong/Work/CSST_sim/input_data/PSFCube/SLS_PSF_PCA_fp/" Loading @@ -136,7 +136,7 @@ shear_setting: # Output options ############################################### output_setting: # format_output: NO # Whether to export as 16 channels (subimages) with pre- and over-scan ("image"/"channels") # format_output: YES # Whether to export as 16 channels (subimages) with pre- and over-scan ("image"/"channels") shutter_output: NO # Whether to export shutter effect 16-bit image prnu_output: NO # Whether to export the PRNU (pixel-to-pixel flat-fielding) files Loading config/obs_config_SCI.yaml +2 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ obs_id: "00000001" # this setting will only be used if pointing list file is not # Define list of chips # run_chips: [6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,23,24,25] # Photometric chips #run_chips: [1,2,3,4,5,10,21,26,27,28,29,30] # Spectroscopic chips run_chips: [7] run_chips: [8] # Define observation sequence call_sequence: Loading Loading @@ -89,5 +89,5 @@ call_sequence: gain_16channel: YES # Output the final image quantization_and_output: format_output: NO format_output: YES ... csst_msc_instrument/definition_sets/legacy/1.0.0/readout_modes.yaml +58 −16 Original line number Diff line number Diff line Loading @@ -47,48 +47,69 @@ readout_modes: raw_mosaic_bbox: {x0: 8750, y0: 0, width: 1250, height: 4700} - id: CH09 detector_bbox: {x0: 0, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 0, y0: 4700, width: 1250, height: 4700} - id: CH10 detector_bbox: {x0: 1152, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 1250, y0: 4700, width: 1250, height: 4700} - id: CH11 detector_bbox: {x0: 2304, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 2500, y0: 4700, width: 1250, height: 4700} - id: CH12 detector_bbox: {x0: 3456, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 3750, y0: 4700, width: 1250, height: 4700} - id: CH13 detector_bbox: {x0: 4608, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 5000, y0: 4700, width: 1250, height: 4700} - id: CH14 detector_bbox: {x0: 5760, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 6250, y0: 4700, width: 1250, height: 4700} - id: CH15 detector_bbox: {x0: 6912, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 7500, y0: 4700, width: 1250, height: 4700} - id: CH16 detector_bbox: {x0: 8064, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 8750, y0: 4700, width: 1250, height: 4700} raw_output: layout: single_mosaic mosaic_shape: {columns: 10000, rows: 9400} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] formatted_output: layout: single_mosaic mosaic_shape: {columns: 20000, rows: 4700} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] channel_placements: CH01: {x0: 0, y0: 0, width: 1250, height: 4700} CH02: {x0: 1250, y0: 0, width: 1250, height: 4700} CH03: {x0: 2500, y0: 0, width: 1250, height: 4700} CH04: {x0: 3750, y0: 0, width: 1250, height: 4700} CH05: {x0: 5000, y0: 0, width: 1250, height: 4700} CH06: {x0: 6250, y0: 0, width: 1250, height: 4700} CH07: {x0: 7500, y0: 0, width: 1250, height: 4700} CH08: {x0: 8750, y0: 0, width: 1250, height: 4700} CH16: {x0: 10000, y0: 0, width: 1250, height: 4700} CH15: {x0: 11250, y0: 0, width: 1250, height: 4700} CH14: {x0: 12500, y0: 0, width: 1250, height: 4700} CH13: {x0: 13750, y0: 0, width: 1250, height: 4700} CH12: {x0: 15000, y0: 0, width: 1250, height: 4700} CH11: {x0: 16250, y0: 0, width: 1250, height: 4700} CH10: {x0: 17500, y0: 0, width: 1250, height: 4700} CH09: {x0: 18750, y0: 0, width: 1250, height: 4700} fgs_16ch_legacy: detector_family: fgs_cmos Loading Loading @@ -136,45 +157,66 @@ readout_modes: raw_mosaic_bbox: {x0: 10542, y0: 0, width: 1506, height: 3924} - id: CH09 detector_bbox: {x0: 0, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 0, y0: 3924, width: 1506, height: 3924} - id: CH10 detector_bbox: {x0: 1408, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 1506, y0: 3924, width: 1506, height: 3924} - id: CH11 detector_bbox: {x0: 2816, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 3012, y0: 3924, width: 1506, height: 3924} - id: CH12 detector_bbox: {x0: 4224, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 4518, y0: 3924, width: 1506, height: 3924} - id: CH13 detector_bbox: {x0: 5632, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 6024, y0: 3924, width: 1506, height: 3924} - id: CH14 detector_bbox: {x0: 7040, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 7530, y0: 3924, width: 1506, height: 3924} - id: CH15 detector_bbox: {x0: 8448, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 9036, y0: 3924, width: 1506, height: 3924} - id: CH16 detector_bbox: {x0: 9856, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 10542, y0: 3924, width: 1506, height: 3924} raw_output: layout: single_mosaic mosaic_shape: {columns: 12048, rows: 7848} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] formatted_output: layout: single_mosaic mosaic_shape: {columns: 24096, rows: 3924} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] channel_placements: CH01: {x0: 0, y0: 0, width: 1506, height: 3924} CH02: {x0: 1506, y0: 0, width: 1506, height: 3924} CH03: {x0: 3012, y0: 0, width: 1506, height: 3924} CH04: {x0: 4518, y0: 0, width: 1506, height: 3924} CH05: {x0: 6024, y0: 0, width: 1506, height: 3924} CH06: {x0: 7530, y0: 0, width: 1506, height: 3924} CH07: {x0: 9036, y0: 0, width: 1506, height: 3924} CH08: {x0: 10542, y0: 0, width: 1506, height: 3924} CH16: {x0: 12048, y0: 0, width: 1506, height: 3924} CH15: {x0: 13554, y0: 0, width: 1506, height: 3924} CH14: {x0: 15060, y0: 0, width: 1506, height: 3924} CH13: {x0: 16566, y0: 0, width: 1506, height: 3924} CH12: {x0: 18072, y0: 0, width: 1506, height: 3924} CH11: {x0: 19578, y0: 0, width: 1506, height: 3924} CH10: {x0: 21084, y0: 0, width: 1506, height: 3924} CH09: {x0: 22590, y0: 0, width: 1506, height: 3924} csst_msc_instrument/models.py +29 −0 Original line number Diff line number Diff line Loading @@ -173,12 +173,27 @@ class RawOutput(StrictModel): return tuple(value) class FormattedOutput(StrictModel): """Placement of processed raw channel frames in a delivered mosaic.""" layout: Literal["single_mosaic"] mosaic_shape: PixelShape channel_order: tuple[str, ...] channel_placements: dict[str, BBox] @field_validator("channel_order", mode="before") @classmethod def freeze_channel_order(cls, value): return tuple(value) class ReadoutMode(StrictModel): detector_family: str detector_types: tuple[str, ...] = () require_full_active_coverage: bool = True channels: tuple[ChannelGeometry, ...] raw_output: RawOutput formatted_output: FormattedOutput | None = None @field_validator("detector_types", mode="before") @classmethod Loading Loading @@ -206,6 +221,20 @@ class ReadoutMode(StrictModel): raise ValueError( "raw_output.channel_order must list every channel exactly once" ) formatted = self.formatted_output if formatted is not None: formatted_order = formatted.channel_order if len(formatted_order) != len(set(formatted_order)): raise ValueError("formatted_output.channel_order contains duplicates") if set(ids) != set(formatted_order): raise ValueError( "formatted_output.channel_order must list every channel exactly once" ) if set(ids) != set(formatted.channel_placements): raise ValueError( "formatted_output.channel_placements must place every channel " "exactly once" ) return self def channel(self, channel_id: str) -> ChannelGeometry: Loading csst_msc_instrument/repository.py +54 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,36 @@ class ResolvedDetector: mosaic[channel.raw_mosaic_slices] = raw return mosaic def format_raw_output(self, raw_mosaic: np.ndarray) -> np.ndarray: """Place processed raw channel frames in the delivered output mosaic.""" raw_output = self.readout_mode.raw_output if raw_output.layout != "single_mosaic" or raw_output.mosaic_shape is None: raise ValueError( f"readout mode {self.readout_mode_id!r} does not define a raw mosaic" ) expected = (raw_output.mosaic_shape.rows, raw_output.mosaic_shape.columns) if raw_mosaic.shape != expected: raise ValueError( f"raw mosaic shape is {raw_mosaic.shape}, expected {expected}" ) output = self.readout_mode.formatted_output if output is None: raise ValueError( f"readout mode {self.readout_mode_id!r} does not define a " "formatted output" ) formatted = np.zeros( (output.mosaic_shape.rows, output.mosaic_shape.columns), dtype=raw_mosaic.dtype, ) for channel_id in output.channel_order: channel = self.channel(channel_id) destination = output.channel_placements[channel_id] formatted[destination.slices] = raw_mosaic[channel.raw_mosaic_slices] return formatted @property def legacy_attributes(self) -> dict[str, object]: """Compatibility values for code not yet converted to the wrapper API.""" Loading Loading @@ -1206,6 +1236,30 @@ class InstrumentRepository: elif output.mosaic_shape is not None: raise ValueError("channel_hdus output must not define mosaic_shape") formatted = mode.formatted_output if formatted is not None: formatted_boxes = [] for channel_id in formatted.channel_order: channel = mode.channel(channel_id) box = formatted.channel_placements[channel_id] raw = channel.raw_shape if box.width != raw.columns or box.height != raw.rows: raise ValueError( f"channel {channel_id!r} formatted placement does not match " "raw_shape" ) if ( box.x1 > formatted.mosaic_shape.columns or box.y1 > formatted.mosaic_shape.rows ): raise ValueError( f"channel {channel_id!r} lies outside the formatted mosaic" ) formatted_boxes.append(box) InstrumentRepository._validate_no_overlap( formatted_boxes, mode_id, "formatted mosaic" ) @staticmethod def _validate_no_overlap(boxes: list[BBox], mode_id: str, space: str) -> None: for index, box in enumerate(boxes): Loading Loading
config/config_overall.yaml +5 −5 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ # ok to pass either way or both, as long as they are consistent # work_dir: "/public/home/fangyuedong/project/workplace/" work_dir: "/home/yuedong/Work/CSST_sim/output/" run_name: "test_ghost" run_name: "legacy_v1" data_set: "csst-msc-c11-1000sqdeg-wide-v1" # Project cycle and run counter are used to name the outputs Loading @@ -21,7 +21,7 @@ run_counter: 1 # Versioned detector definitions used by Chip and the readout simulation steps instrument_data: release: next-v1 release: legacy-v1 release_directory: null detector_overrides: {} Loading Loading @@ -113,8 +113,8 @@ psf_setting: # path to PSF data # NOTE: only valid for "Interp" PSF # PSF models for photometry survey simulation # psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/PSFCube/set1_dynamic/" psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/psfCube202607/" psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/PSFCube/set1_dynamic/" # psf_pho_dir: "/home/yuedong/Work/CSST_sim/input_data/psfCube202607/" # PSF models for slitless spectrum survey simulation psf_sls_dir: "/home/yuedong/Work/CSST_sim/input_data/PSFCube/SLS_PSF_PCA_fp/" Loading @@ -136,7 +136,7 @@ shear_setting: # Output options ############################################### output_setting: # format_output: NO # Whether to export as 16 channels (subimages) with pre- and over-scan ("image"/"channels") # format_output: YES # Whether to export as 16 channels (subimages) with pre- and over-scan ("image"/"channels") shutter_output: NO # Whether to export shutter effect 16-bit image prnu_output: NO # Whether to export the PRNU (pixel-to-pixel flat-fielding) files Loading
config/obs_config_SCI.yaml +2 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ obs_id: "00000001" # this setting will only be used if pointing list file is not # Define list of chips # run_chips: [6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,23,24,25] # Photometric chips #run_chips: [1,2,3,4,5,10,21,26,27,28,29,30] # Spectroscopic chips run_chips: [7] run_chips: [8] # Define observation sequence call_sequence: Loading Loading @@ -89,5 +89,5 @@ call_sequence: gain_16channel: YES # Output the final image quantization_and_output: format_output: NO format_output: YES ...
csst_msc_instrument/definition_sets/legacy/1.0.0/readout_modes.yaml +58 −16 Original line number Diff line number Diff line Loading @@ -47,48 +47,69 @@ readout_modes: raw_mosaic_bbox: {x0: 8750, y0: 0, width: 1250, height: 4700} - id: CH09 detector_bbox: {x0: 0, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 0, y0: 4700, width: 1250, height: 4700} - id: CH10 detector_bbox: {x0: 1152, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 1250, y0: 4700, width: 1250, height: 4700} - id: CH11 detector_bbox: {x0: 2304, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 2500, y0: 4700, width: 1250, height: 4700} - id: CH12 detector_bbox: {x0: 3456, y0: 4616, width: 1152, height: 4616} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *science_scan raw_mosaic_bbox: {x0: 3750, y0: 4700, width: 1250, height: 4700} - id: CH13 detector_bbox: {x0: 4608, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 5000, y0: 4700, width: 1250, height: 4700} - id: CH14 detector_bbox: {x0: 5760, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 6250, y0: 4700, width: 1250, height: 4700} - id: CH15 detector_bbox: {x0: 6912, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 7500, y0: 4700, width: 1250, height: 4700} - id: CH16 detector_bbox: {x0: 8064, y0: 4616, width: 1152, height: 4616} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *science_scan raw_mosaic_bbox: {x0: 8750, y0: 4700, width: 1250, height: 4700} raw_output: layout: single_mosaic mosaic_shape: {columns: 10000, rows: 9400} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] formatted_output: layout: single_mosaic mosaic_shape: {columns: 20000, rows: 4700} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] channel_placements: CH01: {x0: 0, y0: 0, width: 1250, height: 4700} CH02: {x0: 1250, y0: 0, width: 1250, height: 4700} CH03: {x0: 2500, y0: 0, width: 1250, height: 4700} CH04: {x0: 3750, y0: 0, width: 1250, height: 4700} CH05: {x0: 5000, y0: 0, width: 1250, height: 4700} CH06: {x0: 6250, y0: 0, width: 1250, height: 4700} CH07: {x0: 7500, y0: 0, width: 1250, height: 4700} CH08: {x0: 8750, y0: 0, width: 1250, height: 4700} CH16: {x0: 10000, y0: 0, width: 1250, height: 4700} CH15: {x0: 11250, y0: 0, width: 1250, height: 4700} CH14: {x0: 12500, y0: 0, width: 1250, height: 4700} CH13: {x0: 13750, y0: 0, width: 1250, height: 4700} CH12: {x0: 15000, y0: 0, width: 1250, height: 4700} CH11: {x0: 16250, y0: 0, width: 1250, height: 4700} CH10: {x0: 17500, y0: 0, width: 1250, height: 4700} CH09: {x0: 18750, y0: 0, width: 1250, height: 4700} fgs_16ch_legacy: detector_family: fgs_cmos Loading Loading @@ -136,45 +157,66 @@ readout_modes: raw_mosaic_bbox: {x0: 10542, y0: 0, width: 1506, height: 3924} - id: CH09 detector_bbox: {x0: 0, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 0, y0: 3924, width: 1506, height: 3924} - id: CH10 detector_bbox: {x0: 1408, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 1506, y0: 3924, width: 1506, height: 3924} - id: CH11 detector_bbox: {x0: 2816, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 3012, y0: 3924, width: 1506, height: 3924} - id: CH12 detector_bbox: {x0: 4224, y0: 3840, width: 1408, height: 3840} detector_to_raw: rotate_180 detector_to_raw: flip_y scan: *fgs_scan raw_mosaic_bbox: {x0: 4518, y0: 3924, width: 1506, height: 3924} - id: CH13 detector_bbox: {x0: 5632, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 6024, y0: 3924, width: 1506, height: 3924} - id: CH14 detector_bbox: {x0: 7040, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 7530, y0: 3924, width: 1506, height: 3924} - id: CH15 detector_bbox: {x0: 8448, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 9036, y0: 3924, width: 1506, height: 3924} - id: CH16 detector_bbox: {x0: 9856, y0: 3840, width: 1408, height: 3840} detector_to_raw: flip_y detector_to_raw: rotate_180 scan: *fgs_scan raw_mosaic_bbox: {x0: 10542, y0: 3924, width: 1506, height: 3924} raw_output: layout: single_mosaic mosaic_shape: {columns: 12048, rows: 7848} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] formatted_output: layout: single_mosaic mosaic_shape: {columns: 24096, rows: 3924} channel_order: [CH01, CH02, CH03, CH04, CH05, CH06, CH07, CH08, CH16, CH15, CH14, CH13, CH12, CH11, CH10, CH09] channel_placements: CH01: {x0: 0, y0: 0, width: 1506, height: 3924} CH02: {x0: 1506, y0: 0, width: 1506, height: 3924} CH03: {x0: 3012, y0: 0, width: 1506, height: 3924} CH04: {x0: 4518, y0: 0, width: 1506, height: 3924} CH05: {x0: 6024, y0: 0, width: 1506, height: 3924} CH06: {x0: 7530, y0: 0, width: 1506, height: 3924} CH07: {x0: 9036, y0: 0, width: 1506, height: 3924} CH08: {x0: 10542, y0: 0, width: 1506, height: 3924} CH16: {x0: 12048, y0: 0, width: 1506, height: 3924} CH15: {x0: 13554, y0: 0, width: 1506, height: 3924} CH14: {x0: 15060, y0: 0, width: 1506, height: 3924} CH13: {x0: 16566, y0: 0, width: 1506, height: 3924} CH12: {x0: 18072, y0: 0, width: 1506, height: 3924} CH11: {x0: 19578, y0: 0, width: 1506, height: 3924} CH10: {x0: 21084, y0: 0, width: 1506, height: 3924} CH09: {x0: 22590, y0: 0, width: 1506, height: 3924}
csst_msc_instrument/models.py +29 −0 Original line number Diff line number Diff line Loading @@ -173,12 +173,27 @@ class RawOutput(StrictModel): return tuple(value) class FormattedOutput(StrictModel): """Placement of processed raw channel frames in a delivered mosaic.""" layout: Literal["single_mosaic"] mosaic_shape: PixelShape channel_order: tuple[str, ...] channel_placements: dict[str, BBox] @field_validator("channel_order", mode="before") @classmethod def freeze_channel_order(cls, value): return tuple(value) class ReadoutMode(StrictModel): detector_family: str detector_types: tuple[str, ...] = () require_full_active_coverage: bool = True channels: tuple[ChannelGeometry, ...] raw_output: RawOutput formatted_output: FormattedOutput | None = None @field_validator("detector_types", mode="before") @classmethod Loading Loading @@ -206,6 +221,20 @@ class ReadoutMode(StrictModel): raise ValueError( "raw_output.channel_order must list every channel exactly once" ) formatted = self.formatted_output if formatted is not None: formatted_order = formatted.channel_order if len(formatted_order) != len(set(formatted_order)): raise ValueError("formatted_output.channel_order contains duplicates") if set(ids) != set(formatted_order): raise ValueError( "formatted_output.channel_order must list every channel exactly once" ) if set(ids) != set(formatted.channel_placements): raise ValueError( "formatted_output.channel_placements must place every channel " "exactly once" ) return self def channel(self, channel_id: str) -> ChannelGeometry: Loading
csst_msc_instrument/repository.py +54 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,36 @@ class ResolvedDetector: mosaic[channel.raw_mosaic_slices] = raw return mosaic def format_raw_output(self, raw_mosaic: np.ndarray) -> np.ndarray: """Place processed raw channel frames in the delivered output mosaic.""" raw_output = self.readout_mode.raw_output if raw_output.layout != "single_mosaic" or raw_output.mosaic_shape is None: raise ValueError( f"readout mode {self.readout_mode_id!r} does not define a raw mosaic" ) expected = (raw_output.mosaic_shape.rows, raw_output.mosaic_shape.columns) if raw_mosaic.shape != expected: raise ValueError( f"raw mosaic shape is {raw_mosaic.shape}, expected {expected}" ) output = self.readout_mode.formatted_output if output is None: raise ValueError( f"readout mode {self.readout_mode_id!r} does not define a " "formatted output" ) formatted = np.zeros( (output.mosaic_shape.rows, output.mosaic_shape.columns), dtype=raw_mosaic.dtype, ) for channel_id in output.channel_order: channel = self.channel(channel_id) destination = output.channel_placements[channel_id] formatted[destination.slices] = raw_mosaic[channel.raw_mosaic_slices] return formatted @property def legacy_attributes(self) -> dict[str, object]: """Compatibility values for code not yet converted to the wrapper API.""" Loading Loading @@ -1206,6 +1236,30 @@ class InstrumentRepository: elif output.mosaic_shape is not None: raise ValueError("channel_hdus output must not define mosaic_shape") formatted = mode.formatted_output if formatted is not None: formatted_boxes = [] for channel_id in formatted.channel_order: channel = mode.channel(channel_id) box = formatted.channel_placements[channel_id] raw = channel.raw_shape if box.width != raw.columns or box.height != raw.rows: raise ValueError( f"channel {channel_id!r} formatted placement does not match " "raw_shape" ) if ( box.x1 > formatted.mosaic_shape.columns or box.y1 > formatted.mosaic_shape.rows ): raise ValueError( f"channel {channel_id!r} lies outside the formatted mosaic" ) formatted_boxes.append(box) InstrumentRepository._validate_no_overlap( formatted_boxes, mode_id, "formatted mosaic" ) @staticmethod def _validate_no_overlap(boxes: list[BBox], mode_id: str, space: str) -> None: for index, box in enumerate(boxes): Loading