|
11 | 11 | import astropy.units as u |
12 | 12 |
|
13 | 13 | from ctapipe.instrument.camera import PixelShape |
14 | | -from ctapipe.core import TelescopeComponent |
15 | | -from ctapipe.core.traits import Bool, Int |
| 14 | +from ctapipe.core import Component |
| 15 | +from ctapipe.core.traits import Bool, Int, Float |
16 | 16 |
|
17 | 17 | __all__ = [ |
18 | 18 | "ImageMapper", |
|
27 | 27 | "HexagonalPatchMapper", |
28 | 28 | ] |
29 | 29 |
|
30 | | -class ImageMapper(TelescopeComponent): |
| 30 | +class ImageMapper(Component): |
31 | 31 | """ |
32 | 32 | Base component for mapping raw 1D vectors into 2D mapped images. |
33 | 33 |
|
@@ -90,8 +90,23 @@ def __init__( |
90 | 90 | parent : ctapipe.core.Component or ctapipe.core.Tool |
91 | 91 | Parent of this component in the configuration hierarchy, |
92 | 92 | this is mutually exclusive with passing ``config`` |
| 93 | + **kwargs |
| 94 | + Additional keyword arguments for traitlets. Non-traitlet kwargs |
| 95 | + (like 'subarray') are filtered out for compatibility. |
93 | 96 | """ |
94 | 97 |
|
| 98 | + # Filter out non-traitlet kwargs before passing to Component |
| 99 | + # This allows compatibility with ctapipe's reader which may pass extra kwargs |
| 100 | + component_kwargs = { |
| 101 | + key: value for key, value in kwargs.items() |
| 102 | + if self.class_own_traits().get(key) is not None |
| 103 | + } |
| 104 | + |
| 105 | + super().__init__( |
| 106 | + config=config, |
| 107 | + parent=parent, |
| 108 | + **component_kwargs, |
| 109 | + ) |
95 | 110 | # Camera types |
96 | 111 | self.geometry = geometry |
97 | 112 | self.camera_type = self.geometry.name |
@@ -1259,6 +1274,16 @@ class RebinMapper(ImageMapper): |
1259 | 1274 | ), |
1260 | 1275 | ).tag(config=True) |
1261 | 1276 |
|
| 1277 | + max_memory_gb = Float( |
| 1278 | + default_value=10, |
| 1279 | + allow_none=True, |
| 1280 | + help=( |
| 1281 | + "Maximum memory in GB that RebinMapper is allowed to allocate. " |
| 1282 | + "Set to None to disable memory checks. Default is 10 GB. " |
| 1283 | + "Note: RebinMapper uses approximately (image_shape * 10)^2 * image_shape^2 * 4 bytes." |
| 1284 | + ), |
| 1285 | + ).tag(config=True) |
| 1286 | + |
1262 | 1287 | def __init__( |
1263 | 1288 | self, |
1264 | 1289 | geometry, |
@@ -1298,6 +1323,26 @@ def __init__( |
1298 | 1323 | self.image_shape = self.interpolation_image_shape |
1299 | 1324 | self.internal_shape = self.image_shape + self.internal_pad * 2 |
1300 | 1325 | self.rebinning_mult_factor = 10 |
| 1326 | + |
| 1327 | + # Validate memory requirements before proceeding (if max_memory_gb is set) |
| 1328 | + if self.max_memory_gb is not None: |
| 1329 | + # RebinMapper uses a fine grid (internal_shape * rebinning_mult_factor)^2 |
| 1330 | + # and creates a mapping matrix of shape (fine_grid_size, internal_shape, internal_shape) |
| 1331 | + fine_grid_size = (self.internal_shape * self.rebinning_mult_factor) ** 2 |
| 1332 | + estimated_memory_gb = ( |
| 1333 | + fine_grid_size * self.internal_shape * self.internal_shape * 4 |
| 1334 | + ) / (1024**3) # 4 bytes per float32 |
| 1335 | + |
| 1336 | + if estimated_memory_gb > self.max_memory_gb: |
| 1337 | + raise ValueError( |
| 1338 | + f"RebinMapper with image_shape={self.image_shape} would require " |
| 1339 | + f"approximately {estimated_memory_gb:.1f} GB of memory, which exceeds " |
| 1340 | + f"the limit of {self.max_memory_gb:.1f} GB. " |
| 1341 | + f"To allow this allocation, set max_memory_gb to a higher value or None. " |
| 1342 | + f"Alternatively, consider using a smaller interpolation_image_shape (recommended < 60) " |
| 1343 | + f"or use BilinearMapper or BicubicMapper instead, which are more memory-efficient." |
| 1344 | + ) |
| 1345 | + |
1301 | 1346 | # Creating the hexagonal and the output grid for the conversion methods. |
1302 | 1347 | input_grid, output_grid = super()._get_grids_for_interpolation() |
1303 | 1348 | # Calculate the mapping table |
|
0 commit comments